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.
This commit is contained in:
parent
c9a42c4670
commit
59d903fbd7
65
dist/index.html
vendored
65
dist/index.html
vendored
@ -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(`<div class="warning-banner svelte-7sq1ct" role="alert">You're viewing this from a web server. For best security, download this HTML file and open it locally on your computer instead.</div>`);
|
||||
var root_1$7 = /* @__PURE__ */ from_html(`<div class="warning-banner svelte-7sq1ct" role="alert"><span class="warning-text svelte-7sq1ct">You're viewing this from a web server. For best security, download this HTML file and open it locally on your computer instead.</span> <button class="warning-dismiss svelte-7sq1ct" aria-label="Dismiss warning">✕</button></div>`);
|
||||
var root_2$6 = /* @__PURE__ */ from_html(`<div class="error-banner svelte-7sq1ct" role="alert"> </div>`);
|
||||
var root_3$6 = /* @__PURE__ */ from_html(`<div class="form-group"><label for="confirm-password">Confirm Password</label> <input id="confirm-password" type="password" placeholder="Confirm master password" autocomplete="new-password"/></div>`);
|
||||
var root$7 = /* @__PURE__ */ from_html(`<div class="lock-screen svelte-7sq1ct"><div class="lock-card svelte-7sq1ct"><div class="lock-icon svelte-7sq1ct">🔐</div> <h1 class="svelte-7sq1ct">Password Vault</h1> <p class="subtitle svelte-7sq1ct"> </p> <!> <!> <form class="lock-form svelte-7sq1ct"><div class="form-group"><label for="master-password">Master Password</label> <input id="master-password" type="password" placeholder="Enter master password" autocomplete="current-password"/></div> <!> <button type="submit" class="btn btn-primary w-full"> </button></form> <p class="hint svelte-7sq1ct"> </p></div></div>`);
|
||||
@ -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 {
|
||||
|
||||
@ -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 @@
|
||||
<h1>Password Vault</h1>
|
||||
<p class="subtitle">{isSetup ? 'Create your vault' : 'Unlock your vault'}</p>
|
||||
|
||||
{#if notLocal}
|
||||
<div class="warning-banner" role="alert">This HTML file is intended for offline use.</div>
|
||||
{#if notLocal && showLocalWarning && !settings.dismissedLocalWarning}
|
||||
<div class="warning-banner" role="alert">
|
||||
<span class="warning-text">You're viewing this from a web server. For best security, download this HTML file and open it locally on your computer instead.</span>
|
||||
<button class="warning-dismiss" onclick={dismissLocalWarning} aria-label="Dismiss warning">✕</button>
|
||||
</div>
|
||||
{/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 {
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user