import test from 'node:test'; import assert from 'node:assert/strict'; import {readFile, readdir} from 'node:fs/promises'; import {pageTarget, metadata, publicSource, request, DEFAULT_SCOPES, BASE} from '../core.mjs'; const target = pageTarget('https://wp.phly.cloud/wp-admin/'); const response = (data, status = 200, type = 'application/json') => new Response(JSON.stringify(data), {status, headers: {'content-type': type}}); test('HTTPS origin only; no path/query exposed as origin', () => { assert.equal(target.origin, 'https://wp.phly.cloud'); assert.deepEqual(pageTarget('https://wp.phly.cloud/private?token=example#fragment'), {origin: 'https://wp.phly.cloud'}); for (const url of ['http://example.org', 'chrome://extensions', 'file:///tmp/a', 'https://user:pass@example.org']) assert.throws(() => pageTarget(url)); }); test('My vault metadata does not pretend to attenuate provider authority', () => { const meta = metadata({origin: target.origin, name: 'Site session', scopes: DEFAULT_SCOPES, minutes: 60}, 0); assert.equal(meta.vault_kind, 'user'); assert.equal(meta.expires, undefined); assert.deepEqual(meta.scopes, ['content:read', 'content:draft-write']); assert.equal(meta.credential_type, 'api-token'); assert.throws(() => metadata({...meta, origin: target.origin, scopes: ['admin'], minutes: 60})); }); test('public source projection retains id/name only, rejects repository context', () => { assert.deepEqual(publicSource({id: 'ABC123', name: 'Site', vault_kind: 'user', credential: 'SENSITIVE_FIXTURE'}), {id: 'ABC123', name: 'Site'}); assert.throws(() => publicSource({id: 'ABC123', name: 'Site', vault_kind: 'repository'})); }); test('exact create route, browser authority and safe request settings', async () => { await request('create', {vault_kind: 'user', credential: 'SENSITIVE_FIXTURE'}, async (url, options) => { assert.equal(url, `${BASE}/create`); assert.equal(options.credentials, 'include'); assert.equal(options.redirect, 'error'); assert.equal(options.cache, 'no-store'); assert.equal(options.method, 'POST'); assert.equal(JSON.parse(options.body).vault_kind, 'user'); return response({id: 'ABC123', name: 'Site', vault_kind: 'user'}); }); for (const path of ['juice/create', 'juice/revoke']) await request(path, {vault_kind: 'user'}, async url => { assert.equal(url, `${BASE}/${path}`); return response({ok: true}); }); }); test('missing Juice, rejected auth, redirects/HTML, echoed secrets and timeouts are safe', async () => { for (const [status, expected] of [[404, /Juice unavailable/], [503, /Juice unavailable/], [401, /Sign in/], [403, /Sign in/]]) { await assert.rejects(request('juice/create', {}, async () => response({error: 'SENSITIVE_FIXTURE'}, status)), expected); } await assert.rejects(request('list', undefined, async () => response('SENSITIVE_FIXTURE', 200, 'text/html')), /expected JSON/); await assert.rejects(request('create', {}, async () => response({error: 'SENSITIVE_FIXTURE'})), /did not confirm/); await assert.rejects(request('create', {}, async () => { throw new Error('SENSITIVE_FIXTURE'); }), /unreachable or timed out/); let called = false; await assert.rejects(request('create', {credential: '\\'.repeat(16384)}, async () => { called = true; }), /24 KiB/); assert.equal(called, false); }); test('legacy token module still has no persistence or injection; MV3 exposure is bounded', async () => { const root = new URL('../', import.meta.url); const manifest = JSON.parse(await readFile(new URL('manifest.json', root), 'utf8')); assert.equal(manifest.manifest_version, 3); assert.deepEqual(manifest.permissions, ['activeTab', 'scripting', 'storage']); assert.deepEqual(manifest.host_permissions, ['https://teahub.xyz/*']); assert.equal(manifest.optional_host_permissions, undefined); assert.equal(manifest.content_scripts, undefined); assert.deepEqual(manifest.background, {service_worker:'connection.mjs',type:'module'}); assert.equal(manifest.web_accessible_resources, undefined); assert.deepEqual(manifest.externally_connectable, {matches:['https://persimmons.app/*']}); for (const name of await readdir(root)) { if (!/\.(mjs|html)$/.test(name)) continue; const source = await readFile(new URL(name, root), 'utf8'); assert.doesNotMatch(source, /console\.|chrome\.cookies|localStorage|sessionStorage|indexedDB|innerHTML|eval\(/); if (['core.mjs', 'popup.mjs'].includes(name)) assert.doesNotMatch(source, /chrome\.scripting|chrome\.storage/); } const html = await readFile(new URL('popup.html', root), 'utf8'); assert.match(html, /human-popup\.mjs/); assert.doesNotMatch(html, /juice-panel|value="content:read"|value="content:draft-write"/); for (const scope of ['manage:users', 'billing', 'destructive']) assert.doesNotMatch(html, new RegExp(`value="${scope}" checked`)); });