1 import { type FormikErrors } from 'formik';
2 import { c } from 'ttag';
4 import type { SanitizedAliasOptions } from '@proton/pass/hooks/useAliasOptions';
11 } from '@proton/pass/types';
12 import { validateLocalPart } from '@proton/shared/lib/helpers/email';
13 import { normalize } from '@proton/shared/lib/helpers/string';
15 import { validateItemErrors } from './item';
17 /* Normalize unicode representation of the string
18 * Remove diacritics (accents) + 20 max characters length
19 * for the auto-derived alias name.
20 * Removes trailing/leading dots. */
21 export const deriveAliasPrefix = (name: string) => {
22 const prefix = normalize(name, true)
23 .replace(/[^a-z0-9\-\_.]/g, '')
26 return prefix.replace(/\.*$/, '').replace(/^\.+/, '');
29 export const validateAliasForm = ({
33 }: AliasFormValues): FormikErrors<AliasFormValues> => {
34 const errors: FormikErrors<AliasFormValues> = {};
36 if (aliasPrefix === undefined || !validateLocalPart(aliasPrefix + (aliasSuffix?.value?.split('@')?.[0] ?? ''))) {
37 errors.aliasPrefix = c('Warning').t`Invalid alias prefix`;
40 if (aliasSuffix === undefined) {
41 errors.aliasSuffix = c('Warning').t`Missing alias suffix`;
44 if (mailboxes.length === 0) {
45 errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
51 export const validateNewAliasForm = (values: NewAliasFormValues): FormikErrors<NewAliasFormValues> => {
52 const errors: FormikErrors<NewAliasFormValues> = { ...validateItemErrors(values), ...validateAliasForm(values) };
53 const { aliasPrefix, aliasSuffix, mailboxes } = values;
55 if (aliasPrefix === undefined || aliasPrefix.trim() === '') {
56 errors.aliasPrefix = c('Warning').t`Missing alias prefix`;
59 if (aliasPrefix && !validateLocalPart(aliasPrefix + (aliasSuffix?.value?.split('@')?.[0] ?? ''))) {
60 errors.aliasPrefix = c('Warning').t`Invalid alias prefix`;
63 if (aliasPrefix && !/^[a-z0-9\-\_.]*$/.test(aliasPrefix)) {
64 errors.aliasPrefix = c('Warning').t`Only alphanumeric characters, dots, hyphens and underscores are allowed`;
67 if (aliasPrefix && aliasPrefix.length > 40) {
68 errors.aliasPrefix = c('Warning').t`The alias prefix cannot be longer than 40 characters`;
71 if (aliasSuffix === undefined) {
72 errors.aliasSuffix = c('Warning').t`Missing alias suffix`;
75 if (mailboxes.length === 0) {
76 errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
82 export const createEditAliasFormValidator =
83 (aliasOwner: boolean) =>
84 (values: EditAliasFormValues): FormikErrors<EditAliasFormValues> => {
85 const errors: FormikErrors<EditAliasFormValues> = validateItemErrors(values);
87 if (aliasOwner && values.mailboxes.length === 0) {
88 errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
94 export const reconciliateAliasFromDraft = <V extends AliasFormValues>(
96 aliasOptions: MaybeNull<SanitizedAliasOptions>,
97 fallback?: Partial<AliasFormValues>
98 ): AliasFormValues => {
99 const { aliasSuffix, mailboxes, aliasPrefix } = aliasValues;
100 const suffixOptions = aliasOptions?.suffixes ?? [];
101 const mailboxOptions = aliasOptions?.mailboxes ?? [];
103 const suffixMatch = suffixOptions.find(({ signature }) => signature === aliasSuffix?.signature);
104 const mailboxesMatch = mailboxOptions.filter(({ id }) => mailboxes.some((mailbox) => id === mailbox.id));
107 aliasPrefix: aliasPrefix,
108 aliasSuffix: suffixMatch ?? fallback?.aliasSuffix,
109 mailboxes: mailboxesMatch.length > 0 ? mailboxesMatch : fallback?.mailboxes ?? [],
113 export const sanitizeLoginAliasSave = (formData: LoginItemFormValues): LoginItemFormValues => {
114 const { itemEmail, aliasPrefix, aliasSuffix } = formData;
116 if (aliasSuffix !== undefined && itemEmail !== `${aliasPrefix}${aliasSuffix.value}`) {
121 aliasSuffix: undefined,
129 export const sanitizeLoginAliasHydration =
130 (aliasOptions: MaybeNull<SanitizedAliasOptions>) =>
131 (formData: LoginItemFormValues): LoginItemFormValues => {
132 if (!formData.withAlias) return formData;
134 const aliasValues = reconciliateAliasFromDraft(formData, aliasOptions);
135 const withAlias = aliasValues.aliasSuffix !== undefined && aliasValues.mailboxes.length > 0;
136 return { ...formData, ...aliasValues, withAlias, itemEmail: withAlias ? formData.itemEmail : '' };