import assert from 'node:assert/strict'; import { once } from 'node:events'; import test from 'node:test'; import { adminSignature, uploadSignature } from '../src/auth.mjs'; import { createApp } from '../src/server.mjs'; const noUploadStore = { async initialize() {}, async store() { throw new Error('must not upload'); } }; test('sync endpoint authenticates a scoped caller and passes only an optional commit', async (t) => { const calls = []; const service = { async initialize() {}, async deploySync(value) { calls.push(value); return { changed: false }; }, async recordError() {}, }; const secret = 's'.repeat(32); const { server } = await createApp({ maxBodyBytes: 4096, syncClientSecrets: { core: secret }, }, { service, uploadStore: noUploadStore }); server.listen(0, '127.0.0.1'); await once(server, 'listening'); t.after(() => server.close()); const address = server.address(); const body = Buffer.from(JSON.stringify({ commit: 'a'.repeat(40) })); const timestamp = String(Date.now()); const requestId = 'sync-request-1234'; const response = await fetch(`http://127.0.0.1:${address.port}/v1/sync`, { method: 'POST', headers: { 'content-type': 'application/json', 'x-image-client': 'core', 'x-image-timestamp': timestamp, 'x-image-request-id': requestId, 'x-image-signature': adminSignature(secret, timestamp, requestId, body), }, body, }); assert.equal(response.status, 200); assert.deepEqual(calls, [{ requestKey: `core:${requestId}`, expectedCommit: 'a'.repeat(40) }]); }); test('upload endpoint accepts a short-lived body-bound grant and rejects replay or tampering', async (t) => { const service = { async initialize() {}, async recordError() {}, }; const calls = []; const uploadStore = { async initialize() {}, async store(value) { calls.push(value); return { duplicate: false, path: `icons/users/${value.client}/${value.filename}` }; }, }; const secret = 'u'.repeat(32); const config = { maxBodyBytes: 4096, maxUploadBytes: 51200, maxContentUploadBytes: 1048576, syncClientSecrets: { core: 's'.repeat(32) }, uploadClientSecrets: { core2026: secret }, publicBases: ['https://sam-image.hided.net', 'https://sam.hided.net/image'], }; const { server } = await createApp(config, { service, uploadStore }); server.listen(0, '127.0.0.1'); await once(server, 'listening'); t.after(() => server.close()); const address = server.address(); const pathname = `/v1/uploads/user-icons/core2026/${'a'.repeat(32)}.png`; const body = Buffer.from('89504e470d0a1a0a00000000', 'hex'); const expires = String(Math.floor(Date.now() / 1000) + 60); const requestId = 'upload-request-1234'; const signature = uploadSignature(secret, { expires, requestId, pathname, contentType: 'image/png', body }); const headers = { 'content-type': 'image/png', 'x-image-client': 'core2026', 'x-image-expires': expires, 'x-image-request-id': requestId, 'x-image-signature': signature, }; const accepted = await fetch(`http://127.0.0.1:${address.port}${pathname}`, { method: 'PUT', headers, body }); assert.equal(accepted.status, 201); assert.deepEqual(calls[0], { requestKey: `core2026:${requestId}`, category: 'user-icons', client: 'core2026', filename: `${'a'.repeat(32)}.png`, body, }); assert.deepEqual((await accepted.json()).urls, [ `https://sam-image.hided.net/icons/users/core2026/${'a'.repeat(32)}.png`, `https://sam.hided.net/image/icons/users/core2026/${'a'.repeat(32)}.png`, ]); const contentPath = `/v1/uploads/content/core2026/${'b'.repeat(32)}.webp`; const contentBody = Buffer.concat([Buffer.from('RIFF'), Buffer.alloc(4), Buffer.from('WEBP'), Buffer.alloc(4)]); const contentRequestId = 'content-request-1234'; const contentSignature = uploadSignature(secret, { expires, requestId: contentRequestId, pathname: contentPath, contentType: 'image/webp', body: contentBody, }); const contentResponse = await fetch(`http://127.0.0.1:${address.port}${contentPath}`, { method: 'PUT', headers: { 'content-type': 'image/webp', 'x-image-client': 'core2026', 'x-image-expires': expires, 'x-image-request-id': contentRequestId, 'x-image-signature': contentSignature, }, body: contentBody, }); assert.equal(contentResponse.status, 201); assert.equal(calls[1].category, 'content'); assert.equal(calls[1].filename, `${'b'.repeat(32)}.webp`); const tampered = await fetch(`http://127.0.0.1:${address.port}${pathname}`, { method: 'PUT', headers, body: Buffer.from('89504e470d0a1a0affffffff', 'hex'), }); assert.equal(tampered.status, 401); const expired = '1000000000'; const expiredHeaders = { ...headers, 'x-image-expires': expired, 'x-image-signature': uploadSignature(secret, { expires: expired, requestId, pathname, contentType: 'image/png', body }), }; const expiredResponse = await fetch(`http://127.0.0.1:${address.port}${pathname}`, { method: 'PUT', headers: expiredHeaders, body, }); assert.equal(expiredResponse.status, 401); }); test('sync endpoint rejects unknown callers and body fields outside the sync contract', async (t) => { const service = { async initialize() {}, async deploySync() { throw new Error('must not deploy'); }, async recordError() {}, }; const secret = 's'.repeat(32); const { server } = await createApp( { maxBodyBytes: 4096, syncClientSecrets: { core: secret } }, { service, uploadStore: noUploadStore }, ); server.listen(0, '127.0.0.1'); await once(server, 'listening'); t.after(() => server.close()); const address = server.address(); const body = Buffer.from(JSON.stringify({ branch: 'preview' })); const timestamp = String(Date.now()); const requestId = 'sync-request-5678'; const signedHeaders = { 'content-type': 'application/json', 'x-image-timestamp': timestamp, 'x-image-request-id': requestId, 'x-image-signature': adminSignature(secret, timestamp, requestId, body), }; const unknown = await fetch(`http://127.0.0.1:${address.port}/v1/sync`, { method: 'POST', headers: { ...signedHeaders, 'x-image-client': 'unknown' }, body, }); assert.equal(unknown.status, 401); const prototypeName = await fetch(`http://127.0.0.1:${address.port}/v1/sync`, { method: 'POST', headers: { ...signedHeaders, 'x-image-client': 'toString' }, body, }); assert.equal(prototypeName.status, 401); const extraField = await fetch(`http://127.0.0.1:${address.port}/v1/sync`, { method: 'POST', headers: { ...signedHeaders, 'x-image-client': 'core' }, body, }); assert.equal(extraField.status, 400); });