34 lines
1.6 KiB
JavaScript
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)), []);
|
|
});
|