diff --git a/lambdainst/admin.py b/lambdainst/admin.py
index 01f6d2c..ad6dfe3 100644
--- a/lambdainst/admin.py
+++ b/lambdainst/admin.py
@@ -15,18 +15,29 @@ from payments.admin import UserCouponInline, UserLedgerInline
def make_user_link(user):
- change_url = resolve_url('admin:auth_user_change', user.id)
+ change_url = resolve_url("admin:auth_user_change", user.id)
return format_html('{}', change_url, user.username)
+
class VPNUserInline(admin.StackedInline):
model = VPNUser
can_delete = False
- fk_name = 'user'
-
- fields = ('notes', 'expiration', 'last_expiry_notice', 'notify_expiration',
- 'last_vpn_auth_fail_notice', 'notify_vpn_auth_fail',
- 'trial_periods_given', 'referrer_a', 'campaign', 'last_vpn_auth', 'last_core_sync')
- readonly_fields = ('referrer_a', 'last_vpn_auth', 'last_core_sync', 'campaign')
+ fk_name = "user"
+
+ fields = (
+ "notes",
+ "expiration",
+ "last_expiry_notice",
+ "notify_expiration",
+ "last_vpn_auth_fail_notice",
+ "notify_vpn_auth_fail",
+ "trial_periods_given",
+ "referrer_a",
+ "campaign",
+ "last_vpn_auth",
+ "last_core_sync",
+ )
+ readonly_fields = ("referrer_a", "last_vpn_auth", "last_core_sync", "campaign")
def referrer_a(self, object):
if not object.referrer:
@@ -38,40 +49,58 @@ class VPNUserInline(admin.StackedInline):
else:
s += _("(not rewarded)")
return s
+
referrer_a.allow_tags = True
referrer_a.short_description = _("Referrer")
def is_paid(self, object):
return object.is_paid
+
is_paid.boolean = True
is_paid.short_description = _("Is paid?")
class UserAdmin(UserAdmin):
inlines = (VPNUserInline, UserLedgerInline, UserCouponInline)
- list_display = ('username', 'email', 'is_staff', 'date_joined', 'is_paid')
- ordering = ('-date_joined', )
+ list_display = ("username", "email", "is_staff", "date_joined", "is_paid")
+ ordering = ("-date_joined",)
fieldsets = (
- (None, {'fields': ('username', 'password', 'email', 'links')}),
- (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
- (_('Permissions'), {'fields': ('is_active', 'is_staff', 'is_superuser',
- 'groups', 'user_permissions')}),
+ (None, {"fields": ("username", "password", "email", "links")}),
+ (_("Important dates"), {"fields": ("last_login", "date_joined")}),
+ (
+ _("Permissions"),
+ {
+ "fields": (
+ "is_active",
+ "is_staff",
+ "is_superuser",
+ "groups",
+ "user_permissions",
+ )
+ },
+ ),
)
- readonly_fields = ('last_login', 'date_joined', 'links')
- actions = (django_lcore.core_sync_action, )
+ readonly_fields = ("last_login", "date_joined", "links")
+ actions = (django_lcore.core_sync_action,)
def is_paid(self, object):
return object.vpnuser.is_paid
+
is_paid.boolean = True
is_paid.short_description = _("Is paid?")
def links(self, object):
- payments_url = resolve_url('admin:payments_payment_changelist')
- tickets_url = resolve_url('admin:tickets_ticket_changelist')
+ payments_url = resolve_url("admin:payments_payment_changelist")
+ tickets_url = resolve_url("admin:tickets_ticket_changelist")
fmt = '{}'
- return format_html(fmt + " - " + fmt,
- payments_url, object.id, "Payments",
- tickets_url, object.id, "Tickets",
+ return format_html(
+ fmt + " - " + fmt,
+ payments_url,
+ object.id,
+ "Payments",
+ tickets_url,
+ object.id,
+ "Tickets",
)
def save_model(self, request, obj, form, change):
diff --git a/lambdainst/forms.py b/lambdainst/forms.py
index fba6c2f..9c06608 100644
--- a/lambdainst/forms.py
+++ b/lambdainst/forms.py
@@ -7,14 +7,14 @@ from django.utils.safestring import mark_safe
class FormPureRender:
def as_pure_aligned(self):
- html = ''
+ html = ""
for f in self:
html += '
\n'
- html += str(f.label_tag()) + '\n'
- html += str(f) + '\n'
+ html += str(f.label_tag()) + "\n"
+ html += str(f) + "\n"
if f.errors:
- html += str(f.errors) + '\n'
- html += '
\n'
+ html += str(f.errors) + "\n"
+ html += "\n"
return mark_safe(html)
@@ -30,36 +30,43 @@ class UserField(forms.RegexField):
class SignupForm(forms.Form, FormPureRender):
username = UserField(
- label=_("Username"), min_length=2, max_length=16, regex='^[a-zA-Z0-9_-]+$',
- widget=forms.TextInput(attrs={'required': 'true',
- 'pattern': '[a-zA-Z0-9_-]{2,32}',
- 'placeholder': _("Username"),
- 'autofocus': 'true'})
+ label=_("Username"),
+ min_length=2,
+ max_length=16,
+ regex="^[a-zA-Z0-9_-]+$",
+ widget=forms.TextInput(
+ attrs={
+ "required": "true",
+ "pattern": "[a-zA-Z0-9_-]{2,32}",
+ "placeholder": _("Username"),
+ "autofocus": "true",
+ }
+ ),
)
password = forms.CharField(
label=_("Password"),
- widget=forms.PasswordInput(attrs={'placeholder': _("Anything")})
+ widget=forms.PasswordInput(attrs={"placeholder": _("Anything")}),
)
password2 = forms.CharField(
label=_("Repeat"),
- widget=forms.PasswordInput(attrs={'placeholder': _("Same Anything")})
+ widget=forms.PasswordInput(attrs={"placeholder": _("Same Anything")}),
)
email = forms.EmailField(
label=_("E-Mail"),
- widget=forms.EmailInput(attrs={'placeholder': _("E-Mail")}),
+ widget=forms.EmailInput(attrs={"placeholder": _("E-Mail")}),
required=False,
)
def clean_password(self):
- if self.data['password'] != self.data['password2']:
+ if self.data["password"] != self.data["password2"]:
raise forms.ValidationError(_("Passwords are not the same"))
- return self.data['password']
+ return self.data["password"]
class ReqEmailForm(forms.Form, FormPureRender):
email = forms.EmailField(
label=_("E-Mail"),
- widget=forms.EmailInput(attrs={'placeholder': _("E-Mail")}),
+ widget=forms.EmailInput(attrs={"placeholder": _("E-Mail")}),
)
@@ -73,7 +80,11 @@ def wg_pk_validator(s):
class WgPeerForm(forms.Form):
- public_key = forms.CharField(min_length=3, max_length=100, strip=True, required=False, validators=[
- wg_pk_validator
- ])
+ public_key = forms.CharField(
+ min_length=3,
+ max_length=100,
+ strip=True,
+ required=False,
+ validators=[wg_pk_validator],
+ )
name = forms.CharField(max_length=21, required=False)
diff --git a/lambdainst/graphs.py b/lambdainst/graphs.py
index 52ff026..3e76d7d 100644
--- a/lambdainst/graphs.py
+++ b/lambdainst/graphs.py
@@ -8,8 +8,8 @@ from payments.models import Payment
PERIOD_VERBOSE_NAME = {
- 'y': "per month",
- 'm': "per day",
+ "y": "per month",
+ "m": "per day",
}
@@ -18,9 +18,23 @@ def monthdelta(date, delta):
y = date.year + (date.month + delta - 1) // 12
if not m:
m = 12
- d = min(date.day, [31, 29 if y % 4 == 0 and not y % 400 == 0
- else 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- ][m - 1])
+ d = min(
+ date.day,
+ [
+ 31,
+ 29 if y % 4 == 0 and not y % 400 == 0 else 28,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ ][m - 1],
+ )
return date.replace(day=d, month=m, year=y)
@@ -38,57 +52,64 @@ def last_months(n=12):
def time_filter_future(period, m, df):
def _filter(o):
- if period == 'm':
+ if period == "m":
return df(o).date() <= m
- if period == 'y':
+ if period == "y":
return df(o).date().replace(day=1) <= m
+
return _filter
def time_filter_between(period, m, df):
def _filter(o):
- if period == 'm':
- return df(o).year == m.year and df(o).month == m.month and df(o).day == m.day
+ if period == "m":
+ return (
+ df(o).year == m.year and df(o).month == m.month and df(o).day == m.day
+ )
return df(o).date() <= m and df(o).date() > (m - timedelta(days=1))
- if period == 'y':
+ if period == "y":
return df(o).year == m.year and df(o).month == m.month
- return (df(o).date().replace(day=1) <= m and
- df(o).date().replace(day=1) > (m - timedelta(days=30)))
+ return df(o).date().replace(day=1) <= m and df(o).date().replace(day=1) > (
+ m - timedelta(days=30)
+ )
+
return _filter
def users_graph(period):
chart = pygal.Line(fill=True, x_label_rotation=75, show_legend=False)
- chart.title = 'Users %s' % PERIOD_VERBOSE_NAME[period]
+ chart.title = "Users %s" % PERIOD_VERBOSE_NAME[period]
chart.x_labels = []
values = []
- gen = last_days(30) if period == 'm' else last_months(12)
+ gen = last_days(30) if period == "m" else last_months(12)
users = User.objects.all()
for m in gen:
filter_ = time_filter_future(period, m, lambda o: o.date_joined)
users_filtered = filter(filter_, users)
values.append(len(list(users_filtered)))
- chart.x_labels.append('%02d/%02d' % (m.month, m.day))
+ chart.x_labels.append("%02d/%02d" % (m.month, m.day))
- chart.add('Users', values)
+ chart.add("Users", values)
return chart.render()
def payments_paid_graph(period):
chart = pygal.StackedBar(x_label_rotation=75, show_legend=True)
chart.x_labels = []
- gen = list(last_days(30) if period == 'm' else last_months(12))
+ gen = list(last_days(30) if period == "m" else last_months(12))
- chart.title = 'Payments %s in €' % (PERIOD_VERBOSE_NAME[period])
+ chart.title = "Payments %s in €" % (PERIOD_VERBOSE_NAME[period])
for m in gen:
- chart.x_labels.append('%02d/%02d' % (m.month, m.day))
+ chart.x_labels.append("%02d/%02d" % (m.month, m.day))
values = dict()
for backend_id, backend in BACKENDS.items():
values = []
- payments = list(Payment.objects.filter(status='confirmed', backend_id=backend_id))
+ payments = list(
+ Payment.objects.filter(status="confirmed", backend_id=backend_id)
+ )
for m in gen:
filter_ = time_filter_between(period, m, lambda o: o.created)
@@ -103,17 +124,19 @@ def payments_paid_graph(period):
def payments_success_graph(period):
chart = pygal.StackedBar(x_label_rotation=75, show_legend=True)
chart.x_labels = []
- gen = list(last_days(30) if period == 'm' else last_months(12))
+ gen = list(last_days(30) if period == "m" else last_months(12))
- chart.title = 'Successful payments %s' % (PERIOD_VERBOSE_NAME[period])
+ chart.title = "Successful payments %s" % (PERIOD_VERBOSE_NAME[period])
for m in gen:
- chart.x_labels.append('%02d/%02d' % (m.month, m.day))
+ chart.x_labels.append("%02d/%02d" % (m.month, m.day))
values = dict()
for backend_id, backend in BACKENDS.items():
values = []
- payments = list(Payment.objects.filter(status='confirmed', backend_id=backend_id))
+ payments = list(
+ Payment.objects.filter(status="confirmed", backend_id=backend_id)
+ )
for m in gen:
filter_ = time_filter_between(period, m, lambda o: o.created)
@@ -123,4 +146,3 @@ def payments_success_graph(period):
chart.add(backend_id, values)
return chart.render()
-
diff --git a/lambdainst/middleware.py b/lambdainst/middleware.py
index 67ce1b6..32c03a2 100644
--- a/lambdainst/middleware.py
+++ b/lambdainst/middleware.py
@@ -8,10 +8,10 @@ from .models import User
class ReferrerMiddleware(MiddlewareMixin):
def process_request(self, request):
- if 'ref' in request.GET:
- id = request.GET['ref']
- elif 'referrer' in request.COOKIES:
- id = request.COOKIES['referrer']
+ if "ref" in request.GET:
+ id = request.GET["ref"]
+ elif "referrer" in request.COOKIES:
+ id = request.COOKIES["referrer"]
else:
return
@@ -25,33 +25,36 @@ class ReferrerMiddleware(MiddlewareMixin):
except User.DoesNotExist:
return
- request.session['referrer'] = u.id
+ request.session["referrer"] = u.id
def process_response(self, request, response):
- id = request.session.get('referrer')
+ id = request.session.get("referrer")
if not id:
return response
max_age = 365 * 24 * 60 * 60
- expires = (datetime.utcnow() + timedelta(seconds=max_age))
+ expires = datetime.utcnow() + timedelta(seconds=max_age)
expires = expires.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
- response.set_cookie('referrer', id,
- max_age=max_age,
- expires=expires,
- domain=settings.SESSION_COOKIE_DOMAIN,
- secure=settings.SESSION_COOKIE_SECURE or None)
+ response.set_cookie(
+ "referrer",
+ id,
+ max_age=max_age,
+ expires=expires,
+ domain=settings.SESSION_COOKIE_DOMAIN,
+ secure=settings.SESSION_COOKIE_SECURE or None,
+ )
return response
class CampaignMiddleware(MiddlewareMixin):
- GET_FIELDS = ['pk_campaign', 'utm_campaign', 'utm_medium', 'utm_source']
+ GET_FIELDS = ["pk_campaign", "utm_campaign", "utm_medium", "utm_source"]
def _get_name(self, request):
for f in self.GET_FIELDS:
if f in request.GET and request.GET[f]:
return request.GET[f]
- if 'campaign' in request.COOKIES:
- return request.COOKIES['campaign']
+ if "campaign" in request.COOKIES:
+ return request.COOKIES["campaign"]
return None
def process_request(self, request):
@@ -61,22 +64,25 @@ class CampaignMiddleware(MiddlewareMixin):
name = name.strip()
- if len(name) >= 64 or not re.match('^[a-zA-Z0-9_.:-]+$', name):
+ if len(name) >= 64 or not re.match("^[a-zA-Z0-9_.:-]+$", name):
return
- request.session['campaign'] = name
+ request.session["campaign"] = name
def process_response(self, request, response):
- name = request.session.get('campaign')
+ name = request.session.get("campaign")
if not name:
return response
max_age = 365 * 24 * 60 * 60
- expires = (datetime.utcnow() + timedelta(seconds=max_age))
+ expires = datetime.utcnow() + timedelta(seconds=max_age)
expires = expires.strftime("%a, %d-%b-%Y %H:%M:%S GMT")
- response.set_cookie('campaign', name,
- max_age=max_age,
- expires=expires,
- domain=settings.SESSION_COOKIE_DOMAIN,
- secure=settings.SESSION_COOKIE_SECURE or None)
+ response.set_cookie(
+ "campaign",
+ name,
+ max_age=max_age,
+ expires=expires,
+ domain=settings.SESSION_COOKIE_DOMAIN,
+ secure=settings.SESSION_COOKIE_SECURE or None,
+ )
return response
diff --git a/lambdainst/models.py b/lambdainst/models.py
index 0a993fd..145c034 100644
--- a/lambdainst/models.py
+++ b/lambdainst/models.py
@@ -2,7 +2,11 @@ import random
from django.db import models, IntegrityError
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
-from django_lcore.core import LcoreUserProfileMethods, setup_sync_hooks, VPN_AUTH_STORAGE
+from django_lcore.core import (
+ LcoreUserProfileMethods,
+ setup_sync_hooks,
+ VPN_AUTH_STORAGE,
+)
from payments.models import BaseSubUser
@@ -11,7 +15,7 @@ prng = random.SystemRandom()
def random_gift_code():
charset = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ"
- return ''.join([prng.choice(charset) for n in range(10)])
+ return "".join([prng.choice(charset) for n in range(10)])
class VPNUser(models.Model, BaseSubUser, LcoreUserProfileMethods):
@@ -33,8 +37,9 @@ class VPNUser(models.Model, BaseSubUser, LcoreUserProfileMethods):
last_vpn_auth = models.DateTimeField(blank=True, null=True)
last_core_sync = models.DateTimeField(blank=True, null=True)
- referrer = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL,
- related_name='referrals')
+ referrer = models.ForeignKey(
+ User, blank=True, null=True, on_delete=models.SET_NULL, related_name="referrals"
+ )
referrer_used = models.BooleanField(default=False)
campaign = models.CharField(blank=True, null=True, max_length=64)
@@ -49,15 +54,20 @@ class VPNUser(models.Model, BaseSubUser, LcoreUserProfileMethods):
def on_payment_confirmed(self, payment):
if self.referrer and not self.referrer_used:
- self.referrer.vpnuser.add_paid_months(1, 'referrer', f"rewarded for {self.user.username} (payment #{payment.id})")
+ self.referrer.vpnuser.add_paid_months(
+ 1,
+ "referrer",
+ f"rewarded for {self.user.username} (payment #{payment.id})",
+ )
self.referrer.vpnuser.save()
self.referrer_used = True
self.save()
def lcore_sync(self):
- if VPN_AUTH_STORAGE == 'inst':
+ if VPN_AUTH_STORAGE == "inst":
return
from lambdainst.tasks import push_user
+
push_user.delay(user_id=self.user.id)
def notify_payment(self, payment):
@@ -72,12 +82,13 @@ class VPNUser(models.Model, BaseSubUser, LcoreUserProfileMethods):
def __str__(self):
return self.user.username
+
setup_sync_hooks(User, VPNUser)
-#from django.db.models.signals import post_save
-#from django.dispatch import receiver
-#@receiver(post_save, sender=User)
-#def create_vpnuser(sender, instance, created, **kwargs):
+# from django.db.models.signals import post_save
+# from django.dispatch import receiver
+# @receiver(post_save, sender=User)
+# def create_vpnuser(sender, instance, created, **kwargs):
# if created:
# try:
# VPNUser.objects.create(user=instance)
diff --git a/lambdainst/openvpn.py b/lambdainst/openvpn.py
index 4d25e05..2f3bec0 100644
--- a/lambdainst/openvpn.py
+++ b/lambdainst/openvpn.py
@@ -7,83 +7,86 @@ from django.conf import settings
CA_CERT = settings.OPENVPN_CA
CONFIG_OS = (
- ('windows', _("Windows")),
- ('android', _("Android")),
- ('ubuntu', _("Ubuntu")),
- ('osx', _("OS X")),
- ('ios', _("iOS")),
- ('chromeos', _("Chrome OS")),
- ('freebox', _("Freebox")),
- ('other', _("Other / GNU/Linux")),
+ ("windows", _("Windows")),
+ ("android", _("Android")),
+ ("ubuntu", _("Ubuntu")),
+ ("osx", _("OS X")),
+ ("ios", _("iOS")),
+ ("chromeos", _("Chrome OS")),
+ ("freebox", _("Freebox")),
+ ("other", _("Other / GNU/Linux")),
)
PROTOCOLS = (
- ('udp', _("UDP (default)")),
- ('tcp', _("TCP")),
- ('udpl', _("UDP (low MTU)")),
+ ("udp", _("UDP (default)")),
+ ("tcp", _("TCP")),
+ ("udpl", _("UDP (low MTU)")),
)
def _make_onc(username, name, hostname, port, protocol, http_proxy=None, ipv6=True):
- cert_id = '{%s}' % uuid.uuid4()
- vpn_id = '{%s}' % uuid.uuid4()
+ cert_id = "{%s}" % uuid.uuid4()
+ vpn_id = "{%s}" % uuid.uuid4()
openvpn_config = {
- 'ServerCARef': cert_id,
- 'ClientCertType': 'None',
- 'CompLZO': 'true',
- 'Port': port,
- 'Proto': protocol,
- 'ServerPollTimeout': 10,
- 'NsCertType': 'server',
- 'Username': username,
+ "ServerCARef": cert_id,
+ "ClientCertType": "None",
+ "CompLZO": "true",
+ "Port": port,
+ "Proto": protocol,
+ "ServerPollTimeout": 10,
+ "NsCertType": "server",
+ "Username": username,
}
cert = {
- 'GUID': cert_id,
- 'Type': 'Authority',
- 'X509': CA_CERT.strip(),
+ "GUID": cert_id,
+ "Type": "Authority",
+ "X509": CA_CERT.strip(),
}
vpn = {
- 'GUID': vpn_id,
- 'Name': name,
- 'Type': 'VPN',
- 'VPN': {
- 'Type': 'OpenVPN',
- 'Host': hostname,
- 'OpenVPN': openvpn_config,
+ "GUID": vpn_id,
+ "Name": name,
+ "Type": "VPN",
+ "VPN": {
+ "Type": "OpenVPN",
+ "Host": hostname,
+ "OpenVPN": openvpn_config,
},
}
- return json.dumps({
- 'type': 'UnencryptedConfiguration',
- 'Certificates': [cert],
- 'NetworkConfigurations': [vpn],
- }, indent=2)
+ return json.dumps(
+ {
+ "type": "UnencryptedConfiguration",
+ "Certificates": [cert],
+ "NetworkConfigurations": [vpn],
+ },
+ indent=2,
+ )
def make_config(username, gw_name, os, protocol, http_proxy=None, ipv6=True):
- use_frag = protocol == 'udpl' and os != 'ios'
- ipv6 = ipv6 and (os != 'freebox')
- http_proxy = http_proxy if protocol == 'tcp' else None
- resolvconf = os in ('ubuntu', 'other')
+ use_frag = protocol == "udpl" and os != "ios"
+ ipv6 = ipv6 and (os != "freebox")
+ http_proxy = http_proxy if protocol == "tcp" else None
+ resolvconf = os in ("ubuntu", "other")
- openvpn_proto = {'udp': 'udp', 'udpl': 'udp', 'tcp': 'tcp'}
- openvpn_ports = {'udp': 1196, 'udpl': 1194, 'tcp': 443}
+ openvpn_proto = {"udp": "udp", "udpl": "udp", "tcp": "tcp"}
+ openvpn_ports = {"udp": 1196, "udpl": 1194, "tcp": 443}
- hostname = 'gw.%s.204vpn.net' % gw_name
+ hostname = "gw.%s.204vpn.net" % gw_name
port = openvpn_ports[protocol]
proto = openvpn_proto[protocol]
- if os == 'chromeos':
+ if os == "chromeos":
name = "CCrypto VPN"
- if gw_name != 'random':
+ if gw_name != "random":
name += " " + gw_name.upper()
return _make_onc(username, name, hostname, port, proto, http_proxy, ipv6)
remote = str(hostname)
- remote += ' ' + str(port)
- remote += ' ' + proto
+ remote += " " + str(port)
+ remote += " " + proto
config = """\
# +----------------------------+
@@ -106,9 +109,11 @@ remote {remote}
auth-user-pass
-""".format(remote=remote)
+""".format(
+ remote=remote
+ )
- if os == 'ios':
+ if os == "ios":
# i'd like to note here how much i hate OpenVPN
config += "redirect-gateway ipv6\n"
config += 'push "route 0.0.0.0 128.0.0.0"\n'
@@ -133,16 +138,13 @@ auth-user-pass
config += "down /etc/openvpn/update-resolv-conf\n"
config += "\n"
- if os == 'windows':
+ if os == "windows":
config += "register-dns\n"
config += "\n"
config += "\n%s\n" % CA_CERT
- if os == 'windows':
- config = config.replace('\n', '\r\n')
+ if os == "windows":
+ config = config.replace("\n", "\r\n")
return config
-
-
-
diff --git a/lambdainst/tasks.py b/lambdainst/tasks.py
index f8aa3ec..7674657 100644
--- a/lambdainst/tasks.py
+++ b/lambdainst/tasks.py
@@ -69,7 +69,7 @@ def notify_vpn_auth_fails():
NOTIFY_EVERY = timedelta(days=180) # users notified recently should be ignored
def find_fails_for_user(u):
- """ returns true if there are 'many' recent fails """
+ """returns true if there are 'many' recent fails"""
path = api.info["current_instance"] + "/users/" + u.username + "/auth-events/"
try:
r = api.get(path)
@@ -181,7 +181,7 @@ def notify_vpn_auth_fails():
@shared_task
def notify_account_expiration():
- """ Notify users near the end of their subscription """
+ """Notify users near the end of their subscription"""
from_email = settings.DEFAULT_FROM_EMAIL
for v in parse_integer_list(site_config.NOTIFY_DAYS_BEFORE):
@@ -213,7 +213,7 @@ def notify_account_expiration():
def get_next_expirations(days=3):
- """ Gets users whose subscription will expire in some days """
+ """Gets users whose subscription will expire in some days"""
limit_date = timezone.now() + timedelta(days=days)
diff --git a/lambdainst/templatetags/active.py b/lambdainst/templatetags/active.py
index 07ff79f..7230169 100644
--- a/lambdainst/templatetags/active.py
+++ b/lambdainst/templatetags/active.py
@@ -9,11 +9,10 @@ register = template.Library()
@register.simple_tag(takes_context=True)
def active(context, pattern_or_urlname):
try:
- pattern = '^' + reverse(pattern_or_urlname)
+ pattern = "^" + reverse(pattern_or_urlname)
except NoReverseMatch:
pattern = pattern_or_urlname
- path = context['request'].path
+ path = context["request"].path
if re.search(pattern, path):
- return 'active'
- return ''
-
+ return "active"
+ return ""
diff --git a/lambdainst/templatetags/bw.py b/lambdainst/templatetags/bw.py
index 04c5d9f..06d4dd4 100644
--- a/lambdainst/templatetags/bw.py
+++ b/lambdainst/templatetags/bw.py
@@ -11,7 +11,7 @@ def bwformat(bps):
try:
bps = float(bps)
except (TypeError, ValueError, UnicodeDecodeError):
- value = ungettext("%(bw)d bps", "%(bw)d bps", 0) % {'bw': 0}
+ value = ungettext("%(bw)d bps", "%(bw)d bps", 0) % {"bw": 0}
return avoid_wrapping(value)
filesize_number_format = lambda value: formats.number_format(round(value, 1), -1)
@@ -23,7 +23,7 @@ def bwformat(bps):
P = 1 * 10 ** 15
if bps < K:
- value = ungettext("%(size)d bps", "%(size)d bps", bps) % {'size': bps}
+ value = ungettext("%(size)d bps", "%(size)d bps", bps) % {"size": bps}
elif bps < M:
value = ugettext("%s Kbps") % filesize_number_format(bps / K)
elif bps < G:
diff --git a/lambdainst/tests/online.py b/lambdainst/tests/online.py
index a2ed413..6b65a04 100644
--- a/lambdainst/tests/online.py
+++ b/lambdainst/tests/online.py
@@ -103,12 +103,14 @@ class OnlineStripeTests(BaseOnlineTest):
self.selenium.find_element_by_xpath('//button[@type="submit"]').click()
self.wait.until(
- EC.presence_of_element_located((By.XPATH, '//*[contains(text(), "Waiting for payment")]'))
+ EC.presence_of_element_located(
+ (By.XPATH, '//*[contains(text(), "Waiting for payment")]')
+ )
)
def check_active():
# refresh payment as we dont have a worker
- p = Payment.objects.order_by('id').first()
+ p = Payment.objects.order_by("id").first()
p.refresh()
self.selenium.refresh()
@@ -159,12 +161,14 @@ class OnlineStripeTests(BaseOnlineTest):
self.selenium.find_element_by_xpath('//button[@type="submit"]').click()
self.wait.until(
- EC.presence_of_element_located((By.XPATH, '//*[contains(text(), "Your subscription is processing.")]'))
+ EC.presence_of_element_located(
+ (By.XPATH, '//*[contains(text(), "Your subscription is processing.")]')
+ )
)
def check_active():
# refresh sub as we dont have a worker
- p = Subscription.objects.order_by('id').first()
+ p = Subscription.objects.order_by("id").first()
p.refresh()
self.selenium.refresh()
diff --git a/lambdainst/tests/units.py b/lambdainst/tests/units.py
index e392288..b492d86 100644
--- a/lambdainst/tests/units.py
+++ b/lambdainst/tests/units.py
@@ -14,24 +14,24 @@ from payments.models import Payment, Subscription
class UserTestMixin:
def assertRemaining(self, vpnuser, time, delta=5):
- """ Check that the vpnuser will expire in time (+/- 5 seconds) """
+ """Check that the vpnuser will expire in time (+/- 5 seconds)"""
exp = vpnuser.expiration or timezone.now()
seconds = (exp - timezone.now() - time).total_seconds()
self.assertAlmostEqual(seconds, 0, delta=delta)
-
class UserModelReferrerTest(TestCase, UserTestMixin):
def setUp(self):
- self.referrer = User.objects.create_user('ref')
+ self.referrer = User.objects.create_user("ref")
- self.without_ref = User.objects.create_user('aaaa')
+ self.without_ref = User.objects.create_user("aaaa")
- self.with_ref = User.objects.create_user('bbbb')
+ self.with_ref = User.objects.create_user("bbbb")
self.with_ref.vpnuser.referrer = self.referrer
self.payment = Payment.objects.create(
- user=self.with_ref, status='confirmed', amount=300, time=timedelta(days=30))
+ user=self.with_ref, status="confirmed", amount=300, time=timedelta(days=30)
+ )
def test_no_ref(self):
self.without_ref.vpnuser.on_payment_confirmed(self.payment)
@@ -40,125 +40,153 @@ class UserModelReferrerTest(TestCase, UserTestMixin):
self.with_ref.vpnuser.on_payment_confirmed(self.payment)
self.assertTrue(self.with_ref.vpnuser.referrer_used)
self.assertEqual(self.with_ref.vpnuser.referrer, self.referrer)
- self.assertRemaining(self.referrer.vpnuser, timedelta(days=30), delta=24*3600*3)
+ self.assertRemaining(
+ self.referrer.vpnuser, timedelta(days=30), delta=24 * 3600 * 3
+ )
class SignupViewTest(TestCase):
def test_form(self):
- response = self.client.get('/account/signup')
+ response = self.client.get("/account/signup")
self.assertEqual(response.status_code, 200)
- self.assertIsInstance(response.context['form'], SignupForm)
+ self.assertIsInstance(response.context["form"], SignupForm)
def test_post(self):
- response = self.client.post('/account/signup', {
- 'username': 'test_un', 'password': 'test_pw', 'password2': 'test_pw'})
- self.assertRedirects(response, '/account/')
+ response = self.client.post(
+ "/account/signup",
+ {"username": "test_un", "password": "test_pw", "password2": "test_pw"},
+ )
+ self.assertRedirects(response, "/account/")
- user = User.objects.get(username='test_un')
- self.assertTrue(user.check_password('test_pw'))
+ user = User.objects.get(username="test_un")
+ self.assertTrue(user.check_password("test_pw"))
def test_post_error(self):
- response = self.client.post('/account/signup', {
- 'username': 'test_un', 'password': 'test_pw', 'password2': 'qsdf'})
+ response = self.client.post(
+ "/account/signup",
+ {"username": "test_un", "password": "test_pw", "password2": "qsdf"},
+ )
self.assertEqual(response.status_code, 200)
- self.assertIsInstance(response.context['form'], SignupForm)
- self.assertFormError(response, 'form', 'password',
- 'Passwords are not the same')
+ self.assertIsInstance(response.context["form"], SignupForm)
+ self.assertFormError(response, "form", "password", "Passwords are not the same")
def test_post_referrer(self):
- ref = User.objects.create_user('referrer')
+ ref = User.objects.create_user("referrer")
- response = self.client.post('/account/signup?ref=%d' % ref.id, {
- 'username': 'test_un', 'password': 'test_pw', 'password2': 'test_pw'})
- self.assertRedirects(response, '/account/')
+ response = self.client.post(
+ "/account/signup?ref=%d" % ref.id,
+ {"username": "test_un", "password": "test_pw", "password2": "test_pw"},
+ )
+ self.assertRedirects(response, "/account/")
- user = User.objects.get(username='test_un')
- self.assertTrue(user.check_password('test_pw'))
+ user = User.objects.get(username="test_un")
+ self.assertTrue(user.check_password("test_pw"))
self.assertEqual(user.vpnuser.referrer, ref)
class AccountViewsTest(TestCase, UserTestMixin):
def setUp(self):
- User.objects.create_user('test', None, 'test_pw')
- self.client.login(username='test', password='test_pw')
+ User.objects.create_user("test", None, "test_pw")
+ self.client.login(username="test", password="test_pw")
def test_account(self):
- response = self.client.get('/account/')
+ response = self.client.get("/account/")
self.assertEqual(response.status_code, 200)
def test_settings_form(self):
- response = self.client.get('/account/settings')
+ response = self.client.get("/account/settings")
self.assertEqual(response.status_code, 200)
def print_message(self, response):
from django.contrib.messages import get_messages
+
messages = list(get_messages(response.wsgi_request))
for m in messages:
print(f"[message: {m.message!r} level={m.level} tags={m.tags!r}]")
def test_settings_post_email(self):
- response = self.client.post('/account/settings', {
- 'action': 'email',
- 'current_password': 'test_pw',
- 'email': 'new_email@example.com'})
+ response = self.client.post(
+ "/account/settings",
+ {
+ "action": "email",
+ "current_password": "test_pw",
+ "email": "new_email@example.com",
+ },
+ )
self.assertEqual(response.status_code, 302)
- user = User.objects.get(username='test')
- self.assertEqual(user.email, 'new_email@example.com')
+ user = User.objects.get(username="test")
+ self.assertEqual(user.email, "new_email@example.com")
def test_settings_post_email_fail(self):
- response = self.client.post('/account/settings', {
- 'action': 'email',
- 'current_password': 'not_test_pw',
- 'email': 'new_email@example.com'})
+ response = self.client.post(
+ "/account/settings",
+ {
+ "action": "email",
+ "current_password": "not_test_pw",
+ "email": "new_email@example.com",
+ },
+ )
self.assertEqual(response.status_code, 302)
- user = User.objects.get(username='test')
- self.assertNotEqual(user.email, 'new_email@example.com')
+ user = User.objects.get(username="test")
+ self.assertNotEqual(user.email, "new_email@example.com")
def test_settings_post_pw(self):
- response = self.client.post('/account/settings', {
- 'action': 'password',
- 'current_password': 'test_pw',
- 'password': 'new_test_pw', 'password2': 'new_test_pw'})
+ response = self.client.post(
+ "/account/settings",
+ {
+ "action": "password",
+ "current_password": "test_pw",
+ "password": "new_test_pw",
+ "password2": "new_test_pw",
+ },
+ )
self.assertEqual(response.status_code, 302)
- user = User.objects.get(username='test')
- self.assertTrue(user.check_password('new_test_pw'))
+ user = User.objects.get(username="test")
+ self.assertTrue(user.check_password("new_test_pw"))
def test_settings_post_pw_fail(self):
- response = self.client.post('/account/settings', {
- 'action': 'password',
- 'current_password': 'oops',
- 'password': 'new_test_pw',
- 'password2': 'new_test_pw'})
+ response = self.client.post(
+ "/account/settings",
+ {
+ "action": "password",
+ "current_password": "oops",
+ "password": "new_test_pw",
+ "password2": "new_test_pw",
+ },
+ )
self.assertEqual(response.status_code, 302)
- response = self.client.post('/account/settings', {
- 'action': 'password',
- 'current_password': 'test_pw',
- 'password': 'new_test_pw2',
- 'password2': 'new_test_pw_qsdfg'})
+ response = self.client.post(
+ "/account/settings",
+ {
+ "action": "password",
+ "current_password": "test_pw",
+ "password": "new_test_pw2",
+ "password2": "new_test_pw_qsdfg",
+ },
+ )
self.assertEqual(response.status_code, 302)
- user = User.objects.get(username='test')
- self.assertFalse(user.check_password('new_test_pw'))
- self.assertFalse(user.check_password('new_test_pw2'))
- self.assertTrue(user.check_password('test_pw'))
+ user = User.objects.get(username="test")
+ self.assertFalse(user.check_password("new_test_pw"))
+ self.assertFalse(user.check_password("new_test_pw2"))
+ self.assertTrue(user.check_password("test_pw"))
class CACrtViewTest(TestCase):
def test_ca_crt(self):
- with self.settings(OPENVPN_CA='test ca'):
- response = self.client.get('/ca.crt')
+ with self.settings(OPENVPN_CA="test ca"):
+ response = self.client.get("/ca.crt")
self.assertEqual(response.status_code, 200)
- self.assertEqual(response['Content-Type'], 'application/x-x509-ca-cert')
- self.assertEqual(response.content, b'test ca')
+ self.assertEqual(response["Content-Type"], "application/x-x509-ca-cert")
+ self.assertEqual(response.content, b"test ca")
def email_text(body):
- return body.replace('\n', ' ') \
- .replace('\xa0', ' ') # nbsp
+ return body.replace("\n", " ").replace("\xa0", " ") # nbsp
class ExpireNotifyTest(TestCase):
@@ -167,68 +195,68 @@ class ExpireNotifyTest(TestCase):
def test_notify_first(self):
out = StringIO()
- u = User.objects.create_user('test_username', 'test@example.com', 'testpw')
- u.vpnuser.add_paid_time(timedelta(days=2), 'initial')
+ u = User.objects.create_user("test_username", "test@example.com", "testpw")
+ u.vpnuser.add_paid_time(timedelta(days=2), "initial")
u.vpnuser.save()
- call_command('expire_notify', stdout=out)
+ call_command("expire_notify", stdout=out)
self.assertEqual(len(mail.outbox), 1)
- self.assertEqual(mail.outbox[0].to, ['test@example.com'])
- self.assertIn('expire in 1 day', email_text(mail.outbox[0].body))
+ self.assertEqual(mail.outbox[0].to, ["test@example.com"])
+ self.assertIn("expire in 1 day", email_text(mail.outbox[0].body))
- u = User.objects.get(username='test_username')
- self.assertAlmostEqual(u.vpnuser.last_expiry_notice, timezone.now(),
- delta=timedelta(minutes=1))
+ u = User.objects.get(username="test_username")
+ self.assertAlmostEqual(
+ u.vpnuser.last_expiry_notice, timezone.now(), delta=timedelta(minutes=1)
+ )
def test_notify_second(self):
out = StringIO()
- u = User.objects.create_user('test_username', 'test@example.com', 'testpw')
+ u = User.objects.create_user("test_username", "test@example.com", "testpw")
u.vpnuser.last_expiry_notice = timezone.now() - timedelta(days=2)
- u.vpnuser.add_paid_time(timedelta(days=1), 'initial')
+ u.vpnuser.add_paid_time(timedelta(days=1), "initial")
u.vpnuser.save()
- call_command('expire_notify', stdout=out)
+ call_command("expire_notify", stdout=out)
self.assertEqual(len(mail.outbox), 1)
- self.assertEqual(mail.outbox[0].to, ['test@example.com'])
- self.assertIn('expire in 23 hours, 59 minutes', email_text(mail.outbox[0].body))
+ self.assertEqual(mail.outbox[0].to, ["test@example.com"])
+ self.assertIn("expire in 23 hours, 59 minutes", email_text(mail.outbox[0].body))
- u = User.objects.get(username='test_username')
- self.assertAlmostEqual(u.vpnuser.last_expiry_notice, timezone.now(),
- delta=timedelta(minutes=1))
+ u = User.objects.get(username="test_username")
+ self.assertAlmostEqual(
+ u.vpnuser.last_expiry_notice, timezone.now(), delta=timedelta(minutes=1)
+ )
def test_notify_subscription(self):
out = StringIO()
- u = User.objects.create_user('test_username', 'test@example.com', 'testpw')
- u.vpnuser.add_paid_time(timedelta(days=2), 'initial')
+ u = User.objects.create_user("test_username", "test@example.com", "testpw")
+ u.vpnuser.add_paid_time(timedelta(days=2), "initial")
u.vpnuser.save()
- s = Subscription(user=u, backend_id='paypal', status='active')
+ s = Subscription(user=u, backend_id="paypal", status="active")
s.save()
- call_command('expire_notify', stdout=out)
+ call_command("expire_notify", stdout=out)
self.assertEqual(len(mail.outbox), 0)
- u = User.objects.get(username='test_username')
+ u = User.objects.get(username="test_username")
# FIXME:
# self.assertNotAlmostEqual(u.vpnuser.last_expiry_notice, timezone.now(),
# delta=timedelta(minutes=1))
def test_notify_subscription_new(self):
out = StringIO()
- u = User.objects.create_user('test_username', 'test@example.com', 'testpw')
- u.vpnuser.add_paid_time(timedelta(days=2), 'initial')
+ u = User.objects.create_user("test_username", "test@example.com", "testpw")
+ u.vpnuser.add_paid_time(timedelta(days=2), "initial")
u.vpnuser.last_expiry_notice = timezone.now() - timedelta(days=5)
u.vpnuser.save()
- s = Subscription(user=u, backend_id='paypal', status='new')
+ s = Subscription(user=u, backend_id="paypal", status="new")
s.save()
- call_command('expire_notify', stdout=out)
+ call_command("expire_notify", stdout=out)
self.assertEqual(len(mail.outbox), 1)
- u = User.objects.get(username='test_username')
+ u = User.objects.get(username="test_username")
# FIXME:
# self.assertNotAlmostEqual(u.vpnuser.last_expiry_notice, timezone.now(),
# delta=timedelta(minutes=1))
-
-
diff --git a/lambdainst/urls.py b/lambdainst/urls.py
index 7edaa29..8499746 100644
--- a/lambdainst/urls.py
+++ b/lambdainst/urls.py
@@ -4,18 +4,17 @@ import django_lcore
from . import views
-app_name = 'lambdainst'
+app_name = "lambdainst"
urlpatterns = [
- path('login', auth_views.LoginView.as_view(), name='login'),
- path('discourse_login', views.discourse_login, name='discourse_login'),
- path('logout', views.logout, name='logout'),
- path('signup', views.signup, name='signup'),
-
- path('settings', views.settings, name='account_settings'),
- path('config', views.config),
- path('config_dl', django_lcore.views.openvpn_dl),
- path('wireguard', views.wireguard),
- path('wireguard/new', views.wireguard_new, name='wireguard_new'),
- path('', views.index, name='index'),
+ path("login", auth_views.LoginView.as_view(), name="login"),
+ path("discourse_login", views.discourse_login, name="discourse_login"),
+ path("logout", views.logout, name="logout"),
+ path("signup", views.signup, name="signup"),
+ path("settings", views.settings, name="account_settings"),
+ path("config", views.config),
+ path("config_dl", django_lcore.views.openvpn_dl),
+ path("wireguard", views.wireguard),
+ path("wireguard/new", views.wireguard_new, name="wireguard_new"),
+ path("", views.index, name="index"),
]
diff --git a/lambdainst/views.py b/lambdainst/views.py
index c6ede44..3ae1b1f 100644
--- a/lambdainst/views.py
+++ b/lambdainst/views.py
@@ -14,9 +14,12 @@ from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.models import User
from django.db.models import Count
from django.db import transaction
-from django.http import (HttpResponse,
- HttpResponseNotFound, HttpResponseRedirect,
- JsonResponse)
+from django.http import (
+ HttpResponse,
+ HttpResponseNotFound,
+ HttpResponseRedirect,
+ JsonResponse,
+)
from django.shortcuts import redirect, render
from django.utils import timezone
from django.utils.translation import ugettext as _
@@ -33,16 +36,18 @@ from . import graphs
def get_locations():
- """ Pretty bad thing that returns get_locations() with translated stuff
+ """Pretty bad thing that returns get_locations() with translated stuff
that depends on the request
"""
countries_d = dict(countries)
locations = django_lcore.get_clusters()
for (_), loc in locations:
- code = loc['country_code'].upper()
- loc['country_name'] = countries_d.get(code, code)
+ code = loc["country_code"].upper()
+ 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]))
return locations
@@ -56,58 +61,61 @@ def log_errors(request, form):
def ca_crt(request):
- return HttpResponse(content=project_settings.OPENVPN_CA,
- content_type='application/x-x509-ca-cert')
+ return HttpResponse(
+ content=project_settings.OPENVPN_CA, content_type="application/x-x509-ca-cert"
+ )
def logout(request):
auth.logout(request)
- return redirect('index')
+ return redirect("index")
def signup(request):
if request.user.is_authenticated:
- return redirect('account:index')
+ return redirect("account:index")
- if request.method != 'POST':
+ if request.method != "POST":
form = SignupForm()
- return render(request, 'ccvpn/signup.html', dict(form=form))
+ return render(request, "ccvpn/signup.html", dict(form=form))
form = SignupForm(request.POST)
- grr = request.POST.get('g-recaptcha-response', '')
+ grr = request.POST.get("g-recaptcha-response", "")
if captcha_test(grr, request):
- request.session['signup_captcha_pass'] = True
- elif not request.session.get('signup_captcha_pass'):
+ request.session["signup_captcha_pass"] = True
+ elif not request.session.get("signup_captcha_pass"):
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():
- 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'],
- form.cleaned_data['email'],
- form.cleaned_data['password'])
+ user = User.objects.create_user(
+ form.cleaned_data["username"],
+ form.cleaned_data["email"],
+ form.cleaned_data["password"],
+ )
user.save()
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:
pass
- user.vpnuser.campaign = request.session.get('campaign')
- user.vpnuser.add_paid_time(timedelta(days=7), 'trial')
+ user.vpnuser.campaign = request.session.get("campaign")
+ user.vpnuser.add_paid_time(timedelta(days=7), "trial")
user.vpnuser.save()
user.vpnuser.lcore_sync()
- user.backend = 'django.contrib.auth.backends.ModelBackend'
+ user.backend = "django.contrib.auth.backends.ModelBackend"
auth.login(request, user)
# 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
@@ -118,70 +126,73 @@ def discourse_login(request):
if project_settings.DISCOURSE_SSO is not True:
return HttpResponseNotFound()
- payload = request.GET.get('sso', '')
- signature = request.GET.get('sig', '')
+ payload = request.GET.get("sso", "")
+ signature = request.GET.get("sig", "")
- expected_signature = hmac.new(sso_secret.encode('utf-8'),
- payload.encode('utf-8'),
- sha256).hexdigest()
+ expected_signature = hmac.new(
+ sso_secret.encode("utf-8"), payload.encode("utf-8"), sha256
+ ).hexdigest()
if signature != expected_signature:
return HttpResponseNotFound()
- if request.method == 'POST' and 'email' in request.POST:
+ if request.method == "POST" and "email" in request.POST:
form = ReqEmailForm(request.POST)
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()
if not request.user.email:
form = ReqEmailForm()
- return render(request, 'ccvpn/require_email.html', dict(form=form))
+ return render(request, "ccvpn/require_email.html", dict(form=form))
try:
- payload = base64.b64decode(payload).decode('utf-8')
+ payload = base64.b64decode(payload).decode("utf-8")
payload_data = dict(parse_qsl(payload))
except (TypeError, ValueError):
return HttpResponseNotFound()
- payload_data.update({
- 'external_id': request.user.id,
- 'username': request.user.username,
- 'email': request.user.email,
- 'require_activation': 'true',
- })
+ payload_data.update(
+ {
+ "external_id": request.user.id,
+ "username": request.user.username,
+ "email": request.user.email,
+ "require_activation": "true",
+ }
+ )
payload = urlencode(payload_data)
- payload = base64.b64encode(payload.encode('utf-8'))
- signature = hmac.new(sso_secret.encode('utf-8'), payload, sha256).hexdigest()
+ payload = base64.b64encode(payload.encode("utf-8"))
+ signature = hmac.new(sso_secret.encode("utf-8"), payload, sha256).hexdigest()
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)
@login_required
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 = {
- 'text': _("Awesome VPN! 3€ per month, with a free 7 days trial!"),
- 'via': 'CCrypto_VPN',
- 'url': ref_url,
- 'related': 'CCrypto_VPN,CCrypto_org'
+ "text": _("Awesome VPN! 3€ per month, with a free 7 days trial!"),
+ "via": "CCrypto_VPN",
+ "url": ref_url,
+ "related": "CCrypto_VPN,CCrypto_org",
}
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
"""
+
def __getitem__(self, months):
n = int(months) * get_price_float()
c = project_settings.PAYMENTS_CURRENCY[1]
- return '%.2f %s' % (n, c)
+ return "%.2f %s" % (n, c)
context = dict(
title=_("Account"),
@@ -189,15 +200,16 @@ def index(request):
twitter_link=twitter_url + urlencode(twitter_args),
subscription=request.user.vpnuser.get_subscription(),
backends=sorted(ACTIVE_BACKENDS.values(), key=lambda x: x.backend_display_name),
- subscr_backends=sorted((b for b in ACTIVE_BACKENDS.values()
- if b.backend_has_recurring),
- key=lambda x: x.backend_id),
- default_backend='paypal',
+ subscr_backends=sorted(
+ (b for b in ACTIVE_BACKENDS.values() if b.backend_has_recurring),
+ key=lambda x: x.backend_id,
+ ),
+ default_backend="paypal",
hcaptcha_site_key=project_settings.HCAPTCHA_SITE_KEY,
price=price_fn(),
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):
@@ -206,18 +218,17 @@ def captcha_test(grr, request):
if not project_settings.HCAPTCHA_SITE_KEY:
return True
- if api_url == 'TEST' and grr == 'TEST-TOKEN':
+ if api_url == "TEST" and grr == "TEST-TOKEN":
# FIXME: i'm sorry.
return True
- data = dict(secret=project_settings.HCAPTCHA_SECRET_KEY,
- response=grr)
+ data = dict(secret=project_settings.HCAPTCHA_SECRET_KEY, response=grr)
try:
r = requests.post(api_url, data=data)
r.raise_for_status()
d = r.json()
- return d.get('success')
+ return d.get("success")
except (requests.ConnectionError, requests.HTTPError, ValueError):
return False
@@ -233,13 +244,29 @@ def make_export_zip(user, name):
gw_cache = {}
def process_wg_peer(item):
- keys = {"gateway_port", "id", "local_ipv4", "local_ipv6", "name", "object",
- "private_key", "public_key"}
+ keys = {
+ "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}
def process_ovpn_sess(item):
- keys = {"connect_date", "disconnect_date", "remote", "object", "protocol", "id",
- "stats", "tunnel"}
+ keys = {
+ "connect_date",
+ "disconnect_date",
+ "remote",
+ "object",
+ "protocol",
+ "id",
+ "stats",
+ "tunnel",
+ }
def convert(v):
if isinstance(v, datetime):
@@ -277,41 +304,50 @@ def make_export_zip(user, name):
return obj
with z.open(name + "/account.json", "w") as jf:
- jf.write(json.dumps({
- "username": user.username,
- "email": user.email,
- "date_joined": user.date_joined.isoformat(),
- "expiration": user.vpnuser.expiration.isoformat() if user.vpnuser.expiration else None,
- }, indent=2).encode('ascii'))
+ jf.write(
+ json.dumps(
+ {
+ "username": user.username,
+ "email": user.email,
+ "date_joined": user.date_joined.isoformat(),
+ "expiration": user.vpnuser.expiration.isoformat()
+ if user.vpnuser.expiration
+ else None,
+ },
+ indent=2,
+ ).encode("ascii")
+ )
with z.open(name + "/wireguard_peers.json", "w") as jf:
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:
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:
- base = django_lcore.api.info['current_instance']
- next_page = '/users/' + user.username + '/sessions/'
+ base = django_lcore.api.info["current_instance"]
+ next_page = "/users/" + user.username + "/sessions/"
try:
items = django_lcore.api.get(base + next_page).list_iter()
except lcoreapi.APINotFoundError:
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:
items = user.payment_set.all()
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()
return f.getvalue()
def deactivate_user(user):
- """ clear most information from a user, keeping the username and id """
+ """clear most information from a user, keeping the username and id"""
user.vpnuser.clear_fields()
user.vpnuser.save()
@@ -330,33 +366,37 @@ def deactivate_user(user):
def settings(request):
can_delete = request.user.vpnuser.get_subscription() is None
- if request.method != 'POST':
- return render(request, 'lambdainst/settings.html', dict(
- can_delete=can_delete,
- ))
+ if request.method != "POST":
+ return render(
+ request,
+ "lambdainst/settings.html",
+ dict(
+ 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):
messages.error(request, _("Invalid password"))
- return redirect('lambdainst:account_settings')
+ return redirect("lambdainst:account_settings")
- if action == 'email':
- email = request.POST.get('email')
+ if action == "email":
+ email = request.POST.get("email")
if email:
request.user.email = email
messages.success(request, _("OK! Email address changed."))
else:
- request.user.email = ''
+ request.user.email = ""
messages.success(request, _("OK! Email address unset."))
request.user.save()
- return redirect('lambdainst:account_settings')
+ return redirect("lambdainst:account_settings")
- elif action == 'password':
- pw = request.POST.get('password')
- pw2 = request.POST.get('password2')
+ elif action == "password":
+ pw = request.POST.get("password")
+ pw2 = request.POST.get("password2")
if pw != pw2 or not pw:
messages.error(request, _("Password and confirmation do not match"))
else:
@@ -364,95 +404,120 @@ def settings(request):
messages.success(request, _("OK! Password changed."))
request.user.save()
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")
data = make_export_zip(request.user, timestamp)
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
- elif action == 'delete' and can_delete:
+ elif action == "delete" and can_delete:
with transaction.atomic():
deactivate_user(request.user)
logout(request)
messages.success(request, _("OK! Your account has been deactivated."))
- return redirect('/')
-
- return render(request, 'lambdainst/settings.html', dict(
- title=_("Settings"),
- user=request.user,
- can_delete=can_delete,
- ))
+ return redirect("/")
+
+ return render(
+ request,
+ "lambdainst/settings.html",
+ dict(
+ title=_("Settings"),
+ user=request.user,
+ can_delete=can_delete,
+ ),
+ )
@login_required
def config(request):
- return render(request, 'lambdainst/config.html', dict(
- title=_("Config"),
- config_os=django_lcore.openvpn.CONFIG_OS,
- config_countries=(c for _, c in get_locations()),
- config_protocols=django_lcore.openvpn.PROTOCOLS,
- ))
+ return render(
+ request,
+ "lambdainst/config.html",
+ dict(
+ title=_("Config"),
+ config_os=django_lcore.openvpn.CONFIG_OS,
+ config_countries=(c for _, c in get_locations()),
+ config_protocols=django_lcore.openvpn.PROTOCOLS,
+ ),
+ )
def api_locations(request):
def format_loc(cc, l):
msg = ""
- tags = l.get('tags', {})
- message = tags.get('message')
+ tags = l.get("tags", {})
+ message = tags.get("message")
if message:
msg = " [%s]" % message
return {
- 'country_name': l['country_name'] + msg,
- 'country_code': cc,
- 'hostname': l['hostname'],
- 'bandwidth': l['bandwidth'],
- 'servers': l['servers'],
+ "country_name": l["country_name"] + msg,
+ "country_code": cc,
+ "hostname": l["hostname"],
+ "bandwidth": l["bandwidth"],
+ "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):
locations = get_locations()
ctx = {
- 'title': _("Servers"),
- 'locations': locations,
+ "title": _("Servers"),
+ "locations": locations,
}
- return render(request, 'lambdainst/status.html', ctx)
+ return render(request, "lambdainst/status.html", ctx)
@user_passes_test(lambda user: user.is_staff)
def admin_status(request):
- graph_name = request.GET.get('graph_name')
- graph_period = request.GET.get('period')
- if graph_period not in ('y', 'm'):
- graph_period = 'm'
+ graph_name = request.GET.get("graph_name")
+ graph_period = request.GET.get("period")
+ if graph_period not in ("y", "m"):
+ graph_period = "m"
if graph_name:
- if graph_name == 'users':
+ if graph_name == "users":
content = graphs.users_graph(graph_period)
- elif graph_name == 'payments_paid':
+ elif graph_name == "payments_paid":
content = graphs.payments_paid_graph(graph_period)
- elif graph_name == 'payments_success':
+ elif graph_name == "payments_success":
content = graphs.payments_success_graph(graph_period)
else:
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, 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 = {
- 'api_status': {k: str(v) for k, v in django_lcore.api.info.items() if k in lcore_keys},
- 'payment_backends': sorted(ACTIVE_BACKENDS.values(), key=lambda x: x.backend_id),
- 'payment_status': payment_status,
+ "api_status": {
+ k: str(v) for k, v in django_lcore.api.info.items() if k in lcore_keys
+ },
+ "payment_backends": sorted(
+ ACTIVE_BACKENDS.values(), key=lambda x: x.backend_id
+ ),
+ "payment_status": payment_status,
}
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)
@@ -460,36 +525,40 @@ def admin_ref(request):
last_week = datetime.now() - timedelta(days=7)
last_month = datetime.now() - timedelta(days=30)
- 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) \
- .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]
+ 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)
+ .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 = {
- 'top_ref': top_ref,
- 'top_ref_week': top_ref_week,
- 'top_ref_month': top_ref_month,
+ "top_ref": top_ref,
+ "top_ref_week": top_ref_week,
+ "top_ref_month": top_ref_month,
}
ctx.update(site.each_context(request))
- return render(request, 'lambdainst/admin_ref.html', ctx)
+ return render(request, "lambdainst/admin_ref.html", ctx)
@login_required
def wireguard(request):
api = django_lcore.api
- if request.method == 'POST':
- action = request.POST.get('action')
- if action == 'delete_key':
- key = api.get_wg_peer(request.user.username, request.POST.get('peer_id'))
+ if request.method == "POST":
+ action = request.POST.get("action")
+ if action == "delete_key":
+ key = api.get_wg_peer(request.user.username, request.POST.get("peer_id"))
if key:
key.delete()
- elif action == 'set_name':
- key = api.get_wg_peer(request.user.username, request.POST.get('peer_id'))
+ elif action == "set_name":
+ key = api.get_wg_peer(request.user.username, request.POST.get("peer_id"))
if key:
- name = request.POST.get('name')
+ name = request.POST.get("name")
if name:
name = name[:21]
key.rename(name)
@@ -503,19 +572,19 @@ def wireguard(request):
context = dict(
can_create_key=len(keys) < int(site_config.WIREGUARD_MAX_PEERS),
- menu_item='wireguard',
+ menu_item="wireguard",
enabled=request.user.vpnuser.is_paid,
config_countries=[(k, v) for (k, v) in django_lcore.get_clusters()],
keys=keys,
locations=get_locations(),
)
- return render(request, 'lambdainst/wireguard.html', context)
+ return render(request, "lambdainst/wireguard.html", context)
@login_required
def wireguard_new(request):
if not request.user.vpnuser.is_paid:
- return redirect('account:index')
+ return redirect("account:index")
try:
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)
keys = []
if len(keys) >= int(site_config.WIREGUARD_MAX_PEERS):
- return redirect('/account/wireguard')
+ return redirect("/account/wireguard")
api = django_lcore.api
- if request.method == 'POST':
- action = request.POST.get('action')
+ if request.method == "POST":
+ action = request.POST.get("action")
form = WgPeerForm(request.POST)
- if action == 'add_key':
+ if action == "add_key":
if form.is_valid():
api.create_wg_peer(
request.user.username,
- public_key=form.cleaned_data['public_key'],
- name=form.cleaned_data['name'],
+ public_key=form.cleaned_data["public_key"],
+ name=form.cleaned_data["name"],
)
else:
log_errors(request, form)
- return redirect('/account/wireguard')
+ return redirect("/account/wireguard")
context = dict(
- menu_item='wireguard',
+ menu_item="wireguard",
locations=get_locations(),
)
- return render(request, 'lambdainst/wireguard_new.html', context)
-
+ return render(request, "lambdainst/wireguard_new.html", context)
diff --git a/poetry.lock b/poetry.lock
index 55c7ce5..c31004d 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -71,25 +71,27 @@ python-versions = "*"
[[package]]
name = "black"
-version = "20.8b1"
+version = "21.7b0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.6.2"
[package.dependencies]
appdirs = "*"
click = ">=7.1.2"
mypy-extensions = ">=0.4.3"
-pathspec = ">=0.6,<1"
+pathspec = ">=0.8.1,<1"
regex = ">=2020.1.8"
-toml = ">=0.10.1"
-typed-ast = ">=1.4.0"
-typing-extensions = ">=3.7.4"
+tomli = ">=0.2.6,<2.0.0"
+typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\""}
+typing-extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""}
[package.extras]
colorama = ["colorama (>=0.4.3)"]
-d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
+d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"]
+python2 = ["typed-ast (>=1.4.2)"]
+uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "cached-property"
@@ -408,18 +410,18 @@ jsmin = "*"
[[package]]
name = "flower"
-version = "0.9.5"
+version = "1.0.0"
description = "Celery Flower"
category = "main"
optional = false
python-versions = "*"
[package.dependencies]
-celery = {version = ">=4.3.0", markers = "python_version >= \"3.7\""}
+celery = ">=5.0.5"
humanize = "*"
-prometheus-client = "0.8.0"
+prometheus-client = ">=0.8.0"
pytz = "*"
-tornado = {version = ">=5.0.0,<7.0.0", markers = "python_version >= \"3.5.2\""}
+tornado = ">=5.0.0,<7.0.0"
[[package]]
name = "humanize"
@@ -499,16 +501,17 @@ python-versions = "*"
[[package]]
name = "isort"
-version = "5.8.0"
+version = "5.9.2"
description = "A Python utility / library to sort Python imports."
category = "dev"
optional = false
-python-versions = ">=3.6,<4.0"
+python-versions = ">=3.6.1,<4.0"
[package.extras]
pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
requirements_deprecated_finder = ["pipreqs", "pip-api"]
colors = ["colorama (>=0.4.3,<0.5.0)"]
+plugins = ["setuptools"]
[[package]]
name = "jedi"
@@ -682,22 +685,22 @@ python-versions = "*"
[[package]]
name = "prometheus-client"
-version = "0.8.0"
+version = "0.11.0"
description = "Python client for the Prometheus monitoring system."
category = "main"
optional = false
-python-versions = "*"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
twisted = ["twisted"]
[[package]]
name = "prompt-toolkit"
-version = "3.0.3"
+version = "3.0.19"
description = "Library for building powerful interactive command lines in Python"
category = "main"
optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.6.1"
[package.dependencies]
wcwidth = "*"
@@ -782,14 +785,6 @@ python-versions = "*"
[package.dependencies]
pylint = ">=1.7"
-[[package]]
-name = "python-bitcoinlib"
-version = "0.11.0"
-description = "The Swiss Army Knife of the Bitcoin protocol."
-category = "main"
-optional = false
-python-versions = "*"
-
[[package]]
name = "python-crontab"
version = "2.5.1"
@@ -930,6 +925,14 @@ category = "dev"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
+[[package]]
+name = "tomli"
+version = "1.1.0"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
[[package]]
name = "tornado"
version = "6.1"
@@ -1020,7 +1023,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes
[metadata]
lock-version = "1.1"
python-versions = ">=3.7,<4.0"
-content-hash = "80258fdb7e8f9b695a3a5ad92efb52c47433243bccc905d701d1e377f38877d9"
+content-hash = "5e7e869eb1d76bb7621e1653d293566a4ad761932fcc33e74c88602554c6d7f4"
[metadata.files]
amqp = [
@@ -1052,8 +1055,8 @@ billiard = [
{file = "billiard-3.6.4.0.tar.gz", hash = "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547"},
]
black = [
- {file = "black-20.8b1-py3-none-any.whl", hash = "sha256:70b62ef1527c950db59062cda342ea224d772abdf6adc58b86a45421bab20a6b"},
- {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"},
+ {file = "black-21.7b0-py3-none-any.whl", hash = "sha256:1c7aa6ada8ee864db745b22790a32f94b2795c253a75d6d9b5e439ff10d23116"},
+ {file = "black-21.7b0.tar.gz", hash = "sha256:c8373c6491de9362e39271630b65b964607bc5c79c83783547d76c839b3aa219"},
]
cached-property = [
{file = "cached-property-1.5.2.tar.gz", hash = "sha256:9fa5755838eecbb2d234c3aa390bd80fbd3ac6b6869109bfc1b499f7bd89a130"},
@@ -1137,8 +1140,8 @@ django-tinymce4-lite = [
{file = "django_tinymce4_lite-1.8.0-py3-none-any.whl", hash = "sha256:2d53510ddb5fe20f25e525d4eaf7c8f8a567b85c9cc29f8ab2964419d9352d88"},
]
flower = [
- {file = "flower-0.9.5-py2.py3-none-any.whl", hash = "sha256:71be02bff7b2f56b0a07bd947fb3c748acba7f44f80ae88125d8954ce1a89697"},
- {file = "flower-0.9.5.tar.gz", hash = "sha256:56916d1d2892e25453d6023437427fc04706a1308e0bd4822321da34e1643f9c"},
+ {file = "flower-1.0.0-py2.py3-none-any.whl", hash = "sha256:a4fcf959881135303e98a74cc7533298b7dfeb48abcd1d90c5bd52cb789430a8"},
+ {file = "flower-1.0.0.tar.gz", hash = "sha256:2e17c4fb55c569508f3bfee7fe41f44b8362d30dbdf77b604a9d9f4740fe8cbd"},
]
humanize = [
{file = "humanize-3.10.0-py3-none-any.whl", hash = "sha256:aab7625d62dd5e0a054c8413a47d1fa257f3bdd8e9a2442c2fe36061bdd1d9bf"},
@@ -1161,8 +1164,8 @@ ipython-genutils = [
{file = "ipython_genutils-0.2.0.tar.gz", hash = "sha256:eb2e116e75ecef9d4d228fdc66af54269afa26ab4463042e33785b887c628ba8"},
]
isort = [
- {file = "isort-5.8.0-py3-none-any.whl", hash = "sha256:2bb1680aad211e3c9944dbce1d4ba09a989f04e238296c87fe2139faa26d655d"},
- {file = "isort-5.8.0.tar.gz", hash = "sha256:0a943902919f65c5684ac4e0154b1ad4fac6dcaa5d9f3426b732f1c8b5419be6"},
+ {file = "isort-5.9.2-py3-none-any.whl", hash = "sha256:eed17b53c3e7912425579853d078a0832820f023191561fcee9d7cae424e0813"},
+ {file = "isort-5.9.2.tar.gz", hash = "sha256:f65ce5bd4cbc6abdfbe29afc2f0245538ab358c14590912df638033f157d555e"},
]
jedi = [
{file = "jedi-0.18.0-py2.py3-none-any.whl", hash = "sha256:18456d83f65f400ab0c2d3319e48520420ef43b23a086fdc05dff34132f0fb93"},
@@ -1237,12 +1240,12 @@ pickleshare = [
{file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
]
prometheus-client = [
- {file = "prometheus_client-0.8.0-py2.py3-none-any.whl", hash = "sha256:983c7ac4b47478720db338f1491ef67a100b474e3bc7dafcbaefb7d0b8f9b01c"},
- {file = "prometheus_client-0.8.0.tar.gz", hash = "sha256:c6e6b706833a6bd1fd51711299edee907857be10ece535126a158f911ee80915"},
+ {file = "prometheus_client-0.11.0-py2.py3-none-any.whl", hash = "sha256:b014bc76815eb1399da8ce5fc84b7717a3e63652b0c0f8804092c9363acab1b2"},
+ {file = "prometheus_client-0.11.0.tar.gz", hash = "sha256:3a8baade6cb80bcfe43297e33e7623f3118d660d41387593758e2fb1ea173a86"},
]
prompt-toolkit = [
- {file = "prompt_toolkit-3.0.3-py3-none-any.whl", hash = "sha256:c93e53af97f630f12f5f62a3274e79527936ed466f038953dfa379d4941f651a"},
- {file = "prompt_toolkit-3.0.3.tar.gz", hash = "sha256:a402e9bf468b63314e37460b68ba68243d55b2f8c4d0192f85a019af3945050e"},
+ {file = "prompt_toolkit-3.0.19-py3-none-any.whl", hash = "sha256:7089d8d2938043508aa9420ec18ce0922885304cddae87fb96eebca942299f88"},
+ {file = "prompt_toolkit-3.0.19.tar.gz", hash = "sha256:08360ee3a3148bdb5163621709ee322ec34fc4375099afa4bbf751e9b7b7fa4f"},
]
psycopg2-binary = [
{file = "psycopg2-binary-2.9.1.tar.gz", hash = "sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773"},
@@ -1299,10 +1302,6 @@ pylint-plugin-utils = [
{file = "pylint-plugin-utils-0.6.tar.gz", hash = "sha256:57625dcca20140f43731311cd8fd879318bf45a8b0fd17020717a8781714a25a"},
{file = "pylint_plugin_utils-0.6-py3-none-any.whl", hash = "sha256:2f30510e1c46edf268d3a195b2849bd98a1b9433229bb2ba63b8d776e1fc4d0a"},
]
-python-bitcoinlib = [
- {file = "python-bitcoinlib-0.11.0.tar.gz", hash = "sha256:3daafd63cb755f6e2067b7c9c514053856034c9f9363c80c37007744d54a2e06"},
- {file = "python_bitcoinlib-0.11.0-py3-none-any.whl", hash = "sha256:6e7982734637135599e2136d3c88d622f147e3b29201636665f799365784cd9e"},
-]
python-crontab = [
{file = "python-crontab-2.5.1.tar.gz", hash = "sha256:4bbe7e720753a132ca4ca9d4094915f40e9d9dc8a807a4564007651018ce8c31"},
]
@@ -1420,6 +1419,10 @@ toml = [
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]
+tomli = [
+ {file = "tomli-1.1.0-py3-none-any.whl", hash = "sha256:f4a182048010e89cbec0ae4686b21f550a7f2903f665e34a6de58ec15424f919"},
+ {file = "tomli-1.1.0.tar.gz", hash = "sha256:33d7984738f8bb699c9b0a816eb646a8178a69eaa792d258486776a5d21b8ca5"},
+]
tornado = [
{file = "tornado-6.1-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32"},
{file = "tornado-6.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c"},
diff --git a/pyproject.toml b/pyproject.toml
index 42f0169..88fdfea 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -13,7 +13,6 @@ markdown = "^3.1"
requests = "^2.21"
pygal = "^2.4"
pytz = "^2021.1"
-python-bitcoinlib = "^0.11"
stripe = "^2.24"
django-constance = {version = "^2.7",extras = ["database"]}
lcoreapi = {git = "https://git.packetimpact.net/lvpn/lcoreapi.git", tag = "v1.1.1"}
@@ -28,13 +27,13 @@ django-pipayments = {git = "git@git.packetimpact.net:lvpn/django-pipayments.git"
celery = "^5"
django-celery-beat = "^2.0.0"
redis = "^3.5.3"
-flower = "^0.9.5"
+flower = "^1"
django-extensions = "^3.1.3"
[tool.poetry.dev-dependencies]
pylint = "^2.3"
pylint-django = "^2.0.14"
-black = {version = "^20.8b1", allow-prereleases = true}
+black = {version = "^21.7b0", allow-prereleases = true}
selenium = "^3.141.0"
ipython = "^7.25.0"