feat(ui): encryption-vault panel in Settings privacy (enable/unlock/lock/change) (T8.8)

This commit is contained in:
iamdoubz
2026-07-03 08:06:06 -05:00
parent 3402a4552f
commit 0b7461dc9d
+102
View File
@@ -63,6 +63,58 @@
let showConsent = $state(false);
let testResult = $state<{ ok: boolean; message: string } | null>(null);
// ---- At-rest encryption vault (T8.8, FR-SEC-3) ----
let vault = $state<{ enabled: boolean; unlocked: boolean } | null>(null);
let vaultPw = $state("");
let vaultPw2 = $state("");
let vaultMsg = $state<string | null>(null);
async function loadVault() {
try {
vault = await api.vaultStatus();
} catch {
vault = null;
}
}
onMount(loadVault);
async function enableVault() {
vaultMsg = null;
try {
await api.enableVault(vaultPw);
vaultPw = "";
vaultMsg = "Vault enabled and unlocked.";
await loadVault();
} catch (e) {
vaultMsg = `${e}`;
}
}
async function unlockVault() {
vaultMsg = null;
try {
await api.unlockVault(vaultPw);
vaultPw = "";
vaultMsg = "Unlocked.";
await loadVault();
} catch (e) {
vaultMsg = `${e}`;
}
}
async function lockVault() {
await api.lockVault();
vaultMsg = "Locked.";
await loadVault();
}
async function changeVaultPassword() {
vaultMsg = null;
try {
await api.changeVaultPassword(vaultPw, vaultPw2);
vaultPw = "";
vaultPw2 = "";
vaultMsg = "Password changed.";
} catch (e) {
vaultMsg = `${e}`;
}
}
// ---- NPU package download (T3.4) ----
let npuBusy = $state(false);
let npuMsg = $state<string | null>(null);
@@ -612,6 +664,56 @@
{:else}
<p class="muted">Privacy self-check unavailable.</p>
{/if}
{#if vault}
<h4>Encryption vault</h4>
{#if !vault.enabled}
<p class="muted">
Encrypt notes, transcripts, and summaries at rest with a password. (Audio files are
not encrypted yet.)
</p>
<div class="grid">
<label class="wide"
>Vault password<input type="password" bind:value={vaultPw} /></label
>
</div>
<button class="primary" onclick={enableVault} disabled={vaultPw.length < 8}
>Enable vault</button
>
<p class="muted">
Use at least 8 characters. If you forget it, encrypted content can't be recovered.
</p>
{:else if !vault.unlocked}
<p class="muted">
Vault is <strong>locked</strong>. Unlock to read encrypted meetings.
</p>
<div class="grid">
<label class="wide">Password<input type="password" bind:value={vaultPw} /></label>
</div>
<button class="primary" onclick={unlockVault} disabled={!vaultPw}>Unlock</button>
{:else}
<p class="muted">
Vault is <strong>unlocked</strong>. New notes, transcripts, and summaries are
encrypted at rest.
</p>
<button onclick={lockVault}>Lock now</button>
<details>
<summary>Change password</summary>
<div class="grid">
<label class="wide"
>Current password<input type="password" bind:value={vaultPw} /></label
>
<label class="wide"
>New password<input type="password" bind:value={vaultPw2} /></label
>
</div>
<button onclick={changeVaultPassword} disabled={!vaultPw || vaultPw2.length < 8}
>Change password</button
>
</details>
{/if}
{#if vaultMsg}<p class="muted">{vaultMsg}</p>{/if}
{/if}
</section>
{/if}
</div>