From d557d3a2f87ac3a2b31c25fe0cdfdf5712639c9e Mon Sep 17 00:00:00 2001 From: matcha Date: Sun, 4 Oct 2026 02:46:18 +0000 Subject: [PATCH] Consolidate Persimmons extension --- extension/tests/core.test.mjs | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 extension/tests/core.test.mjs diff --git a/extension/tests/core.test.mjs b/extension/tests/core.test.mjs new file mode 100644 index 0000000..4567af7 --- /dev/null +++ b/extension/tests/core.test.mjs @@ -0,0 +1,72 @@ +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.deepEqual(manifest.optional_host_permissions, ['https://persimmons.app/*']); + 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`)); +});