feat(audit-logging): Implement Edge-compatible audit logging utility and safe logging module

- Added `auditLogEdge.js` for Edge Runtime compatible audit logging, including console logging and API fallback.
- Introduced `auditLogSafe.js` for safe audit logging without direct database imports, ensuring compatibility across runtimes.
- Enhanced `auth.js` to integrate safe audit logging for login actions, including success and failure cases.
- Created middleware `auditLog.js` to facilitate audit logging for API routes with predefined configurations.
- Updated `middleware.js` to allow API route access without authentication checks.
- Added tests for audit logging functionality and Edge compatibility in `test-audit-logging.mjs` and `test-edge-compatibility.mjs`.
- Implemented safe audit logging tests in `test-safe-audit-logging.mjs` to verify functionality across environments.
This commit is contained in:
Chop
2025-07-09 23:08:16 +02:00
parent 90875db28b
commit b1a78bf7a8
20 changed files with 2943 additions and 130 deletions

View File

@@ -1,6 +1,14 @@
// Force this API route to use Node.js runtime for database access
export const runtime = "nodejs";
import db from "@/lib/db";
import { NextResponse } from "next/server";
import { withUserAuth } from "@/lib/middleware/auth";
import {
logApiActionSafe,
AUDIT_ACTIONS,
RESOURCE_TYPES,
} from "@/lib/auditLogSafe.js";
async function createNoteHandler(req) {
const { project_id, task_id, note } = await req.json();
@@ -10,12 +18,26 @@ async function createNoteHandler(req) {
}
try {
db.prepare(
`
const result = db
.prepare(
`
INSERT INTO notes (project_id, task_id, note, created_by, note_date)
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)
`
).run(project_id || null, task_id || null, note, req.user?.id || null);
)
.run(project_id || null, task_id || null, note, req.user?.id || null);
// Log note creation
await logApiActionSafe(
req,
AUDIT_ACTIONS.NOTE_CREATE,
RESOURCE_TYPES.NOTE,
result.lastInsertRowid.toString(),
req.session,
{
noteData: { project_id, task_id, note_length: note.length },
}
);
return NextResponse.json({ success: true });
} catch (error) {
@@ -27,11 +49,30 @@ async function createNoteHandler(req) {
}
}
async function deleteNoteHandler(_, { params }) {
async function deleteNoteHandler(req, { params }) {
const { id } = params;
// Get note data before deletion for audit log
const note = db.prepare("SELECT * FROM notes WHERE note_id = ?").get(id);
db.prepare("DELETE FROM notes WHERE note_id = ?").run(id);
// Log note deletion
await logApiActionSafe(
req,
AUDIT_ACTIONS.NOTE_DELETE,
RESOURCE_TYPES.NOTE,
id,
req.session,
{
deletedNote: {
project_id: note?.project_id,
task_id: note?.task_id,
note_length: note?.note?.length || 0,
},
}
);
return NextResponse.json({ success: true });
}
@@ -43,12 +84,36 @@ async function updateNoteHandler(req, { params }) {
return NextResponse.json({ error: "Missing note or ID" }, { status: 400 });
}
// Get original note for audit log
const originalNote = db
.prepare("SELECT * FROM notes WHERE note_id = ?")
.get(noteId);
db.prepare(
`
UPDATE notes SET note = ? WHERE note_id = ?
`
).run(note, noteId);
// Log note update
await logApiActionSafe(
req,
AUDIT_ACTIONS.NOTE_UPDATE,
RESOURCE_TYPES.NOTE,
noteId,
req.session,
{
originalNote: {
note_length: originalNote?.note?.length || 0,
project_id: originalNote?.project_id,
task_id: originalNote?.task_id,
},
updatedNote: {
note_length: note.length,
},
}
);
return NextResponse.json({ success: true });
}