auth.validate-registration@1.0.0
impl/typescript.ts
2,435 bytes · the TypeScript implementation · view raw
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
import { normaliseEmail } from "./auth_normalise_email.ts"; ← from auth.normalise-email ^1.0.0 · built alongside by fune
import { checkPassword } from "./auth_password_policy_check_password.ts";
import { type PasswordPolicy } from "./auth_password_policy_types.ts";
import { type RegistrationCheck } from "./auth_validate_registration_types.ts";
const MAX_NAME = 100;
function isAsciiSpace(ch: string): boolean {
return ch === " " || ch === "\t" || ch === "\n" || ch === "\r" || ch === "\f" || ch === "\v";
}
function trimAscii(text: string): string {
let start = 0;
let end = text.length;
while (start < end && isAsciiSpace(text[start])) start++;
while (end > start && isAsciiSpace(text[end - 1])) end--;
return text.slice(start, end);
}
/**
* 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.
*/
export function validateRegistration(email: string, password: string, name: string, policy: PasswordPolicy): RegistrationCheck {
// A non-string (a malformed JSON body) is an empty field, not an exception.
const emailText = typeof email === "string" ? email : "";
const passwordText = typeof password === "string" ? password : "";
const nameText = typeof name === "string" ? name : "";
const fields: Record<string, string> = {};
const normalised = normaliseEmail(emailText);
if (normalised === null) {
fields.email = trimAscii(emailText) === "" ? "Enter your email address." : "Enter a valid email address, like name@example.com.";
}
const trimmedName = trimAscii(nameText);
const nameChars = Array.from(trimmedName);
let nameError: string | null = null;
if (nameChars.length === 0) nameError = "Enter your name.";
else if (nameChars.length > MAX_NAME) nameError = `Use no more than ${MAX_NAME} characters for your name.`;
else if (nameChars.some((ch) => ch.charCodeAt(0) < 0x20 || ch.charCodeAt(0) === 0x7f)) nameError = "Your name cannot contain control characters.";
const check = checkPassword(passwordText, normalised, nameError === null ? trimmedName : null, policy);
if (passwordText === "") {
fields.password = "Enter a password.";
} else if (!check.valid) {
fields.password = check.failures.map((f) => f.message).join(" ");
}
if (nameError !== null) fields.name = nameError;
return {
valid: Object.keys(fields).length === 0,
email: normalised,
name: nameError === null ? trimmedName : null,
fields,
};
}