@riavzon/bot-detector 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -9
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/main.cjs +1 -1
- package/dist/main.cjs.map +1 -1
- package/dist/main.d.cts +2 -2
- package/dist/main.d.cts.map +1 -1
- package/dist/main.d.mts +2 -2
- package/dist/main.d.mts.map +1 -1
- package/dist/main.mjs +1 -1
- package/dist/main.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -45,16 +45,14 @@ package for details.
|
|
|
45
45
|
If you prefer to wire things up yourself:
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
npm install @riavzon/bot-detector
|
|
48
|
+
npm install @riavzon/bot-detector express cookie-parser <data-base-driver>
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
-
After installation,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
data from bgp.tools, which requires it before granting API access. See
|
|
57
|
-
[BGP.tools](https://bgp.tools/kb/api) for details.
|
|
51
|
+
After installation, run `bot-detector init` in an interactive terminal to download its data sources and validate that [mmdbctl](https://github.com/ipinfo/mmdbctl) is installed, if not it prompts you about it, and installs it automatically, it also ask you to provide an user agent that will be used to fetch [BGP](https://en.wikipedia.org/wiki/Border_Gateway_Protocol) data from bgp.tools as they requires it before they allow you to use their data, more info at [BGP.tools](https://bgp.tools/kb/api).
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
npx @riavzon/bot-detector init
|
|
55
|
+
```
|
|
58
56
|
|
|
59
57
|
The compiled databases are written to `_data-sources/` inside the package directory, which include the following files:
|
|
60
58
|
|
|
@@ -135,6 +133,13 @@ app.get('/', (req, res) => {
|
|
|
135
133
|
});
|
|
136
134
|
```
|
|
137
135
|
|
|
136
|
+
Once your app has a `defineConfiguration` call wired up, run `load-schema` to create the database tables:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npx @riavzon/bot-detector load-schema
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
|
|
138
143
|
## Configuration
|
|
139
144
|
|
|
140
145
|
`defineConfiguration` accepts a configuration object. Every field has a default value, only `store.main` is required. The full schema with all defaults is defined in [`src/botDetector/types/configSchema.ts`](src/botDetector/types/configSchema.ts).
|
|
@@ -216,7 +221,6 @@ await defineConfiguration({
|
|
|
216
221
|
});
|
|
217
222
|
|
|
218
223
|
```
|
|
219
|
-
After you configured the database run `bot-detector load-schema` to load the database schema before usage.
|
|
220
224
|
|
|
221
225
|
### Score modes
|
|
222
226
|
|
package/dist/index.mjs
CHANGED
|
@@ -289,7 +289,7 @@ const configSchema = z.object({
|
|
|
289
289
|
enable: z.literal(true),
|
|
290
290
|
highRiskPenalty: z.number().default(30)
|
|
291
291
|
})]).prefault({ enable: true })
|
|
292
|
-
}),
|
|
292
|
+
}).prefault({}),
|
|
293
293
|
generator: z.object({
|
|
294
294
|
scoreThreshold: z.number().default(70),
|
|
295
295
|
generateTypes: z.boolean().default(false),
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["path","path","path"],"sources":["../src/botDetector/db/findDataPath.ts","../src/botDetector/cli/commands/start.ts","../src/botDetector/cli/commands/refresh.ts","../src/botDetector/types/configSchema.ts","../src/botDetector/utils/logger.ts","../src/botDetector/db/dialectUtils.ts","../src/botDetector/checkers/CheckerRegistry.ts","../src/botDetector/checkers/badUaChecker.ts","../src/botDetector/config/config.ts","../src/botDetector/db/generator.ts","../src/botDetector/cli/commands/cleanUp.ts","../src/botDetector/db/schema.ts","../src/botDetector/cli/commands/makeTables.ts","../src/botDetector/cli/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nexport function getLibraryRoot(currentDir: string = __moduleDir): string {\n if (fs.existsSync(path.join(currentDir, 'package.json'))) {\n return currentDir;\n }\n \n const parentDir = path.resolve(currentDir, '..');\n if (parentDir === currentDir) throw new Error('Could not find library root');\n return getLibraryRoot(parentDir);\n}\n\nexport function resolveDataPath(fileName: string): string | never {\n const root = getLibraryRoot();\n \n const possiblePaths = [\n path.resolve(root, '_data-sources', fileName),\n path.resolve(root, 'dist', '_data-sources', fileName),\n ];\n\n for (const path of possiblePaths) {\n if (fs.existsSync(path)) return path;\n }\n\n if (fileName !== 'banned.mmdb' && fileName !== 'highRisk.mmdb') {\n throw new Error(\n `[Bot Detector] Data file \"${fileName}\" not found. ` +\n `Run 'bot-detector init' to download required data files.`\n );\n }\n\n return '';\n}\n","import { defineCommand } from 'citty';\nimport { __cache, __askForUserAgent, __ensureMmdbctl } from '@riavzon/shield-base/internal';\nimport {\n getBGPAndASN,\n buildCitiesData,\n getGeoDatas,\n getListOfProxies,\n getThreatLists,\n getTorLists,\n getCrawlersIps,\n getUserAgentLmdbList,\n getJaDatabaseLmdb,\n type InputCache\n} from '@riavzon/shield-base';\nimport consola from 'consola';\nimport { getLibraryRoot } from '@db/findDataPath.js';\nimport path from 'path';\nimport fs from 'node:fs';\n\nexport const startCommand = defineCommand({\n meta: {\n name: 'Bot Detector',\n description: 'Get started with the installation wizard'\n },\n\n async run() {\n const output = path.resolve(getLibraryRoot(), '_data-sources');\n const sentinel = path.resolve(output, 'asn.mmdb');\n\n if (!process.stdout.isTTY) {\n if (fs.existsSync(sentinel)) return;\n consola.warn('bot-detector: data sources not found. Run `npx bot-detector init` in an interactive terminal to set up.');\n return;\n }\n\n const cache: Partial<InputCache> = await __cache()._getCache() ?? {};\n\n consola.start('Starting installation wizard...');\n\n let mmdbPath = '';\n if (cache.mmdbctlPath) {\n mmdbPath = cache.mmdbctlPath;\n } else {\n consola.start('Verifying system dependencies...');\n mmdbPath = await __ensureMmdbctl();\n cache.mmdbctlPath = mmdbPath;\n }\n\n let contactInfo: string | undefined = '';\n if (cache.useragent) {\n contactInfo = cache.useragent;\n } else {\n contactInfo = await __askForUserAgent();\n cache.useragent = contactInfo;\n }\n\n if (fs.existsSync(sentinel)) {\n consola.success('Data sources already initialized. Run `bot-detector refresh` to update them.');\n return;\n }\n\n cache.selectedDataTypes = [\"BGP\", \"City\", \"Geography\", \"Proxy\", \"Tor\", \"SEO\", \"firehol_l1\", \"firehol_l2\", \"firehol_l3\", \"firehol_l4\", \"firehol_anonymous\", \"JA4\", \"UserAgent\"];\n cache.outPutPath = output;\n await __cache()._setCache(cache);\n\n consola.start('Compiling all data sources...');\n\n await Promise.all([\n getBGPAndASN(contactInfo, output, mmdbPath),\n buildCitiesData(output, mmdbPath),\n getTorLists(output, mmdbPath),\n getGeoDatas(output, mmdbPath),\n getListOfProxies(output, mmdbPath),\n getThreatLists(output, mmdbPath, true),\n getCrawlersIps(output, mmdbPath),\n getUserAgentLmdbList(output),\n getJaDatabaseLmdb(output)\n ]);\n\n consola.success('All data successfully compiled. You can now start using bot-detector.');\n }\n});","import { defineCommand } from 'citty';\nimport { __cache, __restartData } from '@riavzon/shield-base/internal';\nimport { InputCache } from '@riavzon/shield-base';\nimport consola from 'consola';\nimport { getLibraryRoot } from '@db/findDataPath.js';\nimport path from 'path';\n\n\nexport const refreshData = defineCommand({\n meta: {\n name: 'refresh',\n description: 'Refresh the local data sources the bot-detector use internally'\n },\n \n async run() {\n const cache: Partial<InputCache> = await __cache()._getCache() ?? {};\n \n if (!cache.outPutPath || !cache.mmdbctlPath || Object.keys(cache).length === 0) {\n consola.error('No data to restart, please first run the installation wizard');\n throw new Error();\n }\n\n const output = path.resolve(getLibraryRoot(), '_data-sources');\n consola.start('Restarting data sources...');\n\n await __restartData(output, true);\n\n consola.success(`✨ All data successfully restarted!`);\n }\n});","import z from \"zod\";\nimport type { CacheConfig } from \"./storageTypes.js\";\nimport { DbConfig } from \"./dbTypes.js\";\n\n\n\nconst dbConfigStorage = z.custom<DbConfig>(\n (val: unknown): val is DbConfig => {\n if (typeof val !== 'object' || val === null) {\n return false;\n }\n const obj = val as DbConfig;\n return typeof obj.driver === 'string';\n },\n { message: 'Database config must be an object with a valid \"driver\" string' }\n);\n\nconst store = z.object({\n main: dbConfigStorage,\n}).required().strict();\n\nconst cache = z.custom<CacheConfig>(\n (val: unknown): val is CacheConfig => {\n if (typeof val !== 'object' || val === null) {\n return false;\n }\n const obj = val as CacheConfig;\n return typeof obj.driver === 'string';\n },\n { message: 'Storage must be an object with a valid \"driver\" string' }\n);\n\nexport const configSchema = z.object({\n store,\n /**\n * Total ban threshold the system accumaltae before banning.\n */\n banScore: z.number().max(100).min(0).default(100),\n /**\n * Total ban score the system can assign.\n */\n maxScore: z.number().max(100).min(0).default(100),\n /**\n * Total score to restore for the next visitor request.\n */\n restoredReputationPoints: z.number().default(10),\n /**\n * setNewComputedScore\n * -------------------\n * Controls how the bot-detector and the reputation-healer cooperate.\n *\n * true ▸ **Live snapshot mode** \n * – Every request:\n * 1. Bot-detector recalculates a fresh `botScore` \n * 2. Row in **visitors** is overwritten with that score \n * 3. Cache is refreshed with the same value \n * 4. Reputation-healer subtracts `restoredReputationPoints`\n * (if the visitor isn’t banned) and writes the lower score back\n * to DB & cache.\n * – Net effect: score oscillates \n * `computed → healed → computed → healed …` \n * Useful when you want the latest risk snapshot visible in the DB\n * after every page view.\n *\n * false ▸ **Snapshot-then-heal mode** \n * – First request for this canary: \n * detector writes the computed score (e.g. 8) to DB & cache. \n * – Subsequent requests while the cache entry lives: \n * detector skips the overwrite → healer slowly counts the\n * score down (`–restoredReputationPoints` per hit) and commits\n * the lower value. \n * – When the cache expires (TTL) or the visitor clears cookies,\n * a fresh snapshot is taken and the cycle restarts.\n * – Net effect: score only **decreases** until a new snapshot is taken.\n *\n * Example\n * -------\n * banScore = 10, restoredReputationPoints = 1\n * R = reqeast\n * Flag = true\n * ───────────\n * R1: detector 8 ➜ DB 8 ➜ healer 7\n * R2: detector 8 ➜ DB 8 ➜ healer 7\n *\n * Flag = false\n * ────────────\n * R1: detector 8 ➜ DB 8, cache 8\n * R2: detector (skip) ➜ healer 7 ➜ DB 7, cache 7\n * R3: detector (skip) ➜ healer 6 ➜ DB 6, cache 6\n *\n * Choose **true** when you always want the latest computed risk stored. \n * Choose **false** when you prefer a single snapshot that only decays until\n * the cache is refreshed.\n */\n setNewComputedScore: z.boolean().default(false),\n whiteList: z.array(z.union([z.ipv4(), z.ipv6(), z.string()])).optional().default([]),\n checksTimeRateControl: z.object({\n checkEveryRequest: z.boolean().default(true),\n checkEvery: z.number().default(1000 * 60 * 5),\n }).prefault({}),\n\n batchQueue: z.object({\n flushIntervalMs: z.number().default(5000),\n maxBufferSize: z.number().default(100),\n maxRetries: z.number().default(3),\n }).prefault({}),\n\n storage: cache.optional(),\n \n checkers: z.object({\n localeMapsCheck: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n ipAndHeaderMismatch: z.number().default(20),\n missingHeader: z.number().default(20),\n missingGeoData: z.number().default(20),\n malformedHeader: z.number().default(30)\n }).prefault({}),\n })\n ]).prefault({enable: true}),\n\n knownBadUserAgents: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n criticalSeverity: z.number().default(100),\n highSeverity: z.number().default(80),\n mediumSeverity: z.number().default(30),\n lowSeverity: z.number().default(10),\n }).prefault({})\n })\n ]).prefault({enable: true}),\n \n enableIpChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n penalties: z.number().default(10)\n })\n ]).prefault({enable: true}),\n\n enableGoodBotsChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }), \n\n z.object({\n enable: z.literal(true),\n /**\n * If settings.banUnlistedBots is true any bot not listed in suffix.json or botsWithoutSuffix will be banned.\n * Everything else exact names and any unknown bots when banning is off—hits the IP-range check..\n */\n banUnlistedBots: z.boolean().default(true),\n penalties: z.number().default(100)\n })\n\n ]).prefault({enable: true}),\n\n enableBehaviorRateCheck: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n behavioral_window: z.number().default(60_000),\n behavioral_threshold: z.number().default(30),\n penalties: z.number().default(60)\n }) \n ]).prefault({enable: true}),\n\n enableProxyIspCookiesChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n \n z.object({\n enable: z.literal(true),\n penalties: z.object({\n cookieMissing: z.number().default(80),\n proxyDetected: z.number().default(40),\n multiSourceBonus2to3: z.number().default(10),\n multiSourceBonus4plus: z.number().default(20),\n hostingDetected: z.number().default(50),\n ispUnknown: z.number().default(10),\n orgUnknown: z.number().default(10),\n }).prefault({}),\n }),\n ]).prefault({enable: true}),\n\n enableUaAndHeaderChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n headlessBrowser: z.number().default(100),\n shortUserAgent: z.number().default(80),\n tlsCheckFailed: z.number().default(60),\n badUaChecker: z.boolean().default(true) \n\n }).prefault({}),\n })\n ]).prefault({enable: true}),\n\n enableBrowserAndDeviceChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n penalties: z.object({ \n cliOrLibrary: z.number().default(100),\n internetExplorer: z.number().default(100),\n linuxOs: z.number().default(10),\n impossibleBrowserCombinations: z.number().default(30),\n browserTypeUnknown: z.number().default(10),\n browserNameUnknown: z.number().default(10),\n desktopWithoutOS: z.number().default(10),\n deviceVendorUnknown: z.number().default(10),\n browserVersionUnknown: z.number().default(10),\n deviceModelUnknown: z.number().default(5),\n }).prefault({}),\n })\n \n ]).prefault({enable: true}),\n\n enableGeoChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n bannedCountries: z.array(z.string()).optional().default([]),\n penalties: z.object({ \n countryUnknown: z.number().default(10),\n regionUnknown: z.number().default(10),\n latLonUnknown: z.number().default(10),\n districtUnknown: z.number().default(10),\n cityUnknown: z.number().default(10),\n timezoneUnknown: z.number().default(10),\n subregionUnknown: z.number().default(10),\n phoneUnknown: z.number().default(10),\n continentUnknown: z.number().default(10),\n }).prefault({}),\n }),\n ]).prefault({enable: true}),\n\n enableKnownThreatsDetections: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n anonymiseNetwork: z.number().default(20),\n threatLevels: z.object({\n criticalLevel1: z.number().default(40),\n currentAttacksLevel2: z.number().default(30),\n threatLevel3: z.number().default(20),\n threatLevel4: z.number().default(10),\n }).prefault({}),\n }).prefault({})\n }),\n ]).prefault({enable: true}),\n\n enableAsnClassification: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n contentClassification: z.number().default(20),\n unknownClassification: z.number().default(10),\n lowVisibilityPenalty: z.number().default(10),\n lowVisibilityThreshold: z.number().default(15),\n comboHostingLowVisibility: z.number().default(20),\n }).prefault({}),\n }),\n ]).prefault({ enable: true }),\n\n enableTorAnalysis: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n runningNode: z.number().default(15),\n exitNode: z.number().default(20),\n webExitCapable: z.number().default(15),\n guardNode: z.number().default(10),\n badExit: z.number().default(40),\n obsoleteVersion: z.number().default(10),\n }).prefault({}),\n }),\n ]).prefault({ enable: true }),\n\n enableTimezoneConsistency: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.number().default(20),\n }),\n ]).prefault({ enable: true }),\n\n honeypot: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n paths: z.array(z.string()).default([]),\n }),\n ]).prefault({ enable: true }),\n\n enableSessionCoherence: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n pathMismatch: z.number().default(10),\n missingReferer: z.number().default(20),\n domainMismatch: z.number().default(30),\n }).prefault({}),\n }),\n ]).prefault({ enable: true }),\n\n enableVelocityFingerprint: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n cvThreshold: z.number().default(0.1),\n penalties: z.number().default(40),\n }),\n ]).prefault({ enable: true }),\n\n enableKnownBadIpsCheck: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n highRiskPenalty: z.number().default(30),\n }),\n ]).prefault({ enable: true }),\n }),\n\n generator: z.object({\n scoreThreshold: z.number().default(70),\n generateTypes: z.boolean().default(false),\n deleteAfterBuild: z.boolean().default(false),\n mmdbctlPath: z.string().default('mmdbctl')\n }).prefault({}),\n\n headerOptions: z.object({\n weightPerMustHeader: z.number().default(20),\n missingBrowserEngine: z.number().default(30),\n postManOrInsomiaHeaders: z.number().default(50),\n AJAXHeaderExists: z.number().default(30),\n connectionHeaderIsClose: z.number().default(20),\n originHeaderIsNULL: z.number().default(10),\n originHeaderMismatch: z.number().default(30),\n omittedAcceptHeader: z.number().default(30),\n\n clientHintsMissingForBlink: z.number().default(30),\n teHeaderUnexpectedForBlink: z.number().default(10),\n clientHintsUnexpectedForGecko: z.number().default(30),\n teHeaderMissingForGecko: z.number().default(20),\n \n aggressiveCacheControlOnGet: z.number().default(15),\n crossSiteRequestMissingReferer: z.number().default(10),\n inconsistentSecFetchMode: z.number().default(20),\n\n hostMismatchWeight: z.number().default(40),\n }).prefault({}),\n\n pathTraveler: z.object({\n maxIterations: z.number().default(3),\n maxPathLength: z.number().default(1500),\n pathLengthToLong: z.number().default(100),\n longDecoding: z.number().default(100),\n traversalDetected: z.number().default(60),\n }).prefault({}),\n\n \n punishmentType: z.object({\n enableFireWallBan: z.boolean().default(false),\n }).prefault({}),\n \n logLevel: z.enum(['debug', 'info', 'warn', 'error', 'fatal']).default('info'),\n});\n\nexport type BotDetectorConfig = z.infer<typeof configSchema>;\nexport type BotDetectorConfigInput = z.input<typeof configSchema>;","import { pino, Logger } from 'pino';\nimport { existsSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { getConfiguration } from '../config/config.js';\n\n\nconst LOG_DIR = path.resolve(process.cwd(), process.env.LOG_DIR || 'bot-detector-logs');\nif (!existsSync(LOG_DIR)) mkdirSync(LOG_DIR, { recursive: true });\n\nconst transport = pino.transport({\n targets: [\n {\n target: 'pino/file',\n level: 'info',\n options: {\n destination: `${LOG_DIR}/info.log`,\n mkdir: true\n }\n },\n {\n target: 'pino/file',\n level: 'warn',\n options: {\n destination: `${LOG_DIR}/warn.log`,\n mkdir: true\n }\n },\n {\n target: 'pino/file',\n level: 'error',\n options: {\n destination: `${LOG_DIR}/errors.log`,\n mkdir:true\n }\n }\n ]\n});\n\nlet logger: pino.Logger; \n\nexport function getLogger(): Logger {\n if (logger) return logger; \n const { logLevel } = getConfiguration();\n logger = (pino) (\n {\n level: logLevel,\n timestamp: pino.stdTimeFunctions.isoTime,\n mixin() { return { uptime: process.uptime() }; },\n redact: {\n paths: [\n '*.password',\n '*.email',\n 'name',\n 'Name',\n '*.cookies',\n '*.cookie',\n 'cookies',\n 'cookie',\n '*.accessToken',\n '*.refresh_token',\n '*.secret'\n ],\n censor: '[SECRET]'\n }\n },\n transport\n );\n return logger;\n}","import type { Database } from 'db0';\n\nexport function isMySQL(db: Database): boolean {\n return db.dialect === 'mysql';\n}\n\nexport function isSQLite(db: Database): boolean {\n return db.dialect === 'sqlite';\n}\n\n/** Convert ? placeholders to $1, $2, for PostgreSQL. */\nexport function prep(db: Database, sql: string) {\n if (db.dialect !== 'postgresql') return db.prepare(sql);\n let i = 0;\n return db.prepare(sql.replace(/\\?/g, () => `$${String(++i)}`));\n}\n\n/** Generate positional placeholders for a dynamic list of values. */\nexport function placeholders(db: Database, count: number, offset = 0): string {\n return Array.from({ length: count }, (_, i) =>\n db.dialect === 'postgresql' ? `$${String(offset + i + 1)}` : '?'\n ).join(', ');\n}\n\n/** NOW() equivalent per dialect. */\nexport function now(db: Database): string {\n return isSQLite(db) ? \"datetime('now')\" : 'NOW()';\n}\n\n/**\n * Upsert conflict clause.\n * MySQL: ON DUPLICATE KEY UPDATE\n * Others: ON CONFLICT(pk) DO UPDATE SET\n */\nexport function onUpsert(db: Database, pk: string): string {\n return isMySQL(db)\n ? 'ON DUPLICATE KEY UPDATE'\n : `ON CONFLICT(${pk}) DO UPDATE SET`;\n}\n\n/**\n * Reference to the incoming row value in an upsert SET clause.\n * MySQL: VALUES(col)\n * Others: excluded.col\n */\nexport function excluded(db: Database, col: string): string {\n return isMySQL(db) ? `VALUES(${col})` : `excluded.${col}`;\n}\n\n/**\n * INSERT IGNORE equivalent.\n * MySQL: INSERT IGNORE INTO\n * SQLite: INSERT OR IGNORE INTO\n * PostgreSQL: INSERT INTO (use onConflictDoNothing() as trailing clause)\n */\nexport function insertIgnore(db: Database): string {\n if (isSQLite(db)) return 'INSERT OR IGNORE INTO';\n if (isMySQL(db)) return 'INSERT IGNORE INTO';\n return 'INSERT INTO';\n}\n\n/** Trailing ON CONFLICT DO NOTHING clause, for PostgreSQL. */\nexport function onConflictDoNothing(db: Database): string {\n return db.dialect === 'postgresql' ? 'ON CONFLICT DO NOTHING' : '';\n}\n","import consola from 'consola';\nimport type { IBotChecker, BanReasonCode } from '../types/checkersTypes.js';\nimport type { BotDetectorConfig } from '../types/configSchema.js';\n\nlet registeredCheckers: IBotChecker<BanReasonCode>[] = [];\n\nexport const CheckerRegistry = {\n register(checker: IBotChecker<BanReasonCode>) {\n consola.log(`Loaded plugin: ${checker.name}`);\n registeredCheckers.push(checker);\n },\n\n getEnabled(phase: 'cheap' | 'heavy', config: BotDetectorConfig): IBotChecker<BanReasonCode>[] {\n return registeredCheckers.filter(\n checker => checker.phase === phase && checker.isEnabled(config)\n );\n },\n\n clear() {\n registeredCheckers = [];\n },\n};\n","import { BanReasonCode, IBotChecker } from '../types/checkersTypes.js';\nimport { BotDetectorConfig } from '../types/configSchema.js';\nimport { ValidationContext } from '../types/botDetectorTypes.js';\nimport { CheckerRegistry } from './CheckerRegistry.js';\nimport { getDataSources } from '../config/config.js';\n\nconst SEVERITY_ORDER = ['critical', 'high', 'medium', 'low'] as const;\ntype Severity = typeof SEVERITY_ORDER[number];\nlet patterns: { rx: RegExp; severity: Severity }[] = [];\n\nexport function loadUaPatterns(): void {\n const db = getDataSources().getUserAgentLmdb();\n const bucketStrings = new Map<Severity, string[]>(\n SEVERITY_ORDER.map(sev => [sev, []])\n );\n\n for (const { value } of db.getRange({ limit: 10_000 })) {\n const sev = value.metadata_severity as Severity;\n bucketStrings.get(sev)?.push(value.useragent_rx);\n }\n\n patterns = SEVERITY_ORDER.map(severity => {\n const patterns = bucketStrings.get(severity) ?? [];\n if (patterns.length === 0) return null;\n \n const combined = patterns.map(p => `(?:${p})`).join('|');\n return {\n rx: new RegExp(combined, 'i'),\n severity\n };\n }).filter((p): p is { rx: RegExp; severity: Severity } => p !== null);\n}\n\nexport class BadUaChecker implements IBotChecker<BanReasonCode> {\n name = 'Bad User Agent list';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig) {\n return config.checkers.knownBadUserAgents.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const { knownBadUserAgents } = config.checkers;\n const reasons: 'BAD_UA_DETECTED'[] = [];\n let score = 0;\n\n if (!knownBadUserAgents.enable) return { score, reasons };\n\n if (patterns.length === 0) {\n loadUaPatterns();\n }\n\n const rawUa = ctx.req.get('User-Agent') ?? '';\n for (const { rx, severity } of patterns) {\n if (rx.test(rawUa)) {\n reasons.push('BAD_UA_DETECTED');\n switch (severity) {\n case 'critical': score += knownBadUserAgents.penalties.criticalSeverity; break;\n case 'high': score += knownBadUserAgents.penalties.highSeverity; break;\n case 'medium': score += knownBadUserAgents.penalties.mediumSeverity; break;\n case 'low': score += knownBadUserAgents.penalties.lowSeverity; break;\n }\n break;\n }\n }\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new BadUaChecker());","import { createConfigManager } from \"@riavzon/utils\";\nimport type { BotDetectorConfig as Configuration, BotDetectorConfigInput } from \"../types/configSchema.js\";\nimport { configSchema } from \"../types/configSchema.js\";\nimport { DataSources } from \"../helpers/mmdbDataReaders.js\";\nimport { BatchQueue } from \"../db/batchQueue.js\";\nimport { initStorage } from \"./storageAdapter.js\";\nimport type { Storage } from 'unstorage';\nimport { initDb } from \"./dbAdapter.js\";\nimport { type Database } from \"db0\";\nimport { loadUaPatterns } from \"../checkers/badUaChecker.js\";\nimport consola from \"consola\";\n\n\nconst {\n defineConfiguration,\n getConfiguration\n} = createConfigManager<Configuration>(configSchema, \"Bot Detector\");\n\nlet globalDataSources: DataSources | undefined;\nlet globalBatchQueue: BatchQueue | undefined;\nlet globalStorage: Storage | undefined;\nlet globalDb: Database | undefined;\n\n/**\n * @description\n * The bot detector library's configuration object.\n * Contains the core configuration to make the library usable client side.\n * @module jwtAuth/config\n * @see {@link ./jwtAuth/types/configSchema.js}\n */\nexport async function configuration(config: BotDetectorConfigInput): Promise<void> {\n const initDataSourcesTask = async () => {\n globalDataSources ??= await DataSources.initialize();\n loadUaPatterns();\n };\n\n const initBatchQueueTask = () => {\n if (!globalBatchQueue) {\n globalBatchQueue = new BatchQueue();\n process.on('SIGTERM', () => { void globalBatchQueue?.shutdown(); });\n process.on('SIGINT', () => { void globalBatchQueue?.shutdown(); });\n }\n };\n\n const initStorageTask = async () => {\n globalStorage ??= await initStorage(config.storage);\n };\n\n const initDbTask = async () => {\n globalDb ??= await initDb(config.store.main);\n };\n\n await defineConfiguration(config, [\n initDataSourcesTask,\n initBatchQueueTask,\n initStorageTask,\n initDbTask\n ]);\n}\n\n\nexport { getConfiguration };\n\nexport function getBatchQueue(): BatchQueue {\n if (!globalBatchQueue) {\n consola.trace(\"Premature getBatchQueue() call\");\n throw new Error('BatchQueue not ready. Call configuration() first.');\n }\n return globalBatchQueue;\n}\n\nexport function getStorage(): Storage {\n if (!globalStorage) {\n consola.trace(\"Premature getStorage() call\");\n throw new Error('Storage not ready. Call configuration() first.');\n }\n return globalStorage;\n}\n\nexport function getDb(): Database {\n if (!globalDb) {\n consola.trace(\"Premature getDb() call\");\n throw new Error('DB not ready. Call configuration() first.');\n }\n return globalDb;\n}\n\nexport function getDataSources(): DataSources {\n if (!globalDataSources) {\n consola.trace(\"Premature getDataSources() call\");\n throw new Error(`##### Must be initialized globally #####\n Bot Detector: DataSources not ready. Call configuration() first.`\n );\n }\n return globalDataSources;\n}\n","import { compiler } from '@riavzon/shield-base';\nimport { getDb, getConfiguration } from '../config/config.js';\nimport { getLogger } from '../utils/logger.js';\nimport path from 'node:path';\nimport { BannedRecord, BannedRow, HighRiskRecord, HighRiskRow } from '../types/generator.js';\nimport { prep, placeholders } from './dialectUtils.js';\nimport { getLibraryRoot } from './findDataPath.js';\n\nconst MMDB_DIR = path.resolve(getLibraryRoot(), '_data-sources');\n\nasync function buildBannedMmdb(generateTypes: boolean, mmdbctlPath: string): Promise<void> {\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'generator', db: 'banned' });\n const db = getDb();\n\n const rows = await db.prepare(\n `SELECT ip_address, country, user_agent, reason, score\n FROM banned\n WHERE ip_address IS NOT NULL`\n ).all() as BannedRow[];\n\n if (rows.length === 0) {\n log.info('No banned IPs — skipping banned.mmdb');\n return;\n }\n\n const data: BannedRecord[] = rows.map(r => ({\n range: r.ip_address,\n score: r.score,\n country: r.country,\n userAgent: r.user_agent,\n reason: r.reason,\n comment: 'Automatically generated by @riavzon/botDetector',\n }));\n await compiler<BannedRecord>({ type: 'mmdb', input: { data, dataBaseName: 'banned', outputPath: MMDB_DIR, mmdbPath: mmdbctlPath, generateTypes } });\n log.info(`banned.mmdb compiled — ${String(data.length)} entries`);\n\n if (getConfiguration().generator.deleteAfterBuild) {\n const compiled = rows.map(r => r.ip_address);\n const ph = placeholders(db, compiled.length);\n await prep(db, `DELETE FROM banned WHERE ip_address IN (${ph})`).run(...compiled);\n log.info(`Deleted ${(String(compiled.length))} rows from banned after build`);\n }\n}\n\n\nasync function buildHighRiskMmdb(scoreThreshold: number, generateTypes: boolean, mmdbctlPath: string): Promise<void> {\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'generator', db: 'highRisk' });\n const db = getDb();\n\n const rows = await prep(db,\n `SELECT\n ip_address, visitor_id, suspicious_activity_score,\n country, region, region_name, city, lat, lon, timezone,\n isp, org, browser, browserType, browserVersion, os,\n device_type, deviceVendor, deviceModel,\n proxy, hosting, request_count, first_seen, last_seen\n FROM visitors\n WHERE suspicious_activity_score >= ? AND ip_address IS NOT NULL`\n ).all(scoreThreshold) as HighRiskRow[];\n\n if (rows.length === 0) {\n log.info(`No high-risk visitors (score >= ${String(scoreThreshold)}) — skipping highRisk.mmdb`);\n return;\n }\n\n const data: HighRiskRecord[] = rows.map(r => ({\n range: r.ip_address,\n visitorId: r.visitor_id,\n score: r.suspicious_activity_score,\n country: r.country,\n region: r.region,\n regionName: r.region_name,\n city: r.city,\n lat: r.lat,\n lon: r.lon,\n timezone: r.timezone,\n isp: r.isp,\n org: r.org,\n browser: r.browser,\n browserType: r.browserType,\n browserVersion: r.browserVersion,\n os: r.os,\n deviceType: r.device_type,\n deviceVendor: r.deviceVendor,\n deviceModel: r.deviceModel,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n proxy: Boolean(r.proxy),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n hosting: Boolean(r.hosting),\n requestCount: r.request_count,\n firstSeen: r.first_seen ? r.first_seen.toISOString() : null,\n lastSeen: r.last_seen ? r.last_seen.toISOString() : null,\n comment: 'Automatically generated by @riavzon/botDetector',\n }));\n\n await compiler<HighRiskRecord>({ type: 'mmdb', input: { data, dataBaseName: 'highRisk', outputPath: MMDB_DIR, mmdbPath: mmdbctlPath, generateTypes } });\n log.info(`highRisk.mmdb compiled — ${String(data.length)} entries`);\n\n if (getConfiguration().generator.deleteAfterBuild) {\n const compiled = rows.map(r => r.ip_address);\n const ph = placeholders(db, compiled.length);\n const scorePh = placeholders(db, 1, compiled.length);\n await prep(db,\n `DELETE FROM visitors WHERE ip_address IN (${ph}) AND suspicious_activity_score >= ${scorePh}`\n ).run(...compiled, scoreThreshold);\n log.info(`Deleted ${String(compiled.length)} rows from visitors after build`);\n }\n}\n\n\nasync function runCycle(): Promise<void> {\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'generator' });\n const { generator } = getConfiguration();\n\n log.info('MMDB generation cycle started');\n try {\n await Promise.all([\n buildBannedMmdb(generator.generateTypes, generator.mmdbctlPath),\n buildHighRiskMmdb(generator.scoreThreshold, generator.generateTypes, generator.mmdbctlPath),\n ]);\n log.info('MMDB generation cycle complete');\n } catch (err) {\n log.error({ err }, 'MMDB generation cycle failed');\n }\n}\n\n\nexport async function runGeneration(): Promise<void> {\n return runCycle();\n}","import { runGeneration } from \"@db/generator.js\";\nimport { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { getConfiguration } from \"../../config/config.js\";\nimport { execSync } from \"child_process\";\nimport { __ensureMmdbctl } from \"@riavzon/shield-base/internal\";\n\nexport const cleanUp = defineCommand({\n meta: {\n name: 'generate',\n description: 'Run the generator: reads banned and high-risk visitors from your database and compiles them into an optimized binary (based on your generator configuration)'\n },\n\n async run() { \n const { generator } = getConfiguration();\n try {\n execSync(`${generator.mmdbctlPath} --help`, { stdio: 'ignore' });\n } catch {\n \n consola.warn(`The configurable mmdbctl path cannot be resolved at ${generator.mmdbctlPath}, You will be prompted to install it.`);\n const path = await __ensureMmdbctl();\n consola.box(`mmdbctl installed successfully. Add the next path in generator.mmdbctlPath configuration option and run the command again: ${path}`);\n\n process.exit(1);\n }\n\n consola.start('Starting clean up operation...');\n await runGeneration();\n consola.success('Success!');\n }\n});","import type { Database } from 'db0';\nimport { isMySQL, isSQLite } from './dialectUtils.js';\nimport consola from 'consola';\n\nfunction visitorIdDefault(db: Database): string {\n if (isMySQL(db)) return 'NOT NULL DEFAULT (UUID())';\n if (db.dialect === 'postgresql') return 'NOT NULL DEFAULT gen_random_uuid()';\n return 'NOT NULL';\n}\n\nfunction lastSeenDef(db: Database): string {\n if (isMySQL(db)) return 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';\n if (isSQLite(db)) return 'TEXT DEFAULT CURRENT_TIMESTAMP';\n return 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP';\n}\n\nfunction tableOptions(db: Database): string {\n return isMySQL(db) ? 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci' : '';\n}\n\nfunction timestampType(db: Database): string {\n return isSQLite(db) ? 'TEXT' : 'TIMESTAMP';\n}\n\nexport async function createTables(db: Database): Promise<void> {\n const visitorId = visitorIdDefault(db);\n const lastSeen = lastSeenDef(db);\n const tblOpts = tableOptions(db);\n const tsType = timestampType(db);\n\n const createVisitorsTable = `\n CREATE TABLE IF NOT EXISTS visitors (\n visitor_id CHAR(36) ${visitorId},\n canary_id VARCHAR(64) PRIMARY KEY,\n ip_address VARCHAR(45),\n user_agent TEXT,\n country VARCHAR(64),\n region VARCHAR(64),\n region_name VARCHAR(350),\n city VARCHAR(64),\n district VARCHAR(260),\n lat VARCHAR(150),\n lon VARCHAR(150),\n timezone VARCHAR(64),\n currency VARCHAR(64),\n isp VARCHAR(64),\n org VARCHAR(64),\n as_org VARCHAR(64),\n device_type VARCHAR(64),\n browser VARCHAR(64),\n proxy BOOLEAN,\n hosting BOOLEAN,\n is_bot BOOLEAN DEFAULT false,\n first_seen ${tsType} DEFAULT CURRENT_TIMESTAMP,\n last_seen ${lastSeen},\n request_count INT DEFAULT 1,\n deviceVendor VARCHAR(64) DEFAULT 'unknown',\n deviceModel VARCHAR(64) DEFAULT 'unknown',\n browserType VARCHAR(64) DEFAULT 'unknown',\n browserVersion VARCHAR(64) DEFAULT 'unknown',\n os VARCHAR(64) DEFAULT 'unknown',\n suspicious_activity_score INT DEFAULT 0\n ) ${tblOpts}\n `;\n\n const createBannedTable = `\n CREATE TABLE IF NOT EXISTS banned (\n canary_id VARCHAR(64) PRIMARY KEY,\n ip_address VARCHAR(45),\n country VARCHAR(64),\n user_agent TEXT,\n reason TEXT,\n score INT DEFAULT NULL,\n FOREIGN KEY (canary_id) REFERENCES visitors(canary_id)\n )\n `;\n\n try {\n await db.exec(createVisitorsTable);\n await db.exec(createBannedTable);\n\n consola.success('Tables created successfully.');\n } catch (error) {\n consola.error('Error creating tables:', error);\n throw error;\n }\n}","import { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { createTables } from \"@db/schema.js\";\nimport { getDb } from \"../../config/config.js\";\n\nexport const makeTables = defineCommand({\n meta: {\n name: 'load-schema',\n description: 'Create database tables'\n },\n\n async run() {\n const db = getDb();\n consola.start(`Creating tables for ${db.dialect}...`);\n await createTables(db);\n }\n});","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from 'citty';\nimport { startCommand } from './commands/start.js';\nimport { refreshData } from './commands/refresh.js';\nimport { cleanUp } from './commands/cleanUp.js';\nimport { makeTables } from './commands/makeTables.js';\n\nexport const main = defineCommand({\n meta: {\n name: 'bot-detector',\n description: 'Automatic traffic analysis and detection',\n version: '1.0.0'\n },\n subCommands: {\n init: startCommand,\n refresh: refreshData,\n generate: cleanUp,\n 'load-schema': makeTables\n },\n});\n\nawait runMain(main);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["path","path","path"],"sources":["../src/botDetector/db/findDataPath.ts","../src/botDetector/cli/commands/start.ts","../src/botDetector/cli/commands/refresh.ts","../src/botDetector/types/configSchema.ts","../src/botDetector/utils/logger.ts","../src/botDetector/db/dialectUtils.ts","../src/botDetector/checkers/CheckerRegistry.ts","../src/botDetector/checkers/badUaChecker.ts","../src/botDetector/config/config.ts","../src/botDetector/db/generator.ts","../src/botDetector/cli/commands/cleanUp.ts","../src/botDetector/db/schema.ts","../src/botDetector/cli/commands/makeTables.ts","../src/botDetector/cli/index.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst __moduleDir = path.dirname(fileURLToPath(import.meta.url));\n\nexport function getLibraryRoot(currentDir: string = __moduleDir): string {\n if (fs.existsSync(path.join(currentDir, 'package.json'))) {\n return currentDir;\n }\n \n const parentDir = path.resolve(currentDir, '..');\n if (parentDir === currentDir) throw new Error('Could not find library root');\n return getLibraryRoot(parentDir);\n}\n\nexport function resolveDataPath(fileName: string): string | never {\n const root = getLibraryRoot();\n \n const possiblePaths = [\n path.resolve(root, '_data-sources', fileName),\n path.resolve(root, 'dist', '_data-sources', fileName),\n ];\n\n for (const path of possiblePaths) {\n if (fs.existsSync(path)) return path;\n }\n\n if (fileName !== 'banned.mmdb' && fileName !== 'highRisk.mmdb') {\n throw new Error(\n `[Bot Detector] Data file \"${fileName}\" not found. ` +\n `Run 'bot-detector init' to download required data files.`\n );\n }\n\n return '';\n}\n","import { defineCommand } from 'citty';\nimport { __cache, __askForUserAgent, __ensureMmdbctl } from '@riavzon/shield-base/internal';\nimport {\n getBGPAndASN,\n buildCitiesData,\n getGeoDatas,\n getListOfProxies,\n getThreatLists,\n getTorLists,\n getCrawlersIps,\n getUserAgentLmdbList,\n getJaDatabaseLmdb,\n type InputCache\n} from '@riavzon/shield-base';\nimport consola from 'consola';\nimport { getLibraryRoot } from '@db/findDataPath.js';\nimport path from 'path';\nimport fs from 'node:fs';\n\nexport const startCommand = defineCommand({\n meta: {\n name: 'Bot Detector',\n description: 'Get started with the installation wizard'\n },\n\n async run() {\n const output = path.resolve(getLibraryRoot(), '_data-sources');\n const sentinel = path.resolve(output, 'asn.mmdb');\n\n if (!process.stdout.isTTY) {\n if (fs.existsSync(sentinel)) return;\n consola.warn('bot-detector: data sources not found. Run `npx bot-detector init` in an interactive terminal to set up.');\n return;\n }\n\n const cache: Partial<InputCache> = await __cache()._getCache() ?? {};\n\n consola.start('Starting installation wizard...');\n\n let mmdbPath = '';\n if (cache.mmdbctlPath) {\n mmdbPath = cache.mmdbctlPath;\n } else {\n consola.start('Verifying system dependencies...');\n mmdbPath = await __ensureMmdbctl();\n cache.mmdbctlPath = mmdbPath;\n }\n\n let contactInfo: string | undefined = '';\n if (cache.useragent) {\n contactInfo = cache.useragent;\n } else {\n contactInfo = await __askForUserAgent();\n cache.useragent = contactInfo;\n }\n\n if (fs.existsSync(sentinel)) {\n consola.success('Data sources already initialized. Run `bot-detector refresh` to update them.');\n return;\n }\n\n cache.selectedDataTypes = [\"BGP\", \"City\", \"Geography\", \"Proxy\", \"Tor\", \"SEO\", \"firehol_l1\", \"firehol_l2\", \"firehol_l3\", \"firehol_l4\", \"firehol_anonymous\", \"JA4\", \"UserAgent\"];\n cache.outPutPath = output;\n await __cache()._setCache(cache);\n\n consola.start('Compiling all data sources...');\n\n await Promise.all([\n getBGPAndASN(contactInfo, output, mmdbPath),\n buildCitiesData(output, mmdbPath),\n getTorLists(output, mmdbPath),\n getGeoDatas(output, mmdbPath),\n getListOfProxies(output, mmdbPath),\n getThreatLists(output, mmdbPath, true),\n getCrawlersIps(output, mmdbPath),\n getUserAgentLmdbList(output),\n getJaDatabaseLmdb(output)\n ]);\n\n consola.success('All data successfully compiled. You can now start using bot-detector.');\n }\n});","import { defineCommand } from 'citty';\nimport { __cache, __restartData } from '@riavzon/shield-base/internal';\nimport { InputCache } from '@riavzon/shield-base';\nimport consola from 'consola';\nimport { getLibraryRoot } from '@db/findDataPath.js';\nimport path from 'path';\n\n\nexport const refreshData = defineCommand({\n meta: {\n name: 'refresh',\n description: 'Refresh the local data sources the bot-detector use internally'\n },\n \n async run() {\n const cache: Partial<InputCache> = await __cache()._getCache() ?? {};\n \n if (!cache.outPutPath || !cache.mmdbctlPath || Object.keys(cache).length === 0) {\n consola.error('No data to restart, please first run the installation wizard');\n throw new Error();\n }\n\n const output = path.resolve(getLibraryRoot(), '_data-sources');\n consola.start('Restarting data sources...');\n\n await __restartData(output, true);\n\n consola.success(`✨ All data successfully restarted!`);\n }\n});","import z from \"zod\";\nimport type { CacheConfig } from \"./storageTypes.js\";\nimport { DbConfig } from \"./dbTypes.js\";\n\n\n\nconst dbConfigStorage = z.custom<DbConfig>(\n (val: unknown): val is DbConfig => {\n if (typeof val !== 'object' || val === null) {\n return false;\n }\n const obj = val as DbConfig;\n return typeof obj.driver === 'string';\n },\n { message: 'Database config must be an object with a valid \"driver\" string' }\n);\n\nconst store = z.object({\n main: dbConfigStorage,\n}).required().strict();\n\nconst cache = z.custom<CacheConfig>(\n (val: unknown): val is CacheConfig => {\n if (typeof val !== 'object' || val === null) {\n return false;\n }\n const obj = val as CacheConfig;\n return typeof obj.driver === 'string';\n },\n { message: 'Storage must be an object with a valid \"driver\" string' }\n);\n\nexport const configSchema = z.object({\n store,\n /**\n * Total ban threshold the system accumaltae before banning.\n */\n banScore: z.number().max(100).min(0).default(100),\n /**\n * Total ban score the system can assign.\n */\n maxScore: z.number().max(100).min(0).default(100),\n /**\n * Total score to restore for the next visitor request.\n */\n restoredReputationPoints: z.number().default(10),\n /**\n * setNewComputedScore\n * -------------------\n * Controls how the bot-detector and the reputation-healer cooperate.\n *\n * true ▸ **Live snapshot mode** \n * – Every request:\n * 1. Bot-detector recalculates a fresh `botScore` \n * 2. Row in **visitors** is overwritten with that score \n * 3. Cache is refreshed with the same value \n * 4. Reputation-healer subtracts `restoredReputationPoints`\n * (if the visitor isn’t banned) and writes the lower score back\n * to DB & cache.\n * – Net effect: score oscillates \n * `computed → healed → computed → healed …` \n * Useful when you want the latest risk snapshot visible in the DB\n * after every page view.\n *\n * false ▸ **Snapshot-then-heal mode** \n * – First request for this canary: \n * detector writes the computed score (e.g. 8) to DB & cache. \n * – Subsequent requests while the cache entry lives: \n * detector skips the overwrite → healer slowly counts the\n * score down (`–restoredReputationPoints` per hit) and commits\n * the lower value. \n * – When the cache expires (TTL) or the visitor clears cookies,\n * a fresh snapshot is taken and the cycle restarts.\n * – Net effect: score only **decreases** until a new snapshot is taken.\n *\n * Example\n * -------\n * banScore = 10, restoredReputationPoints = 1\n * R = reqeast\n * Flag = true\n * ───────────\n * R1: detector 8 ➜ DB 8 ➜ healer 7\n * R2: detector 8 ➜ DB 8 ➜ healer 7\n *\n * Flag = false\n * ────────────\n * R1: detector 8 ➜ DB 8, cache 8\n * R2: detector (skip) ➜ healer 7 ➜ DB 7, cache 7\n * R3: detector (skip) ➜ healer 6 ➜ DB 6, cache 6\n *\n * Choose **true** when you always want the latest computed risk stored. \n * Choose **false** when you prefer a single snapshot that only decays until\n * the cache is refreshed.\n */\n setNewComputedScore: z.boolean().default(false),\n whiteList: z.array(z.union([z.ipv4(), z.ipv6(), z.string()])).optional().default([]),\n checksTimeRateControl: z.object({\n checkEveryRequest: z.boolean().default(true),\n checkEvery: z.number().default(1000 * 60 * 5),\n }).prefault({}),\n\n batchQueue: z.object({\n flushIntervalMs: z.number().default(5000),\n maxBufferSize: z.number().default(100),\n maxRetries: z.number().default(3),\n }).prefault({}),\n\n storage: cache.optional(),\n \n checkers: z.object({\n localeMapsCheck: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n ipAndHeaderMismatch: z.number().default(20),\n missingHeader: z.number().default(20),\n missingGeoData: z.number().default(20),\n malformedHeader: z.number().default(30)\n }).prefault({}),\n })\n ]).prefault({enable: true}),\n\n knownBadUserAgents: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n criticalSeverity: z.number().default(100),\n highSeverity: z.number().default(80),\n mediumSeverity: z.number().default(30),\n lowSeverity: z.number().default(10),\n }).prefault({})\n })\n ]).prefault({enable: true}),\n \n enableIpChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n penalties: z.number().default(10)\n })\n ]).prefault({enable: true}),\n\n enableGoodBotsChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }), \n\n z.object({\n enable: z.literal(true),\n /**\n * If settings.banUnlistedBots is true any bot not listed in suffix.json or botsWithoutSuffix will be banned.\n * Everything else exact names and any unknown bots when banning is off—hits the IP-range check..\n */\n banUnlistedBots: z.boolean().default(true),\n penalties: z.number().default(100)\n })\n\n ]).prefault({enable: true}),\n\n enableBehaviorRateCheck: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n behavioral_window: z.number().default(60_000),\n behavioral_threshold: z.number().default(30),\n penalties: z.number().default(60)\n }) \n ]).prefault({enable: true}),\n\n enableProxyIspCookiesChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n \n z.object({\n enable: z.literal(true),\n penalties: z.object({\n cookieMissing: z.number().default(80),\n proxyDetected: z.number().default(40),\n multiSourceBonus2to3: z.number().default(10),\n multiSourceBonus4plus: z.number().default(20),\n hostingDetected: z.number().default(50),\n ispUnknown: z.number().default(10),\n orgUnknown: z.number().default(10),\n }).prefault({}),\n }),\n ]).prefault({enable: true}),\n\n enableUaAndHeaderChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n headlessBrowser: z.number().default(100),\n shortUserAgent: z.number().default(80),\n tlsCheckFailed: z.number().default(60),\n badUaChecker: z.boolean().default(true) \n\n }).prefault({}),\n })\n ]).prefault({enable: true}),\n\n enableBrowserAndDeviceChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n penalties: z.object({ \n cliOrLibrary: z.number().default(100),\n internetExplorer: z.number().default(100),\n linuxOs: z.number().default(10),\n impossibleBrowserCombinations: z.number().default(30),\n browserTypeUnknown: z.number().default(10),\n browserNameUnknown: z.number().default(10),\n desktopWithoutOS: z.number().default(10),\n deviceVendorUnknown: z.number().default(10),\n browserVersionUnknown: z.number().default(10),\n deviceModelUnknown: z.number().default(5),\n }).prefault({}),\n })\n \n ]).prefault({enable: true}),\n\n enableGeoChecks: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n z.object({\n enable: z.literal(true),\n bannedCountries: z.array(z.string()).optional().default([]),\n penalties: z.object({ \n countryUnknown: z.number().default(10),\n regionUnknown: z.number().default(10),\n latLonUnknown: z.number().default(10),\n districtUnknown: z.number().default(10),\n cityUnknown: z.number().default(10),\n timezoneUnknown: z.number().default(10),\n subregionUnknown: z.number().default(10),\n phoneUnknown: z.number().default(10),\n continentUnknown: z.number().default(10),\n }).prefault({}),\n }),\n ]).prefault({enable: true}),\n\n enableKnownThreatsDetections: z.discriminatedUnion('enable', [\n z.object({\n enable: z.literal(false)\n }),\n\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n anonymiseNetwork: z.number().default(20),\n threatLevels: z.object({\n criticalLevel1: z.number().default(40),\n currentAttacksLevel2: z.number().default(30),\n threatLevel3: z.number().default(20),\n threatLevel4: z.number().default(10),\n }).prefault({}),\n }).prefault({})\n }),\n ]).prefault({enable: true}),\n\n enableAsnClassification: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n contentClassification: z.number().default(20),\n unknownClassification: z.number().default(10),\n lowVisibilityPenalty: z.number().default(10),\n lowVisibilityThreshold: z.number().default(15),\n comboHostingLowVisibility: z.number().default(20),\n }).prefault({}),\n }),\n ]).prefault({ enable: true }),\n\n enableTorAnalysis: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n runningNode: z.number().default(15),\n exitNode: z.number().default(20),\n webExitCapable: z.number().default(15),\n guardNode: z.number().default(10),\n badExit: z.number().default(40),\n obsoleteVersion: z.number().default(10),\n }).prefault({}),\n }),\n ]).prefault({ enable: true }),\n\n enableTimezoneConsistency: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.number().default(20),\n }),\n ]).prefault({ enable: true }),\n\n honeypot: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n paths: z.array(z.string()).default([]),\n }),\n ]).prefault({ enable: true }),\n\n enableSessionCoherence: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n penalties: z.object({\n pathMismatch: z.number().default(10),\n missingReferer: z.number().default(20),\n domainMismatch: z.number().default(30),\n }).prefault({}),\n }),\n ]).prefault({ enable: true }),\n\n enableVelocityFingerprint: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n cvThreshold: z.number().default(0.1),\n penalties: z.number().default(40),\n }),\n ]).prefault({ enable: true }),\n\n enableKnownBadIpsCheck: z.discriminatedUnion('enable', [\n z.object({ enable: z.literal(false) }),\n z.object({\n enable: z.literal(true),\n highRiskPenalty: z.number().default(30),\n }),\n ]).prefault({ enable: true }),\n }).prefault({}),\n\n generator: z.object({\n scoreThreshold: z.number().default(70),\n generateTypes: z.boolean().default(false),\n deleteAfterBuild: z.boolean().default(false),\n mmdbctlPath: z.string().default('mmdbctl')\n }).prefault({}),\n\n headerOptions: z.object({\n weightPerMustHeader: z.number().default(20),\n missingBrowserEngine: z.number().default(30),\n postManOrInsomiaHeaders: z.number().default(50),\n AJAXHeaderExists: z.number().default(30),\n connectionHeaderIsClose: z.number().default(20),\n originHeaderIsNULL: z.number().default(10),\n originHeaderMismatch: z.number().default(30),\n omittedAcceptHeader: z.number().default(30),\n\n clientHintsMissingForBlink: z.number().default(30),\n teHeaderUnexpectedForBlink: z.number().default(10),\n clientHintsUnexpectedForGecko: z.number().default(30),\n teHeaderMissingForGecko: z.number().default(20),\n \n aggressiveCacheControlOnGet: z.number().default(15),\n crossSiteRequestMissingReferer: z.number().default(10),\n inconsistentSecFetchMode: z.number().default(20),\n\n hostMismatchWeight: z.number().default(40),\n }).prefault({}),\n\n pathTraveler: z.object({\n maxIterations: z.number().default(3),\n maxPathLength: z.number().default(1500),\n pathLengthToLong: z.number().default(100),\n longDecoding: z.number().default(100),\n traversalDetected: z.number().default(60),\n }).prefault({}),\n\n \n punishmentType: z.object({\n enableFireWallBan: z.boolean().default(false),\n }).prefault({}),\n \n logLevel: z.enum(['debug', 'info', 'warn', 'error', 'fatal']).default('info'),\n});\n\nexport type BotDetectorConfig = z.infer<typeof configSchema>;\nexport type BotDetectorConfigInput = z.input<typeof configSchema>;","import { pino, Logger } from 'pino';\nimport { existsSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { getConfiguration } from '../config/config.js';\n\n\nconst LOG_DIR = path.resolve(process.cwd(), process.env.LOG_DIR || 'bot-detector-logs');\nif (!existsSync(LOG_DIR)) mkdirSync(LOG_DIR, { recursive: true });\n\nconst transport = pino.transport({\n targets: [\n {\n target: 'pino/file',\n level: 'info',\n options: {\n destination: `${LOG_DIR}/info.log`,\n mkdir: true\n }\n },\n {\n target: 'pino/file',\n level: 'warn',\n options: {\n destination: `${LOG_DIR}/warn.log`,\n mkdir: true\n }\n },\n {\n target: 'pino/file',\n level: 'error',\n options: {\n destination: `${LOG_DIR}/errors.log`,\n mkdir:true\n }\n }\n ]\n});\n\nlet logger: pino.Logger; \n\nexport function getLogger(): Logger {\n if (logger) return logger; \n const { logLevel } = getConfiguration();\n logger = (pino) (\n {\n level: logLevel,\n timestamp: pino.stdTimeFunctions.isoTime,\n mixin() { return { uptime: process.uptime() }; },\n redact: {\n paths: [\n '*.password',\n '*.email',\n 'name',\n 'Name',\n '*.cookies',\n '*.cookie',\n 'cookies',\n 'cookie',\n '*.accessToken',\n '*.refresh_token',\n '*.secret'\n ],\n censor: '[SECRET]'\n }\n },\n transport\n );\n return logger;\n}","import type { Database } from 'db0';\n\nexport function isMySQL(db: Database): boolean {\n return db.dialect === 'mysql';\n}\n\nexport function isSQLite(db: Database): boolean {\n return db.dialect === 'sqlite';\n}\n\n/** Convert ? placeholders to $1, $2, for PostgreSQL. */\nexport function prep(db: Database, sql: string) {\n if (db.dialect !== 'postgresql') return db.prepare(sql);\n let i = 0;\n return db.prepare(sql.replace(/\\?/g, () => `$${String(++i)}`));\n}\n\n/** Generate positional placeholders for a dynamic list of values. */\nexport function placeholders(db: Database, count: number, offset = 0): string {\n return Array.from({ length: count }, (_, i) =>\n db.dialect === 'postgresql' ? `$${String(offset + i + 1)}` : '?'\n ).join(', ');\n}\n\n/** NOW() equivalent per dialect. */\nexport function now(db: Database): string {\n return isSQLite(db) ? \"datetime('now')\" : 'NOW()';\n}\n\n/**\n * Upsert conflict clause.\n * MySQL: ON DUPLICATE KEY UPDATE\n * Others: ON CONFLICT(pk) DO UPDATE SET\n */\nexport function onUpsert(db: Database, pk: string): string {\n return isMySQL(db)\n ? 'ON DUPLICATE KEY UPDATE'\n : `ON CONFLICT(${pk}) DO UPDATE SET`;\n}\n\n/**\n * Reference to the incoming row value in an upsert SET clause.\n * MySQL: VALUES(col)\n * Others: excluded.col\n */\nexport function excluded(db: Database, col: string): string {\n return isMySQL(db) ? `VALUES(${col})` : `excluded.${col}`;\n}\n\n/**\n * INSERT IGNORE equivalent.\n * MySQL: INSERT IGNORE INTO\n * SQLite: INSERT OR IGNORE INTO\n * PostgreSQL: INSERT INTO (use onConflictDoNothing() as trailing clause)\n */\nexport function insertIgnore(db: Database): string {\n if (isSQLite(db)) return 'INSERT OR IGNORE INTO';\n if (isMySQL(db)) return 'INSERT IGNORE INTO';\n return 'INSERT INTO';\n}\n\n/** Trailing ON CONFLICT DO NOTHING clause, for PostgreSQL. */\nexport function onConflictDoNothing(db: Database): string {\n return db.dialect === 'postgresql' ? 'ON CONFLICT DO NOTHING' : '';\n}\n","import consola from 'consola';\nimport type { IBotChecker, BanReasonCode } from '../types/checkersTypes.js';\nimport type { BotDetectorConfig } from '../types/configSchema.js';\n\nlet registeredCheckers: IBotChecker<BanReasonCode>[] = [];\n\nexport const CheckerRegistry = {\n register(checker: IBotChecker<BanReasonCode>) {\n consola.log(`Loaded plugin: ${checker.name}`);\n registeredCheckers.push(checker);\n },\n\n getEnabled(phase: 'cheap' | 'heavy', config: BotDetectorConfig): IBotChecker<BanReasonCode>[] {\n return registeredCheckers.filter(\n checker => checker.phase === phase && checker.isEnabled(config)\n );\n },\n\n clear() {\n registeredCheckers = [];\n },\n};\n","import { BanReasonCode, IBotChecker } from '../types/checkersTypes.js';\nimport { BotDetectorConfig } from '../types/configSchema.js';\nimport { ValidationContext } from '../types/botDetectorTypes.js';\nimport { CheckerRegistry } from './CheckerRegistry.js';\nimport { getDataSources } from '../config/config.js';\n\nconst SEVERITY_ORDER = ['critical', 'high', 'medium', 'low'] as const;\ntype Severity = typeof SEVERITY_ORDER[number];\nlet patterns: { rx: RegExp; severity: Severity }[] = [];\n\nexport function loadUaPatterns(): void {\n const db = getDataSources().getUserAgentLmdb();\n const bucketStrings = new Map<Severity, string[]>(\n SEVERITY_ORDER.map(sev => [sev, []])\n );\n\n for (const { value } of db.getRange({ limit: 10_000 })) {\n const sev = value.metadata_severity as Severity;\n bucketStrings.get(sev)?.push(value.useragent_rx);\n }\n\n patterns = SEVERITY_ORDER.map(severity => {\n const patterns = bucketStrings.get(severity) ?? [];\n if (patterns.length === 0) return null;\n \n const combined = patterns.map(p => `(?:${p})`).join('|');\n return {\n rx: new RegExp(combined, 'i'),\n severity\n };\n }).filter((p): p is { rx: RegExp; severity: Severity } => p !== null);\n}\n\nexport class BadUaChecker implements IBotChecker<BanReasonCode> {\n name = 'Bad User Agent list';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig) {\n return config.checkers.knownBadUserAgents.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const { knownBadUserAgents } = config.checkers;\n const reasons: 'BAD_UA_DETECTED'[] = [];\n let score = 0;\n\n if (!knownBadUserAgents.enable) return { score, reasons };\n\n if (patterns.length === 0) {\n loadUaPatterns();\n }\n\n const rawUa = ctx.req.get('User-Agent') ?? '';\n for (const { rx, severity } of patterns) {\n if (rx.test(rawUa)) {\n reasons.push('BAD_UA_DETECTED');\n switch (severity) {\n case 'critical': score += knownBadUserAgents.penalties.criticalSeverity; break;\n case 'high': score += knownBadUserAgents.penalties.highSeverity; break;\n case 'medium': score += knownBadUserAgents.penalties.mediumSeverity; break;\n case 'low': score += knownBadUserAgents.penalties.lowSeverity; break;\n }\n break;\n }\n }\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new BadUaChecker());","import { createConfigManager } from \"@riavzon/utils\";\nimport type { BotDetectorConfig as Configuration, BotDetectorConfigInput } from \"../types/configSchema.js\";\nimport { configSchema } from \"../types/configSchema.js\";\nimport { DataSources } from \"../helpers/mmdbDataReaders.js\";\nimport { BatchQueue } from \"../db/batchQueue.js\";\nimport { initStorage } from \"./storageAdapter.js\";\nimport type { Storage } from 'unstorage';\nimport { initDb } from \"./dbAdapter.js\";\nimport { type Database } from \"db0\";\nimport { loadUaPatterns } from \"../checkers/badUaChecker.js\";\nimport consola from \"consola\";\n\n\nconst {\n defineConfiguration,\n getConfiguration\n} = createConfigManager<Configuration>(configSchema, \"Bot Detector\");\n\nlet globalDataSources: DataSources | undefined;\nlet globalBatchQueue: BatchQueue | undefined;\nlet globalStorage: Storage | undefined;\nlet globalDb: Database | undefined;\n\n/**\n * @description\n * The bot detector library's configuration object.\n * Contains the core configuration to make the library usable client side.\n * @module jwtAuth/config\n * @see {@link ./jwtAuth/types/configSchema.js}\n */\nexport async function configuration(config: BotDetectorConfigInput): Promise<void> {\n const initDataSourcesTask = async () => {\n globalDataSources ??= await DataSources.initialize();\n loadUaPatterns();\n };\n\n const initBatchQueueTask = () => {\n if (!globalBatchQueue) {\n globalBatchQueue = new BatchQueue();\n process.on('SIGTERM', () => { void globalBatchQueue?.shutdown(); });\n process.on('SIGINT', () => { void globalBatchQueue?.shutdown(); });\n }\n };\n\n const initStorageTask = async () => {\n globalStorage ??= await initStorage(config.storage);\n };\n\n const initDbTask = async () => {\n globalDb ??= await initDb(config.store.main);\n };\n\n await defineConfiguration(config, [\n initDataSourcesTask,\n initBatchQueueTask,\n initStorageTask,\n initDbTask\n ]);\n}\n\n\nexport { getConfiguration };\n\nexport function getBatchQueue(): BatchQueue {\n if (!globalBatchQueue) {\n consola.trace(\"Premature getBatchQueue() call\");\n throw new Error('BatchQueue not ready. Call configuration() first.');\n }\n return globalBatchQueue;\n}\n\nexport function getStorage(): Storage {\n if (!globalStorage) {\n consola.trace(\"Premature getStorage() call\");\n throw new Error('Storage not ready. Call configuration() first.');\n }\n return globalStorage;\n}\n\nexport function getDb(): Database {\n if (!globalDb) {\n consola.trace(\"Premature getDb() call\");\n throw new Error('DB not ready. Call configuration() first.');\n }\n return globalDb;\n}\n\nexport function getDataSources(): DataSources {\n if (!globalDataSources) {\n consola.trace(\"Premature getDataSources() call\");\n throw new Error(`##### Must be initialized globally #####\n Bot Detector: DataSources not ready. Call configuration() first.`\n );\n }\n return globalDataSources;\n}\n","import { compiler } from '@riavzon/shield-base';\nimport { getDb, getConfiguration } from '../config/config.js';\nimport { getLogger } from '../utils/logger.js';\nimport path from 'node:path';\nimport { BannedRecord, BannedRow, HighRiskRecord, HighRiskRow } from '../types/generator.js';\nimport { prep, placeholders } from './dialectUtils.js';\nimport { getLibraryRoot } from './findDataPath.js';\n\nconst MMDB_DIR = path.resolve(getLibraryRoot(), '_data-sources');\n\nasync function buildBannedMmdb(generateTypes: boolean, mmdbctlPath: string): Promise<void> {\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'generator', db: 'banned' });\n const db = getDb();\n\n const rows = await db.prepare(\n `SELECT ip_address, country, user_agent, reason, score\n FROM banned\n WHERE ip_address IS NOT NULL`\n ).all() as BannedRow[];\n\n if (rows.length === 0) {\n log.info('No banned IPs — skipping banned.mmdb');\n return;\n }\n\n const data: BannedRecord[] = rows.map(r => ({\n range: r.ip_address,\n score: r.score,\n country: r.country,\n userAgent: r.user_agent,\n reason: r.reason,\n comment: 'Automatically generated by @riavzon/botDetector',\n }));\n await compiler<BannedRecord>({ type: 'mmdb', input: { data, dataBaseName: 'banned', outputPath: MMDB_DIR, mmdbPath: mmdbctlPath, generateTypes } });\n log.info(`banned.mmdb compiled — ${String(data.length)} entries`);\n\n if (getConfiguration().generator.deleteAfterBuild) {\n const compiled = rows.map(r => r.ip_address);\n const ph = placeholders(db, compiled.length);\n await prep(db, `DELETE FROM banned WHERE ip_address IN (${ph})`).run(...compiled);\n log.info(`Deleted ${(String(compiled.length))} rows from banned after build`);\n }\n}\n\n\nasync function buildHighRiskMmdb(scoreThreshold: number, generateTypes: boolean, mmdbctlPath: string): Promise<void> {\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'generator', db: 'highRisk' });\n const db = getDb();\n\n const rows = await prep(db,\n `SELECT\n ip_address, visitor_id, suspicious_activity_score,\n country, region, region_name, city, lat, lon, timezone,\n isp, org, browser, browserType, browserVersion, os,\n device_type, deviceVendor, deviceModel,\n proxy, hosting, request_count, first_seen, last_seen\n FROM visitors\n WHERE suspicious_activity_score >= ? AND ip_address IS NOT NULL`\n ).all(scoreThreshold) as HighRiskRow[];\n\n if (rows.length === 0) {\n log.info(`No high-risk visitors (score >= ${String(scoreThreshold)}) — skipping highRisk.mmdb`);\n return;\n }\n\n const data: HighRiskRecord[] = rows.map(r => ({\n range: r.ip_address,\n visitorId: r.visitor_id,\n score: r.suspicious_activity_score,\n country: r.country,\n region: r.region,\n regionName: r.region_name,\n city: r.city,\n lat: r.lat,\n lon: r.lon,\n timezone: r.timezone,\n isp: r.isp,\n org: r.org,\n browser: r.browser,\n browserType: r.browserType,\n browserVersion: r.browserVersion,\n os: r.os,\n deviceType: r.device_type,\n deviceVendor: r.deviceVendor,\n deviceModel: r.deviceModel,\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n proxy: Boolean(r.proxy),\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n hosting: Boolean(r.hosting),\n requestCount: r.request_count,\n firstSeen: r.first_seen ? r.first_seen.toISOString() : null,\n lastSeen: r.last_seen ? r.last_seen.toISOString() : null,\n comment: 'Automatically generated by @riavzon/botDetector',\n }));\n\n await compiler<HighRiskRecord>({ type: 'mmdb', input: { data, dataBaseName: 'highRisk', outputPath: MMDB_DIR, mmdbPath: mmdbctlPath, generateTypes } });\n log.info(`highRisk.mmdb compiled — ${String(data.length)} entries`);\n\n if (getConfiguration().generator.deleteAfterBuild) {\n const compiled = rows.map(r => r.ip_address);\n const ph = placeholders(db, compiled.length);\n const scorePh = placeholders(db, 1, compiled.length);\n await prep(db,\n `DELETE FROM visitors WHERE ip_address IN (${ph}) AND suspicious_activity_score >= ${scorePh}`\n ).run(...compiled, scoreThreshold);\n log.info(`Deleted ${String(compiled.length)} rows from visitors after build`);\n }\n}\n\n\nasync function runCycle(): Promise<void> {\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'generator' });\n const { generator } = getConfiguration();\n\n log.info('MMDB generation cycle started');\n try {\n await Promise.all([\n buildBannedMmdb(generator.generateTypes, generator.mmdbctlPath),\n buildHighRiskMmdb(generator.scoreThreshold, generator.generateTypes, generator.mmdbctlPath),\n ]);\n log.info('MMDB generation cycle complete');\n } catch (err) {\n log.error({ err }, 'MMDB generation cycle failed');\n }\n}\n\n\nexport async function runGeneration(): Promise<void> {\n return runCycle();\n}","import { runGeneration } from \"@db/generator.js\";\nimport { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { getConfiguration } from \"../../config/config.js\";\nimport { execSync } from \"child_process\";\nimport { __ensureMmdbctl } from \"@riavzon/shield-base/internal\";\n\nexport const cleanUp = defineCommand({\n meta: {\n name: 'generate',\n description: 'Run the generator: reads banned and high-risk visitors from your database and compiles them into an optimized binary (based on your generator configuration)'\n },\n\n async run() { \n const { generator } = getConfiguration();\n try {\n execSync(`${generator.mmdbctlPath} --help`, { stdio: 'ignore' });\n } catch {\n \n consola.warn(`The configurable mmdbctl path cannot be resolved at ${generator.mmdbctlPath}, You will be prompted to install it.`);\n const path = await __ensureMmdbctl();\n consola.box(`mmdbctl installed successfully. Add the next path in generator.mmdbctlPath configuration option and run the command again: ${path}`);\n\n process.exit(1);\n }\n\n consola.start('Starting clean up operation...');\n await runGeneration();\n consola.success('Success!');\n }\n});","import type { Database } from 'db0';\nimport { isMySQL, isSQLite } from './dialectUtils.js';\nimport consola from 'consola';\n\nfunction visitorIdDefault(db: Database): string {\n if (isMySQL(db)) return 'NOT NULL DEFAULT (UUID())';\n if (db.dialect === 'postgresql') return 'NOT NULL DEFAULT gen_random_uuid()';\n return 'NOT NULL';\n}\n\nfunction lastSeenDef(db: Database): string {\n if (isMySQL(db)) return 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';\n if (isSQLite(db)) return 'TEXT DEFAULT CURRENT_TIMESTAMP';\n return 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP';\n}\n\nfunction tableOptions(db: Database): string {\n return isMySQL(db) ? 'ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci' : '';\n}\n\nfunction timestampType(db: Database): string {\n return isSQLite(db) ? 'TEXT' : 'TIMESTAMP';\n}\n\nexport async function createTables(db: Database): Promise<void> {\n const visitorId = visitorIdDefault(db);\n const lastSeen = lastSeenDef(db);\n const tblOpts = tableOptions(db);\n const tsType = timestampType(db);\n\n const createVisitorsTable = `\n CREATE TABLE IF NOT EXISTS visitors (\n visitor_id CHAR(36) ${visitorId},\n canary_id VARCHAR(64) PRIMARY KEY,\n ip_address VARCHAR(45),\n user_agent TEXT,\n country VARCHAR(64),\n region VARCHAR(64),\n region_name VARCHAR(350),\n city VARCHAR(64),\n district VARCHAR(260),\n lat VARCHAR(150),\n lon VARCHAR(150),\n timezone VARCHAR(64),\n currency VARCHAR(64),\n isp VARCHAR(64),\n org VARCHAR(64),\n as_org VARCHAR(64),\n device_type VARCHAR(64),\n browser VARCHAR(64),\n proxy BOOLEAN,\n hosting BOOLEAN,\n is_bot BOOLEAN DEFAULT false,\n first_seen ${tsType} DEFAULT CURRENT_TIMESTAMP,\n last_seen ${lastSeen},\n request_count INT DEFAULT 1,\n deviceVendor VARCHAR(64) DEFAULT 'unknown',\n deviceModel VARCHAR(64) DEFAULT 'unknown',\n browserType VARCHAR(64) DEFAULT 'unknown',\n browserVersion VARCHAR(64) DEFAULT 'unknown',\n os VARCHAR(64) DEFAULT 'unknown',\n suspicious_activity_score INT DEFAULT 0\n ) ${tblOpts}\n `;\n\n const createBannedTable = `\n CREATE TABLE IF NOT EXISTS banned (\n canary_id VARCHAR(64) PRIMARY KEY,\n ip_address VARCHAR(45),\n country VARCHAR(64),\n user_agent TEXT,\n reason TEXT,\n score INT DEFAULT NULL,\n FOREIGN KEY (canary_id) REFERENCES visitors(canary_id)\n )\n `;\n\n try {\n await db.exec(createVisitorsTable);\n await db.exec(createBannedTable);\n\n consola.success('Tables created successfully.');\n } catch (error) {\n consola.error('Error creating tables:', error);\n throw error;\n }\n}","import { defineCommand } from \"citty\";\nimport consola from \"consola\";\nimport { createTables } from \"@db/schema.js\";\nimport { getDb } from \"../../config/config.js\";\n\nexport const makeTables = defineCommand({\n meta: {\n name: 'load-schema',\n description: 'Create database tables'\n },\n\n async run() {\n const db = getDb();\n consola.start(`Creating tables for ${db.dialect}...`);\n await createTables(db);\n }\n});","#!/usr/bin/env node\n\nimport { defineCommand, runMain } from 'citty';\nimport { startCommand } from './commands/start.js';\nimport { refreshData } from './commands/refresh.js';\nimport { cleanUp } from './commands/cleanUp.js';\nimport { makeTables } from './commands/makeTables.js';\n\nexport const main = defineCommand({\n meta: {\n name: 'bot-detector',\n description: 'Automatic traffic analysis and detection',\n version: '1.0.0'\n },\n subCommands: {\n init: startCommand,\n refresh: refreshData,\n generate: cleanUp,\n 'load-schema': makeTables\n },\n});\n\nawait runMain(main);\n"],"mappings":"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"}
|
package/dist/main.cjs
CHANGED
|
@@ -209,7 +209,7 @@ const configSchema = zod.default.object({
|
|
|
209
209
|
enable: zod.default.literal(true),
|
|
210
210
|
highRiskPenalty: zod.default.number().default(30)
|
|
211
211
|
})]).prefault({ enable: true })
|
|
212
|
-
}),
|
|
212
|
+
}).prefault({}),
|
|
213
213
|
generator: zod.default.object({
|
|
214
214
|
scoreThreshold: zod.default.number().default(70),
|
|
215
215
|
generateTypes: zod.default.boolean().default(false),
|