use phone number as registration means in form validation (#69223)

This commit is contained in:
Paul Marillonnet 2022-10-05 09:30:23 +02:00
parent d40f5d382c
commit e35275fe45
1 changed files with 83 additions and 2 deletions

View File

@ -70,6 +70,7 @@ from .utils import misc as utils_misc
from .utils import switch_user as utils_switch_user
from .utils.evaluate import make_condition_context
from .utils.service import get_service, set_home_url
from .utils.sms import SMSError, send_registration_sms
from .utils.view_decorators import enable_view_restriction
from .utils.views import csrf_token_check
@ -1021,7 +1022,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 +1048,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 = send_registration_sms(self.request, phone, ou=self.ou, **self.token)
except 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(