|
Add PWA shell and a client-side biometric gate on secret reveal
PWA: hand-rolled service worker (public/sw.js, no build plugin) with a precached shell, network-first navigations with a 4s timeout and an inline offline page, and stale-while-revalidate for /assets and public files that byte-compares in the background and replaces an entry only when the server copy differs. API/auth/MCP/webhook traffic is never intercepted or cached — cookie and secret responses stay out of cache storage. manifest.webmanifest + theme-color + apple-touch-icon; icons rasterized from the shield logo by tools/rasterize_icons.py (192/512, any + maskable). SW registers in main.js under the same secure-context condition the gate uses, with silent background update ticks on visibility/online/15min. Biometric gate (frontend/src/biometric.js): a platform-authenticator passkey (Android fingerprints through BiometricPrompt, Touch ID, Windows Hello) is enrolled opt-in from Settings; every reveal and version reveal runs a fresh WebAuthn assertion with userVerification:"required", whose clientData/authenticatorData/ signature are verified offline in the same browser against the stored public key. The server never learns about biometrics — this is an interface lock, not encryption. Disable requires the same proof, and the toggle disables itself with an explanatory note on devices without a platform authenticator. Also fixes a pre-existing bug the verification run caught: the detail panel's Hide button wrote `revealed.value = null` in the template, where refs auto-unwrap, so the panel never returned to masked state. Verified end to end with a CDP virtual authenticator: 16 checks cover manifest/SW/offline shell/freshness/no-API-cache, enrollment, reveal through the gate (HTTP 200), reveal blocked with no sensor, disable refused without the sensor and allowed with it, and the disabled toggle + note on a device without biometrics. Co-Authored-By: Claude Code <noreply@anthropic.com> |
|---|
|
|
| frontend/index.html |
|---|
| frontend/public/icons/icon-192-maskable.png 0 → 100644 |
|---|
|
|
| frontend/public/icons/icon-192.png 0 → 100644 |
|---|
|
|
| frontend/public/icons/icon-512-maskable.png 0 → 100644 |
|---|
|
|
| frontend/public/icons/icon-512.png 0 → 100644 |
|---|
|
|
| frontend/public/manifest.webmanifest 0 → 100644 |
|---|
| frontend/public/sw.js 0 → 100644 |
|---|
| frontend/src/App.vue |
|---|
| frontend/src/biometric.js 0 → 100644 |
|---|
| frontend/src/main.js |
|---|
| tools/rasterize_icons.py 0 → 100644 |
|---|