feat: double audit — impersonated_by in audit_log

- db.js: add impersonated_by column to audit_log
- queries.js: logAudit accepts impersonatedBy, all CRUD pass it
- api/routes/entries.js: pass req.user.originalUserEmail as impersonatedBy
- При имперсонации: created_by=импактируемый, impersonated_by=админ
This commit is contained in:
2026-06-11 16:10:41 +04:00
parent 9c51e449ab
commit 7758d70dcf
4 changed files with 15 additions and 14 deletions
+10 -10
View File
@@ -30,7 +30,7 @@ async function listEntries(companyId, includeDeleted = false) {
return (await pool.query(sql, [companyId])).rows;
}
async function createEntry(companyId, rawValue, comment, userEmail) {
async function createEntry(companyId, rawValue, comment, userEmail, impersonatedBy) {
const { cidr, wasNormalized } = validate(rawValue);
const client = await pool.connect();
try {
@@ -64,7 +64,7 @@ async function createEntry(companyId, rawValue, comment, userEmail) {
VALUES ($1, $2, $3, $4) RETURNING *`,
[companyId, cidr, comment || null, userEmail]
);
await logAudit(userEmail, companyId, 'CREATE', null, cidr, res.rows[0].id, client);
await logAudit(userEmail, companyId, 'CREATE', null, cidr, res.rows[0].id, impersonatedBy, client);
await client.query('COMMIT');
return { entry: res.rows[0], wasNormalized };
} catch (e) {
@@ -75,7 +75,7 @@ async function createEntry(companyId, rawValue, comment, userEmail) {
}
}
async function updateEntry(entryId, companyId, rawValue, comment, userEmail) {
async function updateEntry(entryId, companyId, rawValue, comment, userEmail, impersonatedBy) {
const { cidr, wasNormalized } = validate(rawValue);
const client = await pool.connect();
try {
@@ -105,7 +105,7 @@ async function updateEntry(entryId, companyId, rawValue, comment, userEmail) {
WHERE id = $4 AND company_id = $5 RETURNING *`,
[cidr, comment || old.comment, userEmail, entryId, companyId]
);
await logAudit(userEmail, companyId, 'UPDATE', old.value_cidr, cidr, entryId, client);
await logAudit(userEmail, companyId, 'UPDATE', old.value_cidr, cidr, entryId, impersonatedBy, client);
await client.query('COMMIT');
return { entry: res.rows[0], wasNormalized };
} catch (e) {
@@ -116,7 +116,7 @@ async function updateEntry(entryId, companyId, rawValue, comment, userEmail) {
}
}
async function deleteEntry(entryId, companyId, userEmail) {
async function deleteEntry(entryId, companyId, userEmail, impersonatedBy) {
const client = await pool.connect();
try {
await client.query('BEGIN');
@@ -132,7 +132,7 @@ async function deleteEntry(entryId, companyId, userEmail) {
'UPDATE whitelist_entries SET deleted_by = $1, deleted_at = NOW() WHERE id = $2 AND company_id = $3',
[userEmail, entryId, companyId]
);
await logAudit(userEmail, companyId, 'DELETE', old.value_cidr, null, entryId, client);
await logAudit(userEmail, companyId, 'DELETE', old.value_cidr, null, entryId, impersonatedBy, client);
await client.query('COMMIT');
} catch (e) {
await client.query('ROLLBACK');
@@ -214,11 +214,11 @@ async function getExportCIDRs(companyId = null) {
// ── Audit ──
async function logAudit(userEmail, companyId, action, oldValue, newValue, entryId, db = pool) {
async function logAudit(userEmail, companyId, action, oldValue, newValue, entryId, impersonatedBy, db = pool) {
await db.query(
`INSERT INTO audit_log (user_email, company_id, action, old_value, new_value, entry_id)
VALUES ($1, $2, $3, $4, $5, $6)`,
[userEmail, companyId, action, oldValue, newValue, entryId || null]
`INSERT INTO audit_log (user_email, company_id, action, old_value, new_value, entry_id, impersonated_by)
VALUES ($1, $2, $3, $4, $5, $6, $7)`,
[userEmail, companyId, action, oldValue, newValue, entryId || null, impersonatedBy || null]
);
}