From 59d903fbd71593b6fa3ef587ac97626bea8dc6a4 Mon Sep 17 00:00:00 2001 From: hermes-explorigin Date: Thu, 27 Aug 2026 01:18:28 +0000 Subject: [PATCH] Make the lock-screen web-server warning dismissible - The security banner (shown when opened over http(s), not file://) now has a close button. - Dismissal persists via the settings store (dismissedLocalWarning), so it stays hidden across reloads on this browser, while still appearing fresh by default. - Rephrased text kept; banner made flex with a hoverable, accessible close button. --- dist/index.html | 65 ++++++++++++++++++++++++++----- src/components/LockScreen.svelte | 43 ++++++++++++++++++-- src/lib/stores/settings.svelte.js | 5 +++ 3 files changed, 100 insertions(+), 13 deletions(-) diff --git a/dist/index.html b/dist/index.html index 732195d..a1120d6 100644 --- a/dist/index.html +++ b/dist/index.html @@ -5810,11 +5810,20 @@ var SettingsStore = class { set lockOnTabSwitch(value) { set(this.#lockOnTabSwitch, value, true); } + #dismissedLocalWarning = /* @__PURE__ */ state(false); + get dismissedLocalWarning() { + return get(this.#dismissedLocalWarning); + } + set dismissedLocalWarning(value) { + set(this.#dismissedLocalWarning, value, true); + } async load() { const minutes = await getSetting("autoLockMinutes"); const tabSwitch = await getSetting("lockOnTabSwitch"); + const dismissedWarning = await getSetting("dismissedLocalWarning"); this.autoLockMinutes = minutes != null ? Number(minutes) : 5; this.lockOnTabSwitch = tabSwitch != null ? Boolean(tabSwitch) : true; + this.dismissedLocalWarning = dismissedWarning != null ? Boolean(dismissedWarning) : false; } /** * Persist current settings to IndexedDB. @@ -5822,6 +5831,7 @@ var SettingsStore = class { async save() { await saveSetting("autoLockMinutes", this.autoLockMinutes); await saveSetting("lockOnTabSwitch", this.lockOnTabSwitch); + await saveSetting("dismissedLocalWarning", this.dismissedLocalWarning); } }; var settings = new SettingsStore(); @@ -5927,7 +5937,7 @@ function autofocus(node, condition = true) { } //#endregion //#region src/components/LockScreen.svelte -var root_1$7 = /* @__PURE__ */ from_html(``); +var root_1$7 = /* @__PURE__ */ from_html(``); var root_2$6 = /* @__PURE__ */ from_html(``); var root_3$6 = /* @__PURE__ */ from_html(`
`); var root$7 = /* @__PURE__ */ from_html(`
🔐

Password Vault

`); @@ -5943,6 +5953,16 @@ function LockScreen($$anchor, $$props) { set(isSetup, !await isVaultInitialized()); } checkVault(); + let showLocalWarning = /* @__PURE__ */ state(true); + async function dismissLocalWarning() { + settings.dismissedLocalWarning = true; + set(showLocalWarning, false); + try { + await settings.save(); + } catch (e) { + console.warn("Failed to persist warning dismissal:", e); + } + } async function handleSubmit() { set(error, ""); set(loading, true); @@ -6000,10 +6020,14 @@ function LockScreen($$anchor, $$props) { reset(p); var node = sibling(p, 2); var consequent = ($$anchor) => { - append($$anchor, root_1$7()); + var div_2 = root_1$7(); + var button = sibling(child(div_2), 2); + reset(div_2); + delegated("click", button, dismissLocalWarning); + append($$anchor, div_2); }; if_block(node, ($$render) => { - if (get(notLocal)) $$render(consequent); + if (get(notLocal) && get(showLocalWarning) && !settings.dismissedLocalWarning) $$render(consequent); }); var node_1 = sibling(node, 2); var consequent_1 = ($$anchor) => { @@ -6036,9 +6060,9 @@ function LockScreen($$anchor, $$props) { if_block(node_2, ($$render) => { if (get(isSetup)) $$render(consequent_2); }); - var button = sibling(node_2, 2); - var text_2 = child(button, true); - reset(button); + var button_1 = sibling(node_2, 2); + var text_2 = child(button_1, true); + reset(button_1); reset(form); var p_1 = sibling(form, 2); var text_3 = child(p_1, true); @@ -6048,7 +6072,7 @@ function LockScreen($$anchor, $$props) { template_effect(() => { set_text(text, get(isSetup) ? "Create your vault" : "Unlock your vault"); input.disabled = get(loading); - button.disabled = get(loading); + button_1.disabled = get(loading); set_text(text_2, get(loading) ? "Processing..." : get(isSetup) ? "Create Vault" : "Unlock"); set_text(text_3, get(isSetup) ? "Your master password encrypts all data locally. It cannot be recovered if lost." : "Your data is encrypted with AES-256-GCM. Key is stored only in memory."); }); @@ -6059,6 +6083,7 @@ function LockScreen($$anchor, $$props) { append($$anchor, div); pop(); } +delegate(["click"]); //#endregion //#region src/lib/stores/search.svelte.js var DEBOUNCE_MS = 300; @@ -8204,13 +8229,35 @@ label { .warning-banner.svelte-7sq1ct { width: 100%; - padding: 10px 14px; + display: flex; + align-items: flex-start; + gap: 8px; + padding: 10px 10px 10px 14px; background: rgba(255, 193, 7, 0.15); border: 1px solid rgba(230, 168, 0, 0.5); border-radius: var(--radius-md); color: #b8860b; font-size: 0.85rem; - text-align: center; + } + + .warning-text.svelte-7sq1ct { + flex: 1; + text-align: left; + } + + .warning-dismiss.svelte-7sq1ct { + flex-shrink: 0; + border: none; + background: transparent; + color: inherit; + font-size: 0.9rem; + line-height: 1; + cursor: pointer; + padding: 0 2px; + opacity: 0.7; + } + .warning-dismiss.svelte-7sq1ct:hover { + opacity: 1; } .hint.svelte-7sq1ct { diff --git a/src/components/LockScreen.svelte b/src/components/LockScreen.svelte index 0e5f1e2..e2eb039 100644 --- a/src/components/LockScreen.svelte +++ b/src/components/LockScreen.svelte @@ -19,6 +19,16 @@ } checkVault() + // Dismissed warning state loads from the settings store (which loads on + // unlock/setup). Track locally so the banner hides immediately on click. + let showLocalWarning = $state(true) + + async function dismissLocalWarning() { + settings.dismissedLocalWarning = true + showLocalWarning = false + try { await settings.save() } catch (e) { console.warn('Failed to persist warning dismissal:', e) } + } + async function handleSubmit() { error = '' loading = true @@ -88,8 +98,11 @@

Password Vault

{isSetup ? 'Create your vault' : 'Unlock your vault'}

- {#if notLocal} - + {#if notLocal && showLocalWarning && !settings.dismissedLocalWarning} + {/if} {#if error} @@ -196,13 +209,35 @@ .warning-banner { width: 100%; - padding: 10px 14px; + display: flex; + align-items: flex-start; + gap: 8px; + padding: 10px 10px 10px 14px; background: rgba(255, 193, 7, 0.15); border: 1px solid rgba(230, 168, 0, 0.5); border-radius: var(--radius-md); color: #b8860b; font-size: 0.85rem; - text-align: center; + } + + .warning-text { + flex: 1; + text-align: left; + } + + .warning-dismiss { + flex-shrink: 0; + border: none; + background: transparent; + color: inherit; + font-size: 0.9rem; + line-height: 1; + cursor: pointer; + padding: 0 2px; + opacity: 0.7; + } + .warning-dismiss:hover { + opacity: 1; } .hint { diff --git a/src/lib/stores/settings.svelte.js b/src/lib/stores/settings.svelte.js index 5ee613c..baef51a 100644 --- a/src/lib/stores/settings.svelte.js +++ b/src/lib/stores/settings.svelte.js @@ -10,6 +10,8 @@ import { getSetting, saveSetting } from '../storage/db.js' export class SettingsStore { autoLockMinutes = $state(5) lockOnTabSwitch = $state(true) + // User dismissed the "running from a web server" warning banner on the lock screen. + dismissedLocalWarning = $state(false) /** * Load persisted settings from IndexedDB. @@ -18,9 +20,11 @@ export class SettingsStore { async load() { const minutes = await getSetting('autoLockMinutes') const tabSwitch = await getSetting('lockOnTabSwitch') + const dismissedWarning = await getSetting('dismissedLocalWarning') this.autoLockMinutes = minutes != null ? Number(minutes) : 5 this.lockOnTabSwitch = tabSwitch != null ? Boolean(tabSwitch) : true + this.dismissedLocalWarning = dismissedWarning != null ? Boolean(dismissedWarning) : false } /** @@ -29,6 +33,7 @@ export class SettingsStore { async save() { await saveSetting('autoLockMinutes', this.autoLockMinutes) await saveSetting('lockOnTabSwitch', this.lockOnTabSwitch) + await saveSetting('dismissedLocalWarning', this.dismissedLocalWarning) } }