Use mod_register_json to register with prosody
(untested)
This commit is contained in:
parent
9a51821e42
commit
44a56385f8
@ -2,6 +2,7 @@ from django import forms
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.core.validators import RegexValidator, URLValidator
|
||||
from jabberfr.validators import validate_jid_userpart, validate_jid
|
||||
from jabberfr.utils import pick_captcha, validate_captcha
|
||||
|
||||
USERNAME_HELP = """
|
||||
<ul>
|
||||
@ -116,6 +117,13 @@ class InscriptionForm(forms.Form):
|
||||
if choices:
|
||||
self.fields['server'].widget.choices = choices
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if cleaned_data['password'] != cleaned_data['confirm_password']:
|
||||
self.add_error(
|
||||
'confirm_password', 'Les mots de passe ne correspondent pas.'
|
||||
)
|
||||
|
||||
|
||||
class AdhesionForm(forms.Form):
|
||||
surname = forms.CharField(
|
||||
@ -157,3 +165,9 @@ class AdhesionForm(forms.Form):
|
||||
self.fields['captcha'].help_text = mark_safe(
|
||||
f'\n<br/>Répondez à cette question : {question}'
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
if not validate_captcha(cleaned_data):
|
||||
self.add_error('captcha', 'Êtes-vous un robot ?')
|
||||
self.reset_captcha(*pick_captcha())
|
||||
|
@ -117,6 +117,9 @@ STATICFILES_DIRS = [
|
||||
BASE_DIR / 'static'
|
||||
]
|
||||
|
||||
# Prosody mod_register_json token
|
||||
REGISTRATION_TOKEN = 'CHANGEME'
|
||||
|
||||
# To override in local settings
|
||||
CAPTCHA_QUESTIONS = [
|
||||
('1 + 1 ?', '2'),
|
||||
|
9
jabberfr/templates/inscription_success.html
Normal file
9
jabberfr/templates/inscription_success.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends "page_model.html" %}
|
||||
|
||||
{% block content %}
|
||||
<main>
|
||||
<h2 class="center">Inscription à un serveur Jabber par JabberFR</h2>
|
||||
<p>Votre compte <code>{{ jid }}</code> a été créé avec succès !</p>
|
||||
<hr />
|
||||
</main>
|
||||
{% endblock %}
|
@ -2,11 +2,16 @@ import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
from asyncio import gather, get_event_loop
|
||||
from random import randint
|
||||
from uuid import uuid4
|
||||
|
||||
from aiodns import DNSResolver
|
||||
from aiohttp import ClientSession, ClientTimeout
|
||||
from django import forms
|
||||
from aiohttp.web import (
|
||||
HTTPConflict,
|
||||
HTTPServiceUnavailable,
|
||||
)
|
||||
from django.conf import settings
|
||||
from slixmpp import JID, InvalidJID
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -14,6 +19,9 @@ BASE_MUC_URL = 'http://[::1]:5280/muc_list/?'
|
||||
|
||||
DOMAINS_URL = 'https://jabberfr.org/domains.xml'
|
||||
|
||||
REGISTER_URL = 'http://[::1]:5280/register_account/'
|
||||
VERIFY_URL = REGISTER_URL + 'verify'
|
||||
|
||||
|
||||
async def get_chatrooms(*, limit: int = 25, order: str = 'users') -> str:
|
||||
params = {
|
||||
@ -108,37 +116,76 @@ async def check_dns_config(data: dict) -> list[str]:
|
||||
return errors
|
||||
|
||||
|
||||
def check_passwords(form: forms.Form) -> bool:
|
||||
if form.cleaned_data['password'] != form.cleaned_data['confirm_password']:
|
||||
form.add_error(
|
||||
'confirm_password', 'Les mots de passe ne correspondent pas'
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
||||
def pick_captcha() -> tuple[str, str]:
|
||||
choice = randint(0, len(settings.CAPTCHA_QUESTIONS) - 1)
|
||||
question = settings.CAPTCHA_QUESTIONS[choice][0]
|
||||
return str(choice), question
|
||||
|
||||
|
||||
def validate_captcha(form: forms.Form) -> bool:
|
||||
data = form.cleaned_data
|
||||
print(data)
|
||||
def validate_captcha(data: dict) -> bool:
|
||||
try:
|
||||
captcha_id = data['captcha_id']
|
||||
if captcha_id < 0 or captcha_id >= len(settings.CAPTCHA_QUESTIONS):
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
form.add_error('captcha', 'Êtes-vous un robot ?')
|
||||
return False
|
||||
question_tup = settings.CAPTCHA_QUESTIONS[captcha_id]
|
||||
if question_tup is None:
|
||||
form.add_error('captcha', 'Êtes-vous un robot ?')
|
||||
return False
|
||||
if question_tup[1] != data['captcha']:
|
||||
form.add_error('captcha', 'Êtes-vous un robot ?')
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class RegistrationError(Exception):
|
||||
def __init__(self, text):
|
||||
super().__init__()
|
||||
self.text = text
|
||||
|
||||
|
||||
async def register_account(username: str, host: str, password: str, ip: str):
|
||||
"""Register an account using prosody’s mod_register_json"""
|
||||
try:
|
||||
jid = JID(f'{username}@{host}')
|
||||
except InvalidJID:
|
||||
return
|
||||
headers = {'Host': jid.server}
|
||||
# we don’t care about the email feature
|
||||
email = uuid4().hex + '@example.com'
|
||||
payload = {
|
||||
'username': jid.user,
|
||||
'password': password,
|
||||
'ip': ip,
|
||||
'auth_token': settings.REGISTRATION_TOKEN,
|
||||
'mail': email,
|
||||
}
|
||||
|
||||
tmout = ClientTimeout(total=10)
|
||||
async with ClientSession(raise_for_status=True, timeout=tmout) as session:
|
||||
try:
|
||||
async with session.post(REGISTER_URL, json=payload, headers=headers) as resp:
|
||||
uid = await resp.text()
|
||||
async with session.post(VERIFY_URL, data={'uid': uid}, headers=headers):
|
||||
pass
|
||||
except HTTPConflict:
|
||||
raise RegistrationError(
|
||||
'Ce nom d’utilisateur n’est pas disponible.'
|
||||
)
|
||||
except HTTPServiceUnavailable:
|
||||
raise RegistrationError(
|
||||
'Vous avez fait trop de demandes, veuillez revenir plus tard.'
|
||||
)
|
||||
except BaseException:
|
||||
raise RegistrationError(
|
||||
'Erreur inconnue. (serveur indisponible ?)'
|
||||
)
|
||||
|
||||
|
||||
def get_client_ip(request) -> str:
|
||||
"""Get a client IP"""
|
||||
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
|
||||
if x_forwarded_for:
|
||||
ip = x_forwarded_for.split(',')[0]
|
||||
else:
|
||||
ip = request.META.get('REMOTE_ADDR')
|
||||
return ip
|
||||
|
@ -6,9 +6,11 @@ from jabberfr.utils import (
|
||||
get_chatrooms,
|
||||
get_custom_domains,
|
||||
check_dns_config,
|
||||
check_passwords,
|
||||
pick_captcha,
|
||||
validate_captcha
|
||||
validate_captcha,
|
||||
register_account,
|
||||
RegistrationError,
|
||||
get_client_ip,
|
||||
)
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -79,8 +81,24 @@ async def inscription(request, domain=None):
|
||||
if request.method == 'POST':
|
||||
form = InscriptionForm(request.POST, custom_choices=choices)
|
||||
context['form'] = form
|
||||
if form.is_valid() and check_passwords(form):
|
||||
pass
|
||||
if form.is_valid():
|
||||
try:
|
||||
data = form.cleaned_data
|
||||
await register_account(
|
||||
data['username'],
|
||||
data['server'],
|
||||
data['password'],
|
||||
get_client_ip(request),
|
||||
)
|
||||
except RegistrationError as exc:
|
||||
form.add_error('__all__', exc.text)
|
||||
else:
|
||||
context['jid'] = data['username'] + '@' + data['server']
|
||||
return render(
|
||||
request,
|
||||
'inscription_success.html',
|
||||
context=context
|
||||
)
|
||||
else:
|
||||
form = InscriptionForm(custom_choices=choices)
|
||||
context['form'] = form
|
||||
@ -92,10 +110,8 @@ async def adhesion(request):
|
||||
if request.method == 'POST':
|
||||
form = AdhesionForm(request.POST)
|
||||
context['form'] = form
|
||||
if form.is_valid() and validate_captcha(form):
|
||||
if form.is_valid():
|
||||
return render(request, 'adhesion_success.html', context=context)
|
||||
else:
|
||||
form.reset_captcha(*pick_captcha())
|
||||
else:
|
||||
form = AdhesionForm(captcha=pick_captcha())
|
||||
context['form'] = form
|
||||
|
Loading…
Reference in New Issue
Block a user