UNPKG

@webilix/helper-library

Version:

JavaScript/TypeScript programming helper library.

167 lines (146 loc) 6.18 kB
import { passwordChars } from '../shared'; function generate(length: number): string; function generate( length: number, exclude: { number?: boolean; lower?: boolean; upper?: boolean; special?: boolean }, ): string; function generate( length: number, exclude?: { number?: boolean; lower?: boolean; upper?: boolean; special?: boolean }, ): string { if (length <= 3) throw new Error('Length must be bigger than 3'); if (exclude?.number && exclude?.lower && exclude?.upper && exclude?.special) throw new Error('All possible chars are excluded'); const getRandomChar = (chars: string): string => chars[Math.floor(Math.random() * chars.length)]; const password: string[] = []; if (!exclude?.number) password.push(getRandomChar(passwordChars.number)); if (!exclude?.lower) password.push(getRandomChar(passwordChars.lower)); if (!exclude?.upper) password.push(getRandomChar(passwordChars.upper)); if (!exclude?.special) password.push(getRandomChar(passwordChars.special)); const fullChars: string = [ !exclude?.number ? passwordChars.number : '', !exclude?.lower ? passwordChars.lower : '', !exclude?.upper ? passwordChars.upper : '', !exclude?.special ? passwordChars.special : '', ].join(''); while (password.length < length) password.push(getRandomChar(fullChars)); return password.sort(() => (Math.random() < 0.5 ? 1 : -1)).join(''); } function getStrength(password: string): number { const count = { upper: 0, lower: 0, number: 0, symbol: 0, middle: 0, repeatInc: 0, repeatChar: 0, consecutiveUpper: 0, consecutiveLower: 0, consecutiveNumber: 0, sequentialLetter: 0, sequentialNumber: 0, sequentialSymbol: 0, }; const chars = { letter: passwordChars.lower, number: passwordChars.number, symbol: passwordChars.special }; const aPassword = password.replace(/\s+/g, '').split(/\s*/); let lastCharType: null | 'U' | 'L' | 'N' | 'S' = null; aPassword.forEach((character: string, index: number) => { if (character.match(/[A-Z]/g)) { count.upper++; if (lastCharType === 'U') count.consecutiveUpper++; lastCharType = 'U'; } else if (character.match(/[a-z]/g)) { count.lower++; if (lastCharType === 'L') count.consecutiveLower++; lastCharType = 'L'; } else if (character.match(/[0-9]/g)) { count.number++; if (index > 0 && index < aPassword.length - 1) count.middle++; if (lastCharType === 'N') count.consecutiveNumber++; lastCharType = 'N'; } else { count.symbol++; if (index > 0 && index < aPassword.length - 1) count.middle++; lastCharType = 'S'; } let exists: boolean = false; aPassword.forEach((checkCharacter: string, checkIndex: number) => { if (character === checkCharacter && index !== checkIndex) { exists = true; count.repeatInc += Math.abs(aPassword.length / (checkIndex - index)); } }); if (exists) { count.repeatChar++; const unique: number = aPassword.length - count.repeatChar; count.repeatInc = unique !== 0 ? Math.ceil(count.repeatInc / unique) : Math.ceil(count.repeatInc); } }); const requirement: number = (password.length >= 8 ? 1 : 0) + (count.upper !== 0 ? 1 : 0) + (count.lower !== 0 ? 1 : 0) + (count.number !== 0 ? 1 : 0) + (count.symbol !== 0 ? 1 : 0); for (let l = 0; l < chars.letter.length - 2; l++) { const fwd: string = chars.letter.substring(l, l + 3); const rev: string = fwd.split('').reverse().join(''); if (password.toLowerCase().indexOf(fwd) !== -1 || password.toLowerCase().indexOf(rev) !== -1) count.sequentialLetter++; } for (let n = 0; n < chars.number.length - 2; n++) { const fwd: string = chars.number.substring(n, n + 3); const rev: string = fwd.split('').reverse().join(''); if (password.toLowerCase().indexOf(fwd) !== -1 || password.toLowerCase().indexOf(rev) !== -1) count.sequentialNumber++; } for (let s = 0; s < chars.symbol.length - 2; s++) { const fwd: string = chars.symbol.substring(s, s + 3); const rev: string = fwd.split('').reverse().join(''); if (password.toLowerCase().indexOf(fwd) !== -1 || password.toLowerCase().indexOf(rev) !== -1) count.sequentialSymbol++; } const additions: number = [ // Number of Characters password.length * 4, // Uppercase Letters count.upper ? (password.length - count.upper) * 2 : 0, // Lowercase Letters count.lower ? (password.length - count.lower) * 2 : 0, // Numbers count.number * 4, // Symbols count.symbol * 6, // Middle Numbers or Symbols count.middle * 2, // Requirements requirement > 3 ? requirement * 2 : 0, ].reduce((pv, cv) => pv + cv, 0); const deductions: number = [ // Letters Only count.number !== 0 || count.symbol !== 0 ? 0 : password.length, // Numbers Only count.upper !== 0 || count.lower !== 0 || count.symbol !== 0 ? 0 : password.length, // Repeat Characters (Case Insensitive) count.repeatInc, // Consecutive Uppercase Letters count.consecutiveUpper * 2, // Consecutive Lowercase Letters count.consecutiveLower * 2, // Consecutive Numbers count.consecutiveNumber * 2, // Sequential Letters (3+) count.sequentialLetter * 3, // Sequential Numbers (3+) count.sequentialNumber * 3, // Sequential Symbols (3+) count.sequentialSymbol * 3, ].reduce((pv, cv) => pv + cv, 0); const score: number = (additions - deductions) / 10; return score > 10 ? 10 : score < 0 ? 0 : score; } export const PASSWORD = { generate, getStrength, };