from typing import Any, Dict from .auth_normalise_email import normalise_email from .auth_password_policy_check_password import check_password from .auth_password_policy_types import PasswordPolicy from .auth_validate_registration_types import RegistrationCheck MAX_NAME = 100 _ASCII_SPACE = " \t\n\r\f\v" def _text(value: Any) -> str: # A non-string (a malformed JSON body) is an empty field, not an exception. return value if isinstance(value, str) else "" def validate_registration(email: str, password: str, name: str, policy: PasswordPolicy) -> RegistrationCheck: """A sign-up form's email, password and name checked together: the values to store when valid, and a message for each field that needs fixing.""" email_text, password_text, name_text = _text(email), _text(password), _text(name) fields: Dict[str, str] = {} normalised = normalise_email(email_text) if normalised is None: fields["email"] = ( "Enter your email address." if email_text.strip(_ASCII_SPACE) == "" else "Enter a valid email address, like name@example.com." ) trimmed_name = name_text.strip(_ASCII_SPACE) name_error = None if len(trimmed_name) == 0: name_error = "Enter your name." elif len(trimmed_name) > MAX_NAME: name_error = "Use no more than %d characters for your name." % MAX_NAME elif any(ord(ch) < 0x20 or ord(ch) == 0x7F for ch in trimmed_name): name_error = "Your name cannot contain control characters." check = check_password(password_text, normalised, trimmed_name if name_error is None else None, policy) if password_text == "": fields["password"] = "Enter a password." elif not check.valid: fields["password"] = " ".join(f.message for f in check.failures) if name_error is not None: fields["name"] = name_error return RegistrationCheck( valid=len(fields) == 0, email=normalised, name=trimmed_name if name_error is None else None, fields=fields, )