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 = {
10 seperator: SeperatorOptions;
12 extraNumbers: boolean;
15 export const getSeperatorTranslation = (seperator: SeperatorOptions) =>
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`,
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 => {
34 case SeperatorOptions.HYPHEN:
36 case SeperatorOptions.SPACE:
38 case SeperatorOptions.PERIOD:
40 case SeperatorOptions.COMMA:
42 case SeperatorOptions.UNDERSCORE:
44 case SeperatorOptions.NUMBER:
45 return getRandomCharacter(digitChars);
46 case SeperatorOptions.NUMBER_OR_SYMBOL:
47 return getRandomCharacter(digitChars.concat(specialChars));
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];
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)}`;
68 (password, word, idx) => (idx === 0 ? word : `${password}${getSeperator(options.seperator)}${word}`),