Makes the offline-first vault installable as a standalone PWA, and enforces "no network access aside from the app's own resources" once installed. PWA: - public/manifest.webmanifest: scope ./ (confined to the app's own dir), three icons (192/512 + transparent maskable), standalone display, brand theme. No push/shortcuts (deliberate: offline-first vault, nothing to push). - public/sw.js: a NETWORK SANDBOX service worker. Allows only same-origin requests inside the worker's own directory (index, manifest, icons); returns 403 for every cross-origin request and for same-origin paths outside the app dir. This blocks in-app <img>/<script>/fetch exfiltration at the source. - src/lib/pwa.js + main.js: register the worker (relative path, works at / in dev and under /password_manager/ in prod). - index.html: dev CSP (permits Vite HMR WebSocket) + PWA meta/link tags. Security: - scripts/inline-assets.js swaps the dev CSP for the STRICT production CSP in the shipped dist: connect-src 'none' (no fetch/XHR/WebSockets anywhere), form-action 'none', object-src/base-uri 'none', img/font/media 'self' data:. The browser-native connect-src closes the WebSocket gap the SW cannot see. - Known boundary documented in-file: frame-ancestors / X-Frame-Options is HTTP-header-only (ignored in meta) and not set by the static host, so clickjacking is permissive; all exfiltration channels are closed regardless. Build/deploy: - inline-assets.js now PRESERVES manifest/sw.js/icons in dist (was deleting). - deploy.yml uploads + byte-verifies index.html, manifest, sw.js, and all three icons to WebDAV. Tests: - tests/lib/sw-policy.test.js: 5 tests for the sandbox allow/deny logic (in-scope allowed; cross-origin, out-of-scope, scheme/port mismatch denied). - Verified in headless Chromium against the built dist: SW registers + is active, and both a cross-origin fetch and a same-origin-out-of-scope fetch are refused by the CSP before leaving the device. Fixup: dropped 'frame-ancestors' from the meta CSP after confirming the browser ignores it there (it is a header-only directive).
20 lines
910 B
XML
20 lines
910 B
XML
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
|
<defs>
|
|
<linearGradient id="bg" x1="0" y1="0" x2="1" y2="1">
|
|
<stop offset="0" stop-color="#6c63ff"/>
|
|
<stop offset="1" stop-color="#3b2f8f"/>
|
|
</linearGradient>
|
|
</defs>
|
|
<rect x="0" y="0" width="512" height="512" rx="112" ry="112" fill="url(#bg)"/>
|
|
<!-- Padlock body -->
|
|
<ellipse cx="256" cy="300" rx="150" ry="108" fill="#e4e6f0" opacity="0.95"/>
|
|
<!-- Padlock shackle -->
|
|
<path d="M 190 200 L 210 120 Q 222 96 256 92 Q 290 96 302 120 L 322 200"
|
|
fill="none" stroke="#e4e6f0" stroke-width="40" stroke-linecap="round" opacity="0.95"/>
|
|
<!-- Keyhole -->
|
|
<circle cx="256" cy="292" r="30" fill="#0f1117"/>
|
|
<path d="M 256 322 L 256 352 L 244 352 L 268 352" fill="#0f1117"/>
|
|
<!-- Satin highlight -->
|
|
<ellipse cx="256" cy="204" rx="96" ry="14" fill="rgba(255,255,255,0.28)"/>
|
|
</svg>
|