@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.
138 lines (137 loc) • 6.56 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setPackagesToInstrument = setPackagesToInstrument;
exports.setBuiltinsToInstrument = setBuiltinsToInstrument;
exports.shouldPatchPackage = shouldPatchPackage;
exports.getPackageFileInstrumentationInstructions = getPackageFileInstrumentationInstructions;
exports.shouldPatchFile = shouldPatchFile;
exports.getFunctionCallbackInfo = getFunctionCallbackInfo;
exports.getBuiltinInterceptors = getBuiltinInterceptors;
exports.shouldPatchBuiltin = shouldPatchBuiltin;
exports.getFileCallbackInfo = getFileCallbackInfo;
exports.__internalRewritePackageNamesForTesting = __internalRewritePackageNamesForTesting;
const satisfiesVersion_1 = require("../../../helpers/satisfiesVersion");
// Keys are package / builtin names
let packages = new Map();
// Stores the callbacks for the instrumented functions of builtin modules
// Identifier for builtin is: moduleName.functionName
let builtinRequireInterceptors = new Map();
// Stores the callback functions and necessary information for the instrumented functions of instrumented function
// Identifier for the function is: packageName.relativePath.functionName.nodeType.matchingVersion
let functionCallbackInfo = new Map();
// Callback functions on file level
let fileCallbackInfo = new Map();
// In order to support multiple versions of the same package in unit tests, we need to rewrite the package name
// e.g. In our sources and sinks, we use the real package name `hooks.addPackage("undici")`
// but in the tests we want to `require("undici-v6")` instead of `require("undici")`
let __packageNamesToRewrite = {};
function setPackagesToInstrument(_packages) {
// Clear the previous packages
packages = new Map();
functionCallbackInfo = new Map();
fileCallbackInfo = new Map();
for (const pkg of _packages) {
if (pkg.getName() in __packageNamesToRewrite) {
// If the package name is in the rewrite map, we use the rewritten name
pkg.setName(__packageNamesToRewrite[pkg.getName()]);
}
const packageInstructions = pkg
.getVersions()
.map((versionedPackage) => {
return versionedPackage
.getFileInstrumentationInstructions()
.map((file) => {
var _a, _b, _c;
const fileIdentifier = `${pkg.getName()}.${file.path}.${versionedPackage.getRange()}`;
if ((_a = file.accessLocalVariables) === null || _a === void 0 ? void 0 : _a.cb) {
fileCallbackInfo.set(fileIdentifier, {
pkgName: pkg.getName(),
localVariableAccessCb: file.accessLocalVariables.cb,
});
}
return {
path: file.path,
versionRange: versionedPackage.getRange(),
identifier: fileIdentifier,
functions: file.functions.map((func) => {
var _a, _b;
const identifier = `${pkg.getName()}.${file.path}.${func.name}.${func.nodeType}.${versionedPackage.getRange()}`;
// If bindContext is set to true, but no modifyArgs is defined, modifyArgs will be set to a stub function
// The reason for this is that the bindContext logic needs to modify the arguments
if (func.bindContext && !func.modifyArgs) {
func.modifyArgs = (args) => args;
}
functionCallbackInfo.set(identifier, {
pkgName: pkg.getName(),
methodName: func.name,
operationKind: func.operationKind,
funcs: {
inspectArgs: func.inspectArgs,
modifyArgs: func.modifyArgs,
modifyReturnValue: func.modifyReturnValue,
bindContext: (_a = func.bindContext) !== null && _a !== void 0 ? _a : false,
},
});
return {
nodeType: func.nodeType,
name: func.name,
identifier,
inspectArgs: !!func.inspectArgs,
modifyArgs: !!func.modifyArgs,
modifyReturnValue: !!func.modifyReturnValue,
modifyArgumentsObject: (_b = func.modifyArgumentsObject) !== null && _b !== void 0 ? _b : false,
};
}),
accessLocalVariables: (_c = (_b = file.accessLocalVariables) === null || _b === void 0 ? void 0 : _b.names) !== null && _c !== void 0 ? _c : [],
};
})
.flat();
})
.flat();
if (packageInstructions.length !== 0) {
packages.set(pkg.getName(), packageInstructions);
}
}
}
function setBuiltinsToInstrument(builtinModules) {
// Clear the previous builtins
builtinRequireInterceptors = new Map();
for (const builtin of builtinModules) {
const interceptors = builtin.getRequireInterceptors();
if (interceptors.length > 0) {
builtinRequireInterceptors.set(builtin.getName(), interceptors);
}
}
}
function shouldPatchPackage(name) {
return packages.has(name);
}
function getPackageFileInstrumentationInstructions(packageName, version, filePath) {
const instructions = packages.get(packageName);
if (!instructions) {
return;
}
return instructions.find((f) => f.path === filePath && (0, satisfiesVersion_1.satisfiesVersion)(f.versionRange, version));
}
function shouldPatchFile(packageName, filePath) {
const instructions = packages.get(packageName);
if (!instructions) {
return false;
}
return instructions.some((f) => f.path === filePath);
}
function getFunctionCallbackInfo(identifier) {
return functionCallbackInfo.get(identifier);
}
function getBuiltinInterceptors(name) {
return builtinRequireInterceptors.get(name) || [];
}
function shouldPatchBuiltin(name) {
return builtinRequireInterceptors.has(name);
}
function getFileCallbackInfo(identifier) {
return fileCallbackInfo.get(identifier);
}
function __internalRewritePackageNamesForTesting(rewrite) {
__packageNamesToRewrite = rewrite;
}