import { describe, it, expect } from 'vitest' /** * Canonical network-sandbox decision logic for the Password Vault PWA. * Mirrors `isAppOwnResource` in public/sw.js. It decides whether a request is * permitted: only SAME-ORIGIN requests within the worker's OWN directory scope * are allowed; everything else (cross-origin, or same-origin but a different * app/dir on the same server) is denied. */ function isAppOwnResource(requestUrl, selfUrl) { const req = new URL(requestUrl) const self = new URL(selfUrl) if (req.origin !== self.origin) return false const dir = self.pathname.slice(0, self.pathname.lastIndexOf('/') + 1) return req.pathname.startsWith(dir) } // The deployed worker lives under /password_manager/ -> selfUrl is its own URL. const SELF = 'https://thecookiejar.me/password_manager/sw.js' describe('Vault network-sandbox policy', () => { it('allows the app is own in-scope static resources', () => { expect(isAppOwnResource('https://thecookiejar.me/password_manager/index.html', SELF)).toBe(true) expect(isAppOwnResource('https://thecookiejar.me/password_manager/manifest.webmanifest', SELF)).toBe(true) expect(isAppOwnResource('https://thecookiejar.me/password_manager/icons/icon-192.png', SELF)).toBe(true) expect(isAppOwnResource('https://thecookiejar.me/password_manager/sw.js', SELF)).toBe(true) }) it('denies any cross-origin request (third-party exfiltration)', () => { expect(isAppOwnResource('https://evil.example.com/collect', SELF)).toBe(false) expect(isAppOwnResource('https://api.open-meteo.com/v1/forecast', SELF)).toBe(false) expect(isAppOwnResource('https://google.com/', SELF)).toBe(false) expect(isAppOwnResource('https://thecookiejar.me.evil.com/', SELF)).toBe(false) }) it('denies same-origin requests outside the app directory scope', () => { // Same server, different app/vault dir -> outside the sandbox. expect(isAppOwnResource('https://thecookiejar.me/weather/index.html', SELF)).toBe(false) expect(isAppOwnResource('https://thecookiejar.me/static/switch.css', SELF)).toBe(false) expect(isAppOwnResource('https://thecookiejar.me/', SELF)).toBe(false) }) it('treats a different scheme (http vs https) as a different origin', () => { expect(isAppOwnResource('http://thecookiejar.me/password_manager/index.html', SELF)).toBe(false) }) it('treats a different port as a different origin', () => { expect(isAppOwnResource('https://thecookiejar.me:8443/password_manager/index.html', SELF)).toBe(false) }) })