fortify2-js
Version:
MOST POWERFUL JavaScript Security Library! Military-grade cryptography + 19 enhanced object methods + quantum-resistant algorithms + perfect TypeScript support. More powerful than Lodash with built-in security.
154 lines (151 loc) • 5.59 kB
JavaScript
import { expressStringify } from '../../../components/fortified-function/serializer/safe-serializer.js';
import { logger } from '../server/utils/Logger.js';
/**
* Safe JSON Middleware for Express
* Automatically handles circular references in JSON responses
*/
/**
* Creates middleware that safely handles JSON serialization
*/
function createSafeJsonMiddleware(options = {}) {
const opts = {
enabled: true,
maxDepth: 10,
truncateStrings: 1000,
includeNonEnumerable: false,
logCircularRefs: false,
customReplacer: undefined,
...options,
};
return function safeJsonMiddleware(req, res, next) {
if (!opts.enabled) {
return next();
}
// Store the original json method
const originalJson = res.json.bind(res);
const originalSend = res.send.bind(res);
// Override res.json to use safe serialization
res.json = function (obj) {
try {
// Try standard JSON.stringify first for performance
const standardResult = JSON.stringify(obj);
return originalJson(obj);
}
catch (error) {
if (opts.logCircularRefs &&
error.message.includes("circular")) {
logger.debug("server", "🔄 Circular reference detected, using safe serialization:", {
url: req.url,
method: req.method,
error: error.message,
});
}
try {
// Use our safe serialization
const safeResult = expressStringify(obj);
const parsedResult = JSON.parse(safeResult);
return originalJson(parsedResult);
}
catch (safeError) {
logger.debug("server", "❌ Safe JSON serialization failed:", safeError);
return originalJson({
error: "Serialization failed",
message: "Unable to serialize response object",
originalError: safeError.message,
});
}
}
};
// Override res.send to handle objects that might be passed directly
res.send = function (body) {
if (typeof body === "object" &&
body !== null &&
!Buffer.isBuffer(body)) {
// If it's an object, use our safe json method
return res.json(body);
}
return originalSend(body);
};
next();
};
}
/**
* Quick setup function for common use cases
*/
function setupSafeJson(app, options = {}) {
app.use(createSafeJsonMiddleware(options));
}
/**
* Utility function to safely stringify any object
*/
function safeJsonStringify(obj, options = {}) {
try {
return JSON.stringify(obj);
}
catch (error) {
return expressStringify(obj);
}
}
/**
* Enhanced res.json replacement that can be used manually
*/
function sendSafeJson(res, obj, options = {}) {
try {
const result = safeJsonStringify(obj, options);
res.setHeader("Content-Type", "application/json");
res.send(result);
}
catch (error) {
console.error("❌ Failed to send safe JSON:", error);
res.status(500).json({
error: "Internal Server Error",
message: "Failed to serialize response",
});
}
}
/**
* Middleware specifically for debugging circular references
*/
function createCircularRefDebugger() {
return function circularRefDebugger(req, res, next) {
const originalJson = res.json.bind(res);
res.json = function (obj) {
try {
JSON.stringify(obj);
return originalJson(obj);
}
catch (error) {
if (error.message.includes("circular")) {
console.log("🔍 Circular Reference Debug Info:");
console.log(" Route:", req.method, req.url);
console.log(" Object type:", typeof obj);
console.log(" Object constructor:", obj?.constructor?.name);
console.log(" Object keys:", Object.keys(obj || {}));
// Try to identify the circular reference
const seen = new WeakSet();
const findCircular = (obj, path = []) => {
if (typeof obj !== "object" || obj === null)
return [];
if (seen.has(obj))
return path;
seen.add(obj);
for (const [key, value] of Object.entries(obj)) {
const result = findCircular(value, [...path, key]);
if (result.length > 0)
return result;
}
return [];
};
const circularPath = findCircular(obj);
if (circularPath.length > 0) {
console.log(" Circular path:", circularPath.join(" -> "));
}
}
throw error;
}
};
next();
};
}
export { createCircularRefDebugger, createSafeJsonMiddleware, safeJsonStringify, sendSafeJson, setupSafeJson };
//# sourceMappingURL=safe-json-middleware.js.map