Add secondary core API mode and clean settings

master
Alice 9 years ago
parent 6110cc3bdf
commit c102a15743

@ -157,26 +157,31 @@ SECURE_HSTS_INCLUDE_SUBDOMAINS = True
# OpenVPN CA Certificate # OpenVPN CA Certificate
with open(BASE_DIR + '/ccvpn/ca.crt') as ca_file: with open(BASE_DIR + '/ccvpn/ca.crt') as ca_file:
OPENVPN_CA = ca_file.read() OPENVPN_CA = ca_file.read()
# HTML added before </head>
ADDITIONAL_HEADER_HTML = '' ADDITIONAL_HEADER_HTML = ''
# HTML added before </body>
ADDITIONAL_HTML = '' ADDITIONAL_HTML = ''
LAMBDAINST_CLUSTER_MESSAGES = {} # 'cluster_name': "No P2P" # Custom per cluster message displayed config page
# 'cluster_name': "No P2P"
LAMBDAINST_CLUSTER_MESSAGES = {}
# Name used in ticket emails
TICKETS_SITE_NAME = 'CCrypto VPN Support' TICKETS_SITE_NAME = 'CCrypto VPN Support'
ROOT_URL = "" # Full URL to the site root # Full URL to the site root
ROOT_URL = ''
# reCAPTCHA API details. If empty, no captcha is displayed.
RECAPTCHA_API = 'https://www.google.com/recaptcha/api/siteverify' RECAPTCHA_API = 'https://www.google.com/recaptcha/api/siteverify'
RECAPTCHA_SITE_KEY = '' RECAPTCHA_SITE_KEY = ''
RECAPTCHA_SECRET_KEY = '' RECAPTCHA_SECRET_KEY = ''
# lcore API # lcore API settings
LCORE = dict( LCORE = dict(
BASE_URL='https://core.test.lambdavpn.net/v1/', BASE_URL='https://core.test.lambdavpn.net/v1/',
API_KEY='', API_KEY='',
@ -185,13 +190,24 @@ LCORE = dict(
CACHE_TTL=10, CACHE_TTL=10,
) )
# VPN auth credentials and expiration time storage
# - if 'core', password and expiration_date will be replicated to core and
# auth will be done from there.
# - if 'inst', both will be kept here and core should call the API here to
# authenticate users.
# 'core' is faster and doesn't depend on the instance's stability, 'inst'
# lets you generate client_config dynamically.
# /!\ don't use 'core' with unit tests for now.
VPN_AUTH_STORAGE = 'inst'
# Payment & Trial # Payment & Trial
# Payment backends. See payments/backends.py for more infos.
PAYMENTS_BACKENDS = { PAYMENTS_BACKENDS = {
'paypal': { 'paypal': {
'TEST': True, 'TEST': True, # Sandbox
'ADDRESS': 'paypal@xomg.net', # Your PayPal primary address 'ADDRESS': 'paypal@ccrypto.org', # Your PayPal primary address
}, },
# Remove the leading '_' to enable these backends. # Remove the leading '_' to enable these backends.
'_stripe': { '_stripe': {
@ -206,9 +222,9 @@ PAYMENTS_BACKENDS = {
PAYMENTS_CURRENCY = ('eur', '') PAYMENTS_CURRENCY = ('eur', '')
PAYMENTS_MONTHLY_PRICE = 300 # in currency*100 PAYMENTS_MONTHLY_PRICE = 300 # in currency*100
TRIAL_PERIOD = timedelta(hours=2) TRIAL_PERIOD = timedelta(hours=2) # Time added on each trial awarded
TRIAL_PERIOD_LIMIT = 2 # 2 * 2h = 4h, still has to push the button twice TRIAL_PERIOD_LIMIT = 2 # 2 * 2h = 4h, still has to push the button twice
NOTIFY_DAYS_BEFORE = (3, 1) # notify twice 3 and 1 days before expiration NOTIFY_DAYS_BEFORE = (3, 1) # notify twice: 3 and 1 days before expiration
# Local settings # Local settings

@ -7,7 +7,7 @@ from django.contrib.auth.models import User
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from lambdainst.models import VPNUser, GiftCode, GiftCodeUser from lambdainst.models import VPNUser, GiftCode, GiftCodeUser
from . import core
def make_user_link(user): 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)
@ -52,6 +52,11 @@ class VPNUserInline(admin.StackedInline):
is_paid.boolean = True is_paid.boolean = True
is_paid.short_description = _("Is paid?") is_paid.short_description = _("Is paid?")
def save_model(self, request, obj, form, change):
obj.save()
if change and 'expiration' in form.changed_data:
core.update_user_expiration(obj.user)
class GiftCodeUserAdmin(admin.TabularInline): class GiftCodeUserAdmin(admin.TabularInline):
model = GiftCodeUser model = GiftCodeUser
@ -104,6 +109,20 @@ class UserAdmin(UserAdmin):
return s return s
links.allow_tags = True links.allow_tags = True
def save_model(self, request, obj, form, change):
super().save_model(request, obj, form, change)
# Notify core
if core.VPN_AUTH_STORAGE == 'core':
if change and 'is_active' in form.changed_data:
core.update_user_expiration(obj)
def delete_model(self, request, obj):
if core.VPN_AUTH_STORAGE == 'core':
core.delete_user(obj.username)
super().delete_model(request, obj)
class GiftCodeAdmin(admin.ModelAdmin): class GiftCodeAdmin(admin.ModelAdmin):
fields = ('code', 'time', 'created', 'created_by', 'single_use', 'free_only', fields = ('code', 'time', 'created', 'created_by', 'single_use', 'free_only',

@ -23,6 +23,9 @@ if isinstance(LCORE_CACHE_TTL, int):
LCORE_CACHE_TTL = timedelta(seconds=LCORE_CACHE_TTL) LCORE_CACHE_TTL = timedelta(seconds=LCORE_CACHE_TTL)
assert isinstance(LCORE_CACHE_TTL, timedelta) assert isinstance(LCORE_CACHE_TTL, timedelta)
VPN_AUTH_STORAGE = settings.VPN_AUTH_STORAGE
assert VPN_AUTH_STORAGE in ('core', 'inst')
core_api = lcoreapi.API(LCORE_API_KEY, LCORE_API_SECRET, LCORE_BASE_URL) core_api = lcoreapi.API(LCORE_API_KEY, LCORE_API_SECRET, LCORE_BASE_URL)
@ -97,3 +100,54 @@ def get_locations():
return locations return locations
def create_user(username, cleartext_password):
""" The password will be hashed and stored safely on the core,
so we have to send it clearly here.
"""
path = core_api.info['current_instance'] + '/users/'
core_api.post(path, data={
'username': username,
'password': cleartext_password,
'expiration_date': datetime(1, 1, 1).isoformat(), # Expired.
})
def update_user_expiration(user):
path = core_api.info['current_instance'] + '/users/' + user.username
try:
if not user.is_active:
core_api.patch(path, data={
'expiration_date': datetime(1, 1, 1).isoformat(), # Expired.
})
return
core_api.patch(path, data={
'expiration_date': user.vpnuser.expiration,
})
except lcoreapi.APIError:
# User can't do anything to this, we should just report it
logger = logging.getLogger('django.request')
logger.exception("core api error, missing user (exp update)")
def update_user_password(user, cleartext_password):
path = core_api.info['current_instance'] + '/users/' + user.username
try:
core_api.patch(path, data={
'password': cleartext_password,
})
except lcoreapi.APINotFoundError:
# This time we can try fix it!
create_user(user.username, cleartext_password)
except lcoreapi.APIError:
# and maybe fail.
logger = logging.getLogger('django.request')
logger.exception("core api error (password update)")
def delete_user(username):
path = core_api.info['current_instance'] + '/users/' + username
core_api.delete(path)

@ -7,6 +7,7 @@ from django.utils import timezone
from django.conf import settings from django.conf import settings
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from . import core
assert isinstance(settings.TRIAL_PERIOD, timedelta) assert isinstance(settings.TRIAL_PERIOD, timedelta)
assert isinstance(settings.TRIAL_PERIOD_LIMIT, int) assert isinstance(settings.TRIAL_PERIOD_LIMIT, int)
@ -55,6 +56,10 @@ class VPNUser(models.Model):
self.expiration = now self.expiration = now
self.expiration += time self.expiration += time
# Propagate update to core
if core.VPN_AUTH_STORAGE == 'core':
core.update_user_expiration(self.user)
def give_trial_period(self): def give_trial_period(self):
self.add_paid_time(settings.TRIAL_PERIOD) self.add_paid_time(settings.TRIAL_PERIOD)
self.trial_periods_given += 1 self.trial_periods_given += 1

@ -23,8 +23,8 @@ from django_countries import countries
from payments.models import ACTIVE_BACKENDS from payments.models import ACTIVE_BACKENDS
from .forms import SignupForm from .forms import SignupForm
from .models import GiftCode, VPNUser from .models import GiftCode, VPNUser
from .core import core_api, current_active_sessions, get_locations as core_get_locations from .core import core_api
from .core import LCORE_INST_SECRET, LCORE_SOURCE_ADDR from . import core
from . import graphs from . import graphs
from . import openvpn from . import openvpn
@ -34,7 +34,7 @@ def get_locations():
that depends on the request that depends on the request
""" """
countries_d = dict(countries) countries_d = dict(countries)
locations = core_get_locations() locations = core.get_locations()
for k, v in locations: for k, v in locations:
cc = v['country_code'].upper() cc = v['country_code'].upper()
v['country_name'] = countries_d.get(cc, cc) v['country_name'] = countries_d.get(cc, cc)
@ -69,6 +69,9 @@ def signup(request):
form.cleaned_data['password']) form.cleaned_data['password'])
user.save() user.save()
if core.VPN_AUTH_STORAGE == 'core':
core.create_user(form.cleaned_data['username'], form.cleaned_data['password'])
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:
@ -154,6 +157,11 @@ def settings(request):
else: else:
request.user.set_password(pw) request.user.set_password(pw)
if core.VPN_AUTH_STORAGE == 'core':
core.update_user_password(request.user, pw)
messages.success(request, _("OK!"))
email = request.POST.get('email') email = request.POST.get('email')
if email: if email:
request.user.email = email request.user.email = email
@ -269,11 +277,14 @@ def api_auth(request):
if request.method != 'POST': if request.method != 'POST':
return HttpResponseNotFound() return HttpResponseNotFound()
if core.VPN_AUTH_STORAGE != 'inst':
return HttpResponseNotFound()
username = request.POST.get('username') username = request.POST.get('username')
password = request.POST.get('password') password = request.POST.get('password')
secret = request.POST.get('secret') secret = request.POST.get('secret')
if secret != LCORE_INST_SECRET: if secret != core.LCORE_INST_SECRET:
return HttpResponseForbidden(content="Invalid secret") return HttpResponseForbidden(content="Invalid secret")
user = authenticate(username=username, password=password) user = authenticate(username=username, password=password)
@ -295,7 +306,7 @@ def status(request):
ctx = { ctx = {
'title': _("Status"), 'title': _("Status"),
'n_users': VPNUser.objects.filter(expiration__gte=timezone.now()).count(), 'n_users': VPNUser.objects.filter(expiration__gte=timezone.now()).count(),
'n_sess': current_active_sessions(), 'n_sess': core.current_active_sessions(),
'n_gws': sum(l['servers'] for cc, l in locations), 'n_gws': sum(l['servers'] for cc, l in locations),
'n_countries': len(set(cc for cc, l in locations)), 'n_countries': len(set(cc for cc, l in locations)),
'total_bw': sum(l['bandwidth'] for cc, l in locations), 'total_bw': sum(l['bandwidth'] for cc, l in locations),

Loading…
Cancel
Save