const test = require('node:test'); const assert = require('node:assert/strict'); process.env.NODE_ENV = 'test'; process.env.DATA_ENCRYPTION_SECRET = 'test-only-encryption-secret-with-more-than-32-characters'; const { app, encryptSensitiveValue, decryptSensitiveValue, hashSessionToken, normalizeOptionalHttpUrl, isPdfBuffer, sanitizeDocumentFileName, getDocumentContentDisposition } = require('../backend/server'); async function withTestServer(run) { const server = app.listen(0, '127.0.0.1'); await new Promise((resolve, reject) => { server.once('listening', resolve); server.once('error', reject); }); try { const address = server.address(); await run(`http://127.0.0.1:${address.port}`); } finally { await new Promise(resolve => server.close(resolve)); } } test('stored credentials use authenticated encryption and round-trip safely', () => { const plainText = 'example-password-value'; const first = encryptSensitiveValue(plainText); const second = encryptSensitiveValue(plainText); assert.match(first, /^enc:v2:/); assert.notEqual(first, second); assert.equal(first.includes(plainText), false); assert.equal(decryptSensitiveValue(first), plainText); assert.equal(decryptSensitiveValue(`${first}tampered`), null); }); test('session tokens are stored as deterministic SHA-256 hashes', () => { const token = 'a-private-random-session-token'; const hash = hashSessionToken(token); assert.match(hash, /^[a-f0-9]{64}$/); assert.equal(hash, hashSessionToken(token)); assert.equal(hash.includes(token), false); }); test('application URLs accept only HTTP and HTTPS protocols', () => { assert.equal(normalizeOptionalHttpUrl(''), ''); assert.equal(normalizeOptionalHttpUrl('javascript:alert(1)'), null); assert.equal(normalizeOptionalHttpUrl('file:///etc/passwd'), null); assert.match(normalizeOptionalHttpUrl('https://example.com/path'), /^https:\/\/example\.com\/path/); }); test('PDF uploads require a PDF header and end-of-file marker', () => { assert.equal(isPdfBuffer(Buffer.from('%PDF-1.7\nbody\n%%EOF')), true); assert.equal(isPdfBuffer(Buffer.from('%PDF-1.7\nbody without trailer')), false); assert.equal(isPdfBuffer(Buffer.from('not a pdf')), false); }); test('document filenames and response headers cannot inject control characters', () => { const safeName = sanitizeDocumentFileName('bao/cao\r\nInjected: value'); const longName = sanitizeDocumentFileName('a'.repeat(300)); const disposition = getDocumentContentDisposition('Báo cáo tháng 8.pdf'); assert.equal(safeName, 'bao_caoInjected_ value.pdf'); assert.equal(longName.length, 255); assert.match(longName, /\.pdf$/); assert.match(disposition, /^inline; filename="/); assert.match(disposition, /filename\*=UTF-8''/); assert.equal(disposition.includes('\r'), false); assert.equal(disposition.includes('\n'), false); }); test('forged legacy identity headers cannot bypass protected APIs', async () => { await withTestServer(async baseUrl => { const response = await fetch(`${baseUrl}/api/users`, { headers: { 'x-user-id': '1', 'x-user-role': 'admin' } }); const body = await response.json(); assert.equal(response.status, 401); assert.equal(body.success, false); }); }); test('security headers and no-store API caching are enabled', async () => { await withTestServer(async baseUrl => { const response = await fetch(`${baseUrl}/api/health`); assert.equal(response.status, 200); assert.match(response.headers.get('content-security-policy') || '', /default-src 'self'/); assert.equal(response.headers.get('x-powered-by'), null); assert.equal(response.headers.get('cache-control'), 'no-store'); }); }); test('state-changing requests from untrusted origins are rejected before route handling', async () => { await withTestServer(async baseUrl => { const response = await fetch(`${baseUrl}/api/auth/login`, { method: 'POST', headers: { Origin: 'https://attacker.example', 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'test', password: 'not-a-real-password' }) }); assert.equal(response.status, 403); }); });