Import source: app/backend/src/lib/password-strength
Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
const COMMON_PASSWORDS = new Set([
|
||||
'password', '12345678', 'qwerty12', 'abc12345', 'password1',
|
||||
'123456789', '1234567890', 'iloveyou', 'sunshine1', 'princess',
|
||||
'football', 'charlie1', 'access12', 'master12', 'michael1',
|
||||
'shadow12', 'monkey12', ' letmein1', 'dragon12', 'trustno1',
|
||||
]);
|
||||
|
||||
export interface PasswordStrength {
|
||||
score: number;
|
||||
issues: string[];
|
||||
entropy: number;
|
||||
}
|
||||
|
||||
export function validatePasswordStrength(password: string): PasswordStrength {
|
||||
const issues: string[] = [];
|
||||
let score = 0;
|
||||
|
||||
if (password.length >= 8) score += 1;
|
||||
if (password.length >= 12) score += 1;
|
||||
if (password.length >= 16) score += 1;
|
||||
|
||||
const hasLower = /[a-z]/.test(password);
|
||||
const hasUpper = /[A-Z]/.test(password);
|
||||
const hasDigit = /[0-9]/.test(password);
|
||||
const hasSpecial = /[^a-zA-Z0-9]/.test(password);
|
||||
const hasPersian = /[\u0600-\u06FF]/.test(password);
|
||||
|
||||
const charsetSize =
|
||||
(hasLower ? 26 : 0) +
|
||||
(hasUpper ? 26 : 0) +
|
||||
(hasDigit ? 10 : 0) +
|
||||
(hasSpecial ? 33 : 0) +
|
||||
(hasPersian ? 33 : 0);
|
||||
|
||||
const entropy = Math.log2(Math.max(charsetSize, 1)) * password.length;
|
||||
|
||||
if (hasLower) score += 1;
|
||||
if (hasUpper) score += 1;
|
||||
if (hasDigit) score += 1;
|
||||
if (hasSpecial) score += 1;
|
||||
|
||||
const repeats = /(.)\1{2,}/.test(password);
|
||||
const sequential = /(?:abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz|012|123|234|345|456|567|678|789)/i.test(password);
|
||||
const keyboardRows = /(?:qwerty|asdf|zxcv|qaz|wsx|edc)/i.test(password);
|
||||
|
||||
if (repeats) { score -= 1; issues.push('repeating_characters'); }
|
||||
if (sequential) { score -= 1; issues.push('sequential_characters'); }
|
||||
if (keyboardRows) { score -= 1; issues.push('keyboard_pattern'); }
|
||||
|
||||
if (charsetSize < 2) issues.push('needs_variety');
|
||||
if (entropy < 30) issues.push('low_entropy');
|
||||
if (COMMON_PASSWORDS.has(password.toLowerCase())) issues.push('common_password');
|
||||
|
||||
if (password.length < 8) issues.push('too_short');
|
||||
if (password.length > 256) issues.push('too_long');
|
||||
|
||||
return {
|
||||
score: Math.max(0, Math.min(10, score)),
|
||||
issues,
|
||||
entropy: Math.round(entropy * 10) / 10,
|
||||
};
|
||||
}
|
||||
|
||||
export function isPasswordAcceptable(password: string): { ok: boolean; issues: string[] } {
|
||||
const result = validatePasswordStrength(password);
|
||||
const ok = result.issues.length === 0 && result.score >= 4;
|
||||
return { ok, issues: result.issues };
|
||||
}
|
||||
Reference in New Issue
Block a user