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:
arsam
2026-09-18 23:19:26 +03:30
parent 651cd9fbf8
commit 9412ab53bf
+68
View File
@@ -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 };
}