05/18 Enhanced codes and functionalities 8

This commit is contained in:
2026-05-18 20:14:18 -04:00
parent b9e8f5c357
commit e8b386b2c8
3 changed files with 34 additions and 3 deletions
+22
View File
@@ -272,6 +272,26 @@ Requires Chrome 111+. `content.js` `onChanged` listener watches `area === 'sessi
## Key Implementation Details
### Vault health notifications (background checks)
`runBackgroundHealthCheck()` fires after every `loadVault()` call — async, non-blocking.
**Flow:**
1. Computes weak + reused counts synchronously from `_items` → updates sidebar badge instantly
2. Runs HIBP k-anonymity checks in parallel (`checkHibp`) → updates badge + banner when done
**Module state:**
- `_healthCache``{ weak, reused, breached, breachedItems, hibpResults }` — set after first run
- `_hibpRunning` — boolean guard prevents concurrent runs
**`_updateHealthUI({ weak, reused, breached })`** — renders:
- **Sidebar badge** (`#security-badge`) on the 🛡️ Security link: red for breaches, amber for weak/reused only, hidden when clean
- **Dismissible banner** (`#health-banner`) above the vault list: summarises issues with "View report" link → Security tab; dismiss hides for the session (`banner.dataset.dismissed = "1"`); resets on next vault load
**Security tab caching:** `renderSecurityDashboard` checks `_healthCache?.hibpResults` before querying HIBP — avoids double-calling the API within the same session.
**Banner reset:** `banner.dataset.dismissed` is set to `"0"` on each vault reload so fresh results (e.g. after a password change) are visible again.
### WebAuthn / Passkey
**Library:** `py-webauthn` (`webauthn>=2.0`). Installed via `pip install webauthn`.
@@ -594,6 +614,8 @@ webauthn>=2.0 # Passkey / WebAuthn (py-webauthn)
## Notes
- Never log decrypted vault data server-side — audit details use `item_type` + `id` only
- Background health check runs after every vault load — badge + banner update without user action
- HIBP results cached in `_healthCache` per session — Security tab reuses them, no double-query
- Tags live in `enc_data` as `plain.tags: string[]` — no schema change ever needed
- `vault_items_cs` is in `chrome.storage.session` — decrypted data never written to disk
- HIBP checks run progressively — synchronous sections render first, then parallel async checks
+1
View File
@@ -16,6 +16,7 @@ A self-hosted, zero-knowledge password manager — web app and Chrome/Firefox ex
- **Item sharing** — ECDH P-256 zero-knowledge re-encryption; item name encrypted with shared key — server never sees it
- **Emergency access** — configurable wait-timer access grant for a trusted contact
- **Security dashboard** — weak / reused / old / **no 2FA saved** / **HaveIBeenPwned breach check** (k-anonymity — passwords never transmitted)
- **Proactive health notifications** — sidebar badge and dismissible banner on vault load when breached, weak, or reused passwords are detected; HIBP runs in the background without blocking the UI; results cached so opening the Security tab is instant
- **Import / Export** — encrypted JSON backup; CSV export (plaintext, handle carefully); import from Chrome, Bitwarden, and 1Password CSV formats (RFC 4180 compliant parser)
- **Account MFA** — TOTP-based login (Google Authenticator / Authy); single-use code enforcement prevents replay attacks
- **Passkeys / WebAuthn** — register device biometrics or hardware keys as a sign-in method; master password still required to unlock vault (zero-knowledge preserved); manage passkeys in Account Settings
+11 -3
View File
@@ -1513,15 +1513,23 @@ const Vault = (() => {
}
ul.innerHTML = shares
.map(
(s) => `
(s) => {
// Resolve the display name: prefer the decrypted name from _items
// (owner's vault is already in memory), fall back to item_name which
// is now the item_type label for new shares, or a legacy plaintext
// name for shares created before the enc_name migration.
const vaultItem = _items.find((i) => i.id === s.item_id);
const displayName = vaultItem?.name || s.item_name;
return `
<li class="share-item">
<div class="share-icon">${itemIcon(s.item_type)}</div>
<div class="share-info">
<span class="share-name">${escHtml(s.item_name)}</span>
<span class="share-name">${escHtml(displayName)}</span>
<span class="share-meta">Shared with ${escHtml(s.recipient_email)} · ${s.accepted ? "✅ Accepted" : "⏳ Pending"}</span>
</div>
<button class="btn-icon" title="Revoke share" data-revoke="${s.id}">🗑</button>
</li>`,
</li>`;
},
)
.join("");