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:
129
src/lib/auditLogEdge.js
Normal file
129
src/lib/auditLogEdge.js
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 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 };
|
||||
Reference in New Issue
Block a user