Public Access
New ConfirmEmailPage for users to verify their email and set password. Resend form on registration and error pages. Registration form no longer asks for a password. Confirmation requires a button click. The admin list marks unconfirmed requests and offers only delete for them.
46 lines
1.5 KiB
JavaScript
46 lines
1.5 KiB
JavaScript
import {z} from 'zod';
|
|
|
|
// Error messages are i18n keys — translate them in components via t(error.message)
|
|
|
|
const emailField = z
|
|
.string()
|
|
.min(1, 'VALIDATION.EMAIL_REQUIRED')
|
|
.email('VALIDATION.EMAIL_INVALID');
|
|
|
|
// Auth hashes with BCrypt, which takes at most 72 bytes.
|
|
const passwordField = z
|
|
.string()
|
|
.min(8, 'VALIDATION.PASSWORD_TOO_SHORT')
|
|
.refine((value) => new TextEncoder().encode(value).length <= 72, 'VALIDATION.PASSWORD_TOO_LONG');
|
|
|
|
// Same rule as the Auth service: 3-24 letters, digits, space, _ . - and no space at the ends.
|
|
// An empty field means "no display name" and is sent as null.
|
|
const displayNameField = z
|
|
.string()
|
|
.trim()
|
|
.optional()
|
|
.transform((v) => (v ? v : null))
|
|
.refine((v) => v === null || /^[\p{L}\p{N}_.-][\p{L}\p{N} _.-]{1,22}[\p{L}\p{N}_.-]$/u.test(v), {
|
|
message: 'VALIDATION.DISPLAY_NAME_INVALID',
|
|
});
|
|
|
|
// No password: the address owner chooses it on the confirm page.
|
|
export const registrationSchema = z.object({
|
|
email: emailField,
|
|
displayName: displayNameField,
|
|
});
|
|
|
|
export const confirmEmailSchema = z
|
|
.object({
|
|
password: passwordField,
|
|
passwordConfirmation: z.string().min(1, 'VALIDATION.PASSWORD_CONFIRMATION_REQUIRED'),
|
|
})
|
|
.refine((d) => d.password === d.passwordConfirmation, {
|
|
path: ['passwordConfirmation'],
|
|
message: 'VALIDATION.PASSWORD_MISMATCH',
|
|
});
|
|
|
|
export const settingsSchema = z.object({
|
|
displayName: displayNameField,
|
|
});
|