@brahma-dev/abuseipdb-middleware
Version:
Universal middleware for reporting malicious IPs to AbuseIPDB. Supports Elysia, Express, Koa, Fastify, and Hono.
277 lines (267 loc) • 9.54 kB
JavaScript
;
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// node_modules/fastify-plugin/lib/getPluginName.js
var require_getPluginName = __commonJS({
"node_modules/fastify-plugin/lib/getPluginName.js"(exports2, module2) {
"use strict";
var fpStackTracePattern = /at\s{1}(?:.*\.)?plugin\s{1}.*\n\s*(.*)/;
var fileNamePattern = /(\w*(\.\w*)*)\..*/;
module2.exports = function getPluginName(fn) {
if (fn.name.length > 0)
return fn.name;
const stackTraceLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 10;
try {
throw new Error("anonymous function");
} catch (e) {
Error.stackTraceLimit = stackTraceLimit;
return extractPluginName(e.stack);
}
};
function extractPluginName(stack) {
const m = stack.match(fpStackTracePattern);
return m ? m[1].split(/[/\\]/).slice(-1)[0].match(fileNamePattern)[1] : "anonymous";
}
module2.exports.extractPluginName = extractPluginName;
}
});
// node_modules/fastify-plugin/lib/toCamelCase.js
var require_toCamelCase = __commonJS({
"node_modules/fastify-plugin/lib/toCamelCase.js"(exports2, module2) {
"use strict";
module2.exports = function toCamelCase(name) {
if (name[0] === "@") {
name = name.slice(1).replace("/", "-");
}
const newName = name.replace(/-(.)/g, function(match, g1) {
return g1.toUpperCase();
});
return newName;
};
}
});
// node_modules/fastify-plugin/plugin.js
var require_plugin = __commonJS({
"node_modules/fastify-plugin/plugin.js"(exports2, module2) {
"use strict";
var getPluginName = require_getPluginName();
var toCamelCase = require_toCamelCase();
var count = 0;
function plugin(fn, options = {}) {
let autoName = false;
if (typeof fn.default !== "undefined") {
fn = fn.default;
}
if (typeof fn !== "function") {
throw new TypeError(
`fastify-plugin expects a function, instead got a '${typeof fn}'`
);
}
if (typeof options === "string") {
options = {
fastify: options
};
}
if (typeof options !== "object" || Array.isArray(options) || options === null) {
throw new TypeError("The options object should be an object");
}
if (options.fastify !== void 0 && typeof options.fastify !== "string") {
throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`);
}
if (!options.name) {
autoName = true;
options.name = getPluginName(fn) + "-auto-" + count++;
}
fn[Symbol.for("skip-override")] = options.encapsulate !== true;
fn[Symbol.for("fastify.display-name")] = options.name;
fn[Symbol.for("plugin-meta")] = options;
if (!fn.default) {
fn.default = fn;
}
const camelCase = toCamelCase(options.name);
if (!autoName && !fn[camelCase]) {
fn[camelCase] = fn;
}
return fn;
}
module2.exports = plugin;
module2.exports.default = plugin;
module2.exports.fastifyPlugin = plugin;
}
});
// src/index.ts
var src_exports = {};
__export(src_exports, {
abuseIPDBElysia: () => abuseIPDBElysia,
abuseIPDBExpress: () => abuseIPDBExpress,
abuseIPDBFastify: () => abuseIPDBFastify,
abuseIPDBHono: () => abuseIPDBHono,
abuseIPDBKoa: () => abuseIPDBKoa
});
module.exports = __toCommonJS(src_exports);
// src/core.ts
var createAbuseIPDBPlugin = (options) => {
const {
apiKey,
paths,
additionalPaths = [],
categories = "21",
// Default category: Web App Attack
cacheTTL = 1e3 * 60 * 60
} = options;
if (!apiKey)
throw new Error("AbuseIPDB plugin requires an API key");
const defaultPaths = [
"/wp-login.php",
"/xmlrpc.php",
"/.env",
"/admin",
"/phpmyadmin",
"/wp-admin",
"/wp-content",
"/wp-includes",
"/shell",
"/login.php"
];
const suspiciousPaths = paths ?? [...defaultPaths, ...additionalPaths];
const reportedIPs = /* @__PURE__ */ new Map();
async function reportToAbuseIPDB(ip, comment, reportCategories) {
const now = Date.now();
const lastReported = reportedIPs.get(ip);
if (lastReported && now - lastReported < cacheTTL) {
console.log(`\u23F3 Skipping duplicate report for ${ip}`);
return;
}
reportedIPs.set(ip, now);
try {
await fetch("https://api.abuseipdb.com/api/v2/report", {
method: "POST",
headers: {
"Key": apiKey,
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: new URLSearchParams({
ip,
categories: reportCategories ?? categories,
comment,
timestamp: (/* @__PURE__ */ new Date()).toISOString()
})
});
console.log(`Reported IP ${ip} to AbuseIPDB: "${comment}"`);
} catch (err) {
console.error("Failed to report to AbuseIPDB:", err);
}
}
return { suspiciousPaths, reportToAbuseIPDB };
};
// src/express.ts
var abuseIPDBExpress = (options) => {
const { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);
const middleware = (req, res, next) => {
if (suspiciousPaths.some((p) => req.path.startsWith(p))) {
const ip = req.ip || "unknown";
if (ip !== "unknown") {
reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${req.path}`);
}
}
next();
};
return { middleware, report: reportToAbuseIPDB };
};
// src/koa.ts
var abuseIPDBKoa = (options) => {
const { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);
const middleware = async (ctx, next) => {
if (suspiciousPaths.some((p) => ctx.path.startsWith(p))) {
const ip = ctx.ip || "unknown";
if (ip !== "unknown") {
await reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${ctx.path}`);
}
}
await next();
};
return { middleware, report: reportToAbuseIPDB };
};
// src/fastify.ts
var import_fastify_plugin = __toESM(require_plugin());
var abuseIPDBFastify = (0, import_fastify_plugin.default)(async (fastify, options) => {
const { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);
fastify.decorate("abuseipdb", { report: reportToAbuseIPDB });
fastify.addHook("onRequest", async (request) => {
const path = new URL(request.raw.url, `http://${request.headers.host}`).pathname;
if (suspiciousPaths.some((p) => path.startsWith(p))) {
const ip = request.ip || "unknown";
if (ip !== "unknown") {
await reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${path}`);
}
}
});
});
// src/hono.ts
var abuseIPDBHono = (options) => {
const { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);
const middleware = async (c, next) => {
const path = c.req.path;
if (suspiciousPaths.some((p) => path.startsWith(p))) {
const ip = c.req.header("x-forwarded-for") || c.req.header("cf-connecting-ip") || "unknown";
if (ip !== "unknown") {
await reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${path}`);
}
}
await next();
};
return { middleware, report: reportToAbuseIPDB };
};
// src/elysia.ts
var abuseIPDBElysia = (options) => {
const { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);
const middleware = (app) => app.onBeforeHandle((context) => {
const path = new URL(context.request.url).pathname;
if (suspiciousPaths.some((p) => path.startsWith(p))) {
const ip = context.ip || "unknown";
if (ip !== "unknown") {
reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${path}`);
}
}
});
return { middleware, report: reportToAbuseIPDB };
};
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
abuseIPDBElysia,
abuseIPDBExpress,
abuseIPDBFastify,
abuseIPDBHono,
abuseIPDBKoa
});
//# sourceMappingURL=index.js.map