Source code for flask_unchained.bundles.security.forms

import inspect

from flask import current_app as app, request
from flask_unchained.bundles.controller.utils import _validate_redirect_url
from flask_unchained.bundles.sqlalchemy import ModelForm
from flask_unchained import unchained, lazy_gettext as _
from wtforms import (Field, HiddenField, StringField, SubmitField, ValidationError,
                     fields, validators)

from .models import User
from .services import SecurityUtilsService, UserManager
from .utils import current_user

user_manager: UserManager = unchained.get_local_proxy('user_manager')
security_utils_service: SecurityUtilsService = \
    unchained.get_local_proxy('security_utils_service')


password_required = validators.DataRequired(
    _('flask_unchained.bundles.security:password_required'))

password_equal = validators.EqualTo('password', message=_(
    'flask_unchained.bundles.security:error.retype_password_mismatch'))

new_password_equal = validators.EqualTo('new_password', message=_(
    'flask_unchained.bundles.security:error.retype_password_mismatch'))


[docs]def unique_user_email(form, field): # skipcq: PYL-W0613 (unused arg) if user_manager.get_by(email=field.data) is not None: raise ValidationError( _('flask_unchained.bundles.security:error.email_already_associated', email=field.data))
[docs]def valid_user_email(form, field): form.user = user_manager.get_by(email=field.data) if form.user is None: raise ValidationError( _('flask_unchained.bundles.security:error.user_does_not_exist'))
class BaseForm(ModelForm): class Meta: abstract = True only = () def __init__(self, *args, **kwargs): if app.testing: self.TIME_LIMIT = None super().__init__(*args, **kwargs) class NextFormMixin: next = HiddenField() def validate_next(self, field): if field.data and not _validate_redirect_url(field.data): field.data = '' raise ValidationError( _('flask_unchained.bundles.security:error.invalid_next_redirect'))
[docs]class LoginForm(BaseForm, NextFormMixin): """The default login form.""" class Meta: model = User email = fields.StringField( _('flask_unchained.bundles.security:form_field.email')) password = fields.PasswordField( _('flask_unchained.bundles.security:form_field.password')) remember = fields.BooleanField( _('flask_unchained.bundles.security:form_field.remember_me')) submit = fields.SubmitField( _('flask_unchained.bundles.security:form_submit.login')) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.user = None if not self.next.data: self.next.data = request.args.get('next', '') self.remember.default = app.config.SECURITY_DEFAULT_REMEMBER_ME
[docs] def validate(self): if not super().validate(): # FIXME-identity if (set(self.errors.keys()) - set(security_utils_service.get_identity_attributes())): return False self.user = security_utils_service.user_loader(self.email.data) if self.user is None: self.email.errors.append( _('flask_unchained.bundles.security:error.user_does_not_exist')) return False elif not self.password.data: self.password.errors.append( _('flask_unchained.bundles.security:password_required')) return False elif not security_utils_service.verify_password(self.user, self.password.data): self.password.errors.append( _('flask_unchained.bundles.security:error.invalid_password')) return False return True
[docs]class ForgotPasswordForm(BaseForm): """The default forgot password form.""" class Meta: model = User user = None email = StringField(_('flask_unchained.bundles.security:form_field.email'), validators=[valid_user_email]) submit = fields.SubmitField( _('flask_unchained.bundles.security:form_submit.recover_password'))
class PasswordFormMixin: password = fields.PasswordField( _('flask_unchained.bundles.security:form_field.password'), validators=[password_required]) password_confirm = fields.PasswordField( _('flask_unchained.bundles.security:form_field.retype_password'), validators=[password_equal, password_required])
[docs]class ChangePasswordForm(BaseForm): """The default change password form.""" class Meta: model = User model_fields = {'new_password': 'password', 'new_password_confirm': 'password'} password = fields.PasswordField( _('flask_unchained.bundles.security:form_field.password'), validators=[password_required]) new_password = fields.PasswordField( _('flask_unchained.bundles.security:form_field.new_password'), validators=[password_required]) new_password_confirm = fields.PasswordField( _('flask_unchained.bundles.security:form_field.retype_password'), validators=[new_password_equal, password_required]) submit = fields.SubmitField( _('flask_unchained.bundles.security:form_submit.change_password'))
[docs] def validate(self): result = super().validate() if not security_utils_service.verify_password(current_user, self.password.data): self.password.errors.append( _('flask_unchained.bundles.security:error.invalid_password')) return False elif self.password.data == self.new_password.data: self.new_password.errors.append( _('flask_unchained.bundles.security:error.password_is_the_same')) return False return result
[docs]class RegisterForm(BaseForm, PasswordFormMixin, NextFormMixin): """The default register form.""" class Meta: model = User email = StringField(_('flask_unchained.bundles.security:form_field.email'), validators=[unique_user_email]) submit = SubmitField(_('flask_unchained.bundles.security:form_submit.register')) field_order = ('email', 'password', 'password_confirm', 'submit') def to_dict(self): def is_field_and_user_attr(member): return isinstance(member, Field) and hasattr(self.Meta.model, member.name) return {key: value.data for key, value in inspect.getmembers(self, is_field_and_user_attr)}
[docs]class ResetPasswordForm(BaseForm, PasswordFormMixin): """The default reset password form.""" class Meta: model = User model_fields = {'password_confirm': 'password'} submit = SubmitField( _('flask_unchained.bundles.security:form_submit.reset_password'))
[docs]class SendConfirmationForm(BaseForm): """The default resend confirmation email form.""" class Meta: model = User user = None email = StringField(_('flask_unchained.bundles.security:form_field.email'), validators=[valid_user_email]) submit = SubmitField( _('flask_unchained.bundles.security:form_submit.send_confirmation')) def __init__(self, *args, **kwargs): super(SendConfirmationForm, self).__init__(*args, **kwargs) if request.method == 'GET': self.email.data = request.args.get('email', None)
[docs] def validate(self): if not super(SendConfirmationForm, self).validate(): return False if self.user.confirmed_at is not None: self.email.errors.append( _('flask_unchained.bundles.security:error.already_confirmed')) return False return True