import { describe, it, before, after } from 'node:test'; import assert from 'node:assert/strict'; import http from 'node:http'; import { createApp } from '../../src/app.js'; import { useTempStore, seedProTenant, seedFreeTenant } from '../helpers.js'; import { clearMockJobs } from '../../src/clients/veraeClient.js'; import { config } from '../../src/config.js'; describe('encrypted objects + share + pdf receipt', () => { let ctx; let server; let port; let ownerKey; let otherKey; before(async () => { config.mockVerae = true; config.natsEnabled = false; config.mockJobCompleteMs = 40; clearMockJobs(); ctx = useTempStore(); ownerKey = seedProTenant().apiKey; otherKey = seedFreeTenant({ id: 'tenant-other', veraeUsername: 'other', veraePassword: 'otherpass' }).apiKey; const app = createApp(); await new Promise((resolve) => { server = app.listen(0, '127.0.0.1', () => { port = server.address().port; resolve(); }); }); }); after(async () => { await new Promise((r) => server.close(r)); ctx.cleanup(); }); it('stores encrypted blob, hides it from other tenants, shares via token', async () => { const created = await call(port, 'POST', '/zapier/v1/objects', ownerKey, { filename: 'secret.txt', contentBase64: Buffer.from('top-secret').toString('base64'), publicMetadata: { title: 'pub' }, privateMetadata: { ssn: '000' }, }); assert.equal(created.status, 201); const id = created.body.id; const mine = await call(port, 'GET', `/zapier/v1/objects/${id}`, ownerKey); assert.equal(mine.status, 200); assert.equal(Buffer.from(mine.body.contentBase64, 'base64').toString(), 'top-secret'); assert.equal(mine.body.privateMetadata.ssn, '000'); const theirs = await call(port, 'GET', `/zapier/v1/objects/${id}`, otherKey); assert.equal(theirs.status, 403); const share = await call(port, 'POST', `/zapier/v1/objects/${id}/share`, ownerKey, { label: 'for-other' }); assert.equal(share.status, 201); const redeemed = await call(port, 'GET', `/zapier/v1/shares/${share.body.token}`, otherKey); assert.equal(redeemed.status, 200); assert.equal(redeemed.body.filename, 'secret.txt'); assert.ok(redeemed.body.dek); assert.equal(redeemed.body.publicMetadata.title, 'pub'); }); it('returns a PDF receipt starting with %PDF', async () => { const wait = await call(port, 'POST', '/zapier/v1/timestamp/wait', ownerKey, { data: 'pdf-receipt' }); const jobId = wait.body.id; const rec = await raw(port, 'GET', `/zapier/v1/receipts/${jobId}?format=pdf`, ownerKey); assert.equal(rec.status, 200); assert.match(rec.body.toString('latin1').slice(0, 5), /%PDF-/); }); }); function call(port, method, path, apiKey, body) { return new Promise((resolve, reject) => { const req = http.request( { hostname: '127.0.0.1', port, path, method, headers: { authorization: `Bearer ${apiKey}`, 'content-type': 'application/json' }, }, (res) => { const chunks = []; res.on('data', (c) => chunks.push(c)); res.on('end', () => { const buf = Buffer.concat(chunks); let parsed = {}; try { parsed = buf.length ? JSON.parse(buf.toString()) : {}; } catch { parsed = { raw: buf.toString() }; } resolve({ status: res.statusCode, body: parsed }); }); }, ); req.on('error', reject); if (body) req.write(JSON.stringify(body)); req.end(); }); } function raw(port, method, path, apiKey) { return new Promise((resolve, reject) => { const req = http.request( { hostname: '127.0.0.1', port, path, method, headers: { authorization: `Bearer ${apiKey}` }, }, (res) => { const chunks = []; res.on('data', (c) => chunks.push(c)); res.on('end', () => resolve({ status: res.statusCode, body: Buffer.concat(chunks) })); }, ); req.on('error', reject); req.end(); }); }