|
|
@ -14,9 +14,12 @@ from django.contrib.auth.decorators import login_required, user_passes_test
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.contrib.auth.models import User
|
|
|
|
from django.db.models import Count
|
|
|
|
from django.db.models import Count
|
|
|
|
from django.db import transaction
|
|
|
|
from django.db import transaction
|
|
|
|
from django.http import (HttpResponse,
|
|
|
|
from django.http import (
|
|
|
|
HttpResponseNotFound, HttpResponseRedirect,
|
|
|
|
HttpResponse,
|
|
|
|
JsonResponse)
|
|
|
|
HttpResponseNotFound,
|
|
|
|
|
|
|
|
HttpResponseRedirect,
|
|
|
|
|
|
|
|
JsonResponse,
|
|
|
|
|
|
|
|
)
|
|
|
|
from django.shortcuts import redirect, render
|
|
|
|
from django.shortcuts import redirect, render
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils import timezone
|
|
|
|
from django.utils.translation import ugettext as _
|
|
|
|
from django.utils.translation import ugettext as _
|
|
|
@ -39,10 +42,12 @@ def get_locations():
|
|
|
|
countries_d = dict(countries)
|
|
|
|
countries_d = dict(countries)
|
|
|
|
locations = django_lcore.get_clusters()
|
|
|
|
locations = django_lcore.get_clusters()
|
|
|
|
for (_), loc in locations:
|
|
|
|
for (_), loc in locations:
|
|
|
|
code = loc['country_code'].upper()
|
|
|
|
code = loc["country_code"].upper()
|
|
|
|
loc['country_name'] = countries_d.get(code, code)
|
|
|
|
loc["country_name"] = countries_d.get(code, code)
|
|
|
|
|
|
|
|
|
|
|
|
loc['load_percent'] = ceil((loc['usage'].get('net', 0) / (loc['bandwidth'] / 1e6)) * 100)
|
|
|
|
loc["load_percent"] = ceil(
|
|
|
|
|
|
|
|
(loc["usage"].get("net", 0) / (loc["bandwidth"] / 1e6)) * 100
|
|
|
|
|
|
|
|
)
|
|
|
|
locations = list(sorted(locations, key=lambda l: l[0]))
|
|
|
|
locations = list(sorted(locations, key=lambda l: l[0]))
|
|
|
|
return locations
|
|
|
|
return locations
|
|
|
|
|
|
|
|
|
|
|
@ -56,58 +61,61 @@ def log_errors(request, form):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ca_crt(request):
|
|
|
|
def ca_crt(request):
|
|
|
|
return HttpResponse(content=project_settings.OPENVPN_CA,
|
|
|
|
return HttpResponse(
|
|
|
|
content_type='application/x-x509-ca-cert')
|
|
|
|
content=project_settings.OPENVPN_CA, content_type="application/x-x509-ca-cert"
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def logout(request):
|
|
|
|
def logout(request):
|
|
|
|
auth.logout(request)
|
|
|
|
auth.logout(request)
|
|
|
|
return redirect('index')
|
|
|
|
return redirect("index")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def signup(request):
|
|
|
|
def signup(request):
|
|
|
|
if request.user.is_authenticated:
|
|
|
|
if request.user.is_authenticated:
|
|
|
|
return redirect('account:index')
|
|
|
|
return redirect("account:index")
|
|
|
|
|
|
|
|
|
|
|
|
if request.method != 'POST':
|
|
|
|
if request.method != "POST":
|
|
|
|
form = SignupForm()
|
|
|
|
form = SignupForm()
|
|
|
|
return render(request, 'ccvpn/signup.html', dict(form=form))
|
|
|
|
return render(request, "ccvpn/signup.html", dict(form=form))
|
|
|
|
|
|
|
|
|
|
|
|
form = SignupForm(request.POST)
|
|
|
|
form = SignupForm(request.POST)
|
|
|
|
|
|
|
|
|
|
|
|
grr = request.POST.get('g-recaptcha-response', '')
|
|
|
|
grr = request.POST.get("g-recaptcha-response", "")
|
|
|
|
if captcha_test(grr, request):
|
|
|
|
if captcha_test(grr, request):
|
|
|
|
request.session['signup_captcha_pass'] = True
|
|
|
|
request.session["signup_captcha_pass"] = True
|
|
|
|
elif not request.session.get('signup_captcha_pass'):
|
|
|
|
elif not request.session.get("signup_captcha_pass"):
|
|
|
|
messages.error(request, _("Invalid captcha. Please try again"))
|
|
|
|
messages.error(request, _("Invalid captcha. Please try again"))
|
|
|
|
return render(request, 'ccvpn/signup.html', dict(form=form))
|
|
|
|
return render(request, "ccvpn/signup.html", dict(form=form))
|
|
|
|
|
|
|
|
|
|
|
|
if not form.is_valid():
|
|
|
|
if not form.is_valid():
|
|
|
|
return render(request, 'ccvpn/signup.html', dict(form=form))
|
|
|
|
return render(request, "ccvpn/signup.html", dict(form=form))
|
|
|
|
|
|
|
|
|
|
|
|
user = User.objects.create_user(form.cleaned_data['username'],
|
|
|
|
user = User.objects.create_user(
|
|
|
|
form.cleaned_data['email'],
|
|
|
|
form.cleaned_data["username"],
|
|
|
|
form.cleaned_data['password'])
|
|
|
|
form.cleaned_data["email"],
|
|
|
|
|
|
|
|
form.cleaned_data["password"],
|
|
|
|
|
|
|
|
)
|
|
|
|
user.save()
|
|
|
|
user.save()
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
user.vpnuser.referrer = User.objects.get(id=request.session.get('referrer'))
|
|
|
|
user.vpnuser.referrer = User.objects.get(id=request.session.get("referrer"))
|
|
|
|
except User.DoesNotExist:
|
|
|
|
except User.DoesNotExist:
|
|
|
|
pass
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
user.vpnuser.campaign = request.session.get('campaign')
|
|
|
|
user.vpnuser.campaign = request.session.get("campaign")
|
|
|
|
user.vpnuser.add_paid_time(timedelta(days=7), 'trial')
|
|
|
|
user.vpnuser.add_paid_time(timedelta(days=7), "trial")
|
|
|
|
|
|
|
|
|
|
|
|
user.vpnuser.save()
|
|
|
|
user.vpnuser.save()
|
|
|
|
user.vpnuser.lcore_sync()
|
|
|
|
user.vpnuser.lcore_sync()
|
|
|
|
|
|
|
|
|
|
|
|
user.backend = 'django.contrib.auth.backends.ModelBackend'
|
|
|
|
user.backend = "django.contrib.auth.backends.ModelBackend"
|
|
|
|
auth.login(request, user)
|
|
|
|
auth.login(request, user)
|
|
|
|
|
|
|
|
|
|
|
|
# invalidate that captcha
|
|
|
|
# invalidate that captcha
|
|
|
|
request.session['signup_captcha_pass'] = False
|
|
|
|
request.session["signup_captcha_pass"] = False
|
|
|
|
|
|
|
|
|
|
|
|
return redirect('account:index')
|
|
|
|
return redirect("account:index")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@login_required
|
|
|
@ -118,70 +126,73 @@ def discourse_login(request):
|
|
|
|
if project_settings.DISCOURSE_SSO is not True:
|
|
|
|
if project_settings.DISCOURSE_SSO is not True:
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
|
|
|
|
|
|
|
|
payload = request.GET.get('sso', '')
|
|
|
|
payload = request.GET.get("sso", "")
|
|
|
|
signature = request.GET.get('sig', '')
|
|
|
|
signature = request.GET.get("sig", "")
|
|
|
|
|
|
|
|
|
|
|
|
expected_signature = hmac.new(sso_secret.encode('utf-8'),
|
|
|
|
expected_signature = hmac.new(
|
|
|
|
payload.encode('utf-8'),
|
|
|
|
sso_secret.encode("utf-8"), payload.encode("utf-8"), sha256
|
|
|
|
sha256).hexdigest()
|
|
|
|
).hexdigest()
|
|
|
|
|
|
|
|
|
|
|
|
if signature != expected_signature:
|
|
|
|
if signature != expected_signature:
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
|
|
|
|
|
|
|
|
if request.method == 'POST' and 'email' in request.POST:
|
|
|
|
if request.method == "POST" and "email" in request.POST:
|
|
|
|
form = ReqEmailForm(request.POST)
|
|
|
|
form = ReqEmailForm(request.POST)
|
|
|
|
if not form.is_valid():
|
|
|
|
if not form.is_valid():
|
|
|
|
return render(request, 'ccvpn/require_email.html', dict(form=form))
|
|
|
|
return render(request, "ccvpn/require_email.html", dict(form=form))
|
|
|
|
|
|
|
|
|
|
|
|
request.user.email = form.cleaned_data['email']
|
|
|
|
request.user.email = form.cleaned_data["email"]
|
|
|
|
request.user.save()
|
|
|
|
request.user.save()
|
|
|
|
|
|
|
|
|
|
|
|
if not request.user.email:
|
|
|
|
if not request.user.email:
|
|
|
|
form = ReqEmailForm()
|
|
|
|
form = ReqEmailForm()
|
|
|
|
return render(request, 'ccvpn/require_email.html', dict(form=form))
|
|
|
|
return render(request, "ccvpn/require_email.html", dict(form=form))
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
payload = base64.b64decode(payload).decode('utf-8')
|
|
|
|
payload = base64.b64decode(payload).decode("utf-8")
|
|
|
|
payload_data = dict(parse_qsl(payload))
|
|
|
|
payload_data = dict(parse_qsl(payload))
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
except (TypeError, ValueError):
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
|
|
|
|
|
|
|
|
payload_data.update({
|
|
|
|
payload_data.update(
|
|
|
|
'external_id': request.user.id,
|
|
|
|
{
|
|
|
|
'username': request.user.username,
|
|
|
|
"external_id": request.user.id,
|
|
|
|
'email': request.user.email,
|
|
|
|
"username": request.user.username,
|
|
|
|
'require_activation': 'true',
|
|
|
|
"email": request.user.email,
|
|
|
|
})
|
|
|
|
"require_activation": "true",
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
payload = urlencode(payload_data)
|
|
|
|
payload = urlencode(payload_data)
|
|
|
|
payload = base64.b64encode(payload.encode('utf-8'))
|
|
|
|
payload = base64.b64encode(payload.encode("utf-8"))
|
|
|
|
signature = hmac.new(sso_secret.encode('utf-8'), payload, sha256).hexdigest()
|
|
|
|
signature = hmac.new(sso_secret.encode("utf-8"), payload, sha256).hexdigest()
|
|
|
|
redirect_query = urlencode(dict(sso=payload, sig=signature))
|
|
|
|
redirect_query = urlencode(dict(sso=payload, sig=signature))
|
|
|
|
redirect_path = '/session/sso_login?' + redirect_query
|
|
|
|
redirect_path = "/session/sso_login?" + redirect_query
|
|
|
|
|
|
|
|
|
|
|
|
return HttpResponseRedirect(discourse_url + redirect_path)
|
|
|
|
return HttpResponseRedirect(discourse_url + redirect_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@login_required
|
|
|
|
def index(request):
|
|
|
|
def index(request):
|
|
|
|
ref_url = project_settings.ROOT_URL + '?ref=' + str(request.user.id)
|
|
|
|
ref_url = project_settings.ROOT_URL + "?ref=" + str(request.user.id)
|
|
|
|
|
|
|
|
|
|
|
|
twitter_url = 'https://twitter.com/intent/tweet?'
|
|
|
|
twitter_url = "https://twitter.com/intent/tweet?"
|
|
|
|
twitter_args = {
|
|
|
|
twitter_args = {
|
|
|
|
'text': _("Awesome VPN! 3€ per month, with a free 7 days trial!"),
|
|
|
|
"text": _("Awesome VPN! 3€ per month, with a free 7 days trial!"),
|
|
|
|
'via': 'CCrypto_VPN',
|
|
|
|
"via": "CCrypto_VPN",
|
|
|
|
'url': ref_url,
|
|
|
|
"url": ref_url,
|
|
|
|
'related': 'CCrypto_VPN,CCrypto_org'
|
|
|
|
"related": "CCrypto_VPN,CCrypto_org",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class price_fn:
|
|
|
|
class price_fn:
|
|
|
|
"""Clever hack to get the price in templates with {{price.3}} with
|
|
|
|
"""Clever hack to get the price in templates with {{price.3}} with
|
|
|
|
3 an arbitrary number of months
|
|
|
|
3 an arbitrary number of months
|
|
|
|
"""
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, months):
|
|
|
|
def __getitem__(self, months):
|
|
|
|
n = int(months) * get_price_float()
|
|
|
|
n = int(months) * get_price_float()
|
|
|
|
c = project_settings.PAYMENTS_CURRENCY[1]
|
|
|
|
c = project_settings.PAYMENTS_CURRENCY[1]
|
|
|
|
return '%.2f %s' % (n, c)
|
|
|
|
return "%.2f %s" % (n, c)
|
|
|
|
|
|
|
|
|
|
|
|
context = dict(
|
|
|
|
context = dict(
|
|
|
|
title=_("Account"),
|
|
|
|
title=_("Account"),
|
|
|
@ -189,15 +200,16 @@ def index(request):
|
|
|
|
twitter_link=twitter_url + urlencode(twitter_args),
|
|
|
|
twitter_link=twitter_url + urlencode(twitter_args),
|
|
|
|
subscription=request.user.vpnuser.get_subscription(),
|
|
|
|
subscription=request.user.vpnuser.get_subscription(),
|
|
|
|
backends=sorted(ACTIVE_BACKENDS.values(), key=lambda x: x.backend_display_name),
|
|
|
|
backends=sorted(ACTIVE_BACKENDS.values(), key=lambda x: x.backend_display_name),
|
|
|
|
subscr_backends=sorted((b for b in ACTIVE_BACKENDS.values()
|
|
|
|
subscr_backends=sorted(
|
|
|
|
if b.backend_has_recurring),
|
|
|
|
(b for b in ACTIVE_BACKENDS.values() if b.backend_has_recurring),
|
|
|
|
key=lambda x: x.backend_id),
|
|
|
|
key=lambda x: x.backend_id,
|
|
|
|
default_backend='paypal',
|
|
|
|
),
|
|
|
|
|
|
|
|
default_backend="paypal",
|
|
|
|
hcaptcha_site_key=project_settings.HCAPTCHA_SITE_KEY,
|
|
|
|
hcaptcha_site_key=project_settings.HCAPTCHA_SITE_KEY,
|
|
|
|
price=price_fn(),
|
|
|
|
price=price_fn(),
|
|
|
|
user_motd=site_config.MOTD_USER,
|
|
|
|
user_motd=site_config.MOTD_USER,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return render(request, 'lambdainst/account.html', context)
|
|
|
|
return render(request, "lambdainst/account.html", context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def captcha_test(grr, request):
|
|
|
|
def captcha_test(grr, request):
|
|
|
@ -206,18 +218,17 @@ def captcha_test(grr, request):
|
|
|
|
if not project_settings.HCAPTCHA_SITE_KEY:
|
|
|
|
if not project_settings.HCAPTCHA_SITE_KEY:
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
if api_url == 'TEST' and grr == 'TEST-TOKEN':
|
|
|
|
if api_url == "TEST" and grr == "TEST-TOKEN":
|
|
|
|
# FIXME: i'm sorry.
|
|
|
|
# FIXME: i'm sorry.
|
|
|
|
return True
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
data = dict(secret=project_settings.HCAPTCHA_SECRET_KEY,
|
|
|
|
data = dict(secret=project_settings.HCAPTCHA_SECRET_KEY, response=grr)
|
|
|
|
response=grr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
r = requests.post(api_url, data=data)
|
|
|
|
r = requests.post(api_url, data=data)
|
|
|
|
r.raise_for_status()
|
|
|
|
r.raise_for_status()
|
|
|
|
d = r.json()
|
|
|
|
d = r.json()
|
|
|
|
return d.get('success')
|
|
|
|
return d.get("success")
|
|
|
|
except (requests.ConnectionError, requests.HTTPError, ValueError):
|
|
|
|
except (requests.ConnectionError, requests.HTTPError, ValueError):
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
@ -233,13 +244,29 @@ def make_export_zip(user, name):
|
|
|
|
gw_cache = {}
|
|
|
|
gw_cache = {}
|
|
|
|
|
|
|
|
|
|
|
|
def process_wg_peer(item):
|
|
|
|
def process_wg_peer(item):
|
|
|
|
keys = {"gateway_port", "id", "local_ipv4", "local_ipv6", "name", "object",
|
|
|
|
keys = {
|
|
|
|
"private_key", "public_key"}
|
|
|
|
"gateway_port",
|
|
|
|
|
|
|
|
"id",
|
|
|
|
|
|
|
|
"local_ipv4",
|
|
|
|
|
|
|
|
"local_ipv6",
|
|
|
|
|
|
|
|
"name",
|
|
|
|
|
|
|
|
"object",
|
|
|
|
|
|
|
|
"private_key",
|
|
|
|
|
|
|
|
"public_key",
|
|
|
|
|
|
|
|
}
|
|
|
|
return {k: v for (k, v) in item.items() if k in keys}
|
|
|
|
return {k: v for (k, v) in item.items() if k in keys}
|
|
|
|
|
|
|
|
|
|
|
|
def process_ovpn_sess(item):
|
|
|
|
def process_ovpn_sess(item):
|
|
|
|
keys = {"connect_date", "disconnect_date", "remote", "object", "protocol", "id",
|
|
|
|
keys = {
|
|
|
|
"stats", "tunnel"}
|
|
|
|
"connect_date",
|
|
|
|
|
|
|
|
"disconnect_date",
|
|
|
|
|
|
|
|
"remote",
|
|
|
|
|
|
|
|
"object",
|
|
|
|
|
|
|
|
"protocol",
|
|
|
|
|
|
|
|
"id",
|
|
|
|
|
|
|
|
"stats",
|
|
|
|
|
|
|
|
"tunnel",
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def convert(v):
|
|
|
|
def convert(v):
|
|
|
|
if isinstance(v, datetime):
|
|
|
|
if isinstance(v, datetime):
|
|
|
@ -277,34 +304,43 @@ def make_export_zip(user, name):
|
|
|
|
return obj
|
|
|
|
return obj
|
|
|
|
|
|
|
|
|
|
|
|
with z.open(name + "/account.json", "w") as jf:
|
|
|
|
with z.open(name + "/account.json", "w") as jf:
|
|
|
|
jf.write(json.dumps({
|
|
|
|
jf.write(
|
|
|
|
|
|
|
|
json.dumps(
|
|
|
|
|
|
|
|
{
|
|
|
|
"username": user.username,
|
|
|
|
"username": user.username,
|
|
|
|
"email": user.email,
|
|
|
|
"email": user.email,
|
|
|
|
"date_joined": user.date_joined.isoformat(),
|
|
|
|
"date_joined": user.date_joined.isoformat(),
|
|
|
|
"expiration": user.vpnuser.expiration.isoformat() if user.vpnuser.expiration else None,
|
|
|
|
"expiration": user.vpnuser.expiration.isoformat()
|
|
|
|
}, indent=2).encode('ascii'))
|
|
|
|
if user.vpnuser.expiration
|
|
|
|
|
|
|
|
else None,
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
indent=2,
|
|
|
|
|
|
|
|
).encode("ascii")
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
with z.open(name + "/wireguard_peers.json", "w") as jf:
|
|
|
|
with z.open(name + "/wireguard_peers.json", "w") as jf:
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
keys = list(map(process_wg_peer, django_lcore.api.get_wg_peers(user.username)))
|
|
|
|
keys = list(
|
|
|
|
|
|
|
|
map(process_wg_peer, django_lcore.api.get_wg_peers(user.username))
|
|
|
|
|
|
|
|
)
|
|
|
|
except lcoreapi.APINotFoundError:
|
|
|
|
except lcoreapi.APINotFoundError:
|
|
|
|
keys = []
|
|
|
|
keys = []
|
|
|
|
jf.write(json.dumps(keys, indent=2).encode('ascii'))
|
|
|
|
jf.write(json.dumps(keys, indent=2).encode("ascii"))
|
|
|
|
|
|
|
|
|
|
|
|
with z.open(name + "/openvpn_logs.json", "w") as jf:
|
|
|
|
with z.open(name + "/openvpn_logs.json", "w") as jf:
|
|
|
|
base = django_lcore.api.info['current_instance']
|
|
|
|
base = django_lcore.api.info["current_instance"]
|
|
|
|
next_page = '/users/' + user.username + '/sessions/'
|
|
|
|
next_page = "/users/" + user.username + "/sessions/"
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
items = django_lcore.api.get(base + next_page).list_iter()
|
|
|
|
items = django_lcore.api.get(base + next_page).list_iter()
|
|
|
|
except lcoreapi.APINotFoundError:
|
|
|
|
except lcoreapi.APINotFoundError:
|
|
|
|
items = []
|
|
|
|
items = []
|
|
|
|
items = list(map(process_ovpn_sess, items))
|
|
|
|
items = list(map(process_ovpn_sess, items))
|
|
|
|
jf.write(json.dumps(items, indent=2).encode('ascii'))
|
|
|
|
jf.write(json.dumps(items, indent=2).encode("ascii"))
|
|
|
|
|
|
|
|
|
|
|
|
with z.open(name + "/payments.json", "w") as jf:
|
|
|
|
with z.open(name + "/payments.json", "w") as jf:
|
|
|
|
items = user.payment_set.all()
|
|
|
|
items = user.payment_set.all()
|
|
|
|
items = list(map(process_payments, items))
|
|
|
|
items = list(map(process_payments, items))
|
|
|
|
jf.write(json.dumps(items, indent=2).encode('ascii'))
|
|
|
|
jf.write(json.dumps(items, indent=2).encode("ascii"))
|
|
|
|
|
|
|
|
|
|
|
|
z.close()
|
|
|
|
z.close()
|
|
|
|
return f.getvalue()
|
|
|
|
return f.getvalue()
|
|
|
@ -330,33 +366,37 @@ def deactivate_user(user):
|
|
|
|
def settings(request):
|
|
|
|
def settings(request):
|
|
|
|
can_delete = request.user.vpnuser.get_subscription() is None
|
|
|
|
can_delete = request.user.vpnuser.get_subscription() is None
|
|
|
|
|
|
|
|
|
|
|
|
if request.method != 'POST':
|
|
|
|
if request.method != "POST":
|
|
|
|
return render(request, 'lambdainst/settings.html', dict(
|
|
|
|
return render(
|
|
|
|
|
|
|
|
request,
|
|
|
|
|
|
|
|
"lambdainst/settings.html",
|
|
|
|
|
|
|
|
dict(
|
|
|
|
can_delete=can_delete,
|
|
|
|
can_delete=can_delete,
|
|
|
|
))
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
action = request.POST.get('action')
|
|
|
|
action = request.POST.get("action")
|
|
|
|
|
|
|
|
|
|
|
|
current_pw = request.POST.get('current_password')
|
|
|
|
current_pw = request.POST.get("current_password")
|
|
|
|
if not request.user.check_password(current_pw):
|
|
|
|
if not request.user.check_password(current_pw):
|
|
|
|
messages.error(request, _("Invalid password"))
|
|
|
|
messages.error(request, _("Invalid password"))
|
|
|
|
return redirect('lambdainst:account_settings')
|
|
|
|
return redirect("lambdainst:account_settings")
|
|
|
|
|
|
|
|
|
|
|
|
if action == 'email':
|
|
|
|
if action == "email":
|
|
|
|
email = request.POST.get('email')
|
|
|
|
email = request.POST.get("email")
|
|
|
|
if email:
|
|
|
|
if email:
|
|
|
|
request.user.email = email
|
|
|
|
request.user.email = email
|
|
|
|
messages.success(request, _("OK! Email address changed."))
|
|
|
|
messages.success(request, _("OK! Email address changed."))
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
request.user.email = ''
|
|
|
|
request.user.email = ""
|
|
|
|
messages.success(request, _("OK! Email address unset."))
|
|
|
|
messages.success(request, _("OK! Email address unset."))
|
|
|
|
|
|
|
|
|
|
|
|
request.user.save()
|
|
|
|
request.user.save()
|
|
|
|
return redirect('lambdainst:account_settings')
|
|
|
|
return redirect("lambdainst:account_settings")
|
|
|
|
|
|
|
|
|
|
|
|
elif action == 'password':
|
|
|
|
elif action == "password":
|
|
|
|
pw = request.POST.get('password')
|
|
|
|
pw = request.POST.get("password")
|
|
|
|
pw2 = request.POST.get('password2')
|
|
|
|
pw2 = request.POST.get("password2")
|
|
|
|
if pw != pw2 or not pw:
|
|
|
|
if pw != pw2 or not pw:
|
|
|
|
messages.error(request, _("Password and confirmation do not match"))
|
|
|
|
messages.error(request, _("Password and confirmation do not match"))
|
|
|
|
else:
|
|
|
|
else:
|
|
|
@ -364,95 +404,120 @@ def settings(request):
|
|
|
|
messages.success(request, _("OK! Password changed."))
|
|
|
|
messages.success(request, _("OK! Password changed."))
|
|
|
|
request.user.save()
|
|
|
|
request.user.save()
|
|
|
|
django_lcore.sync_user(request.user.vpnuser)
|
|
|
|
django_lcore.sync_user(request.user.vpnuser)
|
|
|
|
return redirect('lambdainst:account_settings')
|
|
|
|
return redirect("lambdainst:account_settings")
|
|
|
|
|
|
|
|
|
|
|
|
elif action == 'export':
|
|
|
|
elif action == "export":
|
|
|
|
timestamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
|
|
|
|
timestamp = datetime.utcnow().strftime("%Y%m%dT%H%M%SZ")
|
|
|
|
data = make_export_zip(request.user, timestamp)
|
|
|
|
data = make_export_zip(request.user, timestamp)
|
|
|
|
r = HttpResponse(content=data, content_type="application/zip")
|
|
|
|
r = HttpResponse(content=data, content_type="application/zip")
|
|
|
|
r["Content-Disposition"] = 'attachment; filename="ccvpn-export-{}-{}.zip"'.format(request.user.username, timestamp)
|
|
|
|
r[
|
|
|
|
|
|
|
|
"Content-Disposition"
|
|
|
|
|
|
|
|
] = 'attachment; filename="ccvpn-export-{}-{}.zip"'.format(
|
|
|
|
|
|
|
|
request.user.username, timestamp
|
|
|
|
|
|
|
|
)
|
|
|
|
return r
|
|
|
|
return r
|
|
|
|
|
|
|
|
|
|
|
|
elif action == 'delete' and can_delete:
|
|
|
|
elif action == "delete" and can_delete:
|
|
|
|
with transaction.atomic():
|
|
|
|
with transaction.atomic():
|
|
|
|
deactivate_user(request.user)
|
|
|
|
deactivate_user(request.user)
|
|
|
|
logout(request)
|
|
|
|
logout(request)
|
|
|
|
messages.success(request, _("OK! Your account has been deactivated."))
|
|
|
|
messages.success(request, _("OK! Your account has been deactivated."))
|
|
|
|
return redirect('/')
|
|
|
|
return redirect("/")
|
|
|
|
|
|
|
|
|
|
|
|
return render(request, 'lambdainst/settings.html', dict(
|
|
|
|
return render(
|
|
|
|
|
|
|
|
request,
|
|
|
|
|
|
|
|
"lambdainst/settings.html",
|
|
|
|
|
|
|
|
dict(
|
|
|
|
title=_("Settings"),
|
|
|
|
title=_("Settings"),
|
|
|
|
user=request.user,
|
|
|
|
user=request.user,
|
|
|
|
can_delete=can_delete,
|
|
|
|
can_delete=can_delete,
|
|
|
|
))
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@login_required
|
|
|
|
def config(request):
|
|
|
|
def config(request):
|
|
|
|
return render(request, 'lambdainst/config.html', dict(
|
|
|
|
return render(
|
|
|
|
|
|
|
|
request,
|
|
|
|
|
|
|
|
"lambdainst/config.html",
|
|
|
|
|
|
|
|
dict(
|
|
|
|
title=_("Config"),
|
|
|
|
title=_("Config"),
|
|
|
|
config_os=django_lcore.openvpn.CONFIG_OS,
|
|
|
|
config_os=django_lcore.openvpn.CONFIG_OS,
|
|
|
|
config_countries=(c for _, c in get_locations()),
|
|
|
|
config_countries=(c for _, c in get_locations()),
|
|
|
|
config_protocols=django_lcore.openvpn.PROTOCOLS,
|
|
|
|
config_protocols=django_lcore.openvpn.PROTOCOLS,
|
|
|
|
))
|
|
|
|
),
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def api_locations(request):
|
|
|
|
def api_locations(request):
|
|
|
|
def format_loc(cc, l):
|
|
|
|
def format_loc(cc, l):
|
|
|
|
msg = ""
|
|
|
|
msg = ""
|
|
|
|
tags = l.get('tags', {})
|
|
|
|
tags = l.get("tags", {})
|
|
|
|
message = tags.get('message')
|
|
|
|
message = tags.get("message")
|
|
|
|
if message:
|
|
|
|
if message:
|
|
|
|
msg = " [%s]" % message
|
|
|
|
msg = " [%s]" % message
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
'country_name': l['country_name'] + msg,
|
|
|
|
"country_name": l["country_name"] + msg,
|
|
|
|
'country_code': cc,
|
|
|
|
"country_code": cc,
|
|
|
|
'hostname': l['hostname'],
|
|
|
|
"hostname": l["hostname"],
|
|
|
|
'bandwidth': l['bandwidth'],
|
|
|
|
"bandwidth": l["bandwidth"],
|
|
|
|
'servers': l['servers'],
|
|
|
|
"servers": l["servers"],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return JsonResponse(dict(locations=[format_loc(cc, l) for cc, l in get_locations()]))
|
|
|
|
|
|
|
|
|
|
|
|
return JsonResponse(
|
|
|
|
|
|
|
|
dict(locations=[format_loc(cc, l) for cc, l in get_locations()])
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def status(request):
|
|
|
|
def status(request):
|
|
|
|
locations = get_locations()
|
|
|
|
locations = get_locations()
|
|
|
|
|
|
|
|
|
|
|
|
ctx = {
|
|
|
|
ctx = {
|
|
|
|
'title': _("Servers"),
|
|
|
|
"title": _("Servers"),
|
|
|
|
'locations': locations,
|
|
|
|
"locations": locations,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return render(request, 'lambdainst/status.html', ctx)
|
|
|
|
return render(request, "lambdainst/status.html", ctx)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@user_passes_test(lambda user: user.is_staff)
|
|
|
|
@user_passes_test(lambda user: user.is_staff)
|
|
|
|
def admin_status(request):
|
|
|
|
def admin_status(request):
|
|
|
|
graph_name = request.GET.get('graph_name')
|
|
|
|
graph_name = request.GET.get("graph_name")
|
|
|
|
graph_period = request.GET.get('period')
|
|
|
|
graph_period = request.GET.get("period")
|
|
|
|
if graph_period not in ('y', 'm'):
|
|
|
|
if graph_period not in ("y", "m"):
|
|
|
|
graph_period = 'm'
|
|
|
|
graph_period = "m"
|
|
|
|
if graph_name:
|
|
|
|
if graph_name:
|
|
|
|
if graph_name == 'users':
|
|
|
|
if graph_name == "users":
|
|
|
|
content = graphs.users_graph(graph_period)
|
|
|
|
content = graphs.users_graph(graph_period)
|
|
|
|
elif graph_name == 'payments_paid':
|
|
|
|
elif graph_name == "payments_paid":
|
|
|
|
content = graphs.payments_paid_graph(graph_period)
|
|
|
|
content = graphs.payments_paid_graph(graph_period)
|
|
|
|
elif graph_name == 'payments_success':
|
|
|
|
elif graph_name == "payments_success":
|
|
|
|
content = graphs.payments_success_graph(graph_period)
|
|
|
|
content = graphs.payments_success_graph(graph_period)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
return HttpResponseNotFound()
|
|
|
|
return HttpResponse(content=content, content_type='image/svg+xml')
|
|
|
|
return HttpResponse(content=content, content_type="image/svg+xml")
|
|
|
|
|
|
|
|
|
|
|
|
payment_status = ((b, b.get_info()) for b in ACTIVE_BACKENDS.values())
|
|
|
|
payment_status = ((b, b.get_info()) for b in ACTIVE_BACKENDS.values())
|
|
|
|
payment_status = ((b, i) for (b, i) in payment_status if i)
|
|
|
|
payment_status = ((b, i) for (b, i) in payment_status if i)
|
|
|
|
|
|
|
|
|
|
|
|
lcore_keys = {'core_name', 'core_now', 'core_version', 'current_instance', 'key_public'}
|
|
|
|
lcore_keys = {
|
|
|
|
|
|
|
|
"core_name",
|
|
|
|
|
|
|
|
"core_now",
|
|
|
|
|
|
|
|
"core_version",
|
|
|
|
|
|
|
|
"current_instance",
|
|
|
|
|
|
|
|
"key_public",
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ctx = {
|
|
|
|
ctx = {
|
|
|
|
'api_status': {k: str(v) for k, v in django_lcore.api.info.items() if k in lcore_keys},
|
|
|
|
"api_status": {
|
|
|
|
'payment_backends': sorted(ACTIVE_BACKENDS.values(), key=lambda x: x.backend_id),
|
|
|
|
k: str(v) for k, v in django_lcore.api.info.items() if k in lcore_keys
|
|
|
|
'payment_status': payment_status,
|
|
|
|
},
|
|
|
|
|
|
|
|
"payment_backends": sorted(
|
|
|
|
|
|
|
|
ACTIVE_BACKENDS.values(), key=lambda x: x.backend_id
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
"payment_status": payment_status,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx.update(site.each_context(request))
|
|
|
|
ctx.update(site.each_context(request))
|
|
|
|
return render(request, 'lambdainst/admin_status.html', ctx)
|
|
|
|
return render(request, "lambdainst/admin_status.html", ctx)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@user_passes_test(lambda user: user.is_staff)
|
|
|
|
@user_passes_test(lambda user: user.is_staff)
|
|
|
@ -460,36 +525,40 @@ def admin_ref(request):
|
|
|
|
last_week = datetime.now() - timedelta(days=7)
|
|
|
|
last_week = datetime.now() - timedelta(days=7)
|
|
|
|
last_month = datetime.now() - timedelta(days=30)
|
|
|
|
last_month = datetime.now() - timedelta(days=30)
|
|
|
|
|
|
|
|
|
|
|
|
top_ref = User.objects.annotate(n_ref=Count('referrals')).order_by('-n_ref')[:10]
|
|
|
|
top_ref = User.objects.annotate(n_ref=Count("referrals")).order_by("-n_ref")[:10]
|
|
|
|
top_ref_week = User.objects.filter(referrals__user__date_joined__gt=last_week) \
|
|
|
|
top_ref_week = (
|
|
|
|
.annotate(n_ref=Count('referrals')) \
|
|
|
|
User.objects.filter(referrals__user__date_joined__gt=last_week)
|
|
|
|
.order_by('-n_ref')[:10]
|
|
|
|
.annotate(n_ref=Count("referrals"))
|
|
|
|
top_ref_month = User.objects.filter(referrals__user__date_joined__gt=last_month) \
|
|
|
|
.order_by("-n_ref")[:10]
|
|
|
|
.annotate(n_ref=Count('referrals')) \
|
|
|
|
)
|
|
|
|
.order_by('-n_ref')[:10]
|
|
|
|
top_ref_month = (
|
|
|
|
|
|
|
|
User.objects.filter(referrals__user__date_joined__gt=last_month)
|
|
|
|
|
|
|
|
.annotate(n_ref=Count("referrals"))
|
|
|
|
|
|
|
|
.order_by("-n_ref")[:10]
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
ctx = {
|
|
|
|
ctx = {
|
|
|
|
'top_ref': top_ref,
|
|
|
|
"top_ref": top_ref,
|
|
|
|
'top_ref_week': top_ref_week,
|
|
|
|
"top_ref_week": top_ref_week,
|
|
|
|
'top_ref_month': top_ref_month,
|
|
|
|
"top_ref_month": top_ref_month,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx.update(site.each_context(request))
|
|
|
|
ctx.update(site.each_context(request))
|
|
|
|
return render(request, 'lambdainst/admin_ref.html', ctx)
|
|
|
|
return render(request, "lambdainst/admin_ref.html", ctx)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@login_required
|
|
|
|
def wireguard(request):
|
|
|
|
def wireguard(request):
|
|
|
|
api = django_lcore.api
|
|
|
|
api = django_lcore.api
|
|
|
|
if request.method == 'POST':
|
|
|
|
if request.method == "POST":
|
|
|
|
action = request.POST.get('action')
|
|
|
|
action = request.POST.get("action")
|
|
|
|
if action == 'delete_key':
|
|
|
|
if action == "delete_key":
|
|
|
|
key = api.get_wg_peer(request.user.username, request.POST.get('peer_id'))
|
|
|
|
key = api.get_wg_peer(request.user.username, request.POST.get("peer_id"))
|
|
|
|
if key:
|
|
|
|
if key:
|
|
|
|
key.delete()
|
|
|
|
key.delete()
|
|
|
|
elif action == 'set_name':
|
|
|
|
elif action == "set_name":
|
|
|
|
key = api.get_wg_peer(request.user.username, request.POST.get('peer_id'))
|
|
|
|
key = api.get_wg_peer(request.user.username, request.POST.get("peer_id"))
|
|
|
|
if key:
|
|
|
|
if key:
|
|
|
|
name = request.POST.get('name')
|
|
|
|
name = request.POST.get("name")
|
|
|
|
if name:
|
|
|
|
if name:
|
|
|
|
name = name[:21]
|
|
|
|
name = name[:21]
|
|
|
|
key.rename(name)
|
|
|
|
key.rename(name)
|
|
|
@ -503,19 +572,19 @@ def wireguard(request):
|
|
|
|
|
|
|
|
|
|
|
|
context = dict(
|
|
|
|
context = dict(
|
|
|
|
can_create_key=len(keys) < int(site_config.WIREGUARD_MAX_PEERS),
|
|
|
|
can_create_key=len(keys) < int(site_config.WIREGUARD_MAX_PEERS),
|
|
|
|
menu_item='wireguard',
|
|
|
|
menu_item="wireguard",
|
|
|
|
enabled=request.user.vpnuser.is_paid,
|
|
|
|
enabled=request.user.vpnuser.is_paid,
|
|
|
|
config_countries=[(k, v) for (k, v) in django_lcore.get_clusters()],
|
|
|
|
config_countries=[(k, v) for (k, v) in django_lcore.get_clusters()],
|
|
|
|
keys=keys,
|
|
|
|
keys=keys,
|
|
|
|
locations=get_locations(),
|
|
|
|
locations=get_locations(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return render(request, 'lambdainst/wireguard.html', context)
|
|
|
|
return render(request, "lambdainst/wireguard.html", context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@login_required
|
|
|
|
@login_required
|
|
|
|
def wireguard_new(request):
|
|
|
|
def wireguard_new(request):
|
|
|
|
if not request.user.vpnuser.is_paid:
|
|
|
|
if not request.user.vpnuser.is_paid:
|
|
|
|
return redirect('account:index')
|
|
|
|
return redirect("account:index")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
try:
|
|
|
|
keys = django_lcore.api.get_wg_peers(request.user.username)
|
|
|
|
keys = django_lcore.api.get_wg_peers(request.user.username)
|
|
|
@ -523,25 +592,24 @@ def wireguard_new(request):
|
|
|
|
django_lcore.sync_user(request.user.vpnuser)
|
|
|
|
django_lcore.sync_user(request.user.vpnuser)
|
|
|
|
keys = []
|
|
|
|
keys = []
|
|
|
|
if len(keys) >= int(site_config.WIREGUARD_MAX_PEERS):
|
|
|
|
if len(keys) >= int(site_config.WIREGUARD_MAX_PEERS):
|
|
|
|
return redirect('/account/wireguard')
|
|
|
|
return redirect("/account/wireguard")
|
|
|
|
|
|
|
|
|
|
|
|
api = django_lcore.api
|
|
|
|
api = django_lcore.api
|
|
|
|
if request.method == 'POST':
|
|
|
|
if request.method == "POST":
|
|
|
|
action = request.POST.get('action')
|
|
|
|
action = request.POST.get("action")
|
|
|
|
form = WgPeerForm(request.POST)
|
|
|
|
form = WgPeerForm(request.POST)
|
|
|
|
if action == 'add_key':
|
|
|
|
if action == "add_key":
|
|
|
|
if form.is_valid():
|
|
|
|
if form.is_valid():
|
|
|
|
api.create_wg_peer(
|
|
|
|
api.create_wg_peer(
|
|
|
|
request.user.username,
|
|
|
|
request.user.username,
|
|
|
|
public_key=form.cleaned_data['public_key'],
|
|
|
|
public_key=form.cleaned_data["public_key"],
|
|
|
|
name=form.cleaned_data['name'],
|
|
|
|
name=form.cleaned_data["name"],
|
|
|
|
)
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
else:
|
|
|
|
log_errors(request, form)
|
|
|
|
log_errors(request, form)
|
|
|
|
return redirect('/account/wireguard')
|
|
|
|
return redirect("/account/wireguard")
|
|
|
|
context = dict(
|
|
|
|
context = dict(
|
|
|
|
menu_item='wireguard',
|
|
|
|
menu_item="wireguard",
|
|
|
|
locations=get_locations(),
|
|
|
|
locations=get_locations(),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
return render(request, 'lambdainst/wireguard_new.html', context)
|
|
|
|
return render(request, "lambdainst/wireguard_new.html", context)
|
|
|
|
|
|
|
|
|
|
|
|