diff --git a/internal/web/handlers_backup_test.go b/internal/web/handlers_backup_test.go index d9b3492..e614e04 100644 --- a/internal/web/handlers_backup_test.go +++ b/internal/web/handlers_backup_test.go @@ -117,6 +117,7 @@ func TestBackupPageOffersEncryption(t *testing.T) { for _, want := range []string{ `name="encrypt"`, `name="password"`, `name="password_confirm"`, `name="import_password"`, "data-encrypt-toggle", "data-encrypt-fields", + "data-import-password-fields", fmt.Sprintf("at least %d characters", minSecretFilePasswordLen), "The two passwords do not match.", } { diff --git a/internal/web/static/panel.css b/internal/web/static/panel.css index 77207ab..f7fb58c 100644 --- a/internal/web/static/panel.css +++ b/internal/web/static/panel.css @@ -335,20 +335,24 @@ button.copy { flex: none; margin-top: 0.3rem; } } .actions button.danger:hover, .actions a.danger:hover, .nav button.danger:hover { background: var(--danger-bg-hover); } -/* The optional "encrypt this download" block on the backup, export and import - forms. Its label is the one checkbox in the panel, so it opts out of the +/* The optional "encrypt this download" block on the backup and export forms. + Its label is the one checkbox in the panel, so it opts out of the block-level label rule above and sits on one line with its box; the fields it reveals are indented under it to read as its consequence rather than as three more fields of the form. panel.js hides the inner block until the box is ticked (and empties it when unticked); without JavaScript everything stays - visible, which the server handles identically. */ + visible, which the server handles identically. The import form reuses the + same indented .encrypt-fields look for its password field, but reveals it + by file extension instead of a checkbox (see panel.js). */ .encrypt { margin-top: 1.2rem; } .encrypt label.check { display: flex; align-items: center; gap: 0.5rem; margin: 0; font-weight: 600; } .encrypt label.check input { width: auto; margin: 0; } .encrypt-fields { - margin-left: 1.6rem; padding-left: 0.9rem; border-left: 2px solid var(--border); + margin-top: 1.2rem; margin-left: 1.6rem; padding-left: 0.9rem; + border-left: 2px solid var(--border); } +.encrypt .encrypt-fields { margin-top: 0; } .encrypt-fields label { margin-top: 0.7rem; } .encrypt-fields .muted { margin: 0.5rem 0 0; font-size: 0.85rem; } diff --git a/internal/web/static/panel.js b/internal/web/static/panel.js index c4450c1..0f0c453 100644 --- a/internal/web/static/panel.js +++ b/internal/web/static/panel.js @@ -102,6 +102,37 @@ }); } + // --- Import password field shown based on the chosen file's extension --- + // The domain-import file decides for itself whether it is encrypted (the + // server checks the envelope magic, not a checkbox), so the panel offers + // the password field the same way: reveal it for a .spde file, hide and + // clear it for a plain .json one. An unrecognised name leaves the field + // visible rather than guessing wrong and hiding a password the file needs. + function syncImportPasswordField(input) { + var form = input.closest("form"); + var fields = form && form.querySelector("[data-import-password-fields]"); + if (!fields) { + return; + } + var name = (input.files && input.files[0] && input.files[0].name || "").toLowerCase(); + var hide = name !== "" && /\.json$/.test(name); + fields.hidden = hide; + if (hide) { + fields.querySelectorAll("input").forEach(function (pw) { + pw.value = ""; + }); + } + } + + function initImportPasswordField(root) { + root.querySelectorAll("input[data-import-file]").forEach(function (input) { + syncImportPasswordField(input); + input.addEventListener("change", function () { + syncImportPasswordField(input); + }); + }); + } + // --- Section index follows the page ----------------------------------- // The long pages list their own sections in the navigation column (the // "sections" template). Marking the one currently in view turns that list @@ -167,6 +198,7 @@ document.addEventListener("DOMContentLoaded", function () { initAddressFields(document); initEncryptFields(document); + initImportPasswordField(document); initSectionIndex(); }); diff --git a/internal/web/templates/backup.html b/internal/web/templates/backup.html index 60e6f31..aee9bc8 100644 --- a/internal/web/templates/backup.html +++ b/internal/web/templates/backup.html @@ -28,16 +28,10 @@ {{if .ImportErr}}
{{.ImportErr}}
{{end}}