UNPKG

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
"use strict"; 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