From df385e40d5ee5eb5a69d78dd0974fe4760140e47 Mon Sep 17 00:00:00 2001
From: Paul Marillonnet <pmarillonnet@entrouvert.com>
Date: Wed, 5 Oct 2022 09:30:23 +0200
Subject: [PATCH 08/10] use phone number as registration means in form
 validation (#69223)

---
 src/authentic2/views.py | 84 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 82 insertions(+), 2 deletions(-)

diff --git a/src/authentic2/views.py b/src/authentic2/views.py
index 6398ab5bc..81c31f318 100644
--- a/src/authentic2/views.py
+++ b/src/authentic2/views.py
@@ -1021,7 +1021,7 @@ class BaseRegistrationView(HomeURLMixin, FormView):
 
         self.token = {}
         self.ou = get_default_ou()
-        # load pre-filled values
+        # load pre-filled values when registering with email address
         if request.GET.get('token'):
             try:
                 self.token = crypto.loads(
@@ -1047,12 +1047,92 @@ class BaseRegistrationView(HomeURLMixin, FormView):
                 },
             )
         email = form.cleaned_data.pop('email')
+        if email:
+            return self.perform_email_registration(form, email)
 
+        if settings.A2_ACCEPT_PHONE_AUTHENTICATION:
+            phone = form.cleaned_data.pop('phone')
+            return self.perform_phone_registration(form, phone)
+
+        return ValidationError(_('No means of registration provided.'))
+
+    def perform_phone_registration(self, form, phone):
+        code_exists = models.SMSCode.objects.filter(
+            kind=models.SMSCode.KIND_REGISTRATION, phone=phone, expires__gt=timezone.now()
+        ).exists()
+        resend_key = 'registration-allow-sms-resend'
+        if (
+            app_settings.A2_SMS_CODE_EXISTS_WARNING
+            and code_exists
+            and not self.request.session.get(resend_key)
+        ):
+            self.request.session[resend_key] = True
+            form.add_error(
+                'phone',
+                _(
+                    'An SMS code has already been sent to %s. Click "Validate" again if you really want it to be'
+                    ' sent again.'
+                )
+                % phone,
+            )
+            return self.form_invalid(form)
+        self.request.session[resend_key] = False
+
+        if is_ratelimited(
+            self.request,
+            key='post:sms',
+            group='registration-sms',
+            rate=app_settings.A2_SMS_RATELIMIT,
+            increment=True,
+        ):
+            form.add_error(
+                'phone',
+                (
+                    'Multiple SMSs have already been sent to this number. Further attempts are blocked,'
+                    ' try again later.'
+                ),
+            )
+            return self.form_invalid(form)
+        if is_ratelimited(
+            self.request,
+            key='ip',
+            group='registration-sms',
+            rate=app_settings.A2_SMS_IP_RATELIMIT,
+            increment=True,
+        ):
+            form.add_error(
+                'email',
+                _(
+                    'Multiple registration attempts have already been made from this IP address. No further'
+                    ' SMS will be sent for now, try again later.'
+                ),
+            )
+            return self.form_invalid(form)
+        try:
+            code = utils_misc.send_registration_sms(self.request, phone, ou=self.ou, **self.token)
+        except utils_misc.SMSError:
+            messages.warning(
+                self.request,
+                _(
+                    'Something went wrong while trying to send the SMS registration code to you.'
+                    ' Please contact your administrator and try again later.'
+                ),
+            )
+            return utils_misc.redirect(self.request, reverse('auth_homepage'))
+
+        self.request.session['registered_phone'] = phone
+        return utils_misc.redirect(
+            self.request,
+            reverse('input_registration_code', kwargs={'token': code.url_token}),
+            params={REDIRECT_FIELD_NAME: self.next_url, 'token': code.url_token},
+        )
+
+    def perform_email_registration(self, form, email):
         # if an email has already been sent, warn once before allowing resend
         token = models.Token.objects.filter(
             kind='registration', content__email__iexact=email, expires__gt=timezone.now()
         ).exists()
-        resend_key = 'registration-allow-resend'
+        resend_key = 'registration-allow-email-resend'
         if app_settings.A2_TOKEN_EXISTS_WARNING and token and not self.request.session.get(resend_key):
             self.request.session[resend_key] = True
             form.add_error(
-- 
2.37.2

