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';
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, '')
28 return prefix.replace(/\.*$/, '').replace(/^\.+/, '');
31 export const validateAliasPrefix = (prefix: string = ''): Maybe<string> => {
33 PassCoreUI.validate_alias_prefix(prefix);
36 switch (err instanceof Error && err.message) {
38 return c('Warning').t`Missing alias prefix`;
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':
47 return c('Warning').t`Invalid alias prefix`;
52 export const validateAliasForm = ({
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`;
68 export const validateNewAliasForm = (values: NewAliasFormValues): FormikErrors<NewAliasFormValues> => ({
69 ...validateItemErrors(values),
70 ...validateAliasForm(values),
73 export const validateAliasContactSenderName = ({ name }: AliasContactValues): FormikErrors<AliasContactValues> => {
74 const errors: FormikErrors<AliasContactValues> = {};
75 if (!name) errors.name = c('Warning').t`Name is required`;
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`;
92 export const reconciliateAliasFromDraft = <V extends AliasFormValues>(
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));
105 aliasPrefix: aliasPrefix,
106 aliasSuffix: suffixMatch ?? fallback?.aliasSuffix,
107 mailboxes: mailboxesMatch.length > 0 ? mailboxesMatch : (fallback?.mailboxes ?? []),
111 export const sanitizeLoginAliasSave = (formData: LoginItemFormValues): LoginItemFormValues => {
112 const { itemEmail, aliasPrefix, aliasSuffix } = formData;
114 if (aliasSuffix !== undefined && itemEmail !== `${aliasPrefix}${aliasSuffix.value}`) {
119 aliasSuffix: undefined,
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 : '' };