@aikidosec/firewall
Version:
Zen by Aikido is an embedded Web Application Firewall that autonomously protects Node.js apps against common and critical attacks
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);
}