import assert from 'node:assert/strict'; import test from 'node:test'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { randomBytes, pbkdf2Sync, createCipheriv, createHmac } from 'node:crypto'; import { isSuppressed, reachedHalf, suppressionDuration } from '../src/utils/drawer-preference.ts'; import { serviceInquiryCopy } from '../src/data/service-inquiry.ts'; import { decryptPortalStream, encryptPortalStream, validatePortalPayload, portalAlgorithm } from '../src/utils/portal-crypto.mjs'; import { collectResource, resourceReferences, rewriteResources } from './portal-resources.mjs'; import { isFormACompletion } from '../src/utils/jotform-completion.ts'; import { portalLinkPresentation } from '../src/utils/portal-presentation.ts'; test('completion envelope requires exact origin, active frame window and string Form A ID', () => { const source = {}; const check = (event, frame, active) => isFormACompletion(event, frame, active, 'https://form.jotform.com/262946078314059?formContext=consultation&language=en'); const data = { action: 'submission-completed', formID: '262946078314059' }; const event = { origin: 'https://form.jotform.com', source, data }; assert.equal(check(event, source, true), true); assert.equal(check({ ...event, data: JSON.stringify(data) }, source, true), true); for (const change of [ { origin: 'https://form.jotform.com.evil.invalid' }, { origin: 'null' }, { origin: 'http://form.jotform.com' }, { source: {} }, { source: null }, { data: { ...data, formID: 'other' } }, { data: { ...data, formID: 262946078314059 } }, { data: { ...data, action: 'load' } }, { data: '{broken' }, { data: [] }, { data: null }, { data: 'x'.repeat(4097) }, ]) assert.equal(check({ ...event, ...change }, source, true), false); assert.equal(check(event, source, false), false); assert.equal(check(event, null, true), false); assert.equal(isFormACompletion(event, source, true, undefined), false); assert.equal(isFormACompletion(event, source, true, 'broken'), false); }); test('portal presentation translates only explicit button tokens/brand fills and contact protocols', () => { assert.equal(portalLinkPresentation(['hs-button', 'untrusted'], '', 'https:'), 'portal-resource-button'); assert.equal(portalLinkPresentation([], 'rgb(255, 189, 89)', 'https:'), 'portal-resource-button'); assert.equal(portalLinkPresentation(['arbitrary'], 'url(https://example.invalid)', 'https:'), undefined); assert.equal(portalLinkPresentation(['unrecognized-legacy'], '', 'https:', 'Operations Monthly Lineup Report - PM'), 'portal-resource-button'); assert.equal(portalLinkPresentation([], '', 'https:', 'Human Resources Daily Lineup Report - PM'), 'portal-resource-button'); assert.equal(portalLinkPresentation([], '', 'https:', 'Billing Daily Lineup Report - PM'), 'portal-resource-button'); assert.equal(portalLinkPresentation([], '', 'https:', 'Generic reports and documents'), undefined); assert.equal(portalLinkPresentation([], '', 'https:', 'Monthly report'), undefined); assert.equal(portalLinkPresentation([], '', 'mailto:', 'Operations Monthly Lineup Report - PM'), 'portal-contact-link'); assert.equal(portalLinkPresentation([], '', 'mailto:'), 'portal-contact-link'); assert.equal(portalLinkPresentation([], '', 'tel:'), 'portal-contact-link'); }); test('staff template presentation follows sanitized headings, not original HubSpot classes', async () => { const renderer = await fs.readFile('src/scripts/employee-portal.ts', 'utf8'); const css = await fs.readFile('src/components/pages/EmployeePortal.astro', 'utf8'); assert.match(renderer, /enhanceStaffPortalPresentation\(output\)/); assert.match(renderer, /'management templates'/); assert.match(renderer, /fragment\.querySelectorAll\('a\[href\]'\)/); assert.match(renderer, /templatesList\?\.classList\.add\('portal-template-grid'\)/); assert.match(css, /grid-template-columns: repeat\(2, minmax\(0, 1fr\)\)/); assert.match(css, /@media \(max-width: 767px\)/); assert.doesNotMatch(css, /ul\.portal-template-grid a\.portal-resource-button/); assert.match(renderer, /items\.every\(\(item\) => item\.querySelector\('a\.portal-resource-button'\)\)/); assert.match(renderer, /list\.classList\.add\('portal-resource-list'\)/); assert.match(css, /\.portal-resource-list > li::marker\)\s*\{\s*content: none;/); assert.match(css, /\.employee-portal__content:focus\s*\{ outline: none;/); assert.match(css, /input:focus-visible\s*\{ outline: 3px solid/); assert.match(css, /:global\(a:focus-visible\)\s*\{ outline: 3px solid/); }); test('global preference validates expiry, corrupted values and clock anomalies', () => { const now = 10000000000; for (const raw of [null, '', 'NaN', '-1', '1.5', 'Infinity', String(now), String(now - 1), String(now + suppressionDuration + 1)]) assert.equal(isSuppressed(raw, now), false); assert.equal(isSuppressed(String(now + suppressionDuration), now), true); assert.equal(isSuppressed(String(now + 1), now), true); }); test('half-scroll handles short, restored, resized and overscrolled pages', () => { assert.equal(reachedHalf(0, 500, 800), false); assert.equal(reachedHalf(100, 800, 800), false); assert.equal(reachedHalf(499, 1800, 800), false); assert.equal(reachedHalf(500, 1800, 800), true); assert.equal(reachedHalf(-10, 1800, 800), false); assert.equal(reachedHalf(500, 2800, 800), false); }); test('four service configurations are bilingual without adding an Academy route', async () => { assert.equal(Object.keys(serviceInquiryCopy).length, 4); for (const variants of Object.values(serviceInquiryCopy)) for (const copy of Object.values(variants)) { assert.ok(copy.heading && copy.introduction); assert.ok(!copy.introduction.includes('—')); } const { formAIframePlacements } = await import('../src/utils/form-integration.ts'); assert.equal(formAIframePlacements.filter(p => p.context === 'consultation').length, 9); assert.ok(!formAIframePlacements.some((p) => p.route.includes('preparatory'))); }); test('legacy independent crypto fixture and two-view separation round-trip', async () => { const pass = randomBytes(32).toString('base64'), other = randomBytes(32).toString('base64'); const salt = randomBytes(16), iv = randomBytes(16), keys = pbkdf2Sync(pass, salt, 200000, 64, 'sha256'); const cipher = createCipheriv('aes-256-cbc', keys.subarray(0, 32), iv); const ct = Buffer.concat([cipher.update('

Synthetic staff

'), cipher.final()]); const mac = createHmac('sha256', keys.subarray(32)).update(Buffer.concat([iv, ct])).digest(); const stream = { id: 'synthetic-staff', iter: 200000, salt: salt.toString('base64'), iv: iv.toString('base64'), hmac: mac.toString('base64'), ct: ct.toString('base64') }; const second = await encryptPortalStream('synthetic-management', '

Synthetic management

', other); validatePortalPayload({ alg: portalAlgorithm, streams: [stream, second] }); assert.equal(await decryptPortalStream(stream, pass), '

Synthetic staff

'); assert.equal(await decryptPortalStream(second, pass), null); assert.equal(await decryptPortalStream(stream, other), null); assert.equal(await decryptPortalStream(second, other), '

Synthetic management

'); assert.equal(await decryptPortalStream({ ...stream, hmac: randomBytes(32).toString('base64') }, pass), null); assert.throws(() => validatePortalPayload({ alg: portalAlgorithm, streams: [stream, stream] })); }); test('resource extraction reconciles duplicate views and rewrites only approved implemented links', () => { const html = '

Synthetic

ExampleAgainOther'; const refs = resourceReferences(html, 'synthetic'); assert.equal(refs.length, 2); assert.equal(new Set(refs.map((r) => r.sourceUrl)).size, 1); const record = { references: refs, rewriteApproved: true, destinationImplemented: true, destinationVerified: true, deliveryPath: '/staff-resources/example.pdf', classification: 'STAFF-INTERNAL' }; assert.throws(() => rewriteResources(html, [record])); const result = rewriteResources(html, [{ ...record, destinationAccessControlled: true }]); assert.equal(result.count, 2); assert.ok(result.html.includes('>Again')); assert.ok(result.html.includes('https://unapproved.invalid/form')); assert.equal(rewriteResources(html, []).html, html); }); test('private collector validates binary, reuses hash, rejects errors and unapproved redirects', async () => { const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'aia-private-test-')); try { const resource = { sourceUrl: 'https://www.azinstitute4autism.com/hubfs/synthetic.pdf' }; const good = await collectResource(resource, dir, undefined, async () => new Response('%PDF-1.7\nSynthetic', { headers: { 'content-type': 'application/pdf' } })); assert.equal(good.downloadStatus, 'downloaded'); const again = await collectResource(good, dir, undefined, () => { throw new Error('must not fetch'); }); assert.equal(again.downloadStatus, 'verified-existing'); await assert.rejects(collectResource(resource, dir, undefined, async () => new Response('Error', { headers: { 'content-type': 'application/pdf' } }))); await assert.rejects(collectResource(resource, dir, undefined, async () => new Response('', { status: 302, headers: { location: 'https://unapproved.invalid/hubfs/file' } }))); } finally { await fs.rm(dir, { recursive: true }); } }); test('portal input requires every local gate and rejects missing or malformed ciphertext', async () => { const { readPortalInput } = await import('../src/utils/portal-input.mjs'); const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'aia-portal-input-')); try { const pass = randomBytes(24).toString('base64'); const streams = await Promise.all(['one','two'].map((id) => encryptPortalStream(id, '

Synthetic

', pass))); const file = path.join(dir, 'fixture.json'); await fs.writeFile(file, JSON.stringify({ alg: portalAlgorithm, streams }), { mode: 0o600 }); const options = { approved: 'true', indexing: 'false', file }; assert.ok(readPortalInput(options)); // Form modes cannot substitute for the independent private-input approval. for (const mode of ['live', 'off', 'mock']) { assert.ok(readPortalInput({ ...options, mode })); assert.equal(readPortalInput({ indexing: 'false', file, mode }), undefined); } for (const changed of [{ approved: undefined }, { approved: 'false' }, { indexing: 'true' }, { indexing: undefined }, { file: '/missing-fixture' }]) assert.equal(readPortalInput({ ...options, ...changed }), undefined); await fs.writeFile(file, '

Not encrypted

'); assert.equal(readPortalInput(options), undefined); } finally { await fs.rm(dir, { recursive: true }); } });