hébergement form, with DNS checks and form field validation

This commit is contained in:
Mathieu Pasquet 2021-04-17 22:25:35 +02:00
parent ac491fd571
commit 84d7d6334e
5 changed files with 173 additions and 2 deletions

View File

@ -31,6 +31,7 @@ ALLOWED_HOSTS = [
'jabberfr.org',
'irc.jabberfr.org',
'chat.jabberfr.org',
'localhost',
]
DEFAULT_HOST = 'jabberfr'

View File

@ -0,0 +1,31 @@
{% extends "page_model.html" %}
{% block content %}
<div>
<h2>Hébergement</h2>
<p>Vous disposez dun nom de domaine et vous souhaitez lutiliser pour communiquer avec XMPP, mais sans gérer vous même votre serveur?</p>
<p>Vous pouvez désormais nous déléguer ladministration de votre service XMPP!</p>
<p>Ajoutez un enregistrement <code>CNAME</code> pointant vers <code>jabberfr.org.</code> dans votre zone DNS (sans oublier le point à la fin!), et remplissez le formulaire ci-dessous:</p>
</div>
<div>
<div>
{% if errors %}
<p class="error">Des erreurs ont été rencontrées lors de la validation de votre demande:</p>
{% for error in errors %}
{{ error | safe }}
{% endfor %}
<p>Si vous avez du mal à faire ça, nhésitez pas à nous demander de laide sur <a href="xmpp:jabberfr@chat.jabberfr.org?join">jabberfr@chat.jabberfr.org</a> (<a href="https://chat.jabberfr.org/converse.js/jabberfr@chat.jabberfr.org">webchat</a>)!</p>
{% endif %}
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<p>Vous pouvez à tout moment récupérer lintégralité des données de votre serveur, par exemple si vous souhaitez vous auto-héberger, ou passer chez un autre hébergeur.</p>
<p>Nhésitez pas à <a href="/adhesion/">adhérer à lassociation</a> pour décider de lévolution du service avec nous.</p>
</div>
<p><input type="submit" value="Envoyer!"/></p>
</form>
</div>
{% endblock %}

View File

@ -0,0 +1,9 @@
{% extends "page_model.html" %}
{% block content %}
<p>Et voilà!</p>
<p>Nous allons configurer ce quil faut pour gérer votre domaine, nous vous enverrons un email dès que tout est en place de notre côté.</p>
{% endblock %}

View File

@ -16,7 +16,7 @@ Including another URLconf
from django.urls import path
from django.views.generic import TemplateView
from jabberfr.views import get_root_index
from jabberfr.views import get_root_index, hebergement
PAGES = [
@ -26,7 +26,8 @@ PAGES = [
]
urlpatterns = [
path('', get_root_index)
path('', get_root_index),
path('hébergement', hebergement),
]
urlpatterns += [

View File

@ -1,5 +1,9 @@
from asyncio import gather, get_event_loop
from aiohttp import ClientSession, ClientError, ClientTimeout
from aiodns import DNSResolver
from django.shortcuts import render
from django import forms
from django.core.validators import RegexValidator, URLValidator
BASE_MUC_URL = 'http://[::1]:5280/muc_list/?'
@ -10,6 +14,7 @@ TABLE_END = """
</table>
"""
async def get_chatrooms(*, limit: int = 25, order: str = 'users') -> str:
params = {
'limit': str(limit),
@ -47,3 +52,127 @@ async def get_chat_index(request):
}
return render(request, 'chat/index.html', context=context)
class HebergForm(forms.Form):
"""Form for hosted domains"""
domain = forms.CharField(
max_length=100,
required=True,
label='Votre nom de domaine',
validators=[
RegexValidator(
regex=URLValidator.host_re,
message='Ce nom de domaine nest pas valide'
)
],
)
email = forms.EmailField(
required=True,
label='Votre adresse email',
)
type = forms.ChoiceField(
choices=[
('users', 'Comptes utilisateurs'),
('muc', 'Salons'),
],
label='Type dhébergement',
required=True,
)
message = forms.CharField(
widget=forms.Textarea,
max_length=3000,
label='Un petit mot?'
)
cname = forms.BooleanField(
required=True,
label='Jai effectué la redirection CNAME',
)
cgu = forms.BooleanField(
required=True,
label=(
'Jaccepte les CGU'
)
)
def check_srv_contents(srv_client, srv_server) -> bool:
if not isinstance(srv_client, Exception): # No SRV
for srv in srv_client:
if srv.host != 'jabberfr.org' or srv.port != 5222:
return True
if not isinstance(srv_server, Exception): # No SRV
for srv in srv_server:
if srv.host != 'jabberfr.org' or srv.port != 5269:
return True
return False
def format_srv_errors(srv_client, srv_server) -> str:
msg = (
'<p>Vous avez des enregistrements SRV qui ne pointent pas '
'vers JabberFR:</p>\n'
)
records = []
if not isinstance(srv_client, Exception):
for srv in srv_client:
records.append(srv)
if not isinstance(srv_server, Exception):
for srv in srv_server:
records.append(srv)
text = '<pre>'
for rec in records:
text += (
f'{rec.host}. {rec.type} {rec.ttl} {rec.priority} '
f'{rec.weight} {rec.port}\n'
)
text += '</pre>'
return msg + text
async def check_dns_config(form: HebergForm) -> list[str]:
errors = []
data = form.cleaned_data
resolver = DNSResolver(loop=get_event_loop())
cname, srv_client, srv_server = await gather(
resolver.query(data['domain'], 'CNAME'),
resolver.query(f'_xmpp-server._tcp.{data["domain"]}', 'SRV'),
resolver.query(f'_xmpp-client._tcp.{data["domain"]}', 'SRV'),
return_exceptions=True,
)
if check_srv_contents(srv_client, srv_server):
errors.append(format_srv_errors(srv_client, srv_server))
if isinstance(cname, BaseException):
errors.append(
f'<p>Vous navez pas denregistrement <code>CNAME</code> pour ce'
f' domaine, ajoutez-en un qui pointe vers JabberFR:\n'
f'<pre><code>{data["domain"]} IN CNAME jabberfr.org</code></pre>'
)
elif cname.cname != 'jabberfr.org':
errors.append(
f'<p>Votre enregistrement <code>CNAME</code> ne pointe pas '
f'vers <code>jabberfr.org</code> mais vers '
f'<code>{cname.cname}</code>, vous devriez changer ça dans '
f'votre interface de gestion DNS.</p>'
)
return errors
async def hebergement(request):
context = {
'title': 'Hébergement chez JabberFR',
}
if request.method == 'POST':
form = HebergForm(request.POST)
context['form'] = form
if form.is_valid():
errors = await check_dns_config(form)
if not errors:
return render(request, 'hebergement_success.html', context)
context['errors'] = errors
else:
form = HebergForm()
context['form'] = form
return render(request, 'hebergement.html', context=context)