tl-shared-security
Version:
Enterprise-grade security module for frontend and backend applications with comprehensive protection against XSS, CSRF, SQL injection, and other security vulnerabilities
141 lines • 5.67 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.passwordPolicyService = exports.PasswordPolicyService = void 0;
class PasswordPolicyService {
constructor() {
this.defaultOptions = {
minLength: 12,
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
requireSpecialChars: true,
maxRepeatingChars: 3,
disallowCommonPasswords: true,
disallowContextSpecificWords: true,
contextSpecificWords: [],
};
// List of common passwords (abbreviated)
this.commonPasswords = [
'password', '123456', 'qwerty', 'admin', 'welcome',
'password123', '12345678', 'abc123', 'letmein', 'monkey',
'football', '123456789', 'iloveyou', '1234567', 'sunshine',
'princess', 'dragon', 'welcome1', 'admin123', 'passw0rd'
];
}
/**
* Validates a password against the policy
* @param password - Password to validate
* @param options - Password policy options
* @returns Validation result
*/
validate(password, options) {
const opts = { ...this.defaultOptions, ...options };
const errors = [];
// Check length
if (password.length < opts.minLength) {
errors.push(`Password must be at least ${opts.minLength} characters long`);
}
// Check for uppercase letters
if (opts.requireUppercase && !/[A-Z]/.test(password)) {
errors.push('Password must contain at least one uppercase letter');
}
// Check for lowercase letters
if (opts.requireLowercase && !/[a-z]/.test(password)) {
errors.push('Password must contain at least one lowercase letter');
}
// Check for numbers
if (opts.requireNumbers && !/[0-9]/.test(password)) {
errors.push('Password must contain at least one number');
}
// Check for special characters
if (opts.requireSpecialChars && !/[^A-Za-z0-9]/.test(password)) {
errors.push('Password must contain at least one special character');
}
// Check for repeating characters
if (opts.maxRepeatingChars > 0) {
const repeatingRegex = new RegExp(`(.)\\1{${opts.maxRepeatingChars},}`);
if (repeatingRegex.test(password)) {
errors.push(`Password must not contain more than ${opts.maxRepeatingChars} repeating characters`);
}
}
// Check for common passwords
if (opts.disallowCommonPasswords) {
const lowercasePassword = password.toLowerCase();
if (this.commonPasswords.includes(lowercasePassword)) {
errors.push('Password is too common and easily guessable');
}
}
// Check for context-specific words
if (opts.disallowContextSpecificWords && opts.contextSpecificWords.length > 0) {
const lowercasePassword = password.toLowerCase();
for (const word of opts.contextSpecificWords) {
if (lowercasePassword.includes(word.toLowerCase())) {
errors.push('Password contains words specific to your context (e.g., company name)');
break;
}
}
}
return {
isValid: errors.length === 0,
errors,
};
}
/**
* Generates a password strength score (0-100)
* @param password - Password to evaluate
* @returns Strength score (0-100)
*/
calculateStrength(password) {
if (!password)
return 0;
let score = 0;
// Length contribution (up to 30 points)
score += Math.min(30, password.length * 2);
// Character variety contribution (up to 40 points)
const hasUppercase = /[A-Z]/.test(password);
const hasLowercase = /[a-z]/.test(password);
const hasNumbers = /[0-9]/.test(password);
const hasSpecialChars = /[^A-Za-z0-9]/.test(password);
score += hasUppercase ? 10 : 0;
score += hasLowercase ? 10 : 0;
score += hasNumbers ? 10 : 0;
score += hasSpecialChars ? 10 : 0;
// Complexity contribution (up to 30 points)
const uniqueChars = new Set(password.split('')).size;
score += Math.min(15, uniqueChars);
// Penalize common patterns
if (/^[A-Za-z]+$/.test(password))
score -= 10; // Only letters
if (/^[0-9]+$/.test(password))
score -= 15; // Only numbers
if (/^[A-Za-z0-9]+$/.test(password))
score -= 5; // No special chars
// Check for common passwords
const lowercasePassword = password.toLowerCase();
if (this.commonPasswords.includes(lowercasePassword)) {
score = Math.min(score, 20); // Cap score for common passwords
}
// Ensure score is between 0 and 100
return Math.max(0, Math.min(100, score));
}
/**
* Gets a strength label based on the score
* @param score - Strength score (0-100)
* @returns Strength label
*/
getStrengthLabel(score) {
if (score < 20)
return 'very weak';
if (score < 40)
return 'weak';
if (score < 60)
return 'moderate';
if (score < 80)
return 'strong';
return 'very strong';
}
}
exports.PasswordPolicyService = PasswordPolicyService;
// Export singleton instance
exports.passwordPolicyService = new PasswordPolicyService();
//# sourceMappingURL=password-policy.service.js.map
;