import commonPasswords from '../data/commonPasswords'; import Trie from './Trie'; const checkStrength = (pass: string) => { const score = scorePassword(pass); const scoreLabel = mapScoreToLabel(score); const hints = getImprovementHints(pass); return { score, scoreLabel, hints, }; }; export default checkStrength; // Function to score the password based on different criteria const scorePassword = (password: string): number => { if (password.length <= 8 || isCommonPassword(password)) return 0; let score = 0; score += getLengthScore(password); //3 score += getSpecialCharScore(password); //1 score += getCaseMixScore(password); //1 score += getNumberMixScore(password); //1 return Math.min(score, 6); // Maximum score is 6 }; // Initialize the Trie with common passwords const trie = new Trie(); commonPasswords.forEach((password) => trie.insert(password)); const isCommonPassword = (password: string): boolean => { // return commonPasswords.includes(password); return trie.search(password); }; // Length-based scoring const getLengthScore = (password: string): number => { if (password.length > 20 && !hasRepeatChars(password)) return 3; if (password.length > 12 && !hasRepeatChars(password)) return 2; if (password.length > 8) return 1; return 0; }; // const hasRepeatChars = (password: string): boolean => { // const repeatCharRegex = /(\w)(\1+\1+\1+\1+)/g; // return repeatCharRegex.test(password); // }; // Check for repeated characters const hasRepeatChars = (password: string): boolean => /(\w)\1{3,}/.test(password); // Function to get the score based on the presence of special characters const getSpecialCharScore = (password: string): number => { const specialCharRegex = /[^A-Za-z0-9]/g; return specialCharRegex.test(password) ? 1 : 0; }; // Function to get the score based on the mix of uppercase and lowercase letters const getCaseMixScore = (password: string): number => { const hasUpperCase = /[A-Z]/.test(password); const hasLowerCase = /[a-z]/.test(password); return hasUpperCase && hasLowerCase ? 1 : 0; }; // Function to get the score based on the mix of letters and numbers const getNumberMixScore = (password: string): number => { const hasLetter = /[A-Za-z]/.test(password); const hasNumber = /[0-9]/.test(password); return hasLetter && hasNumber ? 1 : 0; }; // Function to map the score to a corresponding label const mapScoreToLabel = (score: number): string => { const labels = ['risky', 'guessable', 'weak', 'safe', 'secure', 'safe-secure', 'optimal']; return labels[score] || ''; }; // Function to get improvement hints const getImprovementHints = (password: string): string[] => { const hints = []; if (password.length <= 8) { hints.push('Increase your password length to more than 8 characters for 1 scoring point.'); } else { if (password.length > 8 && password.length <= 12) { hints.push('Increase your password length to more than 12 characters for additional scoring point.'); } else if (password.length > 12 && password.length <= 20) { hints.push('Increase your password length to more than 20 characters for additional scoring point.'); } // Check for special character score if (!getSpecialCharScore(password)) { hints.push('Include at least one special character for 1 point.'); } // Check for case mix score if (!getCaseMixScore(password)) { hints.push('Mix uppercase and lowercase letters for 1 point.'); } // Check for number mix score if (!getNumberMixScore(password)) { hints.push('Add numbers to your password for 1 point.'); } if (hasRepeatChars(password) && password.length < 20) { hints.push('Remove repeated characters for 1 point.'); } if (hasRepeatChars(password) && password.length > 20) { hints.push('Remove repeated characters for 2 points.'); } } return hints; };