import { Request, Response, NextFunction } from "express"; import { APIFenceAgent } from "./agent"; export function apifenceMiddleware() { return async (req: Request, res: Response, next: NextFunction) => { // 1. Security Check try { const decision = await APIFenceAgent.protect(req); if (decision.action === 'BLOCK') { // Log blocked request to backend APIFenceAgent.addEvent({ type: "blocked_request", timestamp: new Date().toISOString(), blockReason: decision.reason || 'UNKNOWN', ipAddress: req.ip || req.socket.remoteAddress || 'unknown', countryCode: decision.countryCode, countryName: decision.countryName, userAgent: req.headers["user-agent"], method: req.method, path: req.path, queryParams: JSON.stringify(req.query), headers: { 'user-agent': req.headers["user-agent"], 'referer': req.headers["referer"], 'origin': req.headers["origin"] }, blockMessage: `Blocked by APIFence: ${decision.reason}` }); res.status(403).json({ error: 'Access Denied', reason: decision.reason, message: 'Blocked by APIFence' }); return; } } catch (e) { // Fail open if error in protection logic console.error("APIFence Protection Error", e); } const start = Date.now(); let logged = false; const logRequest = () => { if (logged) return; logged = true; const duration = Date.now() - start; const statusCode = res.statusCode || 200; APIFenceAgent.addEvent({ type: "request", timestamp: new Date().toISOString(), path: req.path, method: req.method, statusCode: statusCode, duration, ip: req.ip || req.socket.remoteAddress, userAgent: req.headers["user-agent"] }); }; // Override multiple response methods to ensure we catch all responses const originalSend = res.send.bind(res); const originalJson = res.json.bind(res); const originalEnd = res.end.bind(res); res.send = function (body?: any) { logRequest(); return originalSend(body); }; res.json = function (body?: any) { logRequest(); return originalJson(body); }; res.end = function (chunk?: any, encoding?: any) { logRequest(); return originalEnd(chunk, encoding); }; // Also listen for the 'finish' event as a fallback res.once('finish', () => { logRequest(); }); next(); }; }