Dienstplan-Pro/server/audit-int.test.js

34 lines
1.6 KiB
JavaScript

const { test } = require('node:test');
const assert = require('node:assert');
const fs = require('fs');
const os = require('os');
const path = require('path');
process.env.DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'dp-audit-'));
process.env.RATE_LIMIT_IP = '1000';
delete process.env.SMTP_HOST;
const app = require('./index');
const { db } = require('./db');
const { createLoginToken } = require('./auth');
async function withServer(fn) { const s = app.listen(0); try { return await fn(s.address().port); } finally { s.close(); } }
test('Login schreibt eine PII-freie audit_log-Zeile (login_ok, user_id, ip_hash)', async () => {
const uid = Number(db.prepare('INSERT INTO users (email,is_admin,created_at) VALUES (?,1,?)')
.run('audit@x.de', new Date().toISOString()).lastInsertRowid);
const raw = createLoginToken(uid);
await withServer(async (port) => {
const r = await fetch(`http://127.0.0.1:${port}/auth/confirm`, {
method: 'POST', redirect: 'manual',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: `token=${raw}`,
});
assert.strictEqual(r.status, 302);
});
const row = db.prepare("SELECT event, user_id, ip_hash FROM audit_log WHERE event='login_ok' AND user_id=?").get(uid);
assert.ok(row, 'login_ok-Zeile vorhanden');
assert.strictEqual(row.user_id, uid);
assert.ok(row.ip_hash && row.ip_hash.length === 64, 'ip_hash ist ein SHA-256-Hash, keine rohe IP');
// Strukturell keine PII: audit_log hat keine email/name-Spalte
const cols = db.prepare("PRAGMA table_info('audit_log')").all().map(c => c.name);
assert.deepStrictEqual(cols.filter(c => /email|name/i.test(c)), []);
});