Merge branch 'IDTEAM-1.26.0' into 'main'
[ProtonMail-WebClient.git] / packages / pass / lib / validation / alias.ts
blob0ee41faaa7db1df17c199acd576aecd0788fc38c
1 import { type FormikErrors } from 'formik';
2 import { c } from 'ttag';
4 import type { SanitizedAliasOptions } from '@proton/pass/hooks/useAliasOptions';
5 import PassCoreUI from '@proton/pass/lib/core/core.ui';
6 import type {
7     AliasContactValues,
8     AliasFormValues,
9     EditAliasFormValues,
10     LoginItemFormValues,
11     Maybe,
12     MaybeNull,
13     NewAliasFormValues,
14 } from '@proton/pass/types';
15 import { normalize } from '@proton/shared/lib/helpers/string';
17 import { validateItemErrors } from './item';
19 /* Normalize unicode representation of the string
20  * Remove diacritics (accents) + 20 max characters length
21  * for the auto-derived alias name.
22  * Removes trailing/leading dots. */
23 export const deriveAliasPrefix = (name: string) => {
24     const prefix = normalize(name, true)
25         .replace(/[^a-z0-9\-\_.]/g, '')
26         .slice(0, 20);
28     return prefix.replace(/\.*$/, '').replace(/^\.+/, '');
31 export const validateAliasPrefix = (prefix: string = ''): Maybe<string> => {
32     try {
33         PassCoreUI.validate_alias_prefix(prefix);
34         return;
35     } catch (err) {
36         switch (err instanceof Error && err.message) {
37             case 'PrefixEmpty':
38                 return c('Warning').t`Missing alias prefix`;
39             case 'PrefixTooLong':
40                 return c('Warning').t`The alias prefix cannot be longer than 40 characters`;
41             case 'InvalidCharacter':
42                 return c('Warning').t`Only alphanumeric characters, dots, hyphens and underscores are allowed`;
43             case 'TwoConsecutiveDots':
44             case 'DotAtTheBeginning':
45             case 'DotAtTheEnd':
46             default:
47                 return c('Warning').t`Invalid alias prefix`;
48         }
49     }
52 export const validateAliasForm = ({
53     aliasPrefix,
54     mailboxes,
55     aliasSuffix,
56 }: AliasFormValues): FormikErrors<AliasFormValues> => {
57     const errors: FormikErrors<AliasFormValues> = {};
59     const aliasPrefixError = validateAliasPrefix(aliasPrefix);
60     if (aliasPrefixError) errors.aliasPrefix = aliasPrefixError;
62     if (!aliasSuffix) errors.aliasSuffix = c('Warning').t`Missing alias suffix`;
63     if (mailboxes.length === 0) errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
65     return errors;
68 export const validateNewAliasForm = (values: NewAliasFormValues): FormikErrors<NewAliasFormValues> => ({
69     ...validateItemErrors(values),
70     ...validateAliasForm(values),
71 });
73 export const validateAliasContactSenderName = ({ name }: AliasContactValues): FormikErrors<AliasContactValues> => {
74     const errors: FormikErrors<AliasContactValues> = {};
75     if (!name) errors.name = c('Warning').t`Name is required`;
77     return errors;
80 export const createEditAliasFormValidator =
81     (aliasOwner: boolean) =>
82     (values: EditAliasFormValues): FormikErrors<EditAliasFormValues> => {
83         const errors: FormikErrors<EditAliasFormValues> = validateItemErrors(values);
85         if (aliasOwner && values.mailboxes.length === 0) {
86             errors.mailboxes = c('Warning').t`You must select at least one mailbox`;
87         }
89         return errors;
90     };
92 export const reconciliateAliasFromDraft = <V extends AliasFormValues>(
93     aliasValues: V,
94     aliasOptions: MaybeNull<SanitizedAliasOptions>,
95     fallback?: Partial<AliasFormValues>
96 ): AliasFormValues => {
97     const { aliasSuffix, mailboxes, aliasPrefix } = aliasValues;
98     const suffixOptions = aliasOptions?.suffixes ?? [];
99     const mailboxOptions = aliasOptions?.mailboxes ?? [];
101     const suffixMatch = suffixOptions.find(({ signature }) => signature === aliasSuffix?.signature);
102     const mailboxesMatch = mailboxOptions.filter(({ id }) => mailboxes.some((mailbox) => id === mailbox.id));
104     return {
105         aliasPrefix: aliasPrefix,
106         aliasSuffix: suffixMatch ?? fallback?.aliasSuffix,
107         mailboxes: mailboxesMatch.length > 0 ? mailboxesMatch : (fallback?.mailboxes ?? []),
108     };
111 export const sanitizeLoginAliasSave = (formData: LoginItemFormValues): LoginItemFormValues => {
112     const { itemEmail, aliasPrefix, aliasSuffix } = formData;
114     if (aliasSuffix !== undefined && itemEmail !== `${aliasPrefix}${aliasSuffix.value}`) {
115         return {
116             ...formData,
117             withAlias: false,
118             aliasPrefix: '',
119             aliasSuffix: undefined,
120             mailboxes: [],
121         };
122     }
124     return formData;
127 export const sanitizeLoginAliasHydration =
128     (aliasOptions: MaybeNull<SanitizedAliasOptions>) =>
129     (formData: LoginItemFormValues): LoginItemFormValues => {
130         if (!formData.withAlias) return formData;
132         const aliasValues = reconciliateAliasFromDraft(formData, aliasOptions);
133         const withAlias = aliasValues.aliasSuffix !== undefined && aliasValues.mailboxes.length > 0;
134         return { ...formData, ...aliasValues, withAlias, itemEmail: withAlias ? formData.itemEmail : '' };
135     };