UNPKG

@brahma-dev/abuseipdb-middleware

Version:

Universal middleware for reporting malicious IPs to AbuseIPDB. Supports Elysia, Express, Koa, Fastify, and Hono.

1 lines 13.4 kB
{"version":3,"sources":["../node_modules/fastify-plugin/lib/getPluginName.js","../node_modules/fastify-plugin/lib/toCamelCase.js","../node_modules/fastify-plugin/plugin.js","../src/core.ts","../src/express.ts","../src/koa.ts","../src/fastify.ts","../src/hono.ts","../src/elysia.ts"],"sourcesContent":["'use strict'\n\nconst fpStackTracePattern = /at\\s{1}(?:.*\\.)?plugin\\s{1}.*\\n\\s*(.*)/\nconst fileNamePattern = /(\\w*(\\.\\w*)*)\\..*/\n\nmodule.exports = function getPluginName (fn) {\n if (fn.name.length > 0) return fn.name\n\n const stackTraceLimit = Error.stackTraceLimit\n Error.stackTraceLimit = 10\n try {\n throw new Error('anonymous function')\n } catch (e) {\n Error.stackTraceLimit = stackTraceLimit\n return extractPluginName(e.stack)\n }\n}\n\nfunction extractPluginName (stack) {\n const m = stack.match(fpStackTracePattern)\n\n // get last section of path and match for filename\n return m ? m[1].split(/[/\\\\]/).slice(-1)[0].match(fileNamePattern)[1] : 'anonymous'\n}\nmodule.exports.extractPluginName = extractPluginName\n","'use strict'\n\nmodule.exports = function toCamelCase (name) {\n if (name[0] === '@') {\n name = name.slice(1).replace('/', '-')\n }\n const newName = name.replace(/-(.)/g, function (match, g1) {\n return g1.toUpperCase()\n })\n return newName\n}\n","'use strict'\n\nconst getPluginName = require('./lib/getPluginName')\nconst toCamelCase = require('./lib/toCamelCase')\n\nlet count = 0\n\nfunction plugin (fn, options = {}) {\n let autoName = false\n\n if (typeof fn.default !== 'undefined') {\n // Support for 'export default' behaviour in transpiled ECMAScript module\n fn = fn.default\n }\n\n if (typeof fn !== 'function') {\n throw new TypeError(\n `fastify-plugin expects a function, instead got a '${typeof fn}'`\n )\n }\n\n if (typeof options === 'string') {\n options = {\n fastify: options\n }\n }\n\n if (\n typeof options !== 'object' ||\n Array.isArray(options) ||\n options === null\n ) {\n throw new TypeError('The options object should be an object')\n }\n\n if (options.fastify !== undefined && typeof options.fastify !== 'string') {\n throw new TypeError(`fastify-plugin expects a version string, instead got '${typeof options.fastify}'`)\n }\n\n if (!options.name) {\n autoName = true\n options.name = getPluginName(fn) + '-auto-' + count++\n }\n\n fn[Symbol.for('skip-override')] = options.encapsulate !== true\n fn[Symbol.for('fastify.display-name')] = options.name\n fn[Symbol.for('plugin-meta')] = options\n\n // Faux modules support\n if (!fn.default) {\n fn.default = fn\n }\n\n // TypeScript support for named imports\n // See https://github.com/fastify/fastify/issues/2404 for more details\n // The type definitions would have to be update to match this.\n const camelCase = toCamelCase(options.name)\n if (!autoName && !fn[camelCase]) {\n fn[camelCase] = fn\n }\n\n return fn\n}\n\nmodule.exports = plugin\nmodule.exports.default = plugin\nmodule.exports.fastifyPlugin = plugin\n","export interface AbuseIPDBOptions {\n\tapiKey: string;\n\tpaths?: string[];\n\tadditionalPaths?: string[];\n\tcategories?: string;\n\tcacheTTL?: number;\n}\n\nexport const createAbuseIPDBPlugin = (options: AbuseIPDBOptions) => {\n\tconst {\n\t\tapiKey,\n\t\tpaths,\n\t\tadditionalPaths = [],\n\t\tcategories = \"21\", // Default category: Web App Attack\n\t\tcacheTTL = 1000 * 60 * 60,\n\t} = options;\n\n\tif (!apiKey) throw new Error(\"AbuseIPDB plugin requires an API key\");\n\n\tconst defaultPaths = [\n\t\t\"/wp-login.php\", \"/xmlrpc.php\", \"/.env\", \"/admin\", \"/phpmyadmin\",\n\t\t\"/wp-admin\", \"/wp-content\", \"/wp-includes\", \"/shell\", \"/login.php\"\n\t];\n\n\tconst suspiciousPaths = paths ?? [...defaultPaths, ...additionalPaths];\n\tconst reportedIPs = new Map<string, number>();\n\n\tasync function reportToAbuseIPDB(ip: string, comment: string, reportCategories?: string) {\n\t\tconst now = Date.now();\n\t\tconst lastReported = reportedIPs.get(ip);\n\t\tif (lastReported && now - lastReported < cacheTTL) {\n\t\t\tconsole.log(`⏳ Skipping duplicate report for ${ip}`);\n\t\t\treturn;\n\t\t}\n\t\treportedIPs.set(ip, now);\n\n\t\ttry {\n\t\t\tawait fetch(\"https://api.abuseipdb.com/api/v2/report\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders: {\n\t\t\t\t\t\"Key\": apiKey,\n\t\t\t\t\t\"Accept\": \"application/json\",\n\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\"\n\t\t\t\t},\n\t\t\t\tbody: new URLSearchParams({\n\t\t\t\t\tip,\n\t\t\t\t\tcategories: reportCategories ?? categories,\n\t\t\t\t\tcomment,\n\t\t\t\t\ttimestamp: new Date().toISOString()\n\t\t\t\t})\n\t\t\t});\n\t\t\tconsole.log(`Reported IP ${ip} to AbuseIPDB: \"${comment}\"`);\n\t\t} catch (err) {\n\t\t\tconsole.error(\"Failed to report to AbuseIPDB:\", err);\n\t\t}\n\t}\n\n\treturn { suspiciousPaths, reportToAbuseIPDB };\n};\n","import type { Request, Response, NextFunction } from 'express';\nimport { createAbuseIPDBPlugin, AbuseIPDBOptions } from './core';\n\nexport const abuseIPDBExpress = (options: AbuseIPDBOptions) => {\n\tconst { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);\n\n\tconst middleware = (req: Request, res: Response, next: NextFunction) => {\n\t\tif (suspiciousPaths.some(p => req.path.startsWith(p))) {\n\t\t\tconst ip = req.ip || \"unknown\";\n\t\t\tif (ip !== \"unknown\") {\n\t\t\t\treportToAbuseIPDB(ip, `Attempted access to suspicious path: ${req.path}`);\n\t\t\t}\n\t\t}\n\t\tnext();\n\t};\n\n\treturn { middleware, report: reportToAbuseIPDB };\n};\n","import type { Context, Next } from 'koa';\nimport { createAbuseIPDBPlugin, AbuseIPDBOptions } from './core';\n\nexport const abuseIPDBKoa = (options: AbuseIPDBOptions) => {\n\tconst { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);\n\n\tconst middleware = async (ctx: Context, next: Next) => {\n\t\tif (suspiciousPaths.some(p => ctx.path.startsWith(p))) {\n\t\t\tconst ip = ctx.ip || \"unknown\";\n\t\t\tif (ip !== \"unknown\") {\n\t\t\t\tawait reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${ctx.path}`);\n\t\t\t}\n\t\t}\n\t\tawait next();\n\t};\n\n\treturn { middleware, report: reportToAbuseIPDB };\n};\n","import type { FastifyInstance } from 'fastify';\nimport fp from 'fastify-plugin';\nimport { createAbuseIPDBPlugin, AbuseIPDBOptions } from './core';\n\nexport interface AbuseIPDBReporter {\n\treport: (ip: string, comment: string, categories?: string) => Promise<void>;\n}\n\nexport const abuseIPDBFastify = fp(async (fastify: FastifyInstance, options: AbuseIPDBOptions) => {\n\tconst { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);\n\n\tfastify.decorate('abuseipdb', { report: reportToAbuseIPDB });\n\n\tfastify.addHook('onRequest', async (request) => {\n\t\tconst path = new URL(request.raw.url!, `http://${request.headers.host}`).pathname;\n\t\tif (suspiciousPaths.some(p => path.startsWith(p))) {\n\t\t\tconst ip = request.ip || \"unknown\";\n\t\t\tif (ip !== \"unknown\") {\n\t\t\t\tawait reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${path}`);\n\t\t\t}\n\t\t}\n\t});\n});\n\ndeclare module 'fastify' {\n\texport interface FastifyInstance {\n\t\tabuseipdb: AbuseIPDBReporter;\n\t}\n}\n","import type { Context, Next } from 'hono';\nimport { createAbuseIPDBPlugin, AbuseIPDBOptions } from './core';\n\nexport const abuseIPDBHono = (options: AbuseIPDBOptions) => {\n\tconst { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);\n\n\tconst middleware = async (c: Context, next: Next) => {\n\t\tconst path = c.req.path;\n\n\t\tif (suspiciousPaths.some(p => path.startsWith(p))) {\n\t\t\tconst ip = c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip') || \"unknown\";\n\t\t\tif (ip !== \"unknown\") {\n\t\t\t\tawait reportToAbuseIPDB(ip, `Attempted access to suspicious path: ${path}`);\n\t\t\t}\n\t\t}\n\t\tawait next();\n\t};\n\n\treturn { middleware, report: reportToAbuseIPDB };\n};\n","import type { Elysia } from 'elysia';\nimport { createAbuseIPDBPlugin, AbuseIPDBOptions } from './core';\n\nexport const abuseIPDBElysia = (options: AbuseIPDBOptions) => {\n\tconst { suspiciousPaths, reportToAbuseIPDB } = createAbuseIPDBPlugin(options);\n\n\tconst middleware = (app: Elysia) =>\n\t\tapp.onBeforeHandle((context: { ip?: string; request: Request }) => {\n\t\t\tconst path = new URL(context.request.url).pathname;\n\n\t\t\tif (suspiciousPaths.some(p => path.startsWith(p))) {\n\t\t\t\tconst ip = context.ip || \"unknown\";\n\n\t\t\t\tif (ip !== \"unknown\") {\n\t\t\t\t\treportToAbuseIPDB(ip, `Attempted access to suspicious path: ${path}`);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\treturn { middleware, report: reportToAbuseIPDB };\n};\n"],"mappings":"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","names":["fp"]}