from typing import Any, Dict, List from .auth_password_policy_check_password import check_password from .auth_password_policy_types import PasswordPolicy from .auth_validate_password_change_types import PasswordChangeCheck 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_password_change( current_password: str, new_password: str, current_password_matches: bool, email: str, name: str, policy: PasswordPolicy, ) -> PasswordChangeCheck: """A change-password form checked in one call: the current password must be given and correct, the new one must meet the policy and differ from it.""" current, new = _text(current_password), _text(new_password) fields: Dict[str, str] = {} if current == "": fields["currentPassword"] = "Enter your current password." elif current_password_matches is not True: fields["currentPassword"] = "That is not your current password." # Checked even when empty, so a nonsensical policy always throws. check = check_password(new, email, name, policy) if new == "": fields["newPassword"] = "Enter a new password." else: messages: List[str] = [f.message for f in check.failures] if new == current: messages.append("Choose a password that is different from your current one.") if messages: fields["newPassword"] = " ".join(messages) return PasswordChangeCheck(valid=len(fields) == 0, fields=fields)