Update selected item color in Pass menu
[ProtonMail-WebClient.git] / packages / pass / lib / validation / alias.ts
blobb5f677b75e749402c183ab386043c727459a8aaf
1 import { type FormikErrors } from 'formik';
2 import { c } from 'ttag';
4 import type { SanitizedAliasOptions } from '@proton/pass/hooks/useAliasOptions';
5 import type {
6     AliasFormValues,
7     EditAliasFormValues,
8     LoginItemFormValues,
9     MaybeNull,
10     NewAliasFormValues,
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, '')
24         .slice(0, 20);
26     return prefix.replace(/\.*$/, '').replace(/^\.+/, '');
29 export const validateAliasForm = ({
30     aliasPrefix,
31     mailboxes,
32     aliasSuffix,
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`;
38     }
40     if (aliasSuffix === undefined) {
41         errors.aliasSuffix = c('Warning').t`Missing alias suffix`;
42     }
44     if (mailboxes.length === 0) {
45         errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
46     }
48     return errors;
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`;
57     }
59     if (aliasPrefix && !validateLocalPart(aliasPrefix + (aliasSuffix?.value?.split('@')?.[0] ?? ''))) {
60         errors.aliasPrefix = c('Warning').t`Invalid alias prefix`;
61     }
63     if (aliasPrefix && !/^[a-z0-9\-\_.]*$/.test(aliasPrefix)) {
64         errors.aliasPrefix = c('Warning').t`Only alphanumeric characters, dots, hyphens and underscores are allowed`;
65     }
67     if (aliasPrefix && aliasPrefix.length > 40) {
68         errors.aliasPrefix = c('Warning').t`The alias prefix cannot be longer than 40 characters`;
69     }
71     if (aliasSuffix === undefined) {
72         errors.aliasSuffix = c('Warning').t`Missing alias suffix`;
73     }
75     if (mailboxes.length === 0) {
76         errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
77     }
79     return errors;
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`;
89         }
91         return errors;
92     };
94 export const reconciliateAliasFromDraft = <V extends AliasFormValues>(
95     aliasValues: V,
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));
106     return {
107         aliasPrefix: aliasPrefix,
108         aliasSuffix: suffixMatch ?? fallback?.aliasSuffix,
109         mailboxes: mailboxesMatch.length > 0 ? mailboxesMatch : fallback?.mailboxes ?? [],
110     };
113 export const sanitizeLoginAliasSave = (formData: LoginItemFormValues): LoginItemFormValues => {
114     const { itemEmail, aliasPrefix, aliasSuffix } = formData;
116     if (aliasSuffix !== undefined && itemEmail !== `${aliasPrefix}${aliasSuffix.value}`) {
117         return {
118             ...formData,
119             withAlias: false,
120             aliasPrefix: '',
121             aliasSuffix: undefined,
122             mailboxes: [],
123         };
124     }
126     return formData;
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 : '' };
137     };