UNPKG

@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
"use strict"; 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