import { ENTROPY_CLASSES, MAX_PASSWORD_LENGTH, MIN_PASSWORD_ENTROPY, MIN_PASSWORD_LENGTH } from "./const" export const isPasswordValid = (password: string): [boolean, string] => { if (password.length < MIN_PASSWORD_LENGTH) { return [false, `Password cannot be shorter than ${MIN_PASSWORD_LENGTH} characters`] } if (password.length > MAX_PASSWORD_LENGTH) { return [false, `Password cannot be longer than ${MAX_PASSWORD_LENGTH} characters`] } const entropy = calculateEntropy(password) console.log(`entropy: ${entropy}`) if (entropy < MIN_PASSWORD_ENTROPY) { return [ false, "Password is not complex enough (add uppercase, lowercase, numbers, and symbols)" ] } return [true, ""] } const calculateEntropy = (password: string) => { let poolSize = 0 for (const [eClass, poolPlus] of ENTROPY_CLASSES) { if (eClass.test(password)) { poolSize += poolPlus } } // Empty password exception if (poolSize === 0) { return 0 } const uniqueChars = new Set(password.split("")).size const basicEntropy = password.length * Math.log2(poolSize) const diversityAdjustedEntropy = Math.log2(poolSize) + (password.length - 1) * Math.log2(uniqueChars) return Math.min(basicEntropy, diversityAdjustedEntropy) }