Add Discourse login

master
Alice 8 years ago
parent fc6108f214
commit 957737be1a

@ -155,6 +155,10 @@ SECURE_SSL_REDIRECT = False
SECURE_HSTS_SECONDS = 3600 SECURE_HSTS_SECONDS = 3600
SECURE_HSTS_INCLUDE_SUBDOMAINS = True SECURE_HSTS_INCLUDE_SUBDOMAINS = True
# Enable Discourse SSO
DISCOURSE_SSO = False
DISCOURSE_SECRET = '...'
DISCOURSE_URL = 'https://forum.ccrypto.org/'
# 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:

@ -54,3 +54,11 @@ class SignupForm(forms.Form, FormPureRender):
raise forms.ValidationError(_("Passwords are not the same")) 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")}),
)

@ -5,6 +5,7 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^login$', auth_views.login, name='login'), url(r'^login$', auth_views.login, name='login'),
url(r'^discourse_login', views.discourse_login, name='discourse_login'),
url(r'^logout$', views.logout, name='logout'), url(r'^logout$', views.logout, name='logout'),
url(r'^signup$', views.signup, name='signup'), url(r'^signup$', views.signup, name='signup'),

@ -1,11 +1,17 @@
import requests import requests
import io import io
import zipfile import zipfile
from urllib.parse import urlencode import hmac
import base64
from hashlib import sha256
from urllib.parse import urlencode, parse_qsl
from datetime import timedelta, datetime from datetime import timedelta, datetime
from django.http import HttpResponse, HttpResponseNotFound, HttpResponseForbidden from django.http import (
from django.http import JsonResponse HttpResponse, JsonResponse,
HttpResponseRedirect,
HttpResponseNotFound, HttpResponseForbidden
)
from django.shortcuts import render, redirect from django.shortcuts import render, redirect
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.decorators import login_required, user_passes_test from django.contrib.auth.decorators import login_required, user_passes_test
@ -21,7 +27,7 @@ from django.contrib.auth.models import User
from django_countries import countries 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, ReqEmailForm
from .models import GiftCode, VPNUser from .models import GiftCode, VPNUser
from .core import core_api from .core import core_api
from . import core from . import core
@ -85,6 +91,58 @@ def signup(request):
return redirect('account:index') return redirect('account:index')
@login_required
def discourse_login(request):
sso_secret = project_settings.DISCOURSE_SECRET
discourse_url = project_settings.DISCOURSE_URL
if project_settings.DISCOURSE_SSO is not True:
return HttpResponseNotFound()
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()
if signature != expected_signature:
return HttpResponseNotFound()
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))
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))
try:
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 = urlencode(payload_data)
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
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)

@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-07-07 17:43+0000\n" "POT-Creation-Date: 2016-09-01 03:18+0000\n"
"PO-Revision-Date: 2016-04-07 01:32+0000\n" "PO-Revision-Date: 2016-04-07 01:32+0000\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: \n" "Language-Team: \n"
@ -27,39 +27,39 @@ msgstr ""
msgid "hash" msgid "hash"
msgstr "" msgstr ""
#: lambdainst/admin.py:17 #: lambdainst/admin.py:22
msgid "Code must be [a-zA-Z0-9]" msgid "Code must be [a-zA-Z0-9]"
msgstr "" msgstr ""
#: lambdainst/admin.py:19 #: lambdainst/admin.py:24
msgid "Code must be between 1 and 32 characters" msgid "Code must be between 1 and 32 characters"
msgstr "" msgstr ""
#: lambdainst/admin.py:39 #: lambdainst/admin.py:43
msgid "(rewarded)" msgid "(rewarded)"
msgstr "" msgstr ""
#: lambdainst/admin.py:41 #: lambdainst/admin.py:45
msgid "(not rewarded)" msgid "(not rewarded)"
msgstr "" msgstr ""
#: lambdainst/admin.py:43 #: lambdainst/admin.py:48
msgid "Referrer" msgid "Referrer"
msgstr "" msgstr ""
#: lambdainst/admin.py:48 lambdainst/admin.py:92 #: lambdainst/admin.py:53 lambdainst/admin.py:96
msgid "Is paid?" msgid "Is paid?"
msgstr "Est payé?" msgstr "Est payé?"
#: lambdainst/admin.py:83 #: lambdainst/admin.py:87
msgid "Important dates" msgid "Important dates"
msgstr "Dates importantes" msgstr "Dates importantes"
#: lambdainst/admin.py:84 #: lambdainst/admin.py:88
msgid "Permissions" msgid "Permissions"
msgstr "Permissions" msgstr "Permissions"
#: lambdainst/admin.py:116 tickets/admin.py:52 #: lambdainst/admin.py:133 tickets/admin.py:52
msgid "Comment" msgid "Comment"
msgstr "Notes" msgstr "Notes"
@ -87,8 +87,9 @@ msgstr "Répétez"
msgid "Same Anything" msgid "Same Anything"
msgstr "La même chose" msgstr "La même chose"
#: lambdainst/forms.py:47 lambdainst/forms.py:48 templates/ccvpn/signup.html:30 #: lambdainst/forms.py:47 lambdainst/forms.py:48 lambdainst/forms.py:60
#: templates/lambdainst/settings.html.py:22 #: lambdainst/forms.py:61 templates/ccvpn/require_email.html.py:13
#: templates/ccvpn/signup.html:30 templates/lambdainst/settings.html.py:22
#: templates/registration/password_reset_form.html:11 #: templates/registration/password_reset_form.html:11
msgid "E-Mail" msgid "E-Mail"
msgstr "E-Mail" msgstr "E-Mail"
@ -97,27 +98,27 @@ msgstr "E-Mail"
msgid "Passwords are not the same" msgid "Passwords are not the same"
msgstr "Les mots de passe de correspondent pas" msgstr "Les mots de passe de correspondent pas"
#: lambdainst/models.py:24 #: lambdainst/models.py:25
msgid "VPN User" msgid "VPN User"
msgstr "VPN User" msgstr "VPN User"
#: lambdainst/models.py:25 #: lambdainst/models.py:26
msgid "VPN Users" msgid "VPN Users"
msgstr "VPN Users" msgstr "VPN Users"
#: lambdainst/models.py:92 #: lambdainst/models.py:97
msgid "Gift Code" msgid "Gift Code"
msgstr "Code cadeau" msgstr "Code cadeau"
#: lambdainst/models.py:93 #: lambdainst/models.py:98
msgid "Gift Codes" msgid "Gift Codes"
msgstr "Codes cadeau" msgstr "Codes cadeau"
#: lambdainst/models.py:138 #: lambdainst/models.py:143
msgid "Gift Code User" msgid "Gift Code User"
msgstr "Utilisateur de codes" msgstr "Utilisateur de codes"
#: lambdainst/models.py:139 #: lambdainst/models.py:144
msgid "Gift Code Users" msgid "Gift Code Users"
msgstr "Utilisateurs de codes" msgstr "Utilisateurs de codes"
@ -200,50 +201,50 @@ msgstr ""
msgid "%s Pbps" msgid "%s Pbps"
msgstr "" msgstr ""
#: lambdainst/views.py:91 #: lambdainst/views.py:152
msgid "Awesome VPN! 3€ per month, with a free 7 days trial!" msgid "Awesome VPN! 3€ per month, with a free 7 days trial!"
msgstr "" msgstr ""
#: lambdainst/views.py:98 templates/account_layout.html.py:9 #: lambdainst/views.py:159 templates/account_layout.html.py:9
#: templates/account_layout.html:11 templates/lambdainst/account.html.py:10 #: templates/account_layout.html:11 templates/lambdainst/account.html.py:10
msgid "Account" msgid "Account"
msgstr "Compte" msgstr "Compte"
#: lambdainst/views.py:137 lambdainst/views.py:180 #: lambdainst/views.py:198 lambdainst/views.py:221 lambdainst/views.py:246
msgid "OK!" msgid "OK!"
msgstr "OK!" msgstr "OK!"
#: lambdainst/views.py:139 #: lambdainst/views.py:200
msgid "Invalid captcha" msgid "Invalid captcha"
msgstr "Captcha invalide" msgstr "Captcha invalide"
#: lambdainst/views.py:153 #: lambdainst/views.py:214
msgid "Passwords do not match" msgid "Passwords do not match"
msgstr "Les mots de passe ne correspondent pas" msgstr "Les mots de passe ne correspondent pas"
#: lambdainst/views.py:165 templates/account_layout.html.py:13 #: lambdainst/views.py:231 templates/account_layout.html.py:13
#: templates/lambdainst/settings.html:6 #: templates/lambdainst/settings.html:6
msgid "Settings" msgid "Settings"
msgstr "Options" msgstr "Options"
#: lambdainst/views.py:176 #: lambdainst/views.py:242
msgid "Gift code not found or already used." msgid "Gift code not found or already used."
msgstr "Code inconnu ou déjà utilisé." msgstr "Code inconnu ou déjà utilisé."
#: lambdainst/views.py:178 #: lambdainst/views.py:244
msgid "Gift code only available to free accounts." msgid "Gift code only available to free accounts."
msgstr "Code uniquement disponible pour les nouveaux comptes." msgstr "Code uniquement disponible pour les nouveaux comptes."
#: lambdainst/views.py:200 templates/account_layout.html.py:15 #: lambdainst/views.py:266 templates/account_layout.html.py:15
#: templates/lambdainst/logs.html:6 #: templates/lambdainst/logs.html:6
msgid "Logs" msgid "Logs"
msgstr "Logs" msgstr "Logs"
#: lambdainst/views.py:207 templates/lambdainst/config.html.py:7 #: lambdainst/views.py:273 templates/lambdainst/config.html.py:7
msgid "Config" msgid "Config"
msgstr "Config" msgstr "Config"
#: lambdainst/views.py:296 payments/backends.py:120 payments/backends.py:122 #: lambdainst/views.py:377 payments/backends.py:120 payments/backends.py:122
#: templates/admin/index.html:53 templates/admin/index.html.py:56 #: templates/admin/index.html:53 templates/admin/index.html.py:56
#: templates/lambdainst/admin_ref.html:16 #: templates/lambdainst/admin_ref.html:16
#: templates/lambdainst/admin_status.html:16 templates/payments/list.html:13 #: templates/lambdainst/admin_status.html:16 templates/payments/list.html:13
@ -555,6 +556,18 @@ msgstr "Installation"
msgid "GNU/Linux" msgid "GNU/Linux"
msgstr "GNU/Linux" msgstr "GNU/Linux"
#: templates/ccvpn/require_email.html:8
msgid "E-mail Confirmation"
msgstr "Confirmation de l'adresse e-mail"
#: templates/ccvpn/require_email.html:16
msgid "Required to use the forums. A confirmation will be sent."
msgstr "Nécessaire pour les forums. Une confirmation sera envoyée."
#: templates/ccvpn/require_email.html:19
msgid "Continue"
msgstr "Continuer"
#: templates/ccvpn/signup.html:8 templates/ccvpn/signup.html.py:37 #: templates/ccvpn/signup.html:8 templates/ccvpn/signup.html.py:37
#: templates/layout.html:34 #: templates/layout.html:34
msgid "Sign up" msgid "Sign up"

@ -0,0 +1,25 @@
{% extends 'layout.html' %}
{% load i18n %}
{% load staticfiles %}
{% block content %}
<div class="content formpage signuppage pure-g">
<div class="pure-u-1 pure-u-sm-1-2 pure-u-xl-1-3">
<h1>{% trans 'E-mail Confirmation' %}</h1>
<form class="pure-form pure-form-stacked" action="" method="post">
{% csrf_token %}
{{ form.email.errors }}
<label for="email">{% trans 'E-Mail' %}</label>
<input type="email" id="email" name="email" value="{{email}}" />
<p class="inputhelp">
<b>{% trans 'Required to use the forums. A confirmation will be sent.' %}</b>
</p>
<input type="submit" class="pure-button pure-button-primary" value="{% trans 'Continue' %}" />
</form>
</div>
</div>
{% endblock %}
Loading…
Cancel
Save