mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-02-06 03:13:42 -05:00
Copying what they’ve done on GOV.UK Pay, we should let users: - generate as many keys as they want - only see the key at time of creation - give keys a name - revoke any key at any time (this should be a one way operation) And based on discussions with @minglis and @servingUpAces, the keys should be used in conjunction with some kind of service ID, which gets encrypted with the key. In other words the secret itself never gets sent over the wire. This commit adds the UI (but not the underlying API integration) for doing the above.
242 lines
7.1 KiB
Python
242 lines
7.1 KiB
Python
import re
|
|
from flask_wtf import Form
|
|
|
|
from wtforms import (
|
|
StringField,
|
|
PasswordField,
|
|
ValidationError,
|
|
TextAreaField,
|
|
FileField,
|
|
SelectField
|
|
)
|
|
from wtforms.validators import DataRequired, Email, Length, Regexp
|
|
|
|
from app.main.validators import Blacklist, ValidateUserCodes, CsvFileValidator
|
|
from app.main.dao import verify_codes_dao
|
|
from app.main.encryption import check_hash
|
|
|
|
|
|
def email_address():
|
|
gov_uk_email \
|
|
= "(^[^@^\\s]+@[^@^\\.^\\s]+(\\.[^@^\\.^\\s]*)*.gov.uk)"
|
|
return StringField('Email address', validators=[
|
|
Length(min=5, max=255),
|
|
DataRequired(message='Email cannot be empty'),
|
|
Email(message='Enter a valid email address'),
|
|
Regexp(regex=gov_uk_email, message='Enter a gov.uk email address')])
|
|
|
|
|
|
class UKMobileNumber(StringField):
|
|
|
|
def pre_validate(self, form):
|
|
|
|
self.data = self.data.replace('(', '')
|
|
self.data = self.data.replace(')', '')
|
|
self.data = self.data.replace(' ', '')
|
|
self.data = self.data.replace('-', '')
|
|
|
|
if self.data.startswith('+'):
|
|
self.data = self.data[1:]
|
|
|
|
if not sum(
|
|
self.data.startswith(prefix) for prefix in ['07', '447', '4407', '00447']
|
|
):
|
|
raise ValidationError('Must be a UK mobile number (eg 07700 900460)')
|
|
|
|
for digit in self.data:
|
|
try:
|
|
int(digit)
|
|
except(ValueError):
|
|
raise ValidationError('Must not contain letters or symbols')
|
|
|
|
self.data = self.data.split('7', 1)[1]
|
|
|
|
if len(self.data) > 9:
|
|
raise ValidationError('Too many digits')
|
|
|
|
if len(self.data) < 9:
|
|
raise ValidationError('Not enough digits')
|
|
|
|
def post_validate(self, form, validation_stopped):
|
|
|
|
if len(self.data) != 9:
|
|
return
|
|
# TODO implement in the render field method.
|
|
# API's require no spaces in the number
|
|
# self.data = '+44 7{} {} {}'.format(*re.findall('...', self.data))
|
|
self.data = '+447{}{}{}'.format(*re.findall('...', self.data))
|
|
|
|
|
|
def mobile_number():
|
|
return UKMobileNumber('Mobile phone number',
|
|
validators=[DataRequired(message='Cannot be empty')])
|
|
|
|
|
|
def password(label='Create a password'):
|
|
return PasswordField(label,
|
|
validators=[DataRequired(message='Password can not be empty'),
|
|
Length(10, 255, message='Password must be at least 10 characters'),
|
|
Blacklist(message='That password is blacklisted, too common')])
|
|
|
|
|
|
def sms_code():
|
|
verify_code = '^\d{5}$'
|
|
return StringField('Text message confirmation code',
|
|
validators=[DataRequired(message='Text message confirmation code can not be empty'),
|
|
Regexp(regex=verify_code,
|
|
message='Text message confirmation code must be 5 digits'),
|
|
ValidateUserCodes(code_type='sms')])
|
|
|
|
|
|
def email_code():
|
|
verify_code = '^\d{5}$'
|
|
return StringField("Email confirmation code",
|
|
validators=[DataRequired(message='Email confirmation code can not be empty'),
|
|
Regexp(regex=verify_code, message='Email confirmation code must be 5 digits'),
|
|
ValidateUserCodes(code_type='email')])
|
|
|
|
|
|
class LoginForm(Form):
|
|
email_address = StringField('Email address', validators=[
|
|
Length(min=5, max=255),
|
|
DataRequired(message='Email cannot be empty'),
|
|
Email(message='Enter a valid email address')
|
|
])
|
|
password = PasswordField('Password', validators=[
|
|
DataRequired(message='Enter your password')
|
|
])
|
|
|
|
|
|
class RegisterUserForm(Form):
|
|
def __init__(self, existing_email_addresses, *args, **kwargs):
|
|
self.existing_emails = existing_email_addresses
|
|
super(RegisterUserForm, self).__init__(*args, **kwargs)
|
|
|
|
name = StringField('Full name',
|
|
validators=[DataRequired(message='Name can not be empty')])
|
|
email_address = email_address()
|
|
mobile_number = mobile_number()
|
|
password = password()
|
|
|
|
def validate_email_address(self, field):
|
|
# Validate email address is unique.
|
|
if self.existing_emails(field.data):
|
|
raise ValidationError('Email address already exists')
|
|
|
|
|
|
class TwoFactorForm(Form):
|
|
def __init__(self, user_codes, *args, **kwargs):
|
|
'''
|
|
Keyword arguments:
|
|
user_codes -- List of user code objects which have the fields
|
|
(code_type, expiry_datetime, code)
|
|
'''
|
|
self.user_codes = user_codes
|
|
super(TwoFactorForm, self).__init__(*args, **kwargs)
|
|
|
|
sms_code = sms_code()
|
|
|
|
|
|
class VerifyForm(Form):
|
|
def __init__(self, user_codes, *args, **kwargs):
|
|
'''
|
|
Keyword arguments:
|
|
user_codes -- List of user code objects which have the fields
|
|
(code_type, expiry_datetime, code)
|
|
'''
|
|
self.user_codes = user_codes
|
|
super(VerifyForm, self).__init__(*args, **kwargs)
|
|
|
|
sms_code = sms_code()
|
|
email_code = email_code()
|
|
|
|
|
|
class EmailNotReceivedForm(Form):
|
|
email_address = email_address()
|
|
|
|
|
|
class TextNotReceivedForm(Form):
|
|
mobile_number = mobile_number()
|
|
|
|
|
|
class AddServiceForm(Form):
|
|
def __init__(self, names_func, *args, **kwargs):
|
|
"""
|
|
Keyword arguments:
|
|
names_func -- Returns a list of unique service_names already registered
|
|
on the system.
|
|
"""
|
|
self._names_func = names_func
|
|
super(AddServiceForm, self).__init__(*args, **kwargs)
|
|
|
|
name = StringField(
|
|
'Service name',
|
|
validators=[
|
|
DataRequired(message='Service name can not be empty')
|
|
]
|
|
)
|
|
|
|
def validate_name(self, a):
|
|
if a.data in self._names_func():
|
|
raise ValidationError('Service name already exists')
|
|
|
|
|
|
class ServiceNameForm(Form):
|
|
name = StringField(u'New name')
|
|
|
|
|
|
class ConfirmPasswordForm(Form):
|
|
password = PasswordField(u'Enter password')
|
|
|
|
|
|
class TemplateForm(Form):
|
|
name = StringField(
|
|
u'Template name',
|
|
validators=[DataRequired(message="Template name cannot be empty")])
|
|
template_type = SelectField(u'Template type', choices=[('sms', 'SMS')])
|
|
content = TextAreaField(
|
|
u'Message',
|
|
validators=[DataRequired(message="Template content cannot be empty")])
|
|
|
|
|
|
class ForgotPasswordForm(Form):
|
|
email_address = email_address()
|
|
|
|
|
|
class NewPasswordForm(Form):
|
|
new_password = password()
|
|
|
|
|
|
class ChangePasswordForm(Form):
|
|
old_password = password('Current password')
|
|
new_password = password('New password')
|
|
|
|
|
|
class CsvUploadForm(Form):
|
|
file = FileField('File to upload', validators=[DataRequired(
|
|
message='Please pick a file'), CsvFileValidator()])
|
|
|
|
|
|
class ChangeNameForm(Form):
|
|
new_name = StringField(u'Your name')
|
|
|
|
|
|
class ChangeEmailForm(Form):
|
|
email_address = email_address()
|
|
|
|
|
|
class ConfirmEmailForm(Form):
|
|
email_code = email_code()
|
|
|
|
|
|
class ChangeMobileNumberForm(Form):
|
|
mobile_number = mobile_number()
|
|
|
|
|
|
class ConfirmMobileNumberForm(Form):
|
|
sms_code = sms_code()
|
|
|
|
|
|
class CreateKeyForm(Form):
|
|
key_name = StringField(u'Description of key')
|