← back to AbramsOS
tests/csrf.test.js
65 lines
// Verifies CSRF middleware rejects POSTs without a matching token.
const test = require('node:test');
const assert = require('node:assert');
const http = require('node:http');
require('dotenv').config();
const app = require('../server');
const { pool } = require('../lib/db');
let server;
test.before(() => new Promise((r) => { server = app.listen(0, r); }));
test.after(async () => {
await new Promise((r) => server.close(r));
await pool.end();
});
function post(path, formObj = {}, headers = {}) {
return new Promise((resolve, reject) => {
const port = server.address().port;
const body = new URLSearchParams(formObj).toString();
const req = http.request({
method: 'POST', hostname: '127.0.0.1', port, path,
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(body), ...headers },
}, (res) => {
let data = ''; res.on('data', (c) => (data += c));
res.on('end', () => resolve({ status: res.statusCode, body: data, headers: res.headers }));
});
req.on('error', reject);
req.write(body);
req.end();
});
}
test('POST /signup without CSRF token → 403', async () => {
const r = await post('/signup', { email: 'attacker@example.com', password: 'verystrongpw1234' });
assert.strictEqual(r.status, 403);
assert.match(r.body, /CSRF/i);
});
test('POST /signin without CSRF token → 403', async () => {
const r = await post('/signin', { stage: 'password', email: 'a@b.com', password: 'x' });
assert.strictEqual(r.status, 403);
});
test('POST /signup with WRONG CSRF token → 403', async () => {
// First request to mint a real cookie, then POST with a forged body token
const get = await new Promise((resolve, reject) => {
const port = server.address().port;
http.get(`http://127.0.0.1:${port}/signup`, (res) => { res.resume(); res.on('end', () => resolve(res)); }).on('error', reject);
});
const cookieHeader = (get.headers['set-cookie'] || []).map(c => c.split(';')[0]).join('; ');
const r = await post('/signup', { _csrf: 'forged-token-xxx', email: 'a@b.com', password: 'verystrongpw1234' }, { cookie: cookieHeader });
assert.strictEqual(r.status, 403);
});
test('GET routes mint a CSRF cookie', async () => {
const port = server.address().port;
const got = await new Promise((resolve, reject) => {
http.get(`http://127.0.0.1:${port}/signup`, (res) => { res.resume(); res.on('end', () => resolve(res)); }).on('error', reject);
});
const setCookie = got.headers['set-cookie'] || [];
assert.ok(setCookie.some(c => c.startsWith('aos.csrf=')), 'aos.csrf cookie should be set');
});