Fix config backup/restore failures (related to #646)
Addresses two issues preventing configuration backup/restore:
1. Export passphrase validation mismatch: UI only validated 12+ char
requirement when using custom passphrase, but backend always enforced
it. Users with shorter login passwords saw unexplained failures.
- Frontend now validates all passphrases meet 12-char minimum
- Clear error message suggests custom passphrase if login password too short
2. Import data parsing failed silently: Frontend sent `exportData.data`
which was undefined for legacy/CLI backups (raw base64 strings).
Backend rejected these with no logs.
- Frontend now handles both formats: {status, data} and raw strings
- Backend logs validation failures for easier troubleshooting
Related to #646 where user reported "error after entering password" with
no container logs. These changes ensure proper validation feedback and
make the backup system resilient to different export formats.
This commit is contained in:
parent
b50dba577f
commit
7ed9203e4b
2 changed files with 28 additions and 5 deletions
|
|
@ -1902,10 +1902,14 @@ const Settings: Component<SettingsProps> = (props) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// Just require a passphrase to be entered
|
||||
const hasAuth = securityStatus()?.hasAuthentication;
|
||||
if ((!hasAuth || useCustomPassphrase()) && !exportPassphrase()) {
|
||||
showError('Please enter a passphrase');
|
||||
// Backend requires at least 12 characters for encryption security
|
||||
if (exportPassphrase().length < 12) {
|
||||
const hasAuth = securityStatus()?.hasAuthentication;
|
||||
showError(
|
||||
hasAuth && !useCustomPassphrase()
|
||||
? 'Your password must be at least 12 characters. Please use a custom passphrase instead.'
|
||||
: 'Passphrase must be at least 12 characters long',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -2029,6 +2033,21 @@ const Settings: Component<SettingsProps> = (props) => {
|
|||
return;
|
||||
}
|
||||
|
||||
// Support both formats:
|
||||
// 1. New format: {status: "success", data: "base64string"}
|
||||
// 2. Legacy/CLI format: raw base64 string or {data: "base64string"}
|
||||
let encryptedData: string;
|
||||
if (typeof exportData === 'string') {
|
||||
// Raw base64 string from CLI export
|
||||
encryptedData = exportData;
|
||||
} else if (exportData.data) {
|
||||
// Standard format with data field
|
||||
encryptedData = exportData.data;
|
||||
} else {
|
||||
showError('Invalid backup file format. Expected encrypted data in "data" field.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get CSRF token from cookie
|
||||
const csrfToken = document.cookie
|
||||
.split('; ')
|
||||
|
|
@ -2056,7 +2075,7 @@ const Settings: Component<SettingsProps> = (props) => {
|
|||
credentials: 'include', // Include cookies for session auth
|
||||
body: JSON.stringify({
|
||||
passphrase: importPassphrase(),
|
||||
data: exportData.data,
|
||||
data: encryptedData,
|
||||
}),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2910,12 +2910,14 @@ func (h *ConfigHandlers) HandleExportConfig(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
if req.Passphrase == "" {
|
||||
log.Warn().Msg("Export rejected: passphrase is required")
|
||||
http.Error(w, "Passphrase is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Require strong passphrase (at least 12 characters)
|
||||
if len(req.Passphrase) < 12 {
|
||||
log.Warn().Int("length", len(req.Passphrase)).Msg("Export rejected: passphrase too short (minimum 12 characters)")
|
||||
http.Error(w, "Passphrase must be at least 12 characters long", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -2947,11 +2949,13 @@ func (h *ConfigHandlers) HandleImportConfig(w http.ResponseWriter, r *http.Reque
|
|||
}
|
||||
|
||||
if req.Passphrase == "" {
|
||||
log.Warn().Msg("Import rejected: passphrase is required")
|
||||
http.Error(w, "Passphrase is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if req.Data == "" {
|
||||
log.Warn().Msg("Import rejected: encrypted data is required (ensure backup file has 'data' field)")
|
||||
http.Error(w, "Import data is required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue