@aikidosec/firewall
Version:
Zen by Aikido is an embedded Application Firewall that autonomously protects Node.js apps against common and critical attacks, provides rate limiting, detects malicious traffic (including bots), and more.
65 lines (64 loc) • 2.41 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrap = wrap;
exports.createWrappedFunction = createWrappedFunction;
exports.isWrapped = isWrapped;
function wrap(module, name, wrapper) {
if (!module[name]) {
throw new Error(`no original function ${name} to wrap`);
}
if (typeof module[name] !== "function") {
throw new Error(`original must be a function, instead found: ${typeof module[name]}`);
}
const original = module[name];
const wrapped = createWrappedFunction(original, wrapper);
defineProperty(module, name, wrapped);
return wrapped;
}
function createWrappedFunction(original, wrapper) {
const wrapped = wrapper(original);
defineProperty(wrapped, "__original", original);
defineProperty(wrapped, "__wrapped", true);
// Copy over all properties from the original function to the wrapped one.
// e.g. fs.realpath.native
// .inspect("realpath", (args) => {...})
// We don't want to lose the original function's properties.
// Most of the functions we're wrapping don't have any properties, so this is a rare case.
// Inspired by https://github.com/DataDog/dd-trace-js/blob/master/packages/datadog-shimmer/src/shimmer.js#L8
Object.setPrototypeOf(wrapped, original);
const props = Object.getOwnPropertyDescriptors(original);
const keys = Reflect.ownKeys(props);
for (const key of keys) {
try {
// Define the property on the wrapped function, keeping the original property's attributes.
Object.defineProperty(wrapped, key, props[key]);
}
catch {
//
}
}
return wrapped;
}
// Sets a property on an object, preserving its enumerability.
// This function assumes that the property is already writable.
function defineProperty(obj, name, value) {
const enumerable =
// @ts-expect-error We don't know the type of obj
!!obj[name] && Object.prototype.propertyIsEnumerable.call(obj, name);
Object.defineProperty(obj, name, {
configurable: true,
enumerable: enumerable,
writable: true,
value: value,
});
}
/**
* Check if a function is wrapped
*/
function isWrapped(fn) {
return (fn instanceof Function &&
"__wrapped" in fn &&
fn.__wrapped === true &&
"__original" in fn &&
fn.__original instanceof Function);
}
;