Update selected item color in Pass menu
[ProtonMail-WebClient.git] / packages / pass / lib / password / memorable.ts
blob809d8ebbdec08b178d4efe88f2f10debd4a80516
1 import { c } from 'ttag';
3 import capitalize from '@proton/utils/capitalize';
5 import { SeperatorOptions, digitChars, specialChars } from './constants';
6 import WORD_LIST from './wordlist.json';
8 export type MemorablePasswordOptions = {
9     wordCount: number;
10     seperator: SeperatorOptions;
11     capitalize: boolean;
12     extraNumbers: boolean;
15 export const getSeperatorTranslation = (seperator: SeperatorOptions) =>
16     ({
17         [SeperatorOptions.HYPHEN]: c('Option').t`Hyphens`,
18         [SeperatorOptions.SPACE]: c('Option').t`Spaces`,
19         [SeperatorOptions.PERIOD]: c('Option').t`Periods`,
20         [SeperatorOptions.COMMA]: c('Option').t`Commas`,
21         [SeperatorOptions.UNDERSCORE]: c('Option').t`Underscores`,
22         [SeperatorOptions.NUMBER]: c('Option').t`Numbers`,
23         [SeperatorOptions.NUMBER_OR_SYMBOL]: c('Option').t`Numbers and Symbols`,
24     })[seperator];
26 const getRandomCharacter = (characters: string) => {
27     const seed = Array.from(crypto.getRandomValues(new Uint8Array(1)));
28     const idx = seed.map((val) => val % characters.length)[0];
29     return characters[idx];
32 const getSeperator = (seperator: SeperatorOptions): string => {
33     switch (seperator) {
34         case SeperatorOptions.HYPHEN:
35             return '-';
36         case SeperatorOptions.SPACE:
37             return ' ';
38         case SeperatorOptions.PERIOD:
39             return '.';
40         case SeperatorOptions.COMMA:
41             return ',';
42         case SeperatorOptions.UNDERSCORE:
43             return '_';
44         case SeperatorOptions.NUMBER:
45             return getRandomCharacter(digitChars);
46         case SeperatorOptions.NUMBER_OR_SYMBOL:
47             return getRandomCharacter(digitChars.concat(specialChars));
48     }
51 export const generateMemorablePassword = (options: MemorablePasswordOptions): string => {
52     if (options.wordCount <= 0) throw new Error('invalid options');
54     const getRandomWord = () => {
55         const wordId = Array.from(crypto.getRandomValues(new Uint8Array(5)))
56             .map((num) => (num % 6) + 1)
57             .join('') as keyof typeof WORD_LIST;
59         return WORD_LIST[wordId];
60     };
62     return Array.from({ length: options.wordCount }, () => {
63         let word = getRandomWord();
64         if (options.capitalize) word = capitalize(word)!;
65         if (options.extraNumbers) word = `${word}${getRandomCharacter(digitChars)}`;
66         return word;
67     }).reduce<string>(
68         (password, word, idx) => (idx === 0 ? word : `${password}${getSeperator(options.seperator)}${word}`),
69         ''
70     );