- 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.
130 lines
2.8 KiB
JavaScript
130 lines
2.8 KiB
JavaScript
/**
|
|
* Edge-compatible audit logging utility
|
|
* This version avoids direct database imports and can be used in Edge Runtime
|
|
*/
|
|
|
|
import { AUDIT_ACTIONS, RESOURCE_TYPES } from "./auditLog.js";
|
|
|
|
/**
|
|
* Log an audit event in Edge Runtime compatible way
|
|
* @param {Object} params - Audit log parameters
|
|
*/
|
|
export async function logAuditEventAsync({
|
|
action,
|
|
userId = null,
|
|
resourceType = null,
|
|
resourceId = null,
|
|
ipAddress = null,
|
|
userAgent = null,
|
|
details = null,
|
|
timestamp = null,
|
|
}) {
|
|
try {
|
|
// In Edge Runtime or when database is not available, log to console
|
|
if (
|
|
typeof EdgeRuntime !== "undefined" ||
|
|
process.env.NEXT_RUNTIME === "edge"
|
|
) {
|
|
console.log(
|
|
`[Audit Log - Edge] ${action} by user ${
|
|
userId || "anonymous"
|
|
} on ${resourceType}:${resourceId}`,
|
|
{
|
|
details,
|
|
ipAddress,
|
|
userAgent,
|
|
timestamp: timestamp || new Date().toISOString(),
|
|
}
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Try to make an API call to log the event
|
|
try {
|
|
const response = await fetch("/api/audit-logs/log", {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
action,
|
|
userId,
|
|
resourceType,
|
|
resourceId,
|
|
ipAddress,
|
|
userAgent,
|
|
details,
|
|
timestamp,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`HTTP ${response.status}`);
|
|
}
|
|
} catch (fetchError) {
|
|
// Fallback to console logging if API call fails
|
|
console.log(
|
|
`[Audit Log - Fallback] ${action} by user ${
|
|
userId || "anonymous"
|
|
} on ${resourceType}:${resourceId}`,
|
|
{
|
|
details,
|
|
ipAddress,
|
|
userAgent,
|
|
timestamp: timestamp || new Date().toISOString(),
|
|
error: fetchError.message,
|
|
}
|
|
);
|
|
}
|
|
} catch (error) {
|
|
console.error("Failed to log audit event:", error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper function to extract client information from request (Edge compatible)
|
|
* @param {Request} req - The request object
|
|
* @returns {Object} Object containing IP address and user agent
|
|
*/
|
|
export function getClientInfoEdgeCompatible(req) {
|
|
const ipAddress =
|
|
req.headers.get("x-forwarded-for") ||
|
|
req.headers.get("x-real-ip") ||
|
|
req.headers.get("cf-connecting-ip") ||
|
|
"unknown";
|
|
|
|
const userAgent = req.headers.get("user-agent") || "unknown";
|
|
|
|
return { ipAddress, userAgent };
|
|
}
|
|
|
|
/**
|
|
* Middleware helper to log API actions (Edge compatible)
|
|
*/
|
|
export async function logApiActionAsync(
|
|
req,
|
|
action,
|
|
resourceType,
|
|
resourceId,
|
|
session,
|
|
additionalDetails = {}
|
|
) {
|
|
const { ipAddress, userAgent } = getClientInfoEdgeCompatible(req);
|
|
|
|
await logAuditEventAsync({
|
|
action,
|
|
userId: session?.user?.id || null,
|
|
resourceType,
|
|
resourceId,
|
|
ipAddress,
|
|
userAgent,
|
|
details: {
|
|
method: req.method,
|
|
url: req.url,
|
|
...additionalDetails,
|
|
},
|
|
});
|
|
}
|
|
|
|
export { AUDIT_ACTIONS, RESOURCE_TYPES };
|