All files / app/crypto validate-password.ts

100% Statements 17/17
100% Branches 5/5
100% Functions 4/4
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 441x 1x   1x   1x   1x     4x       4x                   1x 4x 4x 4x 4x 4x   4x   4x                 1x  
import { validateMnemonic } from 'bip39';
import zxcvbn, { ZXCVBNResult, ZXCVBNScore } from 'zxcvbn';
 
const truncateCpuDemandingPassword = (input: string) => input.substr(0, 100);
 
const requiredStrengthScore: ZXCVBNScore = 4;
 
const requiredPasswordLength = 12;
 
function hasHighestPasswordScore(score: ZXCVBNScore) {
  return score === requiredStrengthScore;
}
 
function hasSufficientLength(input: string) {
  return input.length >= requiredPasswordLength;
}
 
export interface ValidatedPassword extends ZXCVBNResult {
  meetsLengthRequirement: boolean;
  meetsScoreRequirement: boolean;
  meetsAllStrengthRequirements: boolean;
  isMnemonicPhrase: boolean;
}
 
export function validatePassword(input: string): ValidatedPassword {
  const isMnemonicPhrase = validateMnemonic(input);
  const password = input.length > 100 ? truncateCpuDemandingPassword(input) : input;
  const result = zxcvbn(password);
  const meetsScoreRequirement = hasHighestPasswordScore(result.score);
  const meetsLengthRequirement = hasSufficientLength(input);
  const meetsAllStrengthRequirements =
    meetsScoreRequirement && meetsLengthRequirement && !isMnemonicPhrase;
 
  return Object.freeze({
    ...result,
    isMnemonicPhrase,
    meetsScoreRequirement,
    meetsLengthRequirement,
    meetsAllStrengthRequirements,
  });
}
 
export const blankPasswordValidation = Object.freeze(validatePassword(''));