fix: implement 9 production enhancements and security fixes
- Password Complexity: Added 4-level complexity selector (Simple/Moderate/Strong/Very Strong) in admin security settings with dynamic backend validation - Gallery Security: Removed event date from login page (security risk), replaced with event type badge - Analytics Config: Fixed "Not Configured" detection logic to check both admin settings and env variables - Analytics Accuracy: Aligned calculation logic between dashboard and analytics endpoints, added totals verification - Translations: Added missing activity keys (analytics_settings_updated, cms_page_updated, security_settings_updated, password_reset, admin_logout, system_activity) - UI Fixes: Fixed German text overflow in CMS page selector with proper CSS truncation - Date Format: Event creation now respects admin-configured date format instead of browser locale - Chrome Compatibility: Replaced emoji flags with SVG components for Windows Chrome support All changes maintain backward compatibility and production stability. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,81 @@ function validatePassword(password, options = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get complexity settings from database
|
||||
* @returns {Object} - Password complexity configuration
|
||||
*/
|
||||
async function getPasswordComplexitySettings() {
|
||||
try {
|
||||
const db = require('../db');
|
||||
const settings = await db('app_settings')
|
||||
.where('setting_key', 'password_complexity')
|
||||
.where('setting_type', 'security')
|
||||
.first();
|
||||
|
||||
if (!settings || !settings.setting_value) {
|
||||
return 'moderate'; // Default
|
||||
}
|
||||
|
||||
const value = typeof settings.setting_value === 'string'
|
||||
? JSON.parse(settings.setting_value)
|
||||
: settings.setting_value;
|
||||
|
||||
return value;
|
||||
} catch (error) {
|
||||
logger.error('Failed to get password complexity settings:', error);
|
||||
return 'moderate'; // Default on error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get password configuration based on complexity level
|
||||
* @param {string} complexityLevel - Complexity level (simple, moderate, strong, very_strong)
|
||||
* @returns {Object} - Password configuration
|
||||
*/
|
||||
function getPasswordConfigForComplexity(complexityLevel) {
|
||||
const configs = {
|
||||
simple: {
|
||||
minLength: 6,
|
||||
requireUppercase: false,
|
||||
requireLowercase: false,
|
||||
requireNumbers: false,
|
||||
requireSpecialChars: false,
|
||||
preventCommonPasswords: true,
|
||||
minStrengthScore: 0
|
||||
},
|
||||
moderate: {
|
||||
minLength: 8,
|
||||
requireUppercase: true,
|
||||
requireLowercase: true,
|
||||
requireNumbers: true,
|
||||
requireSpecialChars: false,
|
||||
preventCommonPasswords: true,
|
||||
minStrengthScore: 2
|
||||
},
|
||||
strong: {
|
||||
minLength: 12,
|
||||
requireUppercase: true,
|
||||
requireLowercase: true,
|
||||
requireNumbers: true,
|
||||
requireSpecialChars: false,
|
||||
preventCommonPasswords: true,
|
||||
minStrengthScore: 3
|
||||
},
|
||||
very_strong: {
|
||||
minLength: 12,
|
||||
requireUppercase: true,
|
||||
requireLowercase: true,
|
||||
requireNumbers: true,
|
||||
requireSpecialChars: true,
|
||||
preventCommonPasswords: true,
|
||||
minStrengthScore: 3
|
||||
}
|
||||
};
|
||||
|
||||
return configs[complexityLevel] || configs.moderate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate password for specific contexts (admin, gallery)
|
||||
* @param {string} password - Password to validate
|
||||
@@ -120,19 +195,16 @@ function validatePassword(password, options = {}) {
|
||||
* @param {Object} userData - Additional user data for context-aware validation
|
||||
* @returns {Object} - Validation result
|
||||
*/
|
||||
function validatePasswordInContext(password, context, userData = {}) {
|
||||
// For gallery context, use more lenient validation
|
||||
async function validatePasswordInContext(password, context, userData = {}) {
|
||||
// For gallery context, use dynamic complexity settings
|
||||
if (context === 'gallery') {
|
||||
// Gallery-specific validation options
|
||||
// Get complexity settings from database
|
||||
const complexityLevel = await getPasswordComplexitySettings();
|
||||
|
||||
// Get configuration for the complexity level
|
||||
const galleryOptions = {
|
||||
minLength: 6, // Reduced minimum length
|
||||
requireUppercase: false, // Don't require uppercase for galleries
|
||||
requireLowercase: false, // Don't require lowercase for galleries
|
||||
requireNumbers: false, // Numbers are optional
|
||||
requireSpecialChars: false, // Special chars are optional
|
||||
preventCommonPasswords: true, // Still prevent common passwords
|
||||
minStrengthScore: 0, // Accept any score for galleries
|
||||
skipStrengthCheck: true // Skip zxcvbn strength analysis for galleries
|
||||
...getPasswordConfigForComplexity(complexityLevel),
|
||||
skipStrengthCheck: complexityLevel === 'simple' // Skip zxcvbn for simple passwords
|
||||
};
|
||||
|
||||
// Base validation with gallery-specific options
|
||||
@@ -281,5 +353,7 @@ module.exports = {
|
||||
generateSecurePassword,
|
||||
getBcryptRounds,
|
||||
logPasswordValidationFailure,
|
||||
getPasswordComplexitySettings,
|
||||
getPasswordConfigForComplexity,
|
||||
PASSWORD_CONFIG
|
||||
};
|
||||
Reference in New Issue
Block a user