import safe from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, IntegerField, SubmitField from wtforms.fields.html5 import DateField from wtforms.validators import DataRequired, Length, EqualTo, InputRequired, \ ValidationError, NumberRange, Optional from datetime import date from db import get_registration_code, get_registered_user def safe_password_validator(form: FlaskForm, field): strength = safe.check(field.data, level=safe.MEDIUM) if not strength.valid: raise ValidationError("Password is not secure enough: %s" % strength.message) def registration_code_validator(form: FlaskForm, field): registration_code = get_registration_code(field.data) if registration_code is None: raise ValidationError("Registration code invalid!") if registration_code.is_expired(): raise ValidationError("Registration code expired!") if not registration_code.has_available_uses(): raise ValidationError("Registration code out of uses!") def username_availability_validator(form: FlaskForm, field): registered_user = get_registered_user(field.data) if registered_user is not None: raise ValidationError("Username already registered!") def registration_code_expiration_date_validator(form: FlaskForm, field): if field.data <= date.today(): raise ValidationError("Expiration Date must be in the future!") class RegistrationForm(FlaskForm): username = StringField( 'Username', validators=[ DataRequired(), Length(min=3, max=30), username_availability_validator ]) password = PasswordField( 'Password', validators=[ InputRequired(), EqualTo('confirm', message='Passwords must match'), safe_password_validator ]) confirm = PasswordField('Repeat Password') registration_code = StringField( 'Registration Code', validators=[DataRequired(), registration_code_validator]) class LoginForm(FlaskForm): username = StringField('Username', validators=[DataRequired()]) token = PasswordField('Token', validators=[DataRequired()]) class RegistrationCodeForm(FlaskForm): expiration_time = DateField('Expiration Time', format='%Y-%m-%d', validators=[Optional(), registration_code_expiration_date_validator]) max_usages = IntegerField('Max Usages', validators=[NumberRange(min=1)]) class ExpireRegistrationCodeForm(FlaskForm): registration_code = StringField('Registration Code') expire = SubmitField(label='Expire') delete = SubmitField(label='Delete')