Functional Weave
Code in Rust

auth.validate-registration@1.0.0

README.md

2,172 bytes · view raw

# auth.validate-registration

One call checks a whole sign-up form and answers in the shape an API's
`validation_failed` error and a form both want:

```
validateRegistration(" Ada@Example.com ", "short", "Ada Lovelace", passwordPolicy("nist-800-63b-4-single-factor"))
# {valid: false, email: "Ada@example.com", name: "Ada Lovelace",
#  fields: {"password": "Use at least 15 characters."}}
```

The browser runs it on submit to show messages beside the fields; the API
runs the very same function and returns `fields` in its 400 response, so the
two can never disagree about what is acceptable. When `valid` is true, store
`email` and `name` from the result (normalised and trimmed), never the raw
input.

**email** goes through `auth.normalise-email` (trimmed, domain lower-cased).
Empty after trimming: "Enter your email address."; otherwise not an address
`validation.email` accepts: "Enter a valid email address, like
name@example.com."

**password** goes through `auth.password-policy`'s `checkPassword`, with the
normalised email and trimmed name as the personal words to refuse. Empty:
"Enter a password."; otherwise every failure's message, joined with a space
in the policy's fixed order, so the field shows the whole story ("Use at least
15 characters. This password is too common. Choose something harder to
guess.").

**name** is trimmed of ASCII whitespace and must then be 1 to 100 characters
(code points), with no control characters (U+0000 to U+001F and U+007F):
"Enter your name.", "Use no more than 100 characters for your name." or
"Your name cannot contain control characters.". Any script is welcome; names
are not otherwise judged (see "Falsehoods Programmers Believe About Names").

`fields` lists only the fields that need fixing, keyed `email`, `password`,
`name`, in that order. A value that is not a string (a JSON body with a
number where the password goes) is treated as empty, so a malformed request
gets field messages rather than an exception. A nonsensical policy throws,
as in `checkPassword`.

Whether the email is already taken is not a rule a pure function can know;
the API checks its database after this passes (409 `email_taken`).