diff --git a/backend/src/utils/passwordValidation.js b/backend/src/utils/passwordValidation.js
index 00efed6..74c3d8b 100644
--- a/backend/src/utils/passwordValidation.js
+++ b/backend/src/utils/passwordValidation.js
@@ -8,13 +8,13 @@ const logger = require('./logger');
// Configuration
const PASSWORD_CONFIG = {
- minLength: 12,
+ minLength: 8, // Reduced from 12 to 8 for better usability
requireUppercase: true,
requireLowercase: true,
requireNumbers: true,
- requireSpecialChars: true,
+ requireSpecialChars: false, // Made optional for gallery passwords
preventCommonPasswords: true,
- minStrengthScore: 3, // zxcvbn score (0-4, where 3 is "good")
+ minStrengthScore: 2, // Reduced from 3 to 2 (moderate strength)
bcryptRounds: parseInt(process.env.BCRYPT_ROUNDS) || 12 // Configurable, default 12
};
@@ -137,18 +137,15 @@ function validatePasswordInContext(password, context, userData = {}) {
}
}
} else if (context === 'gallery') {
- // Gallery passwords can be slightly less strict
- // but still need to be secure
- if (result.score < 2) {
+ // Gallery passwords can be more lenient for user convenience
+ // Allow passwords with score >= 1 (weak but acceptable)
+ if (result.score < 1) {
result.valid = false;
- result.errors.push('Gallery passwords must have moderate strength or better');
+ result.errors.push('Password is too simple. Please add more complexity');
}
- // Check password doesn't contain event name
- if (userData.eventName && password.toLowerCase().includes(userData.eventName.toLowerCase())) {
- result.valid = false;
- result.errors.push('Password must not contain the event name');
- }
+ // Don't check for event name in password - allow date-based passwords
+ // This allows passwords like "Sommer2025!" which users prefer
}
return result;
diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json
index affd1a8..ece35b6 100644
--- a/frontend/src/i18n/locales/de.json
+++ b/frontend/src/i18n/locales/de.json
@@ -872,6 +872,7 @@
"passwordRequired": "Passwort ist erforderlich",
"passwordMinLength": "Passwort muss mindestens 6 Zeichen lang sein",
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
+ "passwordSecurityRequirements": "Passwort erfüllt nicht die Sicherheitsanforderungen",
"expirationRange": "Ablauf muss zwischen 1 und 365 Tagen liegen"
},
"maintenance": {
diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json
index 3dc178c..de93b07 100644
--- a/frontend/src/i18n/locales/en.json
+++ b/frontend/src/i18n/locales/en.json
@@ -792,6 +792,7 @@
"passwordRequired": "Password is required",
"passwordMinLength": "Password must be at least 6 characters",
"passwordsDoNotMatch": "Passwords do not match",
+ "passwordSecurityRequirements": "Password does not meet security requirements",
"expirationRange": "Expiration must be between 1 and 365 days"
},
"legal": {
diff --git a/frontend/src/pages/admin/CreateEventPage.tsx b/frontend/src/pages/admin/CreateEventPage.tsx
index a7756a1..de32a2d 100644
--- a/frontend/src/pages/admin/CreateEventPage.tsx
+++ b/frontend/src/pages/admin/CreateEventPage.tsx
@@ -7,7 +7,9 @@ import {
Clock,
ArrowLeft,
Info,
- Upload
+ Upload,
+ Eye,
+ EyeOff
} from 'lucide-react';
import { format, addDays } from 'date-fns';
import { toast } from 'react-toastify';
@@ -168,7 +170,13 @@ export const CreateEventPage: React.FC = () => {
toast.error(t('errors.sessionExpired'));
navigate('/admin/login');
} else {
- toast.error(error.response?.data?.error || t('errors.failedToCreateEvent'));
+ const errorMessage = error.response?.data?.error;
+ // Check if it's the password security requirements error
+ if (errorMessage === 'Password does not meet security requirements') {
+ toast.error(t('validation.passwordSecurityRequirements'));
+ } else {
+ toast.error(errorMessage || t('errors.failedToCreateEvent'));
+ }
}
},
});
@@ -405,7 +413,20 @@ export const CreateEventPage: React.FC = () => {
error={errors.password}
placeholder={t('events.enterPassword')}
leftIcon={