From cb9d8d1ab13bbb615b482ee3d57e001676420bd7 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 7 Nov 2025 22:51:55 +0000 Subject: [PATCH] Fix config backup/restore by enforcing 12-char minimum password (related to #646) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Users with 8-11 character passwords could not export/restore config backups because the export encryption requires 12+ character passphrases for security, but the password creation UI only enforced an 8-character minimum. This created a confusing UX where users with short passwords saw validation errors when trying to export backups, with the only solution being to use a custom passphrase or change their password. Root cause: - FirstRunSetup and ChangePasswordModal allowed 8+ char passwords - Config export/import requires 12+ char passphrases (backend validation) - The v4.26.4 fix added frontend validation that showed the mismatch - Users hit client-side validation before request was sent (no backend logs) This fix raises the minimum password length to 12 characters everywhere: - internal/auth/password.go: MinPasswordLength 8 → 12 - FirstRunSetup.tsx: validation and placeholder updated - ChangePasswordModal.tsx: validation, minLength, and help text updated - QuickSecuritySetup.tsx: validation and label updated Impact: - New users must create 12+ character passwords - Existing users with <12 char passwords are unaffected (can't detect from hash) - Those users will see the existing helpful error directing them to use custom passphrase for backups - "Use your login password" option now works for all future passwords This aligns password requirements across the system and eliminates the confusing mismatch between login credentials and backup encryption requirements. Related to #646 where user confirmed backups still failed in v4.26.5 --- frontend-modern/src/components/FirstRunSetup.tsx | 6 +++--- .../src/components/Settings/ChangePasswordModal.tsx | 8 ++++---- .../src/components/Settings/QuickSecuritySetup.tsx | 6 +++--- internal/auth/password.go | 3 ++- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/frontend-modern/src/components/FirstRunSetup.tsx b/frontend-modern/src/components/FirstRunSetup.tsx index e9652c1..a991e62 100644 --- a/frontend-modern/src/components/FirstRunSetup.tsx +++ b/frontend-modern/src/components/FirstRunSetup.tsx @@ -100,8 +100,8 @@ export const FirstRunSetup: Component<{ force?: boolean; showLegacyBanner?: bool showError('Passwords do not match'); return; } - if (password().length < 8) { - showError('Password must be at least 8 characters'); + if (password().length < 12) { + showError('Password must be at least 12 characters'); return; } } @@ -404,7 +404,7 @@ IMPORTANT: Keep these credentials secure! value={password()} onInput={(e) => setPassword(e.currentTarget.value)} class="w-full px-4 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-transparent" - placeholder="Enter password (min 8 characters)" + placeholder="Enter password (min 12 characters)" /> = (props) return; } - if (newPassword().length < 8) { - setError('Password must be at least 8 characters'); + if (newPassword().length < 12) { + setError('Password must be at least 12 characters'); return; } @@ -163,9 +163,9 @@ export const ChangePasswordModal: Component = (props) class={controlClass('shadow-sm')} required disabled={loading()} - minLength={8} + minLength={12} /> -

Minimum 8 characters

+

Minimum 12 characters

diff --git a/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx b/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx index 4e00f05..f7e30d3 100644 --- a/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx +++ b/frontend-modern/src/components/Settings/QuickSecuritySetup.tsx @@ -61,8 +61,8 @@ export const QuickSecuritySetup: Component = (props) => const setupSecurity = async () => { // Validate custom password if using if (useCustomPassword()) { - if (customPassword().length < 8) { - showError('Password must be at least 8 characters'); + if (customPassword().length < 12) { + showError('Password must be at least 12 characters'); return; } if (customPassword() !== confirmPassword()) { @@ -267,7 +267,7 @@ Important: />
- +