@riavzon/bot-detector 1.0.13 → 1.0.15
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/dist/index.mjs.map +1 -1
- package/dist/main.cjs +6 -6
- package/dist/main.cjs.map +1 -1
- package/dist/main.mjs +6 -6
- package/dist/main.mjs.map +1 -1
- package/package.json +1 -1
package/dist/main.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.mjs","names":["path","existsSync","PREFIX","PREFIX","URL","path","PREFIX","PREFIX","PREFIX"],"sources":["../src/botDetector/types/configSchema.ts","../src/botDetector/db/findDataPath.ts","../src/botDetector/helpers/mmdbDataReaders.ts","../src/botDetector/utils/logger.ts","../src/botDetector/db/dialectUtils.ts","../src/botDetector/db/updateBanned.ts","../src/botDetector/db/updateIsBot.ts","../src/botDetector/db/updateVisitors.ts","../src/botDetector/db/updateVisitorScore.ts","../src/botDetector/db/batchQueue.ts","../src/botDetector/config/storageAdapter.ts","../src/botDetector/config/dbAdapter.ts","../src/botDetector/checkers/CheckerRegistry.ts","../src/botDetector/checkers/badUaChecker.ts","../src/botDetector/config/config.ts","../src/botDetector/helpers/getIPInformation.ts","../src/botDetector/utils/cookieGenerator.ts","../src/botDetector/helpers/UAparser.ts","../src/botDetector/checkers/ipValidation.ts","../src/botDetector/helpers/cache/dnsLookupCache.ts","../src/botDetector/checkers/goodBots/base.ts","../src/botDetector/checkers/goodBots/goodBots.ts","../src/botDetector/checkers/browserTypesAneDevicesCalc.ts","../src/botDetector/utils/regex/acceptLangRegex.ts","../src/botDetector/checkers/acceptLangMap.ts","../src/botDetector/helpers/cache/rateLimitarCache.ts","../src/botDetector/checkers/rateTracker.ts","../src/botDetector/checkers/proxyISPAndCookieCalc.ts","../src/botDetector/checkers/headers/headersBase.ts","../src/botDetector/checkers/headers/headers.ts","../src/botDetector/utils/regex/pathTravelersRegex.ts","../src/botDetector/checkers/UaAndHeaderChecker/base.ts","../src/botDetector/checkers/UaAndHeaderChecker/headersAndUACalc.ts","../src/botDetector/checkers/geoLocationCalc.ts","../src/botDetector/checkers/fireholEscalation.ts","../src/botDetector/checkers/asnClassification.ts","../src/botDetector/checkers/torAnalysis.ts","../src/botDetector/checkers/timezoneConsistency.ts","../src/botDetector/checkers/honeypot.ts","../src/botDetector/helpers/cache/sessionCache.ts","../src/botDetector/checkers/sessionCoherence.ts","../src/botDetector/helpers/cache/timingCache.ts","../src/botDetector/checkers/velocityFingerprint.ts","../src/botDetector/checkers/knownBadIps.ts","../src/botDetector/helpers/exceptions.ts","../src/botDetector/penalties/banIP.ts","../src/botDetector/helpers/processChecks.ts","../src/botDetector/helpers/cache/reputationCache.ts","../src/botDetector.ts","../src/botDetector/helpers/cache/cannaryCache.ts","../src/botDetector/helpers/reputation.ts","../src/botDetector/utils/whitelist.ts","../src/botDetector/utils/nowMysql.ts","../src/botDetector/middlewares/canaryCookieChecker.ts","../src/botDetector/routes/visitorLog.ts","../src/botDetector/db/generator.ts","../src/botDetector/db/schema.ts","../src/botDetector/db/warmUp.ts","../src/botDetector/db/customUpdate.ts"],"sourcesContent":["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 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 maxmind, { Reader } from 'maxmind';\nimport { open, type RootDatabase } from 'lmdb';\nimport type { BgpRecord, CityGeoRecord, GeoRecord, TorRecord, ThreatRecord, CrawlersRecord, ProxyRecord, UserAgentRecord, JA4 } from '@riavzon/shield-base';\nimport type { BannedRecord, HighRiskRecord } from '../types/generator.js';\nimport { existsSync } from \"node:fs\";\nimport { resolveDataPath } from '@db/findDataPath.js';\n\nexport type ThreatRecordModified = ThreatRecord & { network: string }\n\nexport interface DataReaders {\n asnDataBase(ip: string): BgpRecord | null;\n cityDataBase(ip: string): CityGeoRecord | null;\n countryDataBase(ip: string): GeoRecord | null;\n goodBotsDataBase(ip: string): CrawlersRecord | null;\n torDataBase(ip: string): TorRecord | null;\n proxyDataBase(ip: string): ProxyRecord | null;\n fireholAnonDataBase(ip: string): ThreatRecordModified | null;\n fireholLvl1DataBase(ip: string): ThreatRecordModified | null;\n fireholLvl2DataBase(ip: string): ThreatRecordModified | null;\n fireholLvl3DataBase(ip: string): ThreatRecordModified | null;\n fireholLvl4DataBase(ip: string): ThreatRecordModified | null;\n bannedDataBase(ip: string): BannedRecord | null;\n highRiskDataBase(ip: string): HighRiskRecord | null;\n getUserAgentLmdb(): RootDatabase<UserAgentRecord, string>;\n getJa4Lmdb(): RootDatabase<JA4, string>;\n}\n\nexport interface AppReaders {\n asn: Reader<BgpRecord & maxmind.Response>;\n city: Reader<CityGeoRecord & maxmind.Response>;\n country: Reader<GeoRecord & maxmind.Response>;\n goodBots: Reader<CrawlersRecord & maxmind.Response>;\n tor: Reader<TorRecord & maxmind.Response>;\n proxy: Reader<ProxyRecord & maxmind.Response>;\n fireholAnon: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl1: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl2: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl3: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl4: Reader<ThreatRecordModified & maxmind.Response>;\n banned?: Reader<BannedRecord & maxmind.Response>;\n highRisk?: Reader<HighRiskRecord & maxmind.Response>;\n userAgentLmdb: RootDatabase<UserAgentRecord, string>;\n ja4Lmdb: RootDatabase<JA4, string>;\n}\n\n\nexport class DataSources implements DataReaders {\n private readonly readers: AppReaders;\n private constructor(readers: AppReaders) {\n this.readers = readers;\n }\n\n public static async initialize(): Promise<DataSources> {\n const options = { watchForUpdates: process.env.NODE_ENV !== 'test' };\n \n const [asn, city, country, goodBots, tor, proxy, fireholAnon, fireholLvl1, fireholLvl2, fireholLvl3, fireholLvl4] = await Promise.all([\n maxmind.open<BgpRecord & maxmind.Response>(resolveDataPath('asn.mmdb'), options),\n maxmind.open<CityGeoRecord & maxmind.Response>(resolveDataPath('city.mmdb'), options),\n maxmind.open<GeoRecord & maxmind.Response>(resolveDataPath('country.mmdb'), options),\n maxmind.open<CrawlersRecord& maxmind.Response>(resolveDataPath('goodBots.mmdb'), options),\n maxmind.open<TorRecord & maxmind.Response>(resolveDataPath('tor.mmdb'), options),\n maxmind.open<ProxyRecord & maxmind.Response>(resolveDataPath('proxy.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_anonymous.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l1.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l2.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l3.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l4.mmdb'), options),\n ]);\n\n const bannedPath = resolveDataPath('banned.mmdb');\n const highRiskPath = resolveDataPath('highRisk.mmdb');\n\n const [banned, highRisk] = await Promise.all([\n existsSync(bannedPath) ? maxmind.open<BannedRecord & maxmind.Response>(bannedPath, options): Promise.resolve(undefined),\n existsSync(highRiskPath) ? maxmind.open<HighRiskRecord & maxmind.Response>(highRiskPath, options): Promise.resolve(undefined),\n ]);\n\n const userAgentLmdb = open<UserAgentRecord, string>({\n path: resolveDataPath('useragent-db/useragent.mdb'),\n name: 'useragent',\n compression: true,\n readOnly: true,\n useVersions: true,\n sharedStructuresKey: Symbol.for('structures'),\n pageSize: 4096,\n cache: {\n validated: true\n },\n noReadAhead: true,\n maxReaders: 2024,\n });\n\n const ja4Lmdb = open<JA4, string>({\n path: resolveDataPath('ja4-db/ja4.mdb'),\n name: 'ja4',\n compression: true,\n readOnly: true,\n useVersions: true,\n sharedStructuresKey: Symbol.for('structures'),\n pageSize: 4096,\n cache: {\n validated: true\n },\n noReadAhead: true,\n maxReaders: 2024,\n });\n\n return new DataSources({\n asn,\n city,\n country,\n goodBots,\n tor,\n proxy,\n fireholAnon,\n fireholLvl1,\n fireholLvl2,\n fireholLvl3,\n fireholLvl4,\n banned,\n highRisk,\n userAgentLmdb,\n ja4Lmdb,\n });\n }\n \n public asnDataBase(ip: string): BgpRecord | null {\n const result: BgpRecord | null = this.readers.asn.get(ip);\n return result;\n }\n\n public cityDataBase(ip: string): CityGeoRecord | null {\n const result: CityGeoRecord | null = this.readers.city.get(ip);\n return result;\n }\n\n public countryDataBase(ip: string): GeoRecord | null {\n const result: GeoRecord | null = this.readers.country.get(ip);\n return result;\n }\n\n public goodBotsDataBase(ip: string): CrawlersRecord | null {\n const result: CrawlersRecord | null = this.readers.goodBots.get(ip);\n return result;\n }\n\n public torDataBase(ip: string): TorRecord | null {\n const result: TorRecord | null = this.readers.tor.get(ip);\n return result;\n }\n\n public proxyDataBase(ip: string): ProxyRecord | null {\n const result: ProxyRecord | null = this.readers.proxy.get(ip);\n return result;\n }\n\n public fireholAnonDataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholAnon.get(ip);\n return result;\n }\n\n public fireholLvl1DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl1.get(ip);\n return result;\n }\n\n public fireholLvl2DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl2.get(ip);\n return result;\n }\n\n public fireholLvl3DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl3.get(ip);\n return result;\n }\n\n public fireholLvl4DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl4.get(ip);\n return result;\n }\n\n public bannedDataBase(ip: string): BannedRecord | null {\n return this.readers.banned?.get(ip) ?? null;\n }\n\n public highRiskDataBase(ip: string): HighRiskRecord | null {\n return this.readers.highRisk?.get(ip) ?? null;\n }\n\n public getUserAgentLmdb(): RootDatabase<UserAgentRecord, string> {\n return this.readers.userAgentLmdb;\n }\n\n public getJa4Lmdb(): RootDatabase<JA4, string> {\n return this.readers.ja4Lmdb;\n }\n\n}\n","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 { getLogger } from '../utils/logger.js';\nimport type { BannedInfo } from '../types/checkersTypes.js';\nimport { getDb } from '../config/config.js';\nimport { prep, onUpsert, excluded } from './dialectUtils.js';\n\nexport async function updateBannedIP(\n cookie: string,\n ipAddress: string,\n country: string,\n user_agent: string,\n info: BannedInfo\n) {\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'db', type: 'updateBannedIP' });\n const reasonPayload = JSON.stringify(info.reasons);\n const params = [cookie, ipAddress, country, user_agent, reasonPayload, info.score] satisfies (string | number)[];\n \n const ex = (col: string) => excluded(db, col);\n const upsert = onUpsert(db, 'canary_id');\n try {\n await prep(db,\n `INSERT INTO banned (canary_id, ip_address, country, user_agent, reason, score)\n VALUES (?, ?, ?, ?, ?, ?)\n ${upsert}\n ip_address = ${ex('ip_address')},\n country = ${ex('country')},\n user_agent = ${ex('user_agent')},\n score = ${ex('score')},\n reason = ${ex('reason')}`\n ).run(...params);\n log.info(`Updated Database TABLE - banned. A user has been banned for IP ${ipAddress} (score ${String(info.score)})`);\n } catch (err: unknown) {\n log.error({ err }, 'ERROR UPDATING \"banned\" TABLE');\n throw err;\n }\n}\n","import { getLogger } from '../utils/logger.js';\nimport { getDb } from '../config/config.js';\nimport { prep } from './dialectUtils.js';\n\nexport async function updateIsBot(isBot: boolean, cookie: string) {\n const params = [isBot, cookie] satisfies (string | boolean)[];\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'db', type: 'updateIsBot' });\n\n try { \n await prep(db, `UPDATE visitors SET is_bot = ? WHERE canary_id = ?`).run(...params);\n } catch (err: unknown) {\n log.error({ err }, 'ERROR UPDATING IS_BOT');\n throw err;\n }\n}\n\n ","import { userValidation } from '../types/fingerPrint.js';\nimport { getLogger } from '../utils/logger.js';\nimport { getDb } from '../config/config.js';\nimport { prep, onUpsert, excluded, now } from './dialectUtils.js';\n\nexport async function updateVisitor(u: userValidation) {\n const db = getDb();\n const log = getLogger().child({service: 'BOT DETECTOR', branch: 'db', type: 'updateVisitors'});\n const {\n visitorId,\n cookie,\n ipAddress,\n userAgent,\n country,\n region,\n regionName,\n city,\n district,\n lat,\n lon,\n timezone,\n currency,\n isp,\n org,\n as: asOrg,\n device_type,\n browser,\n proxy,\n hosting,\n is_bot,\n first_seen,\n last_seen,\n request_count,\n deviceVendor,\n deviceModel,\n browserType,\n browserVersion,\n os,\n activity_score,\n } = u;\n const params = [\n visitorId,\n cookie,\n ipAddress,\n userAgent,\n country,\n region,\n regionName,\n city,\n district,\n lat,\n lon,\n timezone,\n currency,\n isp,\n org,\n asOrg,\n device_type,\n browser,\n proxy,\n hosting,\n is_bot,\n first_seen,\n last_seen,\n request_count,\n deviceVendor,\n deviceModel,\n browserType,\n browserVersion,\n os,\n Number(activity_score) || 0,\n ].map(value => value === undefined ? null : value);\n const ex = (col: string) => excluded(db, col);\n const upsert = onUpsert(db, 'canary_id');\n try {\n await prep(db,\n `INSERT INTO visitors (\n visitor_id,\n canary_id,\n ip_address,\n user_agent,\n country,\n region,\n region_name,\n city,\n district,\n lat,\n lon,\n timezone,\n currency,\n isp,\n org,\n as_org,\n device_type,\n browser,\n proxy,\n hosting,\n is_bot,\n first_seen,\n last_seen,\n request_count,\n deviceVendor,\n deviceModel,\n browserType,\n browserVersion,\n os,\n suspicious_activity_score\n ) VALUES (\n ${params.map(() => '?').join(', ')}\n )\n ${upsert}\n ip_address = ${ex('ip_address')},\n user_agent = ${ex('user_agent')},\n country = ${ex('country')},\n region = ${ex('region')},\n region_name = ${ex('region_name')},\n city = ${ex('city')},\n district = ${ex('district')},\n lat = ${ex('lat')},\n lon = ${ex('lon')},\n timezone = ${ex('timezone')},\n currency = ${ex('currency')},\n isp = ${ex('isp')},\n org = ${ex('org')},\n as_org = ${ex('as_org')},\n device_type = ${ex('device_type')},\n browser = ${ex('browser')},\n proxy = ${ex('proxy')},\n hosting = ${ex('hosting')},\n last_seen = ${now(db)},\n request_count = request_count + 1,\n deviceVendor = ${ex('deviceVendor')},\n deviceModel = ${ex('deviceModel')},\n browserType = ${ex('browserType')},\n browserVersion = ${ex('browserVersion')},\n os = ${ex('os')}`\n ).run(...params);\n\n log.info(`Updated visitors table, Visitor row for canary_id=${cookie ?? ''} inserted/updated successfully.`);\n return;\n } catch (err: unknown) {\n log.error({ err },`ERROR UPDATING visitors TABLE`);\n }\n}\n","import { getLogger } from '../utils/logger.js';\nimport { getDb } from '../config/config.js';\nimport { prep } from './dialectUtils.js';\n\nexport async function updateScore(score: number, cookie: string) {\n const params = [score, cookie] satisfies (string | number)[];\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'db', type: 'updateScore' });\n\n try {\n await prep(db, `UPDATE visitors SET suspicious_activity_score = ? WHERE canary_id = ?`).run(...params);\n } catch (err: unknown) {\n log.error({ err }, 'ERROR UPDATING SCORE');\n throw err;\n }\n}\n\n ","import { updateBannedIP } from \"./updateBanned.js\";\nimport { updateIsBot } from \"./updateIsBot.js\";\nimport { updateVisitor } from \"./updateVisitors.js\";\nimport { updateScore } from \"./updateVisitorScore.js\";\nimport { getConfiguration } from \"../config/config.js\";\nimport { OpParams, BatchQueueOps, Priority, BatchJob } from \"../types/batchQueue.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\n\nexport class BatchQueue {\n private jobs = new Map<string, BatchJob>();\n private timer: NodeJS.Timeout | null = null;\n private flushPromise: Promise<void> | null = null;\n\n private get config() {\n return getConfiguration().batchQueue;\n }\n\n private get log() {\n return getLogger().child({service: 'BOT DETECTOR', branch: 'BatchQueue'});\n }\n\n public async addQueue<T extends BatchQueueOps>(\n canary: string,\n ipAddress: string,\n type: T,\n params: OpParams[T],\n priority: Priority = 'deferred'\n ): Promise<void> {\n const key = `${type}:${canary}:${ipAddress}`;\n this.jobs.set(key, { id: key, type, priority, params });\n\n if (priority === 'immediate' || this.jobs.size >= this.config.maxBufferSize) {\n await this.flush();\n } else this.timer ??= setTimeout(() => void this.flush(), this.config.flushIntervalMs);\n }\n\n\n public async flush(): Promise<void> {\n while (this.flushPromise || this.jobs.size > 0) {\n if (this.flushPromise) {\n await this.flushPromise;\n }\n if (this.jobs.size > 0) {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n const currentBatch = Array.from(this.jobs.values());\n this.jobs.clear();\n this.flushPromise = this.executeBatch(currentBatch, 0);\n try {\n await this.flushPromise;\n } finally {\n this.flushPromise = null;\n }\n }\n }\n }\n\n private runJob(job: BatchJob): Promise<void> {\n switch (job.type) {\n case 'visitor_upsert':\n return updateVisitor((job.params as OpParams['visitor_upsert']).insert);\n case 'score_update': {\n const {score, cookie} = job.params as OpParams['score_update'];\n return updateScore(score, cookie);\n }\n case 'is_bot_update': {\n const {isBot, cookie} = job.params as OpParams['is_bot_update'];\n return updateIsBot(isBot, cookie);\n }\n case 'update_banned_ip': {\n const {cookie, ipAddress, country, user_agent, info} = job.params as OpParams['update_banned_ip'];\n return updateBannedIP(cookie, ipAddress, country, user_agent, info);\n }\n }\n }\n\n private async executeBatch(batch: BatchJob[], retryCount: number): Promise<void> {\n try {\n const visitors = batch.filter(j => j.type === 'visitor_upsert');\n const others = batch.filter(j => j.type !== 'visitor_upsert');\n if (visitors.length > 0) {\n await Promise.all(visitors.map(j => this.runJob(j)));\n }\n await Promise.all(others.map(j => this.runJob(j)));\n } catch (err) {\n this.log.error({err}, `Batch flush failed (Attempt ${String(retryCount + 1)})`);\n\n if (retryCount < this.config.maxRetries) {\n await new Promise(res => setTimeout(res, 1000));\n return this.executeBatch(batch, retryCount + 1);\n }\n this.log.error(\"Max retries reached. Discarding batch.\");\n }\n }\n\n public async shutdown(): Promise<void> {\n this.log.info(\"Shutting down BatchQueue: Draining remaining jobs...\");\n await this.flush();\n }\n}","import { createStorage } from 'unstorage';\nimport memoryDriver from 'unstorage/drivers/memory';\nimport type { Driver } from 'unstorage';\nimport type { CacheConfig } from '../types/storageTypes.js';\n\n\nexport async function initStorage(config?: CacheConfig) {\n\n if (!config) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n return createStorage({ driver: memoryDriver() });\n }\n\n const { driver, ...opts } = config;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mod: { default: (opts?: any) => Driver };\n\n switch (driver) {\n case 'redis':\n mod = await import('unstorage/drivers/redis');\n break;\n case 'upstash':\n mod = await import('unstorage/drivers/upstash');\n break;\n case 'lru':\n mod = await import('unstorage/drivers/lru-cache');\n break;\n case 'fs':\n mod = await import('unstorage/drivers/fs-lite');\n break;\n case 'cloudflare-kv-binding':\n mod = await import('unstorage/drivers/cloudflare-kv-binding');\n break;\n case 'cloudflare-kv-http':\n mod = await import('unstorage/drivers/cloudflare-kv-http');\n break;\n case 'cloudflare-r2-binding':\n mod = await import('unstorage/drivers/cloudflare-r2-binding');\n break;\n case 'vercel':\n mod = await import('unstorage/drivers/vercel-runtime-cache');\n break;\n default:\n driver satisfies never;\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unsupported storage driver: ${driver}`);\n }\n\n return createStorage({ driver: mod.default(opts) });\n}\n","import { type Connector, createDatabase, type Database } from 'db0';\nimport type { DbConfig } from '../types/dbTypes.js';\n\n\nexport async function initDb(config: DbConfig): Promise<Database> {\n const { driver, ...opts } = config;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mod: { default: (opts?: any) => Connector };\n\n switch (driver) {\n case 'mysql-pool':\n mod = await import('./mysqlPoolConnector.js');\n break;\n case 'postgresql':\n mod = await import('db0/connectors/postgresql');\n break;\n case 'sqlite':\n mod = await import('db0/connectors/better-sqlite3');\n break;\n case 'cloudflare-d1':\n mod = await import('db0/connectors/cloudflare-d1');\n break;\n case 'planetscale':\n mod = await import('db0/connectors/planetscale');\n break;\n default:\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unsupported database driver: ${driver}`);\n }\n\n return createDatabase(mod.default(opts));\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 type { GeoResponse } from \"../types/geoTypes.js\";\nimport { getDataSources } from \"../config/config.js\";\n\nconst norm = (string?: string) => string?.trim().toLowerCase();\n \nexport function getData(ip: string): GeoResponse {\n const dataSource = getDataSources();\n const countryLvl = dataSource.countryDataBase(ip);\n const cityLvl = dataSource.cityDataBase(ip);\n const asn = dataSource.asnDataBase(ip);\n const proxy = dataSource.proxyDataBase(ip);\n const tor = dataSource.torDataBase(ip);\n\n\n return {\n country: norm(countryLvl?.name ?? cityLvl?.name),\n countryCode: norm(countryLvl?.country_code ?? cityLvl?.country_code),\n region: norm(cityLvl?.region ?? countryLvl?.region),\n regionName: norm(cityLvl?.continent ?? cityLvl?.subregion ?? countryLvl?.subregion),\n subregion: norm(cityLvl?.subregion ?? countryLvl?.subregion),\n state: norm(cityLvl?.state),\n zipCode: norm(cityLvl?.zip_code),\n city: norm(cityLvl?.city ?? cityLvl?.capital ?? countryLvl?.capital),\n phone: norm(cityLvl?.phone ?? countryLvl?.phone),\n numericCode: norm(cityLvl?.numericCode ?? countryLvl?.numericCode),\n native: norm(cityLvl?.native ?? countryLvl?.native),\n continent: norm(cityLvl?.continent),\n capital: norm(cityLvl?.capital ?? countryLvl?.capital),\n district: norm(cityLvl?.state),\n lat: norm(cityLvl?.latitude),\n lon: norm(cityLvl?.longitude),\n timezone: norm(cityLvl?.timezone ?? countryLvl?.timezone),\n timeZoneName: norm(cityLvl?.timeZoneName ?? countryLvl?.timeZoneName),\n utc_offset: norm(cityLvl?.utc_offset ?? countryLvl?.utc_offset),\n tld: norm(cityLvl?.tld ?? countryLvl?.tld),\n nationality: norm(cityLvl?.nationality ?? countryLvl?.nationality),\n currency: norm(cityLvl?.currency ?? countryLvl?.currency),\n iso639: norm(cityLvl?.iso639 ?? countryLvl?.iso639),\n languages: norm(cityLvl?.languages ?? countryLvl?.languages),\n isp: norm(asn?.asn_name),\n org: norm(asn?.asn_id),\n as_org: norm(asn?.asn_name),\n proxy: proxy ? true : false,\n hosting: asn?.classification === \"Content\" || Boolean(tor?.exit_addresses),\n };\n}","import { Response } from \"express\";\n\ninterface cookies {\n httpOnly: boolean,\n sameSite: boolean | \"lax\" | \"strict\" | \"none\";\n maxAge: number; \n secure: boolean; \n expires?: Date;\n domain?: string;\n path?: string; \n }\n\n\n\nexport function makeCookie(res: Response, name: string, value: string, options: cookies) {\n\n if (name.startsWith(\"__Host-\")) {\n options.secure = true;\n options.path = \"/\";\n delete options.domain;\n }\n\n if (name.startsWith(\"__Secure-\")) {\n options.secure = true;\n }\n\n res.cookie(name, value, {\n httpOnly: options.httpOnly,\n sameSite: options.sameSite,\n maxAge: options.maxAge,\n secure: options.secure,\n expires: options.expires,\n domain: options.domain,\n path: options.path,\n });\n}\n\n\n","import { ParsedUAResult } from '../types/UAparserTypes.js';\nimport { UAParser, UAParserExt } from 'ua-parser-js';\nimport { isAIBot, isBot } from 'ua-parser-js/helpers';\nimport { CLIs, Crawlers, Fetchers, Libraries } from 'ua-parser-js/extensions';\n\n\nexport function parseUA(userAgent: string | number): ParsedUAResult {\n\n \n const botParser = new UAParser(\n [Crawlers, CLIs, Fetchers, Libraries] as UAParserExt\n );\n \n const uaString = typeof userAgent === 'string'\n ? userAgent\n : String(userAgent);\n\n\n const result = botParser.setUA(uaString).getResult();\n\n return {\n device: result.device.type ?? 'desktop',\n deviceVendor: result.device.vendor,\n deviceModel: result.device.model,\n browser: result.browser.name,\n browserType: result.browser.type,\n browserVersion: result.browser.version,\n os: result.os.name,\n botAI: isAIBot(result),\n bot: isBot(result),\n allResults: result,\n };\n\n}\nexport default parseUA;\n\n\n\n","import { isIP } from 'node:net';\nimport { IBotChecker } from '../types/checkersTypes.js';\nimport { ValidationContext } from '../types/botDetectorTypes.js';\nimport { BotDetectorConfig } from '../types/configSchema.js';\nimport { CheckerRegistry } from './CheckerRegistry.js';\n\nexport class IpChecker implements IBotChecker<'IP_INVALID'> {\n name = 'IP Validation';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableIpChecks.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const isValid = isIP(ctx.ipAddress) !== 0;\n return {\n score: isValid ? 0 : config.banScore,\n reasons: isValid ? [] : ['IP_INVALID' as const]\n };\n }\n}\n\nCheckerRegistry.register(new IpChecker());\n","import { getStorage } from '~~/src/botDetector/config/config.js';\n\nexport interface CachedResult {\n ip: string;\n trustedBot: boolean;\n}\n\nconst DNS_TTL_SECONDS = 60 * 60 * 2;\nconst PREFIX = 'dns:';\n\nexport const dnsCache = {\n async get(ip: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${ip}`);\n },\n\n async set(ip: string, entry: CachedResult): Promise<void> {\n await getStorage().setItem(`${PREFIX}${ip}`, entry, { ttl: DNS_TTL_SECONDS });\n },\n\n async delete(ip: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${ip}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import { dnsCache } from '@helpers/cache/dnsLookupCache.js';\nimport dns from 'node:dns/promises';\nimport { getDataSources } from '../../config/config.js';\nimport { getLogger } from '@utils/logger.js';\nimport type { Suffix } from '../../types/suffixes.js';\n\nexport class GoodBotsBase {\n private getDomains(suffix: Suffix): string[] {\n const allDomains: string[] = [];\n\n for (const key in suffix) {\n\n const entry = suffix[key];\n const entrySuffix = entry.suffix;\n\n if (Array.isArray(entrySuffix)) {\n allDomains.push(...entrySuffix);\n\n } else if (typeof entrySuffix === 'string') {\n allDomains.push(entrySuffix);\n }\n }\n return allDomains;\n }\n\n private domains: string[];\n\n private _logger?: ReturnType<typeof getLogger>;\n protected get logger(): ReturnType<typeof getLogger> {\n this._logger ??= getLogger().child({ service: 'botDetector', branch: 'checker', type: 'GoodBotsBase' });\n return this._logger;\n }\n\n constructor(protected suffixes: Suffix) {\n this.domains = this.getDomains(this.suffixes).map(d => `.${d.toLowerCase()}`);\n }\n\n protected async isBotFromTrustedDomain(ip: string): Promise<boolean> {\n const cached = await dnsCache.get(ip);\n if (cached) {\n return cached.trustedBot;\n }\n\n try {\n \n const hostnames = await dns.reverse(ip); \n \n const matchingHosts = hostnames.filter(host =>\n this.domains.some(domain => host.endsWith(domain))\n );\n\n if (matchingHosts.length === 0) {\n dnsCache.set(ip, { ip, trustedBot: false }).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save dnsCache in storage');\n });\n return false;\n }\n for (const host of matchingHosts) {\n const addresses = await dns.lookup(host, { all: true });\n\n if (addresses.some(a => a.address === ip)) {\n dnsCache.set(ip, { ip, trustedBot: true }).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save dnsCache in storage');\n });\n\n return true;\n }\n }\n } catch(err: unknown) {\n this.logger.error({ err }, 'DNS reverse lookup failed');\n }\n dnsCache.set(ip, { ip, trustedBot: false }).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save dnsCache in storage');\n });\n return false;\n }\n\n protected isBotIPTrusted(ipAddress: string): boolean {\n \n const dataSources = getDataSources();\n const isKnownBot = dataSources.goodBotsDataBase(ipAddress) !== null;\n \n return isKnownBot; \n }\n}","import fs from 'node:fs';\nimport type { IBotChecker } from \"../../types/checkersTypes.js\";\nimport type { ValidationContext } from \"../../types/botDetectorTypes.js\";\nimport type { BotDetectorConfig } from \"../../types/configSchema.js\";\nimport { CheckerRegistry } from \"../CheckerRegistry.js\";\nimport { GoodBotsBase } from \"./base.js\";\nimport type { Suffix } from '../../types/suffixes.js';\nimport { resolveDataPath } from '@db/findDataPath.js';\n\nconst suffixPath = resolveDataPath('suffix.json');\nconst suffixes = JSON.parse(fs.readFileSync(suffixPath, 'utf-8')) as Suffix;\n\nconst userAgents: string[] = Object.values(suffixes)\n .flatMap((e) =>\n Array.isArray(e.useragent) ? e.useragent : [e.useragent]\n )\n .map(u => u.toLowerCase());\n \nexport class GoodBotsChecker extends GoodBotsBase implements IBotChecker<'BAD_BOT_DETECTED' | 'GOOD_BOT_IDENTIFIED'> {\n name = 'Good/Bad Bot Verification';\n phase = 'cheap' as const;\n\n constructor() {\n super(suffixes);\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableGoodBotsChecks.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const browserType = (ctx.parsedUA.browserType ?? '').toLowerCase();\n const browserName = (ctx.parsedUA.browser ?? '').toLowerCase();\n const ipAddress = ctx.ipAddress;\n \n const score = 0;\n const reasons: ('BAD_BOT_DETECTED' | 'GOOD_BOT_IDENTIFIED')[] = [];\n\n const checkersConfig = config.checkers.enableGoodBotsChecks;\n if (!checkersConfig.enable) return { score, reasons };\n\n if (browserType !== 'crawler' && browserType !== 'fetcher') {\n return { score: 0, reasons: [] };\n }\n\n const name = browserName;\n const botsWithoutSuffix = ['duckduckbot','gptbot','oai-searchbot','chatgpt-user'].includes(name);\n const botsWithSuffix = userAgents.some(suf => name.includes(suf));\n\n if (checkersConfig.banUnlistedBots && !botsWithoutSuffix && !botsWithSuffix) {\n reasons.push('BAD_BOT_DETECTED');\n return { score: 0, reasons }; \n }\n\n let trusted: boolean;\n\n if (botsWithSuffix) {\n trusted = await this.isBotFromTrustedDomain(ipAddress);\n } else {\n trusted = this.isBotIPTrusted(ipAddress);\n }\n\n if (!trusted) {\n reasons.push('BAD_BOT_DETECTED');\n return {\n score: checkersConfig.penalties,\n reasons\n };\n }\n\n reasons.push('GOOD_BOT_IDENTIFIED');\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new GoodBotsChecker());\n","import { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class BrowserDetailsAndDeviceChecker implements IBotChecker<BanReasonCode> {\n name = 'Browser and Device Verification';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableBrowserAndDeviceChecks.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableBrowserAndDeviceChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const penalties = checkConfig.penalties;\n\n const bType = ctx.parsedUA.browserType;\n const bName = ctx.parsedUA.browser ?? \"\";\n const bOS = ctx.parsedUA.os ?? \"\";\n const dType = ctx.parsedUA.device ?? \"desktop\";\n\n if (bType === 'cli' || bType === 'library') {\n score += penalties.cliOrLibrary;\n reasons.push('CLI_OR_LIBRARY');\n } \n\n if (['ie','iemobile','internet explorer'].includes(bName.toLowerCase())) {\n score += penalties.internetExplorer; \n reasons.push('INTERNET_EXPLORER');\n }\n\n if (bOS.toLowerCase().includes('kali')) {\n score += penalties.linuxOs; \n reasons.push('KALI_LINUX_OS');\n }\n\n if (bOS === 'Mac OS' && dType === 'mobile') {\n score += penalties.impossibleBrowserCombinations; \n reasons.push('IMPOSSIBLE_BROWSER_COMBINATION' as BanReasonCode);\n }\n\n if (bName === 'Safari' && bOS === 'Windows') {\n score += penalties.impossibleBrowserCombinations; \n reasons.push('IMPOSSIBLE_BROWSER_COMBINATION' as BanReasonCode);\n }\n\n if (dType === 'desktop' && ctx.parsedUA.deviceVendor) {\n score += penalties.impossibleBrowserCombinations; \n reasons.push('IMPOSSIBLE_BROWSER_COMBINATION' as BanReasonCode);\n }\n\n if (!bType && (!bName || dType !== 'desktop')) {\n score += penalties.browserTypeUnknown;\n reasons.push('BROWSER_TYPE_UNKNOWN');\n }\n\n if (!bName) {\n score += penalties.browserNameUnknown;\n reasons.push('BROWSER_NAME_UNKNOWN');\n }\n\n if (dType === 'desktop' && !bOS) {\n score += penalties.desktopWithoutOS; \n reasons.push('DESKTOP_WITHOUT_OS');\n }\n\n if (dType !== 'desktop' && !ctx.parsedUA.deviceVendor) {\n score += penalties.deviceVendorUnknown;\n reasons.push('DEVICE_VENDOR_UNKNOWN');\n }\n\n if (!ctx.parsedUA.browserVersion) {\n score += penalties.browserVersionUnknown; \n reasons.push('BROWSER_VERSION_UNKNOWN');\n }\n\n if (!ctx.parsedUA.deviceModel) {\n score += penalties.deviceModelUnknown; \n reasons.push('NO_MODEL');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new BrowserDetailsAndDeviceChecker());\n","import { anyOf, createRegExp, exactly, digit, letter, maybe } from \"magic-regexp\";\n\nconst space = anyOf(\" \", \"\\t\").times.any();\n\nconst decimalZero = maybe(anyOf(exactly(\".\", digit.times.between(1, 3))));\nconst qZero = exactly(\"0\", decimalZero);\n\nconst decimalOne = maybe(anyOf(exactly(\".\", exactly(\"0\").times.between(1, 3))));\nconst qOne = exactly(\"1\", decimalOne);\n\nconst qValue = anyOf(qZero, qOne);\n\nconst quality = maybe(\n anyOf(\n exactly(space, \";\", space, \"q\", space, \"=\", space, qValue)\n )\n);\n\nconst primaryTag = letter.times.between(1, 8);\nconst subTag = anyOf(\n exactly(\"-\", anyOf(letter, digit).times.between(1, 8))\n).times.any();\n\nconst acceptLang = anyOf(\n exactly(\"*\"),\n exactly(primaryTag, subTag) \n);\n\nconst language = exactly(acceptLang, quality);\nconst repeatingLanguages = anyOf(\n exactly(space, \",\", space, language)\n).times.any();\n\nexport const acceptLanguageValidator = createRegExp(\n exactly(language, repeatingLanguages)\n .at.lineStart()\n .at.lineEnd(), \n [\"i\"]\n);","import { acceptLanguageValidator } from \"../utils/regex/acceptLangRegex.js\";\nimport { IBotChecker, BanReasonCode } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class LocaleMapChecker implements IBotChecker<BanReasonCode> {\n name = 'Locale and Country Verification';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.localeMapsCheck.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const settings = config.checkers.localeMapsCheck;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!settings.enable) return { score, reasons };\n\n const AccHeader = ctx.req.get('Accept-Language') ?? '';\n if (!AccHeader) {\n score += settings.penalties.missingHeader;\n if (score > 0) reasons.push('LOCALE_MISMATCH');\n return { score, reasons };\n }\n\n const isValidHeader = acceptLanguageValidator.test(AccHeader.trim().toLowerCase());\n\n if (!isValidHeader) {\n score += settings.penalties.malformedHeader; \n if (score > 0) reasons.push('LOCALE_MISMATCH');\n return { score, reasons };\n }\n\n const langs = AccHeader\n .split(',')\n .map(entry => {\n const [tag, q] = entry.trim().split(/\\s*;\\s*q\\s*=\\s*/);\n return { tag: tag.toLowerCase(), weight: q ? parseFloat(q) : 1 };\n })\n .sort((a, b) => b.weight - a.weight);\n\n const country = ctx.geoData.country;\n const countryCode = ctx.geoData.countryCode;\n const iso6 = ctx.geoData.iso639;\n\n if (!country || !countryCode || !iso6) {\n score += settings.penalties.missingGeoData;\n if (score > 0) reasons.push('LOCALE_MISMATCH');\n return { score, reasons };\n }\n\n const expectedCountryCode = countryCode.toLowerCase();\n const expectedLang = iso6.toLowerCase();\n const combined = `${expectedLang}-${expectedCountryCode}`;\n\n let localeMatchesGeo = false;\n\n for (const { tag, weight } of langs) {\n if (weight === 0) continue;\n const parts = tag.split(/[-_]/);\n const langPart = parts[0];\n const regionPart = parts.find(p => p.length === 2 && p === expectedCountryCode);\n \n if (regionPart) {\n localeMatchesGeo = true;\n break;\n }\n\n if (langPart === expectedLang) {\n localeMatchesGeo = true;\n break;\n }\n\n if ((langPart && regionPart) && tag === combined) {\n localeMatchesGeo = true;\n break;\n }\n }\n\n if (!localeMatchesGeo) {\n score += settings.penalties.ipAndHeaderMismatch;\n if (score > 0) reasons.push('LOCALE_MISMATCH');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new LocaleMapChecker());","import { getStorage } from '~~/src/botDetector/config/config.js';\n\nexport interface CachedResult {\n score: number;\n timestamp: number;\n request_count: number;\n}\n\nconst RATE_TTL_SECONDS_FALLBACK = 60 * 2;\nconst PREFIX = 'rate:';\n\nexport const rateCache = {\n async get(cookie: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${cookie}`);\n },\n\n async set(cookie: string, entry: CachedResult, ttlSeconds?: number): Promise<void> {\n await getStorage().setItem(`${PREFIX}${cookie}`, entry, { ttl: ttlSeconds ?? RATE_TTL_SECONDS_FALLBACK });\n },\n\n async delete(cookie: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${cookie}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import { rateCache } from '../helpers/cache/rateLimitarCache.js';\nimport { IBotChecker, BanReasonCode } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\nexport class BehavioralDbChecker implements IBotChecker<BanReasonCode> {\n name = 'Behavior Rate Verification';\n phase = 'heavy' as const;\n private _logger?: ReturnType<typeof getLogger>;\n private get logger() {\n this._logger ??= getLogger().child({ service: 'botDetector', branch: 'checker', type: 'BehavioralDbChecker' });\n return this._logger;\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableBehaviorRateCheck.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const cookie = ctx.cookie ?? '';\n\n const checkConfig = config.checkers.enableBehaviorRateCheck;\n if (!checkConfig.enable) return { score: 0, reasons: [] };\n\n const BEHAVIORAL_THRESHOLD = checkConfig.behavioral_threshold;\n const BEHAVIORAL_WINDOW = checkConfig.behavioral_window;\n const BEHAVIORAL_PENALTY = checkConfig.penalties;\n const ttlSeconds = Math.ceil(BEHAVIORAL_WINDOW / 1000);\n\n const cached = await rateCache.get(cookie);\n\n if (cached) {\n const ageSinceLastSeen = Date.now() - cached.timestamp;\n\n if (ageSinceLastSeen <= BEHAVIORAL_WINDOW) {\n const newCount = cached.request_count + 1;\n const score = newCount > BEHAVIORAL_THRESHOLD ? BEHAVIORAL_PENALTY : 0;\n\n rateCache.set(cookie, { ...cached, request_count: newCount, score }, ttlSeconds).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save rateCache in storage');\n });\n\n return { score, reasons: score ? ['BEHAVIOR_TOO_FAST' as const] : [] };\n } else {\n rateCache.set(cookie, { request_count: 1, timestamp: Date.now(), score: 0 }, ttlSeconds).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to reset rateCache in storage');\n });\n\n return { score: 0, reasons: [] };\n }\n }\n\n return { score: 0, reasons: [] };\n }\n}\n\nCheckerRegistry.register(new BehavioralDbChecker());","import { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class ProxyIspAndCookieChecker implements IBotChecker<BanReasonCode> {\n name = 'Proxy, ISP and Cookie Verification';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableProxyIspCookiesChecks.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableProxyIspCookiesChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const { penalties } = checkConfig;\n\n const cookie = ctx.cookie ?? '';\n const proxy = ctx.proxy.isProxy;\n const proxyType = ctx.proxy.proxyType ?? '';\n const hosting = ctx.geoData.hosting ?? false;\n const isp = ctx.geoData.isp ?? '';\n const org = ctx.geoData.org ?? '';\n\n if (!cookie) {\n score += penalties.cookieMissing;\n reasons.push('COOKIE_MISSING');\n }\n\n if (proxy) {\n score += penalties.proxyDetected;\n reasons.push('PROXY_DETECTED');\n if (proxyType) {\n const sourceCount = proxyType.split(',').length;\n if (sourceCount >= 4) {\n score += penalties.multiSourceBonus4plus;\n } else if (sourceCount >= 2) {\n score += penalties.multiSourceBonus2to3;\n }\n }\n }\n\n if (hosting) {\n score += penalties.hostingDetected;\n reasons.push('HOSTING_DETECTED');\n }\n\n if (!isp) {\n score += penalties.ispUnknown;\n reasons.push('ISP_UNKNOWN');\n }\n\n if (!org) {\n score += penalties.orgUnknown;\n reasons.push('ORG_UNKNOWN');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new ProxyIspAndCookieChecker());\n","/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { Request } from \"express\";\nimport { UAParser } from \"ua-parser-js\";\nimport { getConfiguration } from \"../../config/config.js\";\n\nexport class HeadersBase {\n private readonly config = getConfiguration().headerOptions;\n\n protected mustHaveHeadersChecker(req: Request) {\n let score = 0;\n if (req.httpVersion === '1.0') return score += 40;\n if(!req.get('User-Agent')) score += this.config.weightPerMustHeader;\n if(!req.accepts) score += this.config.weightPerMustHeader;\n if(!req.acceptsEncodings) score += this.config.weightPerMustHeader;\n if(!req.acceptsLanguages) score += this.config.weightPerMustHeader;\n if (!req.host) score += this.config.weightPerMustHeader;\n if (!req.get('Upgrade-Insecure-Requests')) score += this.config.weightPerMustHeader;\n if (!req.get('x-client-id')) score += this.config.weightPerMustHeader;\n if (req.httpVersion === '1.1' || req.get('Connection')) {\n if(!req.get('Connection') || req.get('Connection') !== 'keep-alive') score += this.config.connectionHeaderIsClose;\n }\n if (!req.get('sec-fetch-mode') || \n !req.get('sec-fetch-dest') ||\n !req.get('sec-fetch-site')\n ) {\n score += this.config.weightPerMustHeader;\n }\n\n return score;\n }\n\n protected async engineHeaders(req: Request) {\n let score = 0;\n const ua = req.get('User-Agent');\n const hints = req.headers as Record<string, string>;\n const { name } = await new UAParser(ua, hints).getEngine().withClientHints();\n\n if (!name) return score += this.config.missingBrowserEngine;\n const headers = Object.keys(hints);\n const containsCh = headers.some(sec => sec.toLowerCase().startsWith('sec-ch-ua'));\n const containsTe = headers.some(te => te.toLowerCase() === 'te');\n\n if (name === 'Blink') {\n if (!containsCh) score += this.config.clientHintsMissingForBlink;\n if (containsTe) score += this.config.teHeaderUnexpectedForBlink;\n\n } else if (name === 'Gecko') {\n if (containsCh) score += this.config.clientHintsUnexpectedForGecko; \n if (!containsTe) score += this.config.teHeaderMissingForGecko;\n } else if(name === 'WebKit') {\n if (containsCh) score += this.config.clientHintsUnexpectedForGecko;\n if (containsTe) score += this.config.teHeaderUnexpectedForBlink;\n };\n return score;\n }\n\n protected weirdHeaders(req: Request) {\n let score = 0;\n const accept = req.get('accept');\n \n if (accept === '*/*') score += this.config.omittedAcceptHeader;\n if (req.get('x-requested-with') && req.method === 'GET') score += this.config.AJAXHeaderExists;\n if (req.get('postman-token') || req.get('insomnia')) score += this.config.postManOrInsomiaHeaders;\n\n const hostHeader = req.get('X-Forwarded-Host');\n if (hostHeader && req.hostname && hostHeader !== req.hostname) {\n score += this.config.hostMismatchWeight; \n }\n\n if (req.method === 'GET' && req.get('Cache-Control') === 'no-cache' && req.get('Pragma') === 'no-cache') {\n score += this.config.aggressiveCacheControlOnGet;\n }\n\n if (req.get('sec-fetch-site') === 'cross-site' && !req.get('referer')) {\n score += this.config.crossSiteRequestMissingReferer;\n }\n\n const isBrowserRequest = !req.get('x-client-id'); \n const isTopNavigation = req.method === 'GET' && req.get('sec-fetch-dest') === 'document';\n\n if (isBrowserRequest && !isTopNavigation && req.method !== 'GET') {\n const origin = req.get('origin');\n if (!origin) {\n score += this.config.originHeaderIsNULL;\n } else if (origin !== `${req.protocol}://${req.hostname}`) {\n score += this.config.originHeaderMismatch;\n }\n }\n const mode = req.get('sec-fetch-mode');\n if (mode !== 'same-origin' && mode !== 'navigate') score += this.config.inconsistentSecFetchMode;\n\n return score; \n } \n\n}\n","import { Request } from \"express\";\nimport { HeadersBase } from \"./headersBase.js\";\n\nexport class HeaderAnalysis extends HeadersBase {\n private readonly req: Request;\n\n constructor(req: Request) {\n super();\n this.req = req;\n }\n\n public async scoreHeaders() {\n const missing = this.mustHaveHeadersChecker(this.req);\n const engines = await this.engineHeaders(this.req);\n const weird = this.weirdHeaders(this.req);\n return missing + engines + weird;\n }\n\n}","import { createRegExp, anyOf, maybe, exactly } from 'magic-regexp';\n\nconst startOrSlash = anyOf(exactly('').at.lineStart(), '/').grouped();\nconst slashOrEnd = anyOf('/', exactly('').at.lineEnd());\n\nexport const pathRules: { re: RegExp; weight: number }[] = [\n { re: createRegExp(startOrSlash, '.git', slashOrEnd, ['i']), weight: 10 },\n { re: createRegExp(startOrSlash, '.git/config', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp(startOrSlash, '.env', maybe(anyOf('.local', '.example')), slashOrEnd, ['i']), weight: 10 },\n { re: createRegExp(startOrSlash, 'wp-admin', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp('/wp-json/wp/v2', slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp('/', anyOf('jenkins', 'hudson').grouped(), slashOrEnd, ['i']), weight: 9 }, \n { re: createRegExp('/', anyOf('script', 'login').grouped(), '.groovy', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp('/actuator/', anyOf('env', 'health', 'metrics'), slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp('/web.config', slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp('/.DS_Store', slashOrEnd, ['i']), weight: 4 },\n { re: createRegExp('/latest/meta-data/iam', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp(startOrSlash, '.aws/credentials', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp('/Dockerfile', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('/composer.lock', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('/jnlpJars/jenkins-cli.jar', slashOrEnd, ['i']), weight: 9 }, \n { re: createRegExp('/manager/html', slashOrEnd, ['i']), weight: 10 },\n { re: createRegExp('/shell', maybe('.php'), slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp('/', anyOf('grafana', 'kibana', 'prometheus').grouped(), slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('/', anyOf('owa', 'ecp').grouped(), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp('wp-login.php', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp('/swagger-ui', anyOf('/', '.html'), slashOrEnd, ['i']), weight: 6 }, \n { re: createRegExp('/v2/api-docs', slashOrEnd, ['i']), weight: 5 }, \n { re: createRegExp('/api-docs', anyOf('/', '.json'), slashOrEnd, ['i']), weight: 5 }, \n { re: createRegExp('phpmyadmin', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp(startOrSlash, '.well-known', slashOrEnd, ['i']), weight: 5 },\n { re: createRegExp(startOrSlash, '.htaccess', slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp('composer.json', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('docker-compose.y', maybe('a'), 'ml', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('.', anyOf('sql', 'bak', 'old', 'save', 'log', 'ini', 'conf', 'zip', exactly('tar', maybe('.gz'))), slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp(anyOf('..', '%2e%2e').grouped(), anyOf('/', '\\\\'), ['i']), weight: 5 },\n { re: createRegExp(anyOf('package-lock.json', 'yarn.lock', '.gitignore').grouped(), slashOrEnd, ['i']), weight: 6 }, \n { re: createRegExp(startOrSlash, 'admin', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp('phpinfo', maybe('.php'), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, '.ssh', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp(exactly('').at.lineStart(), '/xmlrpc.php', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, 'wp-config.php', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp(startOrSlash, anyOf('install', 'setup').grouped(), maybe('.php'), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, 'backup', maybe('s'), anyOf('.zip', '.tar.gz', '.sql'), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, '.gitlab-ci.yml', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, '.svn', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp(startOrSlash, '.hg', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp(startOrSlash, 'CVS', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp(startOrSlash, '.vscode', slashOrEnd, ['i']), weight: 4 },\n { re: createRegExp(startOrSlash, '.htpasswd', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp('phpunit', maybe('.phar'), slashOrEnd, ['i']), weight: 9 }, \n { re: createRegExp(startOrSlash, 'config', maybe('uration'), '.', anyOf('php', 'yml', 'json', 'xml', 'ini', 'conf', 'cfg'), slashOrEnd, ['i']), weight: 7 },\n];\n\nexport const whiteList: RegExp[] = [\n createRegExp(\n exactly('').at.lineStart(), \n maybe('/'), \n exactly('').at.lineEnd()\n ),\n\n createRegExp(\n exactly('').at.lineStart(),\n '/',\n anyOf('css', 'js', 'images', 'assets', 'static').grouped(),\n '/',\n ['i']\n ),\n\n createRegExp(\n '.',\n anyOf(\n 'html',\n 'css',\n 'js',\n 'png',\n exactly('jp', maybe('e'), 'g'),\n 'svg',\n 'map',\n exactly('woff', maybe('2')),\n 'ttf',\n 'webp'\n ),\n exactly('').at.lineEnd(),\n ['i']\n ),\n\n createRegExp(\n exactly('').at.lineStart(),\n '/robots.txt',\n exactly('').at.lineEnd(),\n ['i']\n ),\n\n createRegExp(\n exactly('').at.lineStart(),\n '/sitemap.xml',\n exactly('').at.lineEnd(),\n ['i']\n ),\n];","import path from 'path';\nimport { URL } from 'url';\nimport { Request } from 'express';\nimport { pathRules, whiteList } from '@utils/regex/pathTravelersRegex.js';\nimport { BotDetectorConfig } from '../../types/configSchema.js';\n\nexport class UaAndHeaderCheckerBase {\n protected pathScore(req: Request, config: BotDetectorConfig): number {\n const settings = config.pathTraveler;\n const MAX_DECODE_ITERATIONS = settings.maxIterations;\n const MAX_PATH_LENGTH = settings.maxPathLength;\n \n let score = 0;\n const hostHeader = req.get('x-forwarded-host');\n const base = `${req.protocol}://${hostHeader ?? req.get('host') ?? ''}`;\n \n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n const rawPath = req.get('x-original-path') || req.originalUrl;\n\n const traversalRe = /(?:\\.\\.[\\\\/]|\\.\\.%2f|\\.\\.%5c|%2e%2e[\\\\/]|%2e%2e%2f|%2e%2e%5c)/i;\n if (traversalRe.test(rawPath)) {\n return settings.traversalDetected;\n }\n\n let pathname: string;\n try {\n\n const fullUrl = new URL(rawPath, base);\n pathname = fullUrl.pathname;\n \n } catch {\n pathname = rawPath.split('?')[0];\n }\n \n \n \n if (pathname.length > MAX_PATH_LENGTH) {\n return settings.pathLengthToLong;\n }\n \n \n if (whiteList.some(rx => rx.test(pathname))) {\n return 0;\n }\n \n \n let decoded = pathname;\n let totalDecodedLength = 0;\n for (let i = 0; i < MAX_DECODE_ITERATIONS; i++) {\n try {\n const tmp = decodeURIComponent(decoded);\n if (tmp === decoded) break;\n totalDecodedLength += tmp.length;\n if (totalDecodedLength > MAX_PATH_LENGTH * 2) {\n return settings.longDecoding; \n }\n decoded = tmp;\n } catch {\n break;\n }\n }\n \n const normalized = path.normalize(decoded);\n \n for (const { re, weight } of pathRules) {\n if (re.test(normalized)) {\n score += weight;\n if (score >= 30) break;\n }\n }\n \n return score;\n }\n\n protected tlsBotScore(req: Request, config: BotDetectorConfig): number {\n const settings = config.checkers.enableUaAndHeaderChecks;\n if (!settings.enable) return 0;\n const { penalties } = settings;\n\n let score = 0;\n const proto = req.httpVersion === '2.0' ? 'h2'\n : req.httpVersion === '1.1' ? 'http/1.1'\n : '';\n \n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!proto || (proto !== 'h2' && proto !== 'http/1.1')) {\n score += penalties.tlsCheckFailed;\n }\n \n const cipher = req.get('x-client-cipher') ?? '';\n \n const browserCiphers = new Set([\n 'TLS_AES_128_GCM_SHA256', 'TLS_AES_256_GCM_SHA384',\n 'TLS_CHACHA20_POLY1305_SHA256',\n 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256',\n 'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305',\n 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384',\n 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',\n 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',\n 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',\n 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',\n 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',\n 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256'\n ]);\n \n if (!browserCiphers.has(cipher)) score += penalties.tlsCheckFailed;;\n \n const tlsVersion = (req.get('x-client-tls-version') ?? '').toLowerCase();\n if (\n tlsVersion &&\n !tlsVersion.startsWith('tls1.3') &&\n !tlsVersion.startsWith('tls1.2')\n ) {\n score += penalties.tlsCheckFailed; \n }\n \n return score;\n }\n}","import { BanReasonCode, IBotChecker } from '../../types/checkersTypes.js';\nimport { HeaderAnalysis } from '../headers/headers.js';\nimport { ValidationContext } from \"../../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../../types/configSchema.js\";\nimport { CheckerRegistry } from \"../CheckerRegistry.js\";\nimport { anyOf, createRegExp } from 'magic-regexp';\nimport { UaAndHeaderCheckerBase } from './base.js';\n\nexport class UaAndHeaderChecker extends UaAndHeaderCheckerBase implements IBotChecker<BanReasonCode> {\n name = 'User agent and Header Verification';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableUaAndHeaderChecks.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableUaAndHeaderChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const { penalties } = checkConfig;\n\n const req = ctx.req;\n const uaString = req.get(\"User-Agent\") ?? \"\";\n const uaLower = uaString.toLowerCase();\n const regex = createRegExp(anyOf('headless', 'puppeteer', 'selenium', 'playwright', 'phantomjs'));\n \n if (regex.test(uaLower)) {\n score += penalties.headlessBrowser;\n reasons.push('HEADLESS_BROWSER_DETECTED');\n }\n\n if (!uaString || uaString.length < 10) {\n score += penalties.shortUserAgent;\n reasons.push('SHORT_USER_AGENT');\n }\n\n const tlsCheckScore = this.tlsBotScore(req, config);\n if (tlsCheckScore > 0) {\n score += tlsCheckScore;\n reasons.push('TLS_CHECK_FAILED');\n }\n\n const headers = new HeaderAnalysis(req);\n const headerChecker = await headers.scoreHeaders();\n \n if (headerChecker > 0) {\n score += headerChecker;\n reasons.push('HEADER_SCORE_TOO_HIGH');\n }\n\n\n const pathChecker = this.pathScore(req, config);\n if (pathChecker > 0) {\n score += pathChecker;\n reasons.push('PATH_TRAVELER_FOUND');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new UaAndHeaderChecker());","import { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class GeoLocationChecker implements IBotChecker<BanReasonCode> {\n name = 'Geo-Location Verification';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableGeoChecks.enable;\n }\n\n private isAllowedCountry(country: string, bannedCountries: string[]): boolean {\n const blockedCountries = bannedCountries;\n return !blockedCountries.includes(country.trim().toLowerCase());\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableGeoChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const penalties = checkConfig.penalties;\n const banScore = config.banScore;\n\n const details = ctx.geoData;\n const country = details.country;\n const countryCode = details.countryCode;\n\n if (countryCode || country) {\n const banned = checkConfig.bannedCountries;\n const codeMatch = !!countryCode && !this.isAllowedCountry(countryCode, banned);\n const nameMatch = !!country && !this.isAllowedCountry(country, banned);\n if (codeMatch || nameMatch) {\n score += banScore;\n reasons.push('BANNED_COUNTRY');\n }\n\n } else {\n score += penalties.countryUnknown;\n reasons.push('COUNTRY_UNKNOWN');\n }\n\n const region = details.region;\n const regionName = details.regionName;\n if (!region || !regionName) {\n score += penalties.regionUnknown;\n reasons.push('REGION_UNKNOWN');\n }\n \n if (!details.lat || !details.lon) {\n score += penalties.latLonUnknown;\n reasons.push('LAT_LON_UNKNOWN');\n }\n\n if (!details.district) {\n score += penalties.districtUnknown; \n reasons.push('DISTRICT_UNKNOWN');\n }\n \n if (!details.city) {\n score += penalties.cityUnknown; \n reasons.push('CITY_UNKNOWN');\n }\n\n if (!details.timezone) {\n score += penalties.timezoneUnknown;\n reasons.push('TIMEZONE_UNKNOWN');\n }\n\n if (!details.subregion) {\n score += penalties.subregionUnknown; \n reasons.push('SUBREGION_UNKNOWN' as BanReasonCode);\n }\n\n if (!details.phone) {\n score += penalties.phoneUnknown;\n reasons.push('PHONE_UNKNOWN' as BanReasonCode);\n }\n\n if (!details.continent) {\n score += penalties.continentUnknown;\n reasons.push('CONTINENT_UNKNOWN' as BanReasonCode);\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new GeoLocationChecker());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class ThreatLevels implements IBotChecker<BanReasonCode> {\n name = 'Known ThreatLevels';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig) {\n return config.checkers.enableKnownThreatsDetections.enable;\n }\n \n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const { enableKnownThreatsDetections } = config.checkers;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!enableKnownThreatsDetections.enable) return { score, reasons };\n const {anonymiseNetwork, threatLevels} = enableKnownThreatsDetections.penalties;\n\n if (ctx.anon) {\n score += anonymiseNetwork;\n reasons.push('ANONYMITY_NETWORK');\n }\n\n switch (ctx.threatLevel) {\n case 1: {\n score += threatLevels.criticalLevel1;\n reasons.push('FIREHOL_L1_THREAT');\n break;\n }\n case 2: {\n score += threatLevels.currentAttacksLevel2;\n reasons.push('FIREHOL_L2_THREAT');\n break;\n }\n case 3: {\n score += threatLevels.threatLevel3;\n reasons.push('FIREHOL_L3_THREAT');\n break;\n }\n\n case 4: {\n score += threatLevels.threatLevel4;\n reasons.push('FIREHOL_L4_THREAT');\n break;\n }\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new ThreatLevels());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class AsnClassificationChecker implements IBotChecker<BanReasonCode> {\n name = 'ASN Classification';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableAsnClassification.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableAsnClassification;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const { penalties } = checkConfig;\n const { classification, hits } = ctx.bgp;\n\n if (!classification) {\n score += penalties.unknownClassification;\n reasons.push('ASN_CLASSIFICATION_UNKNOWN');\n return { score, reasons };\n }\n\n if (classification === 'Content') {\n score += penalties.contentClassification;\n reasons.push('ASN_HOSTING_CLASSIFIED');\n }\n\n const hitsNum = parseInt(hits ?? '', 10);\n const isLowVisibility = Number.isFinite(hitsNum) && hitsNum >= 0 && hitsNum < penalties.lowVisibilityThreshold;\n\n if (isLowVisibility) {\n score += penalties.lowVisibilityPenalty;\n reasons.push('ASN_LOW_VISIBILITY');\n }\n\n if (classification === 'Content' && isLowVisibility) {\n score += penalties.comboHostingLowVisibility;\n reasons.push('ASN_HOSTING_LOW_VISIBILITY_COMBO');\n }\n\n return { score, reasons };\n }\n}\nCheckerRegistry.register(new AsnClassificationChecker());\n","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class TorAnalysisChecker implements IBotChecker<BanReasonCode> {\n name = 'Tor Node Analysis';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableTorAnalysis.enable;\n }\n\n private parseFlags(flags: string | undefined): Set<string> {\n if (!flags) return new Set();\n return new Set(flags.split(',').map(f => f.trim()));\n }\n\n\n private canExitWebTraffic(summary: string | undefined): boolean {\n if (!summary) return false;\n try {\n const policy = JSON.parse(summary) as { accept?: string[]; reject?: string[] };\n\n const coversWebPort = (entry: string): boolean => {\n if (entry === '80' || entry === '443') return true;\n if (entry.includes('-')) {\n const [lo, hi] = entry.split('-').map(Number);\n return (lo <= 80 && 80 <= hi) || (lo <= 443 && 443 <= hi);\n }\n return false;\n };\n\n if (policy.accept) {\n return policy.accept.some(coversWebPort);\n }\n\n if (policy.reject) {\n return !policy.reject.some(coversWebPort);\n }\n } catch {}\n \n return false;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableTorAnalysis;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!ctx.tor || Object.keys(ctx.tor).length === 0) return { score, reasons };\n\n const { penalties } = checkConfig;\n const {\n running,\n exit_addresses,\n flags,\n recommended_version,\n version_status,\n exit_probability,\n exit_policy_summary,\n guard_probability,\n } = ctx.tor;\n\n const flagSet = this.parseFlags(flags);\n\n if (running) {\n score += penalties.runningNode;\n reasons.push('TOR_ACTIVE_NODE');\n }\n\n const isExitNode = (exit_addresses && exit_addresses.length > 0) ?? flagSet.has('Exit');\n if (isExitNode) {\n score += penalties.exitNode + Math.ceil((exit_probability ?? 0) * 30);\n reasons.push('TOR_EXIT_NODE');\n\n if (this.canExitWebTraffic(exit_policy_summary)) {\n score += penalties.webExitCapable;\n reasons.push('TOR_WEB_EXIT_CAPABLE');\n }\n }\n\n if (flagSet.has('BadExit')) {\n score += penalties.badExit;\n reasons.push('TOR_BAD_EXIT');\n }\n\n if (flagSet.has('Guard') || (guard_probability ?? 0) > 0) {\n score += penalties.guardNode;\n reasons.push('TOR_GUARD_NODE');\n }\n\n if (recommended_version === false || version_status === 'obsolete') {\n score += penalties.obsoleteVersion;\n reasons.push('TOR_OBSOLETE_VERSION');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new TorAnalysisChecker());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class TimezoneConsistencyChecker implements IBotChecker<BanReasonCode> {\n name = 'Timezone Consistency';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableTimezoneConsistency.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableTimezoneConsistency;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n\n const geoTimezone = ctx.geoData.timezone?.toLowerCase();\n if (!geoTimezone) return { score, reasons };\n\n const tzHeader = ctx.req.get('Sec-CH-UA-Timezone') ?? ctx.req.get('X-Timezone');\n if (tzHeader && tzHeader.toLowerCase() !== geoTimezone) {\n score += checkConfig.penalties;\n reasons.push('TZ_HEADER_GEO_MISMATCH');\n }\n\n return { score, reasons };\n }\n}\nCheckerRegistry.register(new TimezoneConsistencyChecker());\n","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class HoneypotChecker implements IBotChecker<BanReasonCode> {\n name = 'Honeypot Path';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.honeypot.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.honeypot;\n const reasons: BanReasonCode[] = [];\n\n if (!checkConfig.enable || checkConfig.paths.length === 0) {\n return { score: 0, reasons };\n }\n\n const requestPath = ctx.req.path.toLowerCase();\n const hit = checkConfig.paths.some(p => requestPath === p.toLowerCase());\n\n if (hit) {\n reasons.push('HONEYPOT_PATH_HIT');\n reasons.push('BAD_BOT_DETECTED');\n }\n\n return { score: 0, reasons };\n }\n}\n\nCheckerRegistry.register(new HoneypotChecker());","import consola from 'consola';\nimport { getStorage } from '~~/src/botDetector/config/config.js';\n\nexport interface SessionEntry {\n lastPath: string;\n}\n\nconst SESSION_TTL_SECONDS = 600;\nconst PREFIX = 'session:';\n\nexport const sessionCache = {\n async get(sessionId: string): Promise<SessionEntry | null> {\n const key = `${PREFIX}${sessionId}`;\n const storage = getStorage();\n const data = await storage.getItem<SessionEntry>(key);\n\n if (data) {\n storage.setItem(key, data, { ttl: SESSION_TTL_SECONDS }).catch((err: unknown) => {\n consola.warn(`Failed to update session TTL for ${key}`, err);\n });\n }\n\n return data;\n },\n\n async set(sessionId: string, entry: SessionEntry): Promise<void> {\n const key = `${PREFIX}${sessionId}`;\n await getStorage().setItem(key, entry, { ttl: SESSION_TTL_SECONDS });\n },\n\n async delete(sessionId: string): Promise<void> {\n const key = `${PREFIX}${sessionId}`;\n await getStorage().removeItem(key);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n\n};","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { sessionCache } from \"../helpers/cache/sessionCache.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\nexport class SessionCoherenceChecker implements IBotChecker<BanReasonCode> {\n name = 'Session Coherence';\n phase = 'heavy' as const;\n \n private _logger?: ReturnType<typeof getLogger>;\n private get logger() {\n this._logger ??= getLogger().child({service: 'botDetector', branch: 'checker', type: 'SessionCoherenceChecker'});\n return this._logger;\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableSessionCoherence.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableSessionCoherence;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n if (!ctx.cookie) return { score, reasons };\n\n const currentPath = ctx.req.path;\n const refererHeader = ctx.req.get('Referer');\n const secFetchSite = ctx.req.get('Sec-Fetch-Site');\n const currentHostname = ctx.req.hostname;\n const cached = await sessionCache.get(ctx.cookie);\n\n const missingSameOriginReferer = secFetchSite === 'same-origin' && !refererHeader;\n const missingSubsequentReferer = cached && !refererHeader;\n\n if (missingSameOriginReferer || missingSubsequentReferer) {\n score += checkConfig.penalties.missingReferer;\n reasons.push('SESSION_COHERENCE_MISSING_REFERER');\n }\n\n else if (refererHeader) {\n try {\n const refererUrl = new URL(refererHeader);\n\n if (refererUrl.hostname !== currentHostname) {\n score += checkConfig.penalties.domainMismatch;\n reasons.push('SESSION_COHERENCE_DOMAIN_MISMATCH');\n } \n\n else if (cached && refererUrl.pathname !== cached.lastPath) {\n score += checkConfig.penalties.pathMismatch;\n reasons.push('SESSION_COHERENCE_PATH_MISMATCH');\n }\n } catch {\n score += checkConfig.penalties.missingReferer; \n reasons.push('SESSION_COHERENCE_INVALID_REFERER');\n }\n }\n\n sessionCache.set(ctx.cookie, { lastPath: currentPath }).catch((err: unknown) => {\n this.logger.error({err}, 'Failed to save session in storage.');\n });\n \n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new SessionCoherenceChecker());","import { getStorage } from '~~/src/botDetector/config/config.js';\n\nconst TIMING_TTL_SECONDS = 60 * 15;\nconst PREFIX = 'timing:';\n\nexport const timingCache = {\n async get(visitorId: string): Promise<number[] | null> {\n const key = `${PREFIX}${visitorId}`;\n return await getStorage().getItem<number[]>(key);\n },\n\n async set(visitorId: string, entry: number[]): Promise<void> {\n const key = `${PREFIX}${visitorId}`;\n await getStorage().setItem(key, entry, { ttl: TIMING_TTL_SECONDS });\n },\n\n async delete(visitorId: string): Promise<void> {\n const key = `${PREFIX}${visitorId}`;\n await getStorage().removeItem(key);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n\n};","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { timingCache } from \"../helpers/cache/timingCache.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\nconst MAX_SAMPLES = 10;\nconst MIN_SAMPLES_TO_EVALUATE = 5;\n\nexport class VelocityFingerprintChecker implements IBotChecker<BanReasonCode> {\n name = 'Velocity Fingerprinting';\n phase = 'heavy' as const;\n private _logger?: ReturnType<typeof getLogger>;\n private get logger() {\n this._logger ??= getLogger().child({service: 'botDetector', branch: 'checker', type: 'VelocityFingerprintChecker'});\n return this._logger;\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableVelocityFingerprint.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableVelocityFingerprint;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable || !ctx.cookie) return { score, reasons };\n\n const now = Date.now();\n const existing = await timingCache.get(ctx.cookie) ?? [];\n const timestamps = [...existing, now].slice(-MAX_SAMPLES);\n\n timingCache.set(ctx.cookie, timestamps).catch((err: unknown) => {\n this.logger.error({err}, 'Failed to save timingCache in storage');\n });\n\n if (timestamps.length < MIN_SAMPLES_TO_EVALUATE) return { score, reasons };\n\n const intervals: number[] = [];\n for (let i = 1; i < timestamps.length; i++) {\n intervals.push(timestamps[i] - timestamps[i - 1]);\n }\n\n const mean = intervals.reduce((a, b) => a + b, 0) / intervals.length;\n if (mean === 0) return { score, reasons };\n\n const variance = intervals.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / intervals.length;\n const cv = Math.sqrt(variance) / mean;\n\n if (cv < checkConfig.cvThreshold) {\n score += checkConfig.penalties;\n reasons.push('TIMING_TOO_REGULAR');\n }\n\n return { score, reasons };\n }\n}\nCheckerRegistry.register(new VelocityFingerprintChecker());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { getDataSources } from \"../config/config.js\";\n\n\nexport class KnownBadIps implements IBotChecker<BanReasonCode> {\n name = 'KnownBadIps';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig) {\n return config.checkers.enableKnownBadIpsCheck.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const { enableKnownBadIpsCheck } = config.checkers;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!enableKnownBadIpsCheck.enable) return { score, reasons };\n\n const ds = getDataSources();\n const ip = ctx.ipAddress;\n\n const banned = ds.bannedDataBase(ip);\n if (banned) {\n reasons.push('PREVIOUSLY_BANNED_IP', 'BAD_BOT_DETECTED');\n return { score, reasons };\n }\n\n const highRisk = ds.highRiskDataBase(ip);\n if (highRisk) {\n const ratio = Math.min(highRisk.score / config.banScore, 1);\n score += Math.round(enableKnownBadIpsCheck.highRiskPenalty * ratio);\n reasons.push('PREVIOUSLY_HIGH_RISK_IP');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new KnownBadIps());","export class BadBotDetected extends Error {\n constructor(message = 'Bad bot detected') {\n super(message);\n this.name = 'BadBotDetected';\n }\n}\n\nexport class GoodBotDetected extends Error {\n constructor(message = 'Good bot detected') {\n super(message);\n this.name = 'GoodBotDetected';\n }\n}\n","import { spawn } from 'child_process';\nimport type { BannedInfo } from '../types/checkersTypes.js';\nimport { getLogger } from '../utils/logger.js';\nimport { getConfiguration } from \"../config/config.js\";\n\nconst UFW = '/usr/sbin/ufw';\n\n\nexport function banIp(ip: string, info: BannedInfo): Promise<void> | void { \n const log = getLogger().child({service: 'BOT DETECTOR', branch: `banIp`, ipAddress: ip, details: info});\n const {punishmentType} = getConfiguration();\n\n if (!punishmentType.enableFireWallBan) {\n log.info(`Firewall punishment ban is disabled, skipping`);\n return;\n }\n\n log.info('about to ban an IP');\n return new Promise((resolve, reject) => {\n const child = spawn('sudo', ['-n', UFW, 'insert', '1', 'deny', 'from', ip], {\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: true \n });\n child.unref(); \n\n let stderr = '';\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n log.warn(`ufw hang timeout on ${ip}`);\n reject(new Error(`ufw hang timeout on ${ip}`));\n }, 5_000);\n\n child.stderr.on('data', (d: Buffer | string) => (stderr += String(d)));\n child.on('error', err => {\n clearTimeout(timer);\n log.fatal({err},`- CRITICAL - UFW spawn failed`);\n reject(err);\n });\n child.on('close', code => {\n clearTimeout(timer);\n if (code !== 0) {\n log.fatal({code},`- CRITICAL - UFW ban failed`);\n reject(new Error(`ufw exited ${String(code)}`)); return;\n }\n log.info(`Banning Detected Bot/Malicious User. IP ${ip} banned (score ${String(info.score)})\\nReasons:\\n- ${info.reasons.join('\\n- ')}`);\n resolve();\n });\n });\n}\n","import type { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { getLogger } from \"../utils/logger.js\";\nimport { performance } from 'perf_hooks';\nimport { getConfiguration } from \"../config/config.js\";\nimport type { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport type { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { BadBotDetected, GoodBotDetected } from \"./exceptions.js\";\n\nexport async function processChecks(\n checkers: IBotChecker<BanReasonCode, unknown>[],\n ctx: ValidationContext<unknown>,\n config: BotDetectorConfig,\n botScore: number,\n reasons: BanReasonCode[],\n phaseLabel = 'phase' \n): Promise<number> {\n\n const {banScore} = getConfiguration();\n const log = getLogger().child({service: `BOT DETECTOR`, branch: 'checks'});\n const reqId = Date.now(); \n\n const phaseStart = performance.now();\n log.info({ phase: phaseLabel, reqId, event: 'start' });\n \n const banLimit = banScore;\n\n for (const checker of checkers) {\n const label = checker.name;\n\n const checkStart = performance.now();\n log.info({ reqId, check: label, event: 'start' });\n\n const { score, reasons: rs } = await checker.run(ctx, config);\n\n const checkEnd = performance.now();\n log.info({reqId,check: label,event: 'end',durationMs: +(checkEnd - checkStart).toFixed(3),score,reasons: rs,});\n\n botScore += score;\n rs.forEach(r => reasons.push(r));\n \n if (rs.includes('GOOD_BOT_IDENTIFIED')) throw new GoodBotDetected();\n if (rs.includes('BAD_BOT_DETECTED')) throw new BadBotDetected();\n\n if (botScore >= banLimit) {\n log.warn({ reqId, botScore }, 'Bot detected — aborting checks');\n break;\n }\n }\n const phaseEnd = performance.now();\n log.info({\n reqId,\n phase: phaseLabel,\n event: 'end',\n durationMs: +(phaseEnd - phaseStart).toFixed(3),\n Score: botScore\n });\n return botScore;\n}","import { getStorage, getConfiguration } from '../../config/config.js';\n\nexport interface CachedResult {\n isBot: boolean;\n score: number;\n}\n\nconst PREFIX = 'reputation:';\n\nexport const reputationCache = {\n async get(cookie: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${cookie}`);\n },\n\n async set(cookie: string, entry: CachedResult): Promise<void> {\n const { checksTimeRateControl } = getConfiguration();\n await getStorage().setItem(`${PREFIX}${cookie}`, entry, { ttl: Math.floor(checksTimeRateControl.checkEvery / 1000) });\n },\n\n async delete(cookie: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${cookie}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import './botDetector/checkers/index.js'; \nimport { Request } from 'express';\nimport { CheckerRegistry } from './botDetector/checkers/CheckerRegistry.js';\nimport { ValidationContext } from './botDetector/types/botDetectorTypes.js';\nimport { BadBotDetected, GoodBotDetected } from './botDetector/helpers/exceptions.js';\nimport { banIp } from './botDetector/penalties/banIP.js';\nimport type { ParsedUAResult } from './botDetector/types/UAparserTypes.js';\nimport type { GeoResponse } from './botDetector/types/geoTypes.js';\nimport { BanReasonCode } from './botDetector/types/checkersTypes.js';\nimport { processChecks } from './botDetector/helpers/processChecks.js';\nimport { reputationCache } from './botDetector/helpers/cache/reputationCache.js';\nimport { getLogger } from './botDetector/utils/logger.js';\nimport { getConfiguration, getDataSources, getBatchQueue } from './botDetector/config/config.js';\n\nexport async function uaAndGeoBotDetector(\n req: Request,\n ipAddress: string,\n userAgent: string,\n geo: GeoResponse,\n parsedUA: ParsedUAResult,\n buildCustomContext?: (req: Request) => unknown,\n): Promise<boolean> {\n \n const log = getLogger().child({service: 'BOT DETECTOR', branch: 'main'});\n const {banScore, maxScore, setNewComputedScore} = getConfiguration();\n const BAN_THRESHOLD = banScore;\n const MAX_SCORE = maxScore;\n\n const reasons: BanReasonCode[] = [];\n let botScore = 0;\n const cookie: string | undefined = req.cookies.canary_id as string | undefined; \n const uaString = req.get(\"User-Agent\") ?? \"\";\n log.info(`BotDetection called for ${req.method} ${req.get('X-Forwarded-Host') ?? ''}`);\n\n const threatsLevels = getDataSources().fireholLvl1DataBase(ipAddress) ? 1 :\n getDataSources().fireholLvl2DataBase(ipAddress) ? 2 :\n getDataSources().fireholLvl3DataBase(ipAddress) ? 3 :\n getDataSources().fireholLvl4DataBase(ipAddress) ? 4 : null as 1 | 2 | 3 | 4 | null;\n\n const proxy = () => {\n const isProxy = getDataSources().proxyDataBase(ipAddress);\n if (isProxy) {\n return {\n proxy: true,\n proxyType: isProxy.comment\n };\n }\n return { proxy: false };\n };\n \n const {tor, asn, threatLevel, anon} = {\n tor: getDataSources().torDataBase(ipAddress),\n asn: getDataSources().asnDataBase(ipAddress),\n threatLevel: threatsLevels,\n anon: getDataSources().fireholAnonDataBase(ipAddress) ? true : false,\n };\n\n const proxyResult = proxy();\n const ctx: ValidationContext<unknown> = {\n req,\n ipAddress,\n parsedUA: parsedUA,\n geoData: geo,\n cookie,\n proxy: {\n isProxy: proxyResult.proxy,\n proxyType: proxyResult.proxyType\n },\n anon,\n bgp: asn ?? {},\n tor: tor ?? {},\n threatLevel,\n custom: buildCustomContext ? buildCustomContext(req) : ({} as unknown),\n };\n\n const cheapChecks = CheckerRegistry.getEnabled('cheap', getConfiguration());\n const checks = CheckerRegistry.getEnabled('heavy', getConfiguration());\n\n try {\n botScore = await processChecks(cheapChecks, ctx, getConfiguration(), botScore, reasons, 'cheapPhase');\n\n if (botScore < BAN_THRESHOLD) {\n botScore = await processChecks(checks, ctx, getConfiguration(), botScore, reasons, 'heavyPhase');\n }\n } catch (error) {\n if (error instanceof BadBotDetected) {\n const bannedInfo = { score: BAN_THRESHOLD, reasons: Array.from(reasons) };\n\n void banIp(ipAddress, bannedInfo);\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'update_banned_ip', { cookie: cookie ?? '', ipAddress, country: ctx.geoData.country ?? '', user_agent: uaString, info: bannedInfo }, 'deferred');\n\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'is_bot_update', { isBot: true, cookie: cookie ?? '' }, 'deferred');\n return true;\n }\n if (error instanceof GoodBotDetected) {\n return false;\n }\n log.error({error},'unexpected error');\n }\n\n botScore = Math.min(botScore, MAX_SCORE);\n if (botScore >= BAN_THRESHOLD) {\n log.info(`Starting Ban for ${ipAddress} ${userAgent}`);\n const bannedInfo = { score: botScore, reasons: Array.from(reasons) };\n\n void banIp(ipAddress, bannedInfo);\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'update_banned_ip', { cookie: cookie ?? '', ipAddress, country: ctx.geoData.country ?? '', user_agent: uaString, info: bannedInfo }, 'deferred');\n\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'is_bot_update', { isBot: true, cookie: cookie ?? '' }, 'deferred');\n return true;\n }\n\n\n if (setNewComputedScore) {\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'score_update', { score: botScore, cookie: cookie ?? '' }, 'deferred');\n\n reputationCache.set(cookie ?? '', { isBot: false, score: botScore }).catch((err: unknown) => {\n log.error({err}, 'Failed to set reputationCache in storage');\n });\n\n } else {\n const cached = await reputationCache.get(cookie ?? '');\n if (!cached || cached.score === 0) {\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'score_update', { score: botScore, cookie: cookie ?? '' }, 'deferred');\n\n reputationCache.set(cookie ?? '', { isBot: false, score: botScore }).catch((err: unknown) => {\n log.error({err}, 'Failed to set reputationCache in storage');\n });\n \n }\n }\n return false;\n}\n\n","import { getStorage, getConfiguration } from '../../config/config.js';\n\nexport interface CachedResult {\n banned: boolean;\n visitor_id: string;\n}\n\nconst PREFIX = 'visitor:';\n\nexport const visitorCache = {\n async get(cookie: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${cookie}`);\n },\n\n async set(cookie: string, entry: CachedResult): Promise<void> {\n const { checksTimeRateControl } = getConfiguration();\n await getStorage().setItem(`${PREFIX}${cookie}`, entry, { ttl: Math.floor(checksTimeRateControl.checkEvery / 1000) });\n },\n\n async delete(cookie: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${cookie}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import { reputationCache } from \"./cache/reputationCache.js\";\nimport { getLogger } from \"../utils/logger.js\";\nimport { getBatchQueue, getConfiguration, getDb } from \"../config/config.js\";\nimport { prep } from \"../db/dialectUtils.js\";\n\ninterface VisitorRow {\n is_bot: number;\n suspicious_activity_score: number;\n}\n\nexport async function userReputation(cookie: string): Promise<void> {\n const log = getLogger().child({service: `BOT DETECTOR`, branch: `reputation`});\n const db = getDb();\n const {banScore, restoredReputationPoints, setNewComputedScore} = getConfiguration();\n\n const botScore = banScore;\n\n const cached = await reputationCache.get(cookie);\n if (cached) {\n log.info(`CACHE HIT cookie=${cookie} score=${String(cached.score)} → (botScore=${String(botScore)})`);\n if(cached.isBot) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!cached.isBot && cached.score > 0 && cached.score < botScore) {\n log.info(`updating cache score cookie=${cookie} score=${String(cached.score)} → (botScore=${String(botScore)})`);\n const newReputation = Math.max(0, cached.score - restoredReputationPoints);\n\n if (newReputation !== cached.score) {\n void getBatchQueue().addQueue(cookie, '', 'score_update', { score: newReputation, cookie }, 'deferred');\n log.info(`updating cache score to DB cookie=${cookie} score=${String(cached.score)} → (botScore=${String(botScore)})`);\n reputationCache.set(cookie, {\n isBot: cached.isBot,\n score: newReputation\n }).catch((err: unknown) => {\n log.error({ err }, 'Failed to save reputationCache in storage');\n });\n }\n log.info(`finished Updating Score from cache to DB cookie: ${cookie} NEW SCORE: ${String(newReputation)}`);\n }\n return;\n }\n\n\n try {\n const VisitorQuery = `\n SELECT is_bot,\n suspicious_activity_score\n FROM visitors\n WHERE canary_id = ?\n LIMIT 1`;\n\n const visitor = await prep(db, VisitorQuery).get(cookie) as VisitorRow | undefined;\n\n if (!visitor) {\n log.warn(`no visitor record for canary_id=${cookie}`);\n return;\n }\n\n const isBot = visitor.is_bot === 0 ? false : true;\n const reputation = visitor.suspicious_activity_score;\n\n\n if (isBot) return;\n\n if (!setNewComputedScore) {\n reputationCache.set(cookie, {\n isBot: isBot,\n score: reputation\n }).catch((err: unknown) => {\n log.error({ err }, 'Failed to save reputationCache in storage');\n });\n }\n\n log.info({\n label: '[REP-GATE]',\n isBot: isBot,\n score: reputation,\n 'score>0': reputation > 0,\n 'score<ban': reputation < botScore,\n healPts: restoredReputationPoints\n });\n\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!isBot && reputation > 0 && reputation < botScore) {\n log.info(`calculating new score cookie=${cookie} score=${String(reputation)} → (botScore=${String(botScore)})`);\n const newReputation = Math.max(0, reputation - restoredReputationPoints);\n\n if (newReputation !== reputation) {\n void getBatchQueue().addQueue(cookie, '', 'score_update', { score: newReputation, cookie }, 'deferred');\n log.info(`Update Score for cookie', ${cookie}, 'New Score:', ${String(newReputation)}`);\n\n reputationCache.set(cookie, {\n isBot: isBot,\n score: newReputation\n }).catch((err: unknown) => {\n log.error({ err }, 'Failed to save reputationCache in storage');\n });\n }\n\n }\n } catch(err) {\n log.error({err},`An error occurred updating visitor reputation`);\n }\n}","/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { getConfiguration } from \"../config/config.js\";\n\n\nexport function getWhiteList(): string[] {\n const {whiteList} = getConfiguration();\n if (whiteList) return whiteList;\n return [];\n}\n\nexport function isInWhiteList(ipAddress: string): boolean {\n const {whiteList} = getConfiguration();\n\n if (whiteList) {\n const match = whiteList.includes(ipAddress);\n return match;\n }\n\n return false;\n}\n\n","export const nowMysql = () => new Date().toISOString().slice(0, 19).replace('T', ' ');","import { getData } from '../helpers/getIPInformation.js';\nimport { makeCookie } from '../utils/cookieGenerator.js';\nimport type { Request, Response, NextFunction, RequestHandler } from \"express\";\nimport { randomBytes, randomUUID } from \"crypto\";\nimport parseUA from '../helpers/UAparser.js';\nimport { uaAndGeoBotDetector } from '../../botDetector.js';\nimport { visitorCache } from '../helpers/cache/cannaryCache.js';\nimport { rateCache } from '../helpers/cache/rateLimitarCache.js';\nimport { userReputation } from '../helpers/reputation.js';\nimport { getLogger } from '../utils/logger.js';\nimport type { userValidation } from '../types/fingerPrint.js';\nimport { getConfiguration, getBatchQueue } from '../config/config.js';\nimport { isInWhiteList } from '../utils/whitelist.js';\nimport { nowMysql } from '@utils/nowMysql.js';\nimport consola from 'consola';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n export interface Request {\n newVisitorId?: string;\n botDetection: {\n success: boolean,\n banned: boolean,\n time: string,\n ipAddress: string\n }\n }\n }\n}\n\n\nexport function validator(\n buildCustomContext?: (req: Request) => unknown,\n): RequestHandler {\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n const {checksTimeRateControl} = getConfiguration();\n let canary: string | undefined = req.cookies.canary_id as string | undefined;\n const ua = req.get(\"User-Agent\") ?? \"\";\n const ip = req.ip ?? '';\n const log = getLogger().child({service: 'BOT DETECTOR', branch: `main`, canary: canary});\n log.info(`Validator entered for ${req.method} ${req.get('X-Forwarded-Host') ?? ''}`);\n log.info({ cookies: req.cookies },`Incoming cookies`);\n const whiteList = isInWhiteList(ip);\n\n if (canary) {\n const cached = await visitorCache.get(canary);\n if (cached) {\n if (cached.banned && !whiteList) {\n res.sendStatus(403);\n return;\n }\n req.newVisitorId = cached.visitor_id;\n if (!checksTimeRateControl.checkEveryRequest){\n next(); return;\n }\n }\n }\n \n if (!canary) {\n log.info(`No canary_id cookie found. Generating a new one.`);\n const cookieValue = randomBytes(32).toString('hex');\n canary = cookieValue;\n \n makeCookie(res,'canary_id', cookieValue, {\n httpOnly: true,\n sameSite: \"lax\", \n maxAge: 1000 * 60 * 60 * 24 * 90,\n secure: true,\n path: \"/\", \n });\n req.cookies.canary_id = canary;\n log.info(`New canary_id cookie set:, ${cookieValue}`);\n }\n\n const geo = getData(ip);\n const parsedUA = parseUA(ua);\n const visitorId = randomUUID();\n\n const userValidation = {\n visitorId,\n cookie: canary,\n userAgent: ua,\n ipAddress: ip,\n device_type: parsedUA.device,\n browser: parsedUA.browser,\n is_bot: false,\n first_seen: nowMysql(), \n last_seen: nowMysql(), \n request_count: 1, \n deviceVendor: parsedUA.deviceVendor,\n deviceModel: parsedUA.deviceModel,\n browserType: parsedUA.browserType,\n browserVersion: parsedUA.browserVersion,\n os: parsedUA.os,\n activity_score: '0',\n ...geo,\n } as userValidation;\n\n void getBatchQueue().addQueue(canary, ip, 'visitor_upsert', { insert: userValidation }, 'deferred');\n req.newVisitorId = visitorId;\n\n if (whiteList) {\n log.info(`${ip} is in white list skipping botDetection checks.`);\n\n visitorCache.set(canary, {\n banned: false,\n visitor_id: visitorId\n }).catch((err: unknown) => { log.error({ err }, 'Failed to save visitorCache in storage'); });\n\n req.botDetection = {\n success: true,\n banned: false,\n time: new Date().toISOString(),\n ipAddress: ip\n };\n\n next(); return;\n };\n\n const brvConfig = getConfiguration().checkers.enableBehaviorRateCheck;\n if (brvConfig.enable) {\n const existing = await rateCache.get(canary);\n if (!existing) {\n const ttlSeconds = Math.ceil(brvConfig.behavioral_window / 1000);\n rateCache.set(canary, { score: 0, timestamp: Date.now(), request_count: 1 }, ttlSeconds)\n .catch((err: unknown) => { log.error({ err }, 'Failed to pre seed rateCache'); });\n }\n }\n\n const isBot = await uaAndGeoBotDetector(req, ip, ua, geo, parsedUA, buildCustomContext);\n\n visitorCache.set(canary, {\n banned: isBot,\n visitor_id: visitorId\n }).catch((err: unknown) => { log.error({ err }, 'Failed to save visitorCache in storage'); });\n\n if (isBot) {\n res.sendStatus(403);\n return;\n }\n\n req.botDetection = {\n success: true,\n banned: isBot,\n time: new Date().toISOString(),\n ipAddress: ip\n };\n \n userReputation(canary).catch((err: unknown) => { consola.error('[BOT DETECTION - MIDDLEWARE] userReputation failed:', err); });\n\n next();\n };\n}\n","import { Router } from 'express';\nimport { validator } from '../middlewares/canaryCookieChecker.js';\n\n\nconst router = Router();\n\nrouter.use('/check', validator(), (req, res) => {\n res.json({results: req.botDetection, message: 'Fingerprint logged successfully' });\n});\n\nexport default router;\n\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 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 consola from 'consola';\nimport { getDb } from '../config/config.js';\nimport { prep } from './dialectUtils.js';\n\nexport async function warmUp() {\nconst db = getDb();\nawait Promise.all(\n Array.from({ length: 10 }, () => db.sql`SELECT 1`)\n);\n\nawait prep(db,\n `SELECT last_seen, request_count\n FROM visitors\n WHERE canary_id = ?\n LIMIT 1`\n).get('00000000‑warm‑up‑row');\n\nconsola.info('botDetector is ready!');\n}","import { getLogger } from \"../utils/logger.js\";\nimport { getDb } from \"../config/config.js\";\nimport { prep } from \"./dialectUtils.js\";\n\nexport interface VisitorFingerPrint {\n userAgent: string;\n ipAddress: string;\n country: string;\n region: string;\n regionName: string;\n city: string;\n district: string;\n lat: string;\n lon: string;\n timezone: string;\n currency: string;\n isp: string;\n org: string;\n as: string;\n device_type: string;\n browser: string;\n proxy: boolean;\n hosting: boolean;\n deviceVendor: string;\n deviceModel: string;\n browserType: string;\n browserVersion: string;\n os: string;\n}\n\n\nexport async function updateVisitors(\n data: VisitorFingerPrint,\n cookie: string,\n visitor_id: string,\n): Promise<{ success: boolean; reason?: string }> {\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'customUpdate' });\n\n const params = [\n data.userAgent,\n data.ipAddress,\n data.country,\n data.region,\n data.regionName,\n data.city,\n data.district,\n data.lat,\n data.lon,\n data.timezone,\n data.currency,\n data.isp,\n data.org,\n data.as,\n data.device_type,\n data.browser,\n data.proxy,\n data.hosting,\n data.deviceVendor,\n data.deviceModel,\n data.browserType,\n data.browserVersion,\n data.os,\n ] satisfies (string | boolean)[];\n\n try {\n const result = await prep(db, `\n UPDATE visitors\n SET\n user_agent = ?,\n ip_address = ?,\n country = ?,\n region = ?,\n region_name = ?,\n city = ?,\n district = ?,\n lat = ?,\n lon = ?,\n timezone = ?,\n currency = ?,\n isp = ?,\n org = ?,\n as_org = ?,\n device_type = ?,\n browser = ?,\n proxy = ?,\n hosting = ?,\n deviceVendor = ?,\n deviceModel = ?,\n browserType = ?,\n browserVersion = ?,\n os = ?\n WHERE canary_id = ?\n AND visitor_id = ?\n `).run(...params, cookie, visitor_id);\n\n if (!result.success) {\n log.warn({ cookie, visitor_id }, `updateVisitors: no rows affected`);\n return { success: false, reason: `No visitor found for canary_id=${cookie} visitor_id=${visitor_id}` };\n }\n\n log.info({ visitor_id }, `updateVisitors: visitor updated`);\n return { success: true };\n } catch (err) {\n log.error({ err }, `updateVisitors: query failed`);\n return { success: false, reason: 'DB error — check logs for details' };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.mjs","names":["path","existsSync","PREFIX","PREFIX","URL","path","PREFIX","PREFIX","PREFIX"],"sources":["../src/botDetector/types/configSchema.ts","../src/botDetector/db/findDataPath.ts","../src/botDetector/helpers/mmdbDataReaders.ts","../src/botDetector/utils/logger.ts","../src/botDetector/db/dialectUtils.ts","../src/botDetector/db/updateBanned.ts","../src/botDetector/db/updateIsBot.ts","../src/botDetector/db/updateVisitors.ts","../src/botDetector/db/updateVisitorScore.ts","../src/botDetector/db/batchQueue.ts","../src/botDetector/config/storageAdapter.ts","../src/botDetector/config/dbAdapter.ts","../src/botDetector/checkers/CheckerRegistry.ts","../src/botDetector/checkers/badUaChecker.ts","../src/botDetector/config/config.ts","../src/botDetector/helpers/getIPInformation.ts","../src/botDetector/utils/cookieGenerator.ts","../src/botDetector/helpers/UAparser.ts","../src/botDetector/checkers/ipValidation.ts","../src/botDetector/helpers/cache/dnsLookupCache.ts","../src/botDetector/checkers/goodBots/base.ts","../src/botDetector/checkers/goodBots/goodBots.ts","../src/botDetector/checkers/browserTypesAneDevicesCalc.ts","../src/botDetector/utils/regex/acceptLangRegex.ts","../src/botDetector/checkers/acceptLangMap.ts","../src/botDetector/helpers/cache/rateLimitarCache.ts","../src/botDetector/checkers/rateTracker.ts","../src/botDetector/checkers/proxyISPAndCookieCalc.ts","../src/botDetector/checkers/headers/headersBase.ts","../src/botDetector/checkers/headers/headers.ts","../src/botDetector/utils/regex/pathTravelersRegex.ts","../src/botDetector/checkers/UaAndHeaderChecker/base.ts","../src/botDetector/checkers/UaAndHeaderChecker/headersAndUACalc.ts","../src/botDetector/checkers/geoLocationCalc.ts","../src/botDetector/checkers/fireholEscalation.ts","../src/botDetector/checkers/asnClassification.ts","../src/botDetector/checkers/torAnalysis.ts","../src/botDetector/checkers/timezoneConsistency.ts","../src/botDetector/checkers/honeypot.ts","../src/botDetector/helpers/cache/sessionCache.ts","../src/botDetector/checkers/sessionCoherence.ts","../src/botDetector/helpers/cache/timingCache.ts","../src/botDetector/checkers/velocityFingerprint.ts","../src/botDetector/checkers/knownBadIps.ts","../src/botDetector/helpers/exceptions.ts","../src/botDetector/penalties/banIP.ts","../src/botDetector/helpers/processChecks.ts","../src/botDetector/helpers/cache/reputationCache.ts","../src/botDetector.ts","../src/botDetector/helpers/cache/cannaryCache.ts","../src/botDetector/helpers/reputation.ts","../src/botDetector/utils/whitelist.ts","../src/botDetector/utils/nowMysql.ts","../src/botDetector/middlewares/canaryCookieChecker.ts","../src/botDetector/routes/visitorLog.ts","../src/botDetector/db/generator.ts","../src/botDetector/db/schema.ts","../src/botDetector/db/warmUp.ts","../src/botDetector/db/customUpdate.ts"],"sourcesContent":["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 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 maxmind, { Reader } from 'maxmind';\nimport { open, type RootDatabase } from 'lmdb';\nimport type { BgpRecord, CityGeoRecord, GeoRecord, TorRecord, ThreatRecord, CrawlersRecord, ProxyRecord, UserAgentRecord, JA4 } from '@riavzon/shield-base';\nimport type { BannedRecord, HighRiskRecord } from '../types/generator.js';\nimport { existsSync } from \"node:fs\";\nimport { resolveDataPath } from '@db/findDataPath.js';\n\nexport type ThreatRecordModified = ThreatRecord & { network: string }\n\nexport interface DataReaders {\n asnDataBase(ip: string): BgpRecord | null;\n cityDataBase(ip: string): CityGeoRecord | null;\n countryDataBase(ip: string): GeoRecord | null;\n goodBotsDataBase(ip: string): CrawlersRecord | null;\n torDataBase(ip: string): TorRecord | null;\n proxyDataBase(ip: string): ProxyRecord | null;\n fireholAnonDataBase(ip: string): ThreatRecordModified | null;\n fireholLvl1DataBase(ip: string): ThreatRecordModified | null;\n fireholLvl2DataBase(ip: string): ThreatRecordModified | null;\n fireholLvl3DataBase(ip: string): ThreatRecordModified | null;\n fireholLvl4DataBase(ip: string): ThreatRecordModified | null;\n bannedDataBase(ip: string): BannedRecord | null;\n highRiskDataBase(ip: string): HighRiskRecord | null;\n getUserAgentLmdb(): RootDatabase<UserAgentRecord, string>;\n getJa4Lmdb(): RootDatabase<JA4, string>;\n}\n\nexport interface AppReaders {\n asn: Reader<BgpRecord & maxmind.Response>;\n city: Reader<CityGeoRecord & maxmind.Response>;\n country: Reader<GeoRecord & maxmind.Response>;\n goodBots: Reader<CrawlersRecord & maxmind.Response>;\n tor: Reader<TorRecord & maxmind.Response>;\n proxy: Reader<ProxyRecord & maxmind.Response>;\n fireholAnon: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl1: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl2: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl3: Reader<ThreatRecordModified & maxmind.Response>;\n fireholLvl4: Reader<ThreatRecordModified & maxmind.Response>;\n banned?: Reader<BannedRecord & maxmind.Response>;\n highRisk?: Reader<HighRiskRecord & maxmind.Response>;\n userAgentLmdb: RootDatabase<UserAgentRecord, string>;\n ja4Lmdb: RootDatabase<JA4, string>;\n}\n\n\nexport class DataSources implements DataReaders {\n private readonly readers: AppReaders;\n private constructor(readers: AppReaders) {\n this.readers = readers;\n }\n\n public static async initialize(): Promise<DataSources> {\n const options = { watchForUpdates: process.env.NODE_ENV !== 'test' };\n \n const [asn, city, country, goodBots, tor, proxy, fireholAnon, fireholLvl1, fireholLvl2, fireholLvl3, fireholLvl4] = await Promise.all([\n maxmind.open<BgpRecord & maxmind.Response>(resolveDataPath('asn.mmdb'), options),\n maxmind.open<CityGeoRecord & maxmind.Response>(resolveDataPath('city.mmdb'), options),\n maxmind.open<GeoRecord & maxmind.Response>(resolveDataPath('country.mmdb'), options),\n maxmind.open<CrawlersRecord& maxmind.Response>(resolveDataPath('goodBots.mmdb'), options),\n maxmind.open<TorRecord & maxmind.Response>(resolveDataPath('tor.mmdb'), options),\n maxmind.open<ProxyRecord & maxmind.Response>(resolveDataPath('proxy.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_anonymous.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l1.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l2.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l3.mmdb'), options),\n maxmind.open<ThreatRecordModified & maxmind.Response>(resolveDataPath('firehol_l4.mmdb'), options),\n ]);\n\n const bannedPath = resolveDataPath('banned.mmdb');\n const highRiskPath = resolveDataPath('highRisk.mmdb');\n\n const [banned, highRisk] = await Promise.all([\n existsSync(bannedPath) ? maxmind.open<BannedRecord & maxmind.Response>(bannedPath, options): Promise.resolve(undefined),\n existsSync(highRiskPath) ? maxmind.open<HighRiskRecord & maxmind.Response>(highRiskPath, options): Promise.resolve(undefined),\n ]);\n\n const userAgentLmdb = open<UserAgentRecord, string>({\n path: resolveDataPath('useragent-db/useragent.mdb'),\n name: 'useragent',\n compression: true,\n readOnly: true,\n useVersions: true,\n sharedStructuresKey: Symbol.for('structures'),\n pageSize: 4096,\n cache: {\n validated: true\n },\n noReadAhead: true,\n maxReaders: 2024,\n });\n\n const ja4Lmdb = open<JA4, string>({\n path: resolveDataPath('ja4-db/ja4.mdb'),\n name: 'ja4',\n compression: true,\n readOnly: true,\n useVersions: true,\n sharedStructuresKey: Symbol.for('structures'),\n pageSize: 4096,\n cache: {\n validated: true\n },\n noReadAhead: true,\n maxReaders: 2024,\n });\n\n return new DataSources({\n asn,\n city,\n country,\n goodBots,\n tor,\n proxy,\n fireholAnon,\n fireholLvl1,\n fireholLvl2,\n fireholLvl3,\n fireholLvl4,\n banned,\n highRisk,\n userAgentLmdb,\n ja4Lmdb,\n });\n }\n \n public asnDataBase(ip: string): BgpRecord | null {\n const result: BgpRecord | null = this.readers.asn.get(ip);\n return result;\n }\n\n public cityDataBase(ip: string): CityGeoRecord | null {\n const result: CityGeoRecord | null = this.readers.city.get(ip);\n return result;\n }\n\n public countryDataBase(ip: string): GeoRecord | null {\n const result: GeoRecord | null = this.readers.country.get(ip);\n return result;\n }\n\n public goodBotsDataBase(ip: string): CrawlersRecord | null {\n const result: CrawlersRecord | null = this.readers.goodBots.get(ip);\n return result;\n }\n\n public torDataBase(ip: string): TorRecord | null {\n const result: TorRecord | null = this.readers.tor.get(ip);\n return result;\n }\n\n public proxyDataBase(ip: string): ProxyRecord | null {\n const result: ProxyRecord | null = this.readers.proxy.get(ip);\n return result;\n }\n\n public fireholAnonDataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholAnon.get(ip);\n return result;\n }\n\n public fireholLvl1DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl1.get(ip);\n return result;\n }\n\n public fireholLvl2DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl2.get(ip);\n return result;\n }\n\n public fireholLvl3DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl3.get(ip);\n return result;\n }\n\n public fireholLvl4DataBase(ip: string): ThreatRecordModified | null {\n const result: ThreatRecordModified | null = this.readers.fireholLvl4.get(ip);\n return result;\n }\n\n public bannedDataBase(ip: string): BannedRecord | null {\n return this.readers.banned?.get(ip) ?? null;\n }\n\n public highRiskDataBase(ip: string): HighRiskRecord | null {\n return this.readers.highRisk?.get(ip) ?? null;\n }\n\n public getUserAgentLmdb(): RootDatabase<UserAgentRecord, string> {\n return this.readers.userAgentLmdb;\n }\n\n public getJa4Lmdb(): RootDatabase<JA4, string> {\n return this.readers.ja4Lmdb;\n }\n\n}\n","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 { getLogger } from '../utils/logger.js';\nimport type { BannedInfo } from '../types/checkersTypes.js';\nimport { getDb } from '../config/config.js';\nimport { prep, onUpsert, excluded } from './dialectUtils.js';\n\nexport async function updateBannedIP(\n cookie: string,\n ipAddress: string,\n country: string,\n user_agent: string,\n info: BannedInfo\n) {\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'db', type: 'updateBannedIP' });\n const reasonPayload = JSON.stringify(info.reasons);\n const params = [cookie, ipAddress, country, user_agent, reasonPayload, info.score] satisfies (string | number)[];\n \n const ex = (col: string) => excluded(db, col);\n const upsert = onUpsert(db, 'canary_id');\n try {\n await prep(db,\n `INSERT INTO banned (canary_id, ip_address, country, user_agent, reason, score)\n VALUES (?, ?, ?, ?, ?, ?)\n ${upsert}\n ip_address = ${ex('ip_address')},\n country = ${ex('country')},\n user_agent = ${ex('user_agent')},\n score = ${ex('score')},\n reason = ${ex('reason')}`\n ).run(...params);\n log.info(`Updated Database TABLE - banned. A user has been banned for IP ${ipAddress} (score ${String(info.score)})`);\n } catch (err: unknown) {\n log.error({ err }, 'ERROR UPDATING \"banned\" TABLE');\n throw err;\n }\n}\n","import { getLogger } from '../utils/logger.js';\nimport { getDb } from '../config/config.js';\nimport { prep } from './dialectUtils.js';\n\nexport async function updateIsBot(isBot: boolean, cookie: string) {\n const params = [isBot ? 1 : 0, cookie];\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'db', type: 'updateIsBot' });\n\n try { \n await prep(db, `UPDATE visitors SET is_bot = ? WHERE canary_id = ?`).run(...params);\n } catch (err: unknown) {\n log.error({ err }, 'ERROR UPDATING IS_BOT');\n throw err;\n }\n}\n\n ","import { userValidation } from '../types/fingerPrint.js';\nimport { getLogger } from '../utils/logger.js';\nimport { getDb } from '../config/config.js';\nimport { prep, onUpsert, excluded, now } from './dialectUtils.js';\n\nexport async function updateVisitor(u: userValidation) {\n const db = getDb();\n const log = getLogger().child({service: 'BOT DETECTOR', branch: 'db', type: 'updateVisitors'});\n const {\n visitorId,\n cookie,\n ipAddress,\n userAgent,\n country,\n region,\n regionName,\n city,\n district,\n lat,\n lon,\n timezone,\n currency,\n isp,\n org,\n as: asOrg,\n device_type,\n browser,\n proxy,\n hosting,\n is_bot,\n first_seen,\n last_seen,\n request_count,\n deviceVendor,\n deviceModel,\n browserType,\n browserVersion,\n os,\n activity_score,\n } = u;\n const params = [\n visitorId,\n cookie,\n ipAddress,\n userAgent,\n country,\n region,\n regionName,\n city,\n district,\n lat,\n lon,\n timezone,\n currency,\n isp,\n org,\n asOrg,\n device_type,\n browser,\n proxy,\n hosting,\n is_bot,\n first_seen,\n last_seen,\n request_count,\n deviceVendor,\n deviceModel,\n browserType,\n browserVersion,\n os,\n Number(activity_score) || 0,\n ].map(value => value === undefined ? null : typeof value === 'boolean' ? (value ? 1 : 0) : value);\n const ex = (col: string) => excluded(db, col);\n const upsert = onUpsert(db, 'canary_id');\n try {\n await prep(db,\n `INSERT INTO visitors (\n visitor_id,\n canary_id,\n ip_address,\n user_agent,\n country,\n region,\n region_name,\n city,\n district,\n lat,\n lon,\n timezone,\n currency,\n isp,\n org,\n as_org,\n device_type,\n browser,\n proxy,\n hosting,\n is_bot,\n first_seen,\n last_seen,\n request_count,\n deviceVendor,\n deviceModel,\n browserType,\n browserVersion,\n os,\n suspicious_activity_score\n ) VALUES (\n ${params.map(() => '?').join(', ')}\n )\n ${upsert}\n ip_address = ${ex('ip_address')},\n user_agent = ${ex('user_agent')},\n country = ${ex('country')},\n region = ${ex('region')},\n region_name = ${ex('region_name')},\n city = ${ex('city')},\n district = ${ex('district')},\n lat = ${ex('lat')},\n lon = ${ex('lon')},\n timezone = ${ex('timezone')},\n currency = ${ex('currency')},\n isp = ${ex('isp')},\n org = ${ex('org')},\n as_org = ${ex('as_org')},\n device_type = ${ex('device_type')},\n browser = ${ex('browser')},\n proxy = ${ex('proxy')},\n hosting = ${ex('hosting')},\n last_seen = ${now(db)},\n request_count = request_count + 1,\n deviceVendor = ${ex('deviceVendor')},\n deviceModel = ${ex('deviceModel')},\n browserType = ${ex('browserType')},\n browserVersion = ${ex('browserVersion')},\n os = ${ex('os')}`\n ).run(...params);\n\n log.info(`Updated visitors table, Visitor row for canary_id=${cookie ?? ''} inserted/updated successfully.`);\n return;\n } catch (err: unknown) {\n log.error({ err },`ERROR UPDATING visitors TABLE`);\n }\n}\n","import { getLogger } from '../utils/logger.js';\nimport { getDb } from '../config/config.js';\nimport { prep } from './dialectUtils.js';\n\nexport async function updateScore(score: number, cookie: string) {\n const params = [score, cookie] satisfies (string | number)[];\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'db', type: 'updateScore' });\n\n try {\n await prep(db, `UPDATE visitors SET suspicious_activity_score = ? WHERE canary_id = ?`).run(...params);\n } catch (err: unknown) {\n log.error({ err }, 'ERROR UPDATING SCORE');\n throw err;\n }\n}\n\n ","import { updateBannedIP } from \"./updateBanned.js\";\nimport { updateIsBot } from \"./updateIsBot.js\";\nimport { updateVisitor } from \"./updateVisitors.js\";\nimport { updateScore } from \"./updateVisitorScore.js\";\nimport { getConfiguration } from \"../config/config.js\";\nimport { OpParams, BatchQueueOps, Priority, BatchJob } from \"../types/batchQueue.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\n\nexport class BatchQueue {\n private jobs = new Map<string, BatchJob>();\n private timer: NodeJS.Timeout | null = null;\n private flushPromise: Promise<void> | null = null;\n\n private get config() {\n return getConfiguration().batchQueue;\n }\n\n private get log() {\n return getLogger().child({service: 'BOT DETECTOR', branch: 'BatchQueue'});\n }\n\n public async addQueue<T extends BatchQueueOps>(\n canary: string,\n ipAddress: string,\n type: T,\n params: OpParams[T],\n priority: Priority = 'deferred'\n ): Promise<void> {\n const key = `${type}:${canary}:${ipAddress}`;\n this.jobs.set(key, { id: key, type, priority, params });\n\n if (priority === 'immediate' || this.jobs.size >= this.config.maxBufferSize) {\n await this.flush();\n } else this.timer ??= setTimeout(() => void this.flush(), this.config.flushIntervalMs);\n }\n\n\n public async flush(): Promise<void> {\n while (this.flushPromise || this.jobs.size > 0) {\n if (this.flushPromise) {\n await this.flushPromise;\n }\n if (this.jobs.size > 0) {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n const currentBatch = Array.from(this.jobs.values());\n this.jobs.clear();\n this.flushPromise = this.executeBatch(currentBatch, 0);\n try {\n await this.flushPromise;\n } finally {\n this.flushPromise = null;\n }\n }\n }\n }\n\n private runJob(job: BatchJob): Promise<void> {\n switch (job.type) {\n case 'visitor_upsert':\n return updateVisitor((job.params as OpParams['visitor_upsert']).insert);\n case 'score_update': {\n const {score, cookie} = job.params as OpParams['score_update'];\n return updateScore(score, cookie);\n }\n case 'is_bot_update': {\n const {isBot, cookie} = job.params as OpParams['is_bot_update'];\n return updateIsBot(isBot, cookie);\n }\n case 'update_banned_ip': {\n const {cookie, ipAddress, country, user_agent, info} = job.params as OpParams['update_banned_ip'];\n return updateBannedIP(cookie, ipAddress, country, user_agent, info);\n }\n }\n }\n\n private async executeBatch(batch: BatchJob[], retryCount: number): Promise<void> {\n try {\n const visitors = batch.filter(j => j.type === 'visitor_upsert');\n const others = batch.filter(j => j.type !== 'visitor_upsert');\n if (visitors.length > 0) {\n await Promise.all(visitors.map(j => this.runJob(j)));\n }\n await Promise.all(others.map(j => this.runJob(j)));\n } catch (err) {\n this.log.error({err}, `Batch flush failed (Attempt ${String(retryCount + 1)})`);\n\n if (retryCount < this.config.maxRetries) {\n await new Promise(res => setTimeout(res, 1000));\n return this.executeBatch(batch, retryCount + 1);\n }\n this.log.error(\"Max retries reached. Discarding batch.\");\n }\n }\n\n public async shutdown(): Promise<void> {\n this.log.info(\"Shutting down BatchQueue: Draining remaining jobs...\");\n await this.flush();\n }\n}","import { createStorage } from 'unstorage';\nimport memoryDriver from 'unstorage/drivers/memory';\nimport type { Driver } from 'unstorage';\nimport type { CacheConfig } from '../types/storageTypes.js';\n\n\nexport async function initStorage(config?: CacheConfig) {\n\n if (!config) {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n return createStorage({ driver: memoryDriver() });\n }\n\n const { driver, ...opts } = config;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mod: { default: (opts?: any) => Driver };\n\n switch (driver) {\n case 'redis':\n mod = await import('unstorage/drivers/redis');\n break;\n case 'upstash':\n mod = await import('unstorage/drivers/upstash');\n break;\n case 'lru':\n mod = await import('unstorage/drivers/lru-cache');\n break;\n case 'fs':\n mod = await import('unstorage/drivers/fs-lite');\n break;\n case 'cloudflare-kv-binding':\n mod = await import('unstorage/drivers/cloudflare-kv-binding');\n break;\n case 'cloudflare-kv-http':\n mod = await import('unstorage/drivers/cloudflare-kv-http');\n break;\n case 'cloudflare-r2-binding':\n mod = await import('unstorage/drivers/cloudflare-r2-binding');\n break;\n case 'vercel':\n mod = await import('unstorage/drivers/vercel-runtime-cache');\n break;\n default:\n driver satisfies never;\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unsupported storage driver: ${driver}`);\n }\n\n return createStorage({ driver: mod.default(opts) });\n}\n","import { type Connector, createDatabase, type Database } from 'db0';\nimport type { DbConfig } from '../types/dbTypes.js';\n\n\nexport async function initDb(config: DbConfig): Promise<Database> {\n const { driver, ...opts } = config;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let mod: { default: (opts?: any) => Connector };\n\n switch (driver) {\n case 'mysql-pool':\n mod = await import('./mysqlPoolConnector.js');\n break;\n case 'postgresql':\n mod = await import('db0/connectors/postgresql');\n break;\n case 'sqlite':\n mod = await import('db0/connectors/better-sqlite3');\n break;\n case 'cloudflare-d1':\n mod = await import('db0/connectors/cloudflare-d1');\n break;\n case 'planetscale':\n mod = await import('db0/connectors/planetscale');\n break;\n default:\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new Error(`Unsupported database driver: ${driver}`);\n }\n\n return createDatabase(mod.default(opts));\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().then(() => process.exit(0)); });\n process.on('SIGINT', () => { void globalBatchQueue?.shutdown().then(() => process.exit(0)); });\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 type { GeoResponse } from \"../types/geoTypes.js\";\nimport { getDataSources } from \"../config/config.js\";\n\nconst norm = (string?: string) => string?.trim().toLowerCase();\n \nexport function getData(ip: string): GeoResponse {\n const dataSource = getDataSources();\n const countryLvl = dataSource.countryDataBase(ip);\n const cityLvl = dataSource.cityDataBase(ip);\n const asn = dataSource.asnDataBase(ip);\n const proxy = dataSource.proxyDataBase(ip);\n const tor = dataSource.torDataBase(ip);\n\n\n return {\n country: norm(countryLvl?.name ?? cityLvl?.name),\n countryCode: norm(countryLvl?.country_code ?? cityLvl?.country_code),\n region: norm(cityLvl?.region ?? countryLvl?.region),\n regionName: norm(cityLvl?.continent ?? cityLvl?.subregion ?? countryLvl?.subregion),\n subregion: norm(cityLvl?.subregion ?? countryLvl?.subregion),\n state: norm(cityLvl?.state),\n zipCode: norm(cityLvl?.zip_code),\n city: norm(cityLvl?.city ?? cityLvl?.capital ?? countryLvl?.capital),\n phone: norm(cityLvl?.phone ?? countryLvl?.phone),\n numericCode: norm(cityLvl?.numericCode ?? countryLvl?.numericCode),\n native: norm(cityLvl?.native ?? countryLvl?.native),\n continent: norm(cityLvl?.continent),\n capital: norm(cityLvl?.capital ?? countryLvl?.capital),\n district: norm(cityLvl?.state),\n lat: norm(cityLvl?.latitude),\n lon: norm(cityLvl?.longitude),\n timezone: norm(cityLvl?.timezone ?? countryLvl?.timezone),\n timeZoneName: norm(cityLvl?.timeZoneName ?? countryLvl?.timeZoneName),\n utc_offset: norm(cityLvl?.utc_offset ?? countryLvl?.utc_offset),\n tld: norm(cityLvl?.tld ?? countryLvl?.tld),\n nationality: norm(cityLvl?.nationality ?? countryLvl?.nationality),\n currency: norm(cityLvl?.currency ?? countryLvl?.currency),\n iso639: norm(cityLvl?.iso639 ?? countryLvl?.iso639),\n languages: norm(cityLvl?.languages ?? countryLvl?.languages),\n isp: norm(asn?.asn_name),\n org: norm(asn?.asn_id),\n as_org: norm(asn?.asn_name),\n proxy: proxy ? true : false,\n hosting: asn?.classification === \"Content\" || Boolean(tor?.exit_addresses),\n };\n}","import { Response } from \"express\";\n\ninterface cookies {\n httpOnly: boolean,\n sameSite: boolean | \"lax\" | \"strict\" | \"none\";\n maxAge: number; \n secure: boolean; \n expires?: Date;\n domain?: string;\n path?: string; \n }\n\n\n\nexport function makeCookie(res: Response, name: string, value: string, options: cookies) {\n\n if (name.startsWith(\"__Host-\")) {\n options.secure = true;\n options.path = \"/\";\n delete options.domain;\n }\n\n if (name.startsWith(\"__Secure-\")) {\n options.secure = true;\n }\n\n res.cookie(name, value, {\n httpOnly: options.httpOnly,\n sameSite: options.sameSite,\n maxAge: options.maxAge,\n secure: options.secure,\n expires: options.expires,\n domain: options.domain,\n path: options.path,\n });\n}\n\n\n","import { ParsedUAResult } from '../types/UAparserTypes.js';\nimport { UAParser, UAParserExt } from 'ua-parser-js';\nimport { isAIBot, isBot } from 'ua-parser-js/helpers';\nimport { CLIs, Crawlers, Fetchers, Libraries } from 'ua-parser-js/extensions';\n\n\nexport function parseUA(userAgent: string | number): ParsedUAResult {\n\n \n const botParser = new UAParser(\n [Crawlers, CLIs, Fetchers, Libraries] as UAParserExt\n );\n \n const uaString = typeof userAgent === 'string'\n ? userAgent\n : String(userAgent);\n\n\n const result = botParser.setUA(uaString).getResult();\n\n return {\n device: result.device.type ?? 'desktop',\n deviceVendor: result.device.vendor,\n deviceModel: result.device.model,\n browser: result.browser.name,\n browserType: result.browser.type,\n browserVersion: result.browser.version,\n os: result.os.name,\n botAI: isAIBot(result),\n bot: isBot(result),\n allResults: result,\n };\n\n}\nexport default parseUA;\n\n\n\n","import { isIP } from 'node:net';\nimport { IBotChecker } from '../types/checkersTypes.js';\nimport { ValidationContext } from '../types/botDetectorTypes.js';\nimport { BotDetectorConfig } from '../types/configSchema.js';\nimport { CheckerRegistry } from './CheckerRegistry.js';\n\nexport class IpChecker implements IBotChecker<'IP_INVALID'> {\n name = 'IP Validation';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableIpChecks.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const isValid = isIP(ctx.ipAddress) !== 0;\n return {\n score: isValid ? 0 : config.banScore,\n reasons: isValid ? [] : ['IP_INVALID' as const]\n };\n }\n}\n\nCheckerRegistry.register(new IpChecker());\n","import { getStorage } from '~~/src/botDetector/config/config.js';\n\nexport interface CachedResult {\n ip: string;\n trustedBot: boolean;\n}\n\nconst DNS_TTL_SECONDS = 60 * 60 * 2;\nconst PREFIX = 'dns:';\n\nexport const dnsCache = {\n async get(ip: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${ip}`);\n },\n\n async set(ip: string, entry: CachedResult): Promise<void> {\n await getStorage().setItem(`${PREFIX}${ip}`, entry, { ttl: DNS_TTL_SECONDS });\n },\n\n async delete(ip: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${ip}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import { dnsCache } from '@helpers/cache/dnsLookupCache.js';\nimport dns from 'node:dns/promises';\nimport { getDataSources } from '../../config/config.js';\nimport { getLogger } from '@utils/logger.js';\nimport type { Suffix } from '../../types/suffixes.js';\n\nexport class GoodBotsBase {\n private getDomains(suffix: Suffix): string[] {\n const allDomains: string[] = [];\n\n for (const key in suffix) {\n\n const entry = suffix[key];\n const entrySuffix = entry.suffix;\n\n if (Array.isArray(entrySuffix)) {\n allDomains.push(...entrySuffix);\n\n } else if (typeof entrySuffix === 'string') {\n allDomains.push(entrySuffix);\n }\n }\n return allDomains;\n }\n\n private domains: string[];\n\n private _logger?: ReturnType<typeof getLogger>;\n protected get logger(): ReturnType<typeof getLogger> {\n this._logger ??= getLogger().child({ service: 'botDetector', branch: 'checker', type: 'GoodBotsBase' });\n return this._logger;\n }\n\n constructor(protected suffixes: Suffix) {\n this.domains = this.getDomains(this.suffixes).map(d => `.${d.toLowerCase()}`);\n }\n\n protected async isBotFromTrustedDomain(ip: string): Promise<boolean> {\n const cached = await dnsCache.get(ip);\n if (cached) {\n return cached.trustedBot;\n }\n\n try {\n \n const hostnames = await dns.reverse(ip); \n \n const matchingHosts = hostnames.filter(host =>\n this.domains.some(domain => host.endsWith(domain))\n );\n\n if (matchingHosts.length === 0) {\n dnsCache.set(ip, { ip, trustedBot: false }).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save dnsCache in storage');\n });\n return false;\n }\n for (const host of matchingHosts) {\n const addresses = await dns.lookup(host, { all: true });\n\n if (addresses.some(a => a.address === ip)) {\n dnsCache.set(ip, { ip, trustedBot: true }).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save dnsCache in storage');\n });\n\n return true;\n }\n }\n } catch(err: unknown) {\n this.logger.error({ err }, 'DNS reverse lookup failed');\n }\n dnsCache.set(ip, { ip, trustedBot: false }).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save dnsCache in storage');\n });\n return false;\n }\n\n protected isBotIPTrusted(ipAddress: string): boolean {\n \n const dataSources = getDataSources();\n const isKnownBot = dataSources.goodBotsDataBase(ipAddress) !== null;\n \n return isKnownBot; \n }\n}","import fs from 'node:fs';\nimport type { IBotChecker } from \"../../types/checkersTypes.js\";\nimport type { ValidationContext } from \"../../types/botDetectorTypes.js\";\nimport type { BotDetectorConfig } from \"../../types/configSchema.js\";\nimport { CheckerRegistry } from \"../CheckerRegistry.js\";\nimport { GoodBotsBase } from \"./base.js\";\nimport type { Suffix } from '../../types/suffixes.js';\nimport { resolveDataPath } from '@db/findDataPath.js';\n\nconst suffixPath = resolveDataPath('suffix.json');\nconst suffixes = JSON.parse(fs.readFileSync(suffixPath, 'utf-8')) as Suffix;\n\nconst userAgents: string[] = Object.values(suffixes)\n .flatMap((e) =>\n Array.isArray(e.useragent) ? e.useragent : [e.useragent]\n )\n .map(u => u.toLowerCase());\n \nexport class GoodBotsChecker extends GoodBotsBase implements IBotChecker<'BAD_BOT_DETECTED' | 'GOOD_BOT_IDENTIFIED'> {\n name = 'Good/Bad Bot Verification';\n phase = 'cheap' as const;\n\n constructor() {\n super(suffixes);\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableGoodBotsChecks.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const browserType = (ctx.parsedUA.browserType ?? '').toLowerCase();\n const browserName = (ctx.parsedUA.browser ?? '').toLowerCase();\n const ipAddress = ctx.ipAddress;\n \n const score = 0;\n const reasons: ('BAD_BOT_DETECTED' | 'GOOD_BOT_IDENTIFIED')[] = [];\n\n const checkersConfig = config.checkers.enableGoodBotsChecks;\n if (!checkersConfig.enable) return { score, reasons };\n\n if (browserType !== 'crawler' && browserType !== 'fetcher') {\n return { score: 0, reasons: [] };\n }\n\n const name = browserName;\n const botsWithoutSuffix = ['duckduckbot','gptbot','oai-searchbot','chatgpt-user'].includes(name);\n const botsWithSuffix = userAgents.some(suf => name.includes(suf));\n\n if (checkersConfig.banUnlistedBots && !botsWithoutSuffix && !botsWithSuffix) {\n reasons.push('BAD_BOT_DETECTED');\n return { score: 0, reasons }; \n }\n\n let trusted: boolean;\n\n if (botsWithSuffix) {\n trusted = await this.isBotFromTrustedDomain(ipAddress);\n } else {\n trusted = this.isBotIPTrusted(ipAddress);\n }\n\n if (!trusted) {\n reasons.push('BAD_BOT_DETECTED');\n return {\n score: checkersConfig.penalties,\n reasons\n };\n }\n\n reasons.push('GOOD_BOT_IDENTIFIED');\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new GoodBotsChecker());\n","import { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class BrowserDetailsAndDeviceChecker implements IBotChecker<BanReasonCode> {\n name = 'Browser and Device Verification';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableBrowserAndDeviceChecks.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableBrowserAndDeviceChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const penalties = checkConfig.penalties;\n\n const bType = ctx.parsedUA.browserType;\n const bName = ctx.parsedUA.browser ?? \"\";\n const bOS = ctx.parsedUA.os ?? \"\";\n const dType = ctx.parsedUA.device ?? \"desktop\";\n\n if (bType === 'cli' || bType === 'library') {\n score += penalties.cliOrLibrary;\n reasons.push('CLI_OR_LIBRARY');\n } \n\n if (['ie','iemobile','internet explorer'].includes(bName.toLowerCase())) {\n score += penalties.internetExplorer; \n reasons.push('INTERNET_EXPLORER');\n }\n\n if (bOS.toLowerCase().includes('kali')) {\n score += penalties.linuxOs; \n reasons.push('KALI_LINUX_OS');\n }\n\n if (bOS === 'Mac OS' && dType === 'mobile') {\n score += penalties.impossibleBrowserCombinations; \n reasons.push('IMPOSSIBLE_BROWSER_COMBINATION' as BanReasonCode);\n }\n\n if (bName === 'Safari' && bOS === 'Windows') {\n score += penalties.impossibleBrowserCombinations; \n reasons.push('IMPOSSIBLE_BROWSER_COMBINATION' as BanReasonCode);\n }\n\n if (dType === 'desktop' && ctx.parsedUA.deviceVendor) {\n score += penalties.impossibleBrowserCombinations; \n reasons.push('IMPOSSIBLE_BROWSER_COMBINATION' as BanReasonCode);\n }\n\n if (!bType && (!bName || dType !== 'desktop')) {\n score += penalties.browserTypeUnknown;\n reasons.push('BROWSER_TYPE_UNKNOWN');\n }\n\n if (!bName) {\n score += penalties.browserNameUnknown;\n reasons.push('BROWSER_NAME_UNKNOWN');\n }\n\n if (dType === 'desktop' && !bOS) {\n score += penalties.desktopWithoutOS; \n reasons.push('DESKTOP_WITHOUT_OS');\n }\n\n if (dType !== 'desktop' && !ctx.parsedUA.deviceVendor) {\n score += penalties.deviceVendorUnknown;\n reasons.push('DEVICE_VENDOR_UNKNOWN');\n }\n\n if (!ctx.parsedUA.browserVersion) {\n score += penalties.browserVersionUnknown; \n reasons.push('BROWSER_VERSION_UNKNOWN');\n }\n\n if (!ctx.parsedUA.deviceModel) {\n score += penalties.deviceModelUnknown; \n reasons.push('NO_MODEL');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new BrowserDetailsAndDeviceChecker());\n","import { anyOf, createRegExp, exactly, digit, letter, maybe } from \"magic-regexp\";\n\nconst space = anyOf(\" \", \"\\t\").times.any();\n\nconst decimalZero = maybe(anyOf(exactly(\".\", digit.times.between(1, 3))));\nconst qZero = exactly(\"0\", decimalZero);\n\nconst decimalOne = maybe(anyOf(exactly(\".\", exactly(\"0\").times.between(1, 3))));\nconst qOne = exactly(\"1\", decimalOne);\n\nconst qValue = anyOf(qZero, qOne);\n\nconst quality = maybe(\n anyOf(\n exactly(space, \";\", space, \"q\", space, \"=\", space, qValue)\n )\n);\n\nconst primaryTag = letter.times.between(1, 8);\nconst subTag = anyOf(\n exactly(\"-\", anyOf(letter, digit).times.between(1, 8))\n).times.any();\n\nconst acceptLang = anyOf(\n exactly(\"*\"),\n exactly(primaryTag, subTag) \n);\n\nconst language = exactly(acceptLang, quality);\nconst repeatingLanguages = anyOf(\n exactly(space, \",\", space, language)\n).times.any();\n\nexport const acceptLanguageValidator = createRegExp(\n exactly(language, repeatingLanguages)\n .at.lineStart()\n .at.lineEnd(), \n [\"i\"]\n);","import { acceptLanguageValidator } from \"../utils/regex/acceptLangRegex.js\";\nimport { IBotChecker, BanReasonCode } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class LocaleMapChecker implements IBotChecker<BanReasonCode> {\n name = 'Locale and Country Verification';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.localeMapsCheck.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const settings = config.checkers.localeMapsCheck;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!settings.enable) return { score, reasons };\n\n const AccHeader = ctx.req.get('Accept-Language') ?? '';\n if (!AccHeader) {\n score += settings.penalties.missingHeader;\n if (score > 0) reasons.push('LOCALE_MISMATCH');\n return { score, reasons };\n }\n\n const isValidHeader = acceptLanguageValidator.test(AccHeader.trim().toLowerCase());\n\n if (!isValidHeader) {\n score += settings.penalties.malformedHeader; \n if (score > 0) reasons.push('LOCALE_MISMATCH');\n return { score, reasons };\n }\n\n const langs = AccHeader\n .split(',')\n .map(entry => {\n const [tag, q] = entry.trim().split(/\\s*;\\s*q\\s*=\\s*/);\n return { tag: tag.toLowerCase(), weight: q ? parseFloat(q) : 1 };\n })\n .sort((a, b) => b.weight - a.weight);\n\n const country = ctx.geoData.country;\n const countryCode = ctx.geoData.countryCode;\n const iso6 = ctx.geoData.iso639;\n\n if (!country || !countryCode || !iso6) {\n score += settings.penalties.missingGeoData;\n if (score > 0) reasons.push('LOCALE_MISMATCH');\n return { score, reasons };\n }\n\n const expectedCountryCode = countryCode.toLowerCase();\n const expectedLang = iso6.toLowerCase();\n const combined = `${expectedLang}-${expectedCountryCode}`;\n\n let localeMatchesGeo = false;\n\n for (const { tag, weight } of langs) {\n if (weight === 0) continue;\n const parts = tag.split(/[-_]/);\n const langPart = parts[0];\n const regionPart = parts.find(p => p.length === 2 && p === expectedCountryCode);\n \n if (regionPart) {\n localeMatchesGeo = true;\n break;\n }\n\n if (langPart === expectedLang) {\n localeMatchesGeo = true;\n break;\n }\n\n if ((langPart && regionPart) && tag === combined) {\n localeMatchesGeo = true;\n break;\n }\n }\n\n if (!localeMatchesGeo) {\n score += settings.penalties.ipAndHeaderMismatch;\n if (score > 0) reasons.push('LOCALE_MISMATCH');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new LocaleMapChecker());","import { getStorage } from '~~/src/botDetector/config/config.js';\n\nexport interface CachedResult {\n score: number;\n timestamp: number;\n request_count: number;\n}\n\nconst RATE_TTL_SECONDS_FALLBACK = 60 * 2;\nconst PREFIX = 'rate:';\n\nexport const rateCache = {\n async get(cookie: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${cookie}`);\n },\n\n async set(cookie: string, entry: CachedResult, ttlSeconds?: number): Promise<void> {\n await getStorage().setItem(`${PREFIX}${cookie}`, entry, { ttl: ttlSeconds ?? RATE_TTL_SECONDS_FALLBACK });\n },\n\n async delete(cookie: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${cookie}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import { rateCache } from '../helpers/cache/rateLimitarCache.js';\nimport { IBotChecker, BanReasonCode } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\nexport class BehavioralDbChecker implements IBotChecker<BanReasonCode> {\n name = 'Behavior Rate Verification';\n phase = 'heavy' as const;\n private _logger?: ReturnType<typeof getLogger>;\n private get logger() {\n this._logger ??= getLogger().child({ service: 'botDetector', branch: 'checker', type: 'BehavioralDbChecker' });\n return this._logger;\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableBehaviorRateCheck.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const cookie = ctx.cookie ?? '';\n\n const checkConfig = config.checkers.enableBehaviorRateCheck;\n if (!checkConfig.enable) return { score: 0, reasons: [] };\n\n const BEHAVIORAL_THRESHOLD = checkConfig.behavioral_threshold;\n const BEHAVIORAL_WINDOW = checkConfig.behavioral_window;\n const BEHAVIORAL_PENALTY = checkConfig.penalties;\n const ttlSeconds = Math.ceil(BEHAVIORAL_WINDOW / 1000);\n\n const cached = await rateCache.get(cookie);\n\n if (cached) {\n const ageSinceLastSeen = Date.now() - cached.timestamp;\n\n if (ageSinceLastSeen <= BEHAVIORAL_WINDOW) {\n const newCount = cached.request_count + 1;\n const score = newCount > BEHAVIORAL_THRESHOLD ? BEHAVIORAL_PENALTY : 0;\n\n rateCache.set(cookie, { ...cached, request_count: newCount, score }, ttlSeconds).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to save rateCache in storage');\n });\n\n return { score, reasons: score ? ['BEHAVIOR_TOO_FAST' as const] : [] };\n } else {\n rateCache.set(cookie, { request_count: 1, timestamp: Date.now(), score: 0 }, ttlSeconds).catch((err: unknown) => {\n this.logger.error({ err }, 'Failed to reset rateCache in storage');\n });\n\n return { score: 0, reasons: [] };\n }\n }\n\n return { score: 0, reasons: [] };\n }\n}\n\nCheckerRegistry.register(new BehavioralDbChecker());","import { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class ProxyIspAndCookieChecker implements IBotChecker<BanReasonCode> {\n name = 'Proxy, ISP and Cookie Verification';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableProxyIspCookiesChecks.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableProxyIspCookiesChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const { penalties } = checkConfig;\n\n const cookie = ctx.cookie ?? '';\n const proxy = ctx.proxy.isProxy;\n const proxyType = ctx.proxy.proxyType ?? '';\n const hosting = ctx.geoData.hosting ?? false;\n const isp = ctx.geoData.isp ?? '';\n const org = ctx.geoData.org ?? '';\n\n if (!cookie) {\n score += penalties.cookieMissing;\n reasons.push('COOKIE_MISSING');\n }\n\n if (proxy) {\n score += penalties.proxyDetected;\n reasons.push('PROXY_DETECTED');\n if (proxyType) {\n const sourceCount = proxyType.split(',').length;\n if (sourceCount >= 4) {\n score += penalties.multiSourceBonus4plus;\n } else if (sourceCount >= 2) {\n score += penalties.multiSourceBonus2to3;\n }\n }\n }\n\n if (hosting) {\n score += penalties.hostingDetected;\n reasons.push('HOSTING_DETECTED');\n }\n\n if (!isp) {\n score += penalties.ispUnknown;\n reasons.push('ISP_UNKNOWN');\n }\n\n if (!org) {\n score += penalties.orgUnknown;\n reasons.push('ORG_UNKNOWN');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new ProxyIspAndCookieChecker());\n","/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { Request } from \"express\";\nimport { UAParser } from \"ua-parser-js\";\nimport { getConfiguration } from \"../../config/config.js\";\n\nexport class HeadersBase {\n private readonly config = getConfiguration().headerOptions;\n\n protected mustHaveHeadersChecker(req: Request) {\n let score = 0;\n if (req.httpVersion === '1.0') return score += 40;\n if(!req.get('User-Agent')) score += this.config.weightPerMustHeader;\n if(!req.accepts) score += this.config.weightPerMustHeader;\n if(!req.acceptsEncodings) score += this.config.weightPerMustHeader;\n if(!req.acceptsLanguages) score += this.config.weightPerMustHeader;\n if (!req.host) score += this.config.weightPerMustHeader;\n if (!req.get('Upgrade-Insecure-Requests')) score += this.config.weightPerMustHeader;\n if (!req.get('x-client-id')) score += this.config.weightPerMustHeader;\n if (req.httpVersion === '1.1' || req.get('Connection')) {\n if(!req.get('Connection') || req.get('Connection') !== 'keep-alive') score += this.config.connectionHeaderIsClose;\n }\n if (!req.get('sec-fetch-mode') || \n !req.get('sec-fetch-dest') ||\n !req.get('sec-fetch-site')\n ) {\n score += this.config.weightPerMustHeader;\n }\n\n return score;\n }\n\n protected async engineHeaders(req: Request) {\n let score = 0;\n const ua = req.get('User-Agent');\n const hints = req.headers as Record<string, string>;\n const { name } = await new UAParser(ua, hints).getEngine().withClientHints();\n\n if (!name) return score += this.config.missingBrowserEngine;\n const headers = Object.keys(hints);\n const containsCh = headers.some(sec => sec.toLowerCase().startsWith('sec-ch-ua'));\n const containsTe = headers.some(te => te.toLowerCase() === 'te');\n\n if (name === 'Blink') {\n if (!containsCh) score += this.config.clientHintsMissingForBlink;\n if (containsTe) score += this.config.teHeaderUnexpectedForBlink;\n\n } else if (name === 'Gecko') {\n if (containsCh) score += this.config.clientHintsUnexpectedForGecko; \n if (!containsTe) score += this.config.teHeaderMissingForGecko;\n } else if(name === 'WebKit') {\n if (containsCh) score += this.config.clientHintsUnexpectedForGecko;\n if (containsTe) score += this.config.teHeaderUnexpectedForBlink;\n };\n return score;\n }\n\n protected weirdHeaders(req: Request) {\n let score = 0;\n const accept = req.get('accept');\n \n if (accept === '*/*') score += this.config.omittedAcceptHeader;\n if (req.get('x-requested-with') && req.method === 'GET') score += this.config.AJAXHeaderExists;\n if (req.get('postman-token') || req.get('insomnia')) score += this.config.postManOrInsomiaHeaders;\n\n const hostHeader = req.get('X-Forwarded-Host');\n if (hostHeader && req.hostname && hostHeader !== req.hostname) {\n score += this.config.hostMismatchWeight; \n }\n\n if (req.method === 'GET' && req.get('Cache-Control') === 'no-cache' && req.get('Pragma') === 'no-cache') {\n score += this.config.aggressiveCacheControlOnGet;\n }\n\n if (req.get('sec-fetch-site') === 'cross-site' && !req.get('referer')) {\n score += this.config.crossSiteRequestMissingReferer;\n }\n\n const isBrowserRequest = !req.get('x-client-id'); \n const isTopNavigation = req.method === 'GET' && req.get('sec-fetch-dest') === 'document';\n\n if (isBrowserRequest && !isTopNavigation && req.method !== 'GET') {\n const origin = req.get('origin');\n if (!origin) {\n score += this.config.originHeaderIsNULL;\n } else if (origin !== `${req.protocol}://${req.hostname}`) {\n score += this.config.originHeaderMismatch;\n }\n }\n const mode = req.get('sec-fetch-mode');\n if (mode !== 'same-origin' && mode !== 'navigate') score += this.config.inconsistentSecFetchMode;\n\n return score; \n } \n\n}\n","import { Request } from \"express\";\nimport { HeadersBase } from \"./headersBase.js\";\n\nexport class HeaderAnalysis extends HeadersBase {\n private readonly req: Request;\n\n constructor(req: Request) {\n super();\n this.req = req;\n }\n\n public async scoreHeaders() {\n const missing = this.mustHaveHeadersChecker(this.req);\n const engines = await this.engineHeaders(this.req);\n const weird = this.weirdHeaders(this.req);\n return missing + engines + weird;\n }\n\n}","import { createRegExp, anyOf, maybe, exactly } from 'magic-regexp';\n\nconst startOrSlash = anyOf(exactly('').at.lineStart(), '/').grouped();\nconst slashOrEnd = anyOf('/', exactly('').at.lineEnd());\n\nexport const pathRules: { re: RegExp; weight: number }[] = [\n { re: createRegExp(startOrSlash, '.git', slashOrEnd, ['i']), weight: 10 },\n { re: createRegExp(startOrSlash, '.git/config', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp(startOrSlash, '.env', maybe(anyOf('.local', '.example')), slashOrEnd, ['i']), weight: 10 },\n { re: createRegExp(startOrSlash, 'wp-admin', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp('/wp-json/wp/v2', slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp('/', anyOf('jenkins', 'hudson').grouped(), slashOrEnd, ['i']), weight: 9 }, \n { re: createRegExp('/', anyOf('script', 'login').grouped(), '.groovy', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp('/actuator/', anyOf('env', 'health', 'metrics'), slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp('/web.config', slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp('/.DS_Store', slashOrEnd, ['i']), weight: 4 },\n { re: createRegExp('/latest/meta-data/iam', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp(startOrSlash, '.aws/credentials', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp('/Dockerfile', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('/composer.lock', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('/jnlpJars/jenkins-cli.jar', slashOrEnd, ['i']), weight: 9 }, \n { re: createRegExp('/manager/html', slashOrEnd, ['i']), weight: 10 },\n { re: createRegExp('/shell', maybe('.php'), slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp('/', anyOf('grafana', 'kibana', 'prometheus').grouped(), slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('/', anyOf('owa', 'ecp').grouped(), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp('wp-login.php', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp('/swagger-ui', anyOf('/', '.html'), slashOrEnd, ['i']), weight: 6 }, \n { re: createRegExp('/v2/api-docs', slashOrEnd, ['i']), weight: 5 }, \n { re: createRegExp('/api-docs', anyOf('/', '.json'), slashOrEnd, ['i']), weight: 5 }, \n { re: createRegExp('phpmyadmin', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp(startOrSlash, '.well-known', slashOrEnd, ['i']), weight: 5 },\n { re: createRegExp(startOrSlash, '.htaccess', slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp('composer.json', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('docker-compose.y', maybe('a'), 'ml', slashOrEnd, ['i']), weight: 7 }, \n { re: createRegExp('.', anyOf('sql', 'bak', 'old', 'save', 'log', 'ini', 'conf', 'zip', exactly('tar', maybe('.gz'))), slashOrEnd, ['i']), weight: 7 },\n { re: createRegExp(anyOf('..', '%2e%2e').grouped(), anyOf('/', '\\\\'), ['i']), weight: 5 },\n { re: createRegExp(anyOf('package-lock.json', 'yarn.lock', '.gitignore').grouped(), slashOrEnd, ['i']), weight: 6 }, \n { re: createRegExp(startOrSlash, 'admin', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp('phpinfo', maybe('.php'), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, '.ssh', slashOrEnd, ['i']), weight: 8 },\n { re: createRegExp(exactly('').at.lineStart(), '/xmlrpc.php', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, 'wp-config.php', slashOrEnd, ['i']), weight: 10 }, \n { re: createRegExp(startOrSlash, anyOf('install', 'setup').grouped(), maybe('.php'), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, 'backup', maybe('s'), anyOf('.zip', '.tar.gz', '.sql'), slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, '.gitlab-ci.yml', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp(startOrSlash, '.svn', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp(startOrSlash, '.hg', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp(startOrSlash, 'CVS', slashOrEnd, ['i']), weight: 6 },\n { re: createRegExp(startOrSlash, '.vscode', slashOrEnd, ['i']), weight: 4 },\n { re: createRegExp(startOrSlash, '.htpasswd', slashOrEnd, ['i']), weight: 8 }, \n { re: createRegExp('phpunit', maybe('.phar'), slashOrEnd, ['i']), weight: 9 }, \n { re: createRegExp(startOrSlash, 'config', maybe('uration'), '.', anyOf('php', 'yml', 'json', 'xml', 'ini', 'conf', 'cfg'), slashOrEnd, ['i']), weight: 7 },\n];\n\nexport const whiteList: RegExp[] = [\n createRegExp(\n exactly('').at.lineStart(), \n maybe('/'), \n exactly('').at.lineEnd()\n ),\n\n createRegExp(\n exactly('').at.lineStart(),\n '/',\n anyOf('css', 'js', 'images', 'assets', 'static').grouped(),\n '/',\n ['i']\n ),\n\n createRegExp(\n '.',\n anyOf(\n 'html',\n 'css',\n 'js',\n 'png',\n exactly('jp', maybe('e'), 'g'),\n 'svg',\n 'map',\n exactly('woff', maybe('2')),\n 'ttf',\n 'webp'\n ),\n exactly('').at.lineEnd(),\n ['i']\n ),\n\n createRegExp(\n exactly('').at.lineStart(),\n '/robots.txt',\n exactly('').at.lineEnd(),\n ['i']\n ),\n\n createRegExp(\n exactly('').at.lineStart(),\n '/sitemap.xml',\n exactly('').at.lineEnd(),\n ['i']\n ),\n];","import path from 'path';\nimport { URL } from 'url';\nimport { Request } from 'express';\nimport { pathRules, whiteList } from '@utils/regex/pathTravelersRegex.js';\nimport { BotDetectorConfig } from '../../types/configSchema.js';\n\nexport class UaAndHeaderCheckerBase {\n protected pathScore(req: Request, config: BotDetectorConfig): number {\n const settings = config.pathTraveler;\n const MAX_DECODE_ITERATIONS = settings.maxIterations;\n const MAX_PATH_LENGTH = settings.maxPathLength;\n \n let score = 0;\n const hostHeader = req.get('x-forwarded-host');\n const base = `${req.protocol}://${hostHeader ?? req.get('host') ?? ''}`;\n \n // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing\n const rawPath = req.get('x-original-path') || req.originalUrl;\n\n const traversalRe = /(?:\\.\\.[\\\\/]|\\.\\.%2f|\\.\\.%5c|%2e%2e[\\\\/]|%2e%2e%2f|%2e%2e%5c)/i;\n if (traversalRe.test(rawPath)) {\n return settings.traversalDetected;\n }\n\n let pathname: string;\n try {\n\n const fullUrl = new URL(rawPath, base);\n pathname = fullUrl.pathname;\n \n } catch {\n pathname = rawPath.split('?')[0];\n }\n \n \n \n if (pathname.length > MAX_PATH_LENGTH) {\n return settings.pathLengthToLong;\n }\n \n \n if (whiteList.some(rx => rx.test(pathname))) {\n return 0;\n }\n \n \n let decoded = pathname;\n let totalDecodedLength = 0;\n for (let i = 0; i < MAX_DECODE_ITERATIONS; i++) {\n try {\n const tmp = decodeURIComponent(decoded);\n if (tmp === decoded) break;\n totalDecodedLength += tmp.length;\n if (totalDecodedLength > MAX_PATH_LENGTH * 2) {\n return settings.longDecoding; \n }\n decoded = tmp;\n } catch {\n break;\n }\n }\n \n const normalized = path.normalize(decoded);\n \n for (const { re, weight } of pathRules) {\n if (re.test(normalized)) {\n score += weight;\n if (score >= 30) break;\n }\n }\n \n return score;\n }\n\n protected tlsBotScore(req: Request, config: BotDetectorConfig): number {\n const settings = config.checkers.enableUaAndHeaderChecks;\n if (!settings.enable) return 0;\n const { penalties } = settings;\n\n let score = 0;\n const proto = req.httpVersion === '2.0' ? 'h2'\n : req.httpVersion === '1.1' ? 'http/1.1'\n : '';\n \n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!proto || (proto !== 'h2' && proto !== 'http/1.1')) {\n score += penalties.tlsCheckFailed;\n }\n \n const cipher = req.get('x-client-cipher') ?? '';\n \n const browserCiphers = new Set([\n 'TLS_AES_128_GCM_SHA256', 'TLS_AES_256_GCM_SHA384',\n 'TLS_CHACHA20_POLY1305_SHA256',\n 'ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256',\n 'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305',\n 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384',\n 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256',\n 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256',\n 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384',\n 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384',\n 'TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256',\n 'TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256'\n ]);\n \n if (!browserCiphers.has(cipher)) score += penalties.tlsCheckFailed;;\n \n const tlsVersion = (req.get('x-client-tls-version') ?? '').toLowerCase();\n if (\n tlsVersion &&\n !tlsVersion.startsWith('tls1.3') &&\n !tlsVersion.startsWith('tls1.2')\n ) {\n score += penalties.tlsCheckFailed; \n }\n \n return score;\n }\n}","import { BanReasonCode, IBotChecker } from '../../types/checkersTypes.js';\nimport { HeaderAnalysis } from '../headers/headers.js';\nimport { ValidationContext } from \"../../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../../types/configSchema.js\";\nimport { CheckerRegistry } from \"../CheckerRegistry.js\";\nimport { anyOf, createRegExp } from 'magic-regexp';\nimport { UaAndHeaderCheckerBase } from './base.js';\n\nexport class UaAndHeaderChecker extends UaAndHeaderCheckerBase implements IBotChecker<BanReasonCode> {\n name = 'User agent and Header Verification';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableUaAndHeaderChecks.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableUaAndHeaderChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const { penalties } = checkConfig;\n\n const req = ctx.req;\n const uaString = req.get(\"User-Agent\") ?? \"\";\n const uaLower = uaString.toLowerCase();\n const regex = createRegExp(anyOf('headless', 'puppeteer', 'selenium', 'playwright', 'phantomjs'));\n \n if (regex.test(uaLower)) {\n score += penalties.headlessBrowser;\n reasons.push('HEADLESS_BROWSER_DETECTED');\n }\n\n if (!uaString || uaString.length < 10) {\n score += penalties.shortUserAgent;\n reasons.push('SHORT_USER_AGENT');\n }\n\n const tlsCheckScore = this.tlsBotScore(req, config);\n if (tlsCheckScore > 0) {\n score += tlsCheckScore;\n reasons.push('TLS_CHECK_FAILED');\n }\n\n const headers = new HeaderAnalysis(req);\n const headerChecker = await headers.scoreHeaders();\n \n if (headerChecker > 0) {\n score += headerChecker;\n reasons.push('HEADER_SCORE_TOO_HIGH');\n }\n\n\n const pathChecker = this.pathScore(req, config);\n if (pathChecker > 0) {\n score += pathChecker;\n reasons.push('PATH_TRAVELER_FOUND');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new UaAndHeaderChecker());","import { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class GeoLocationChecker implements IBotChecker<BanReasonCode> {\n name = 'Geo-Location Verification';\n phase = 'heavy' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableGeoChecks.enable;\n }\n\n private isAllowedCountry(country: string, bannedCountries: string[]): boolean {\n const blockedCountries = bannedCountries;\n return !blockedCountries.includes(country.trim().toLowerCase());\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableGeoChecks;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const penalties = checkConfig.penalties;\n const banScore = config.banScore;\n\n const details = ctx.geoData;\n const country = details.country;\n const countryCode = details.countryCode;\n\n if (countryCode || country) {\n const banned = checkConfig.bannedCountries;\n const codeMatch = !!countryCode && !this.isAllowedCountry(countryCode, banned);\n const nameMatch = !!country && !this.isAllowedCountry(country, banned);\n if (codeMatch || nameMatch) {\n score += banScore;\n reasons.push('BANNED_COUNTRY');\n }\n\n } else {\n score += penalties.countryUnknown;\n reasons.push('COUNTRY_UNKNOWN');\n }\n\n const region = details.region;\n const regionName = details.regionName;\n if (!region || !regionName) {\n score += penalties.regionUnknown;\n reasons.push('REGION_UNKNOWN');\n }\n \n if (!details.lat || !details.lon) {\n score += penalties.latLonUnknown;\n reasons.push('LAT_LON_UNKNOWN');\n }\n\n if (!details.district) {\n score += penalties.districtUnknown; \n reasons.push('DISTRICT_UNKNOWN');\n }\n \n if (!details.city) {\n score += penalties.cityUnknown; \n reasons.push('CITY_UNKNOWN');\n }\n\n if (!details.timezone) {\n score += penalties.timezoneUnknown;\n reasons.push('TIMEZONE_UNKNOWN');\n }\n\n if (!details.subregion) {\n score += penalties.subregionUnknown; \n reasons.push('SUBREGION_UNKNOWN' as BanReasonCode);\n }\n\n if (!details.phone) {\n score += penalties.phoneUnknown;\n reasons.push('PHONE_UNKNOWN' as BanReasonCode);\n }\n\n if (!details.continent) {\n score += penalties.continentUnknown;\n reasons.push('CONTINENT_UNKNOWN' as BanReasonCode);\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new GeoLocationChecker());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class ThreatLevels implements IBotChecker<BanReasonCode> {\n name = 'Known ThreatLevels';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig) {\n return config.checkers.enableKnownThreatsDetections.enable;\n }\n \n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const { enableKnownThreatsDetections } = config.checkers;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!enableKnownThreatsDetections.enable) return { score, reasons };\n const {anonymiseNetwork, threatLevels} = enableKnownThreatsDetections.penalties;\n\n if (ctx.anon) {\n score += anonymiseNetwork;\n reasons.push('ANONYMITY_NETWORK');\n }\n\n switch (ctx.threatLevel) {\n case 1: {\n score += threatLevels.criticalLevel1;\n reasons.push('FIREHOL_L1_THREAT');\n break;\n }\n case 2: {\n score += threatLevels.currentAttacksLevel2;\n reasons.push('FIREHOL_L2_THREAT');\n break;\n }\n case 3: {\n score += threatLevels.threatLevel3;\n reasons.push('FIREHOL_L3_THREAT');\n break;\n }\n\n case 4: {\n score += threatLevels.threatLevel4;\n reasons.push('FIREHOL_L4_THREAT');\n break;\n }\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new ThreatLevels());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class AsnClassificationChecker implements IBotChecker<BanReasonCode> {\n name = 'ASN Classification';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableAsnClassification.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableAsnClassification;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n const { penalties } = checkConfig;\n const { classification, hits } = ctx.bgp;\n\n if (!classification) {\n score += penalties.unknownClassification;\n reasons.push('ASN_CLASSIFICATION_UNKNOWN');\n return { score, reasons };\n }\n\n if (classification === 'Content') {\n score += penalties.contentClassification;\n reasons.push('ASN_HOSTING_CLASSIFIED');\n }\n\n const hitsNum = parseInt(hits ?? '', 10);\n const isLowVisibility = Number.isFinite(hitsNum) && hitsNum >= 0 && hitsNum < penalties.lowVisibilityThreshold;\n\n if (isLowVisibility) {\n score += penalties.lowVisibilityPenalty;\n reasons.push('ASN_LOW_VISIBILITY');\n }\n\n if (classification === 'Content' && isLowVisibility) {\n score += penalties.comboHostingLowVisibility;\n reasons.push('ASN_HOSTING_LOW_VISIBILITY_COMBO');\n }\n\n return { score, reasons };\n }\n}\nCheckerRegistry.register(new AsnClassificationChecker());\n","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class TorAnalysisChecker implements IBotChecker<BanReasonCode> {\n name = 'Tor Node Analysis';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableTorAnalysis.enable;\n }\n\n private parseFlags(flags: string | undefined): Set<string> {\n if (!flags) return new Set();\n return new Set(flags.split(',').map(f => f.trim()));\n }\n\n\n private canExitWebTraffic(summary: string | undefined): boolean {\n if (!summary) return false;\n try {\n const policy = JSON.parse(summary) as { accept?: string[]; reject?: string[] };\n\n const coversWebPort = (entry: string): boolean => {\n if (entry === '80' || entry === '443') return true;\n if (entry.includes('-')) {\n const [lo, hi] = entry.split('-').map(Number);\n return (lo <= 80 && 80 <= hi) || (lo <= 443 && 443 <= hi);\n }\n return false;\n };\n\n if (policy.accept) {\n return policy.accept.some(coversWebPort);\n }\n\n if (policy.reject) {\n return !policy.reject.some(coversWebPort);\n }\n } catch {}\n \n return false;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableTorAnalysis;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!ctx.tor || Object.keys(ctx.tor).length === 0) return { score, reasons };\n\n const { penalties } = checkConfig;\n const {\n running,\n exit_addresses,\n flags,\n recommended_version,\n version_status,\n exit_probability,\n exit_policy_summary,\n guard_probability,\n } = ctx.tor;\n\n const flagSet = this.parseFlags(flags);\n\n if (running) {\n score += penalties.runningNode;\n reasons.push('TOR_ACTIVE_NODE');\n }\n\n const isExitNode = (exit_addresses && exit_addresses.length > 0) ?? flagSet.has('Exit');\n if (isExitNode) {\n score += penalties.exitNode + Math.ceil((exit_probability ?? 0) * 30);\n reasons.push('TOR_EXIT_NODE');\n\n if (this.canExitWebTraffic(exit_policy_summary)) {\n score += penalties.webExitCapable;\n reasons.push('TOR_WEB_EXIT_CAPABLE');\n }\n }\n\n if (flagSet.has('BadExit')) {\n score += penalties.badExit;\n reasons.push('TOR_BAD_EXIT');\n }\n\n if (flagSet.has('Guard') || (guard_probability ?? 0) > 0) {\n score += penalties.guardNode;\n reasons.push('TOR_GUARD_NODE');\n }\n\n if (recommended_version === false || version_status === 'obsolete') {\n score += penalties.obsoleteVersion;\n reasons.push('TOR_OBSOLETE_VERSION');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new TorAnalysisChecker());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class TimezoneConsistencyChecker implements IBotChecker<BanReasonCode> {\n name = 'Timezone Consistency';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableTimezoneConsistency.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableTimezoneConsistency;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n\n const geoTimezone = ctx.geoData.timezone?.toLowerCase();\n if (!geoTimezone) return { score, reasons };\n\n const tzHeader = ctx.req.get('Sec-CH-UA-Timezone') ?? ctx.req.get('X-Timezone');\n if (tzHeader && tzHeader.toLowerCase() !== geoTimezone) {\n score += checkConfig.penalties;\n reasons.push('TZ_HEADER_GEO_MISMATCH');\n }\n\n return { score, reasons };\n }\n}\nCheckerRegistry.register(new TimezoneConsistencyChecker());\n","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\n\nexport class HoneypotChecker implements IBotChecker<BanReasonCode> {\n name = 'Honeypot Path';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.honeypot.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.honeypot;\n const reasons: BanReasonCode[] = [];\n\n if (!checkConfig.enable || checkConfig.paths.length === 0) {\n return { score: 0, reasons };\n }\n\n const requestPath = ctx.req.path.toLowerCase();\n const hit = checkConfig.paths.some(p => requestPath === p.toLowerCase());\n\n if (hit) {\n reasons.push('HONEYPOT_PATH_HIT');\n reasons.push('BAD_BOT_DETECTED');\n }\n\n return { score: 0, reasons };\n }\n}\n\nCheckerRegistry.register(new HoneypotChecker());","import consola from 'consola';\nimport { getStorage } from '~~/src/botDetector/config/config.js';\n\nexport interface SessionEntry {\n lastPath: string;\n}\n\nconst SESSION_TTL_SECONDS = 600;\nconst PREFIX = 'session:';\n\nexport const sessionCache = {\n async get(sessionId: string): Promise<SessionEntry | null> {\n const key = `${PREFIX}${sessionId}`;\n const storage = getStorage();\n const data = await storage.getItem<SessionEntry>(key);\n\n if (data) {\n storage.setItem(key, data, { ttl: SESSION_TTL_SECONDS }).catch((err: unknown) => {\n consola.warn(`Failed to update session TTL for ${key}`, err);\n });\n }\n\n return data;\n },\n\n async set(sessionId: string, entry: SessionEntry): Promise<void> {\n const key = `${PREFIX}${sessionId}`;\n await getStorage().setItem(key, entry, { ttl: SESSION_TTL_SECONDS });\n },\n\n async delete(sessionId: string): Promise<void> {\n const key = `${PREFIX}${sessionId}`;\n await getStorage().removeItem(key);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n\n};","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { sessionCache } from \"../helpers/cache/sessionCache.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\nexport class SessionCoherenceChecker implements IBotChecker<BanReasonCode> {\n name = 'Session Coherence';\n phase = 'heavy' as const;\n \n private _logger?: ReturnType<typeof getLogger>;\n private get logger() {\n this._logger ??= getLogger().child({service: 'botDetector', branch: 'checker', type: 'SessionCoherenceChecker'});\n return this._logger;\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableSessionCoherence.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableSessionCoherence;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable) return { score, reasons };\n if (!ctx.cookie) return { score, reasons };\n\n const currentPath = ctx.req.path;\n const refererHeader = ctx.req.get('Referer');\n const secFetchSite = ctx.req.get('Sec-Fetch-Site');\n const currentHostname = ctx.req.hostname;\n const cached = await sessionCache.get(ctx.cookie);\n\n const missingSameOriginReferer = secFetchSite === 'same-origin' && !refererHeader;\n const missingSubsequentReferer = cached && !refererHeader;\n\n if (missingSameOriginReferer || missingSubsequentReferer) {\n score += checkConfig.penalties.missingReferer;\n reasons.push('SESSION_COHERENCE_MISSING_REFERER');\n }\n\n else if (refererHeader) {\n try {\n const refererUrl = new URL(refererHeader);\n\n if (refererUrl.hostname !== currentHostname) {\n score += checkConfig.penalties.domainMismatch;\n reasons.push('SESSION_COHERENCE_DOMAIN_MISMATCH');\n } \n\n else if (cached && refererUrl.pathname !== cached.lastPath) {\n score += checkConfig.penalties.pathMismatch;\n reasons.push('SESSION_COHERENCE_PATH_MISMATCH');\n }\n } catch {\n score += checkConfig.penalties.missingReferer; \n reasons.push('SESSION_COHERENCE_INVALID_REFERER');\n }\n }\n\n sessionCache.set(ctx.cookie, { lastPath: currentPath }).catch((err: unknown) => {\n this.logger.error({err}, 'Failed to save session in storage.');\n });\n \n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new SessionCoherenceChecker());","import { getStorage } from '~~/src/botDetector/config/config.js';\n\nconst TIMING_TTL_SECONDS = 60 * 15;\nconst PREFIX = 'timing:';\n\nexport const timingCache = {\n async get(visitorId: string): Promise<number[] | null> {\n const key = `${PREFIX}${visitorId}`;\n return await getStorage().getItem<number[]>(key);\n },\n\n async set(visitorId: string, entry: number[]): Promise<void> {\n const key = `${PREFIX}${visitorId}`;\n await getStorage().setItem(key, entry, { ttl: TIMING_TTL_SECONDS });\n },\n\n async delete(visitorId: string): Promise<void> {\n const key = `${PREFIX}${visitorId}`;\n await getStorage().removeItem(key);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n\n};","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { timingCache } from \"../helpers/cache/timingCache.js\";\nimport { getLogger } from \"@utils/logger.js\";\n\nconst MAX_SAMPLES = 10;\nconst MIN_SAMPLES_TO_EVALUATE = 5;\n\nexport class VelocityFingerprintChecker implements IBotChecker<BanReasonCode> {\n name = 'Velocity Fingerprinting';\n phase = 'heavy' as const;\n private _logger?: ReturnType<typeof getLogger>;\n private get logger() {\n this._logger ??= getLogger().child({service: 'botDetector', branch: 'checker', type: 'VelocityFingerprintChecker'});\n return this._logger;\n }\n\n isEnabled(config: BotDetectorConfig): boolean {\n return config.checkers.enableVelocityFingerprint.enable;\n }\n\n async run(ctx: ValidationContext, config: BotDetectorConfig) {\n const checkConfig = config.checkers.enableVelocityFingerprint;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!checkConfig.enable || !ctx.cookie) return { score, reasons };\n\n const now = Date.now();\n const existing = await timingCache.get(ctx.cookie) ?? [];\n const timestamps = [...existing, now].slice(-MAX_SAMPLES);\n\n timingCache.set(ctx.cookie, timestamps).catch((err: unknown) => {\n this.logger.error({err}, 'Failed to save timingCache in storage');\n });\n\n if (timestamps.length < MIN_SAMPLES_TO_EVALUATE) return { score, reasons };\n\n const intervals: number[] = [];\n for (let i = 1; i < timestamps.length; i++) {\n intervals.push(timestamps[i] - timestamps[i - 1]);\n }\n\n const mean = intervals.reduce((a, b) => a + b, 0) / intervals.length;\n if (mean === 0) return { score, reasons };\n\n const variance = intervals.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / intervals.length;\n const cv = Math.sqrt(variance) / mean;\n\n if (cv < checkConfig.cvThreshold) {\n score += checkConfig.penalties;\n reasons.push('TIMING_TOO_REGULAR');\n }\n\n return { score, reasons };\n }\n}\nCheckerRegistry.register(new VelocityFingerprintChecker());","import { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { CheckerRegistry } from \"./CheckerRegistry.js\";\nimport { getDataSources } from \"../config/config.js\";\n\n\nexport class KnownBadIps implements IBotChecker<BanReasonCode> {\n name = 'KnownBadIps';\n phase = 'cheap' as const;\n\n isEnabled(config: BotDetectorConfig) {\n return config.checkers.enableKnownBadIpsCheck.enable;\n }\n\n run(ctx: ValidationContext, config: BotDetectorConfig) {\n const { enableKnownBadIpsCheck } = config.checkers;\n const reasons: BanReasonCode[] = [];\n let score = 0;\n\n if (!enableKnownBadIpsCheck.enable) return { score, reasons };\n\n const ds = getDataSources();\n const ip = ctx.ipAddress;\n\n const banned = ds.bannedDataBase(ip);\n if (banned) {\n reasons.push('PREVIOUSLY_BANNED_IP', 'BAD_BOT_DETECTED');\n return { score, reasons };\n }\n\n const highRisk = ds.highRiskDataBase(ip);\n if (highRisk) {\n const ratio = Math.min(highRisk.score / config.banScore, 1);\n score += Math.round(enableKnownBadIpsCheck.highRiskPenalty * ratio);\n reasons.push('PREVIOUSLY_HIGH_RISK_IP');\n }\n\n return { score, reasons };\n }\n}\n\nCheckerRegistry.register(new KnownBadIps());","export class BadBotDetected extends Error {\n constructor(message = 'Bad bot detected') {\n super(message);\n this.name = 'BadBotDetected';\n }\n}\n\nexport class GoodBotDetected extends Error {\n constructor(message = 'Good bot detected') {\n super(message);\n this.name = 'GoodBotDetected';\n }\n}\n","import { spawn } from 'child_process';\nimport type { BannedInfo } from '../types/checkersTypes.js';\nimport { getLogger } from '../utils/logger.js';\nimport { getConfiguration } from \"../config/config.js\";\n\nconst UFW = '/usr/sbin/ufw';\n\n\nexport function banIp(ip: string, info: BannedInfo): Promise<void> | void { \n const log = getLogger().child({service: 'BOT DETECTOR', branch: `banIp`, ipAddress: ip, details: info});\n const {punishmentType} = getConfiguration();\n\n if (!punishmentType.enableFireWallBan) {\n log.info(`Firewall punishment ban is disabled, skipping`);\n return;\n }\n\n log.info('about to ban an IP');\n return new Promise((resolve, reject) => {\n const child = spawn('sudo', ['-n', UFW, 'insert', '1', 'deny', 'from', ip], {\n stdio: ['ignore', 'ignore', 'pipe'],\n detached: true \n });\n child.unref(); \n\n let stderr = '';\n const timer = setTimeout(() => {\n child.kill('SIGKILL');\n log.warn(`ufw hang timeout on ${ip}`);\n reject(new Error(`ufw hang timeout on ${ip}`));\n }, 5_000);\n\n child.stderr.on('data', (d: Buffer | string) => (stderr += String(d)));\n child.on('error', err => {\n clearTimeout(timer);\n log.fatal({err},`- CRITICAL - UFW spawn failed`);\n reject(err);\n });\n child.on('close', code => {\n clearTimeout(timer);\n if (code !== 0) {\n log.fatal({code},`- CRITICAL - UFW ban failed`);\n reject(new Error(`ufw exited ${String(code)}`)); return;\n }\n log.info(`Banning Detected Bot/Malicious User. IP ${ip} banned (score ${String(info.score)})\\nReasons:\\n- ${info.reasons.join('\\n- ')}`);\n resolve();\n });\n });\n}\n","import type { BanReasonCode, IBotChecker } from \"../types/checkersTypes.js\";\nimport { getLogger } from \"../utils/logger.js\";\nimport { performance } from 'perf_hooks';\nimport { getConfiguration } from \"../config/config.js\";\nimport type { ValidationContext } from \"../types/botDetectorTypes.js\";\nimport type { BotDetectorConfig } from \"../types/configSchema.js\";\nimport { BadBotDetected, GoodBotDetected } from \"./exceptions.js\";\n\nexport async function processChecks(\n checkers: IBotChecker<BanReasonCode, unknown>[],\n ctx: ValidationContext<unknown>,\n config: BotDetectorConfig,\n botScore: number,\n reasons: BanReasonCode[],\n phaseLabel = 'phase' \n): Promise<number> {\n\n const {banScore} = getConfiguration();\n const log = getLogger().child({service: `BOT DETECTOR`, branch: 'checks'});\n const reqId = Date.now(); \n\n const phaseStart = performance.now();\n log.info({ phase: phaseLabel, reqId, event: 'start' });\n \n const banLimit = banScore;\n\n for (const checker of checkers) {\n const label = checker.name;\n\n const checkStart = performance.now();\n log.info({ reqId, check: label, event: 'start' });\n\n const { score, reasons: rs } = await checker.run(ctx, config);\n\n const checkEnd = performance.now();\n log.info({reqId,check: label,event: 'end',durationMs: +(checkEnd - checkStart).toFixed(3),score,reasons: rs,});\n\n botScore += score;\n rs.forEach(r => reasons.push(r));\n \n if (rs.includes('GOOD_BOT_IDENTIFIED')) throw new GoodBotDetected();\n if (rs.includes('BAD_BOT_DETECTED')) throw new BadBotDetected();\n\n if (botScore >= banLimit) {\n log.warn({ reqId, botScore }, 'Bot detected — aborting checks');\n break;\n }\n }\n const phaseEnd = performance.now();\n log.info({\n reqId,\n phase: phaseLabel,\n event: 'end',\n durationMs: +(phaseEnd - phaseStart).toFixed(3),\n Score: botScore\n });\n return botScore;\n}","import { getStorage, getConfiguration } from '../../config/config.js';\n\nexport interface CachedResult {\n isBot: boolean;\n score: number;\n}\n\nconst PREFIX = 'reputation:';\n\nexport const reputationCache = {\n async get(cookie: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${cookie}`);\n },\n\n async set(cookie: string, entry: CachedResult): Promise<void> {\n const { checksTimeRateControl } = getConfiguration();\n await getStorage().setItem(`${PREFIX}${cookie}`, entry, { ttl: Math.floor(checksTimeRateControl.checkEvery / 1000) });\n },\n\n async delete(cookie: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${cookie}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import './botDetector/checkers/index.js'; \nimport { Request } from 'express';\nimport { CheckerRegistry } from './botDetector/checkers/CheckerRegistry.js';\nimport { ValidationContext } from './botDetector/types/botDetectorTypes.js';\nimport { BadBotDetected, GoodBotDetected } from './botDetector/helpers/exceptions.js';\nimport { banIp } from './botDetector/penalties/banIP.js';\nimport type { ParsedUAResult } from './botDetector/types/UAparserTypes.js';\nimport type { GeoResponse } from './botDetector/types/geoTypes.js';\nimport { BanReasonCode } from './botDetector/types/checkersTypes.js';\nimport { processChecks } from './botDetector/helpers/processChecks.js';\nimport { reputationCache } from './botDetector/helpers/cache/reputationCache.js';\nimport { getLogger } from './botDetector/utils/logger.js';\nimport { getConfiguration, getDataSources, getBatchQueue } from './botDetector/config/config.js';\n\nexport async function uaAndGeoBotDetector(\n req: Request,\n ipAddress: string,\n userAgent: string,\n geo: GeoResponse,\n parsedUA: ParsedUAResult,\n buildCustomContext?: (req: Request) => unknown,\n): Promise<boolean> {\n \n const log = getLogger().child({service: 'BOT DETECTOR', branch: 'main'});\n const {banScore, maxScore, setNewComputedScore} = getConfiguration();\n const BAN_THRESHOLD = banScore;\n const MAX_SCORE = maxScore;\n\n const reasons: BanReasonCode[] = [];\n let botScore = 0;\n const cookie: string | undefined = req.cookies.canary_id as string | undefined; \n const uaString = req.get(\"User-Agent\") ?? \"\";\n log.info(`BotDetection called for ${req.method} ${req.get('X-Forwarded-Host') ?? ''}`);\n\n const threatsLevels = getDataSources().fireholLvl1DataBase(ipAddress) ? 1 :\n getDataSources().fireholLvl2DataBase(ipAddress) ? 2 :\n getDataSources().fireholLvl3DataBase(ipAddress) ? 3 :\n getDataSources().fireholLvl4DataBase(ipAddress) ? 4 : null as 1 | 2 | 3 | 4 | null;\n\n const proxy = () => {\n const isProxy = getDataSources().proxyDataBase(ipAddress);\n if (isProxy) {\n return {\n proxy: true,\n proxyType: isProxy.comment\n };\n }\n return { proxy: false };\n };\n \n const {tor, asn, threatLevel, anon} = {\n tor: getDataSources().torDataBase(ipAddress),\n asn: getDataSources().asnDataBase(ipAddress),\n threatLevel: threatsLevels,\n anon: getDataSources().fireholAnonDataBase(ipAddress) ? true : false,\n };\n\n const proxyResult = proxy();\n const ctx: ValidationContext<unknown> = {\n req,\n ipAddress,\n parsedUA: parsedUA,\n geoData: geo,\n cookie,\n proxy: {\n isProxy: proxyResult.proxy,\n proxyType: proxyResult.proxyType\n },\n anon,\n bgp: asn ?? {},\n tor: tor ?? {},\n threatLevel,\n custom: buildCustomContext ? buildCustomContext(req) : ({} as unknown),\n };\n\n const cheapChecks = CheckerRegistry.getEnabled('cheap', getConfiguration());\n const checks = CheckerRegistry.getEnabled('heavy', getConfiguration());\n\n try {\n botScore = await processChecks(cheapChecks, ctx, getConfiguration(), botScore, reasons, 'cheapPhase');\n\n if (botScore < BAN_THRESHOLD) {\n botScore = await processChecks(checks, ctx, getConfiguration(), botScore, reasons, 'heavyPhase');\n }\n } catch (error) {\n if (error instanceof BadBotDetected) {\n const bannedInfo = { score: BAN_THRESHOLD, reasons: Array.from(reasons) };\n\n void banIp(ipAddress, bannedInfo);\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'update_banned_ip', { cookie: cookie ?? '', ipAddress, country: ctx.geoData.country ?? '', user_agent: uaString, info: bannedInfo }, 'deferred');\n\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'is_bot_update', { isBot: true, cookie: cookie ?? '' }, 'deferred');\n return true;\n }\n if (error instanceof GoodBotDetected) {\n return false;\n }\n log.error({error},'unexpected error');\n }\n\n botScore = Math.min(botScore, MAX_SCORE);\n if (botScore >= BAN_THRESHOLD) {\n log.info(`Starting Ban for ${ipAddress} ${userAgent}`);\n const bannedInfo = { score: botScore, reasons: Array.from(reasons) };\n\n void banIp(ipAddress, bannedInfo);\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'update_banned_ip', { cookie: cookie ?? '', ipAddress, country: ctx.geoData.country ?? '', user_agent: uaString, info: bannedInfo }, 'deferred');\n\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'is_bot_update', { isBot: true, cookie: cookie ?? '' }, 'deferred');\n return true;\n }\n\n\n if (setNewComputedScore) {\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'score_update', { score: botScore, cookie: cookie ?? '' }, 'deferred');\n\n reputationCache.set(cookie ?? '', { isBot: false, score: botScore }).catch((err: unknown) => {\n log.error({err}, 'Failed to set reputationCache in storage');\n });\n\n } else {\n const cached = await reputationCache.get(cookie ?? '');\n if (!cached || cached.score === 0) {\n void getBatchQueue().addQueue(cookie ?? '', ipAddress, 'score_update', { score: botScore, cookie: cookie ?? '' }, 'deferred');\n\n reputationCache.set(cookie ?? '', { isBot: false, score: botScore }).catch((err: unknown) => {\n log.error({err}, 'Failed to set reputationCache in storage');\n });\n \n }\n }\n return false;\n}\n\n","import { getStorage, getConfiguration } from '../../config/config.js';\n\nexport interface CachedResult {\n banned: boolean;\n visitor_id: string;\n}\n\nconst PREFIX = 'visitor:';\n\nexport const visitorCache = {\n async get(cookie: string): Promise<CachedResult | null> {\n return getStorage().getItem<CachedResult>(`${PREFIX}${cookie}`);\n },\n\n async set(cookie: string, entry: CachedResult): Promise<void> {\n const { checksTimeRateControl } = getConfiguration();\n await getStorage().setItem(`${PREFIX}${cookie}`, entry, { ttl: Math.floor(checksTimeRateControl.checkEvery / 1000) });\n },\n\n async delete(cookie: string): Promise<void> {\n await getStorage().removeItem(`${PREFIX}${cookie}`);\n },\n\n async clear(): Promise<void> {\n await getStorage().clear();\n }\n};","import { reputationCache } from \"./cache/reputationCache.js\";\nimport { getLogger } from \"../utils/logger.js\";\nimport { getBatchQueue, getConfiguration, getDb } from \"../config/config.js\";\nimport { prep } from \"../db/dialectUtils.js\";\n\ninterface VisitorRow {\n is_bot: number;\n suspicious_activity_score: number;\n}\n\nexport async function userReputation(cookie: string): Promise<void> {\n const log = getLogger().child({service: `BOT DETECTOR`, branch: `reputation`});\n const db = getDb();\n const {banScore, restoredReputationPoints, setNewComputedScore} = getConfiguration();\n\n const botScore = banScore;\n\n const cached = await reputationCache.get(cookie);\n if (cached) {\n log.info(`CACHE HIT cookie=${cookie} score=${String(cached.score)} → (botScore=${String(botScore)})`);\n if(cached.isBot) {\n return;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!cached.isBot && cached.score > 0 && cached.score < botScore) {\n log.info(`updating cache score cookie=${cookie} score=${String(cached.score)} → (botScore=${String(botScore)})`);\n const newReputation = Math.max(0, cached.score - restoredReputationPoints);\n\n if (newReputation !== cached.score) {\n void getBatchQueue().addQueue(cookie, '', 'score_update', { score: newReputation, cookie }, 'deferred');\n log.info(`updating cache score to DB cookie=${cookie} score=${String(cached.score)} → (botScore=${String(botScore)})`);\n reputationCache.set(cookie, {\n isBot: cached.isBot,\n score: newReputation\n }).catch((err: unknown) => {\n log.error({ err }, 'Failed to save reputationCache in storage');\n });\n }\n log.info(`finished Updating Score from cache to DB cookie: ${cookie} NEW SCORE: ${String(newReputation)}`);\n }\n return;\n }\n\n\n try {\n const VisitorQuery = `\n SELECT is_bot,\n suspicious_activity_score\n FROM visitors\n WHERE canary_id = ?\n LIMIT 1`;\n\n const visitor = await prep(db, VisitorQuery).get(cookie) as VisitorRow | undefined;\n\n if (!visitor) {\n log.warn(`no visitor record for canary_id=${cookie}`);\n return;\n }\n\n const isBot = visitor.is_bot === 0 ? false : true;\n const reputation = visitor.suspicious_activity_score;\n\n\n if (isBot) return;\n\n if (!setNewComputedScore) {\n reputationCache.set(cookie, {\n isBot: isBot,\n score: reputation\n }).catch((err: unknown) => {\n log.error({ err }, 'Failed to save reputationCache in storage');\n });\n }\n\n log.info({\n label: '[REP-GATE]',\n isBot: isBot,\n score: reputation,\n 'score>0': reputation > 0,\n 'score<ban': reputation < botScore,\n healPts: restoredReputationPoints\n });\n\n\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n if (!isBot && reputation > 0 && reputation < botScore) {\n log.info(`calculating new score cookie=${cookie} score=${String(reputation)} → (botScore=${String(botScore)})`);\n const newReputation = Math.max(0, reputation - restoredReputationPoints);\n\n if (newReputation !== reputation) {\n void getBatchQueue().addQueue(cookie, '', 'score_update', { score: newReputation, cookie }, 'deferred');\n log.info(`Update Score for cookie', ${cookie}, 'New Score:', ${String(newReputation)}`);\n\n reputationCache.set(cookie, {\n isBot: isBot,\n score: newReputation\n }).catch((err: unknown) => {\n log.error({ err }, 'Failed to save reputationCache in storage');\n });\n }\n\n }\n } catch(err) {\n log.error({err},`An error occurred updating visitor reputation`);\n }\n}","/* eslint-disable @typescript-eslint/no-unnecessary-condition */\nimport { getConfiguration } from \"../config/config.js\";\n\n\nexport function getWhiteList(): string[] {\n const {whiteList} = getConfiguration();\n if (whiteList) return whiteList;\n return [];\n}\n\nexport function isInWhiteList(ipAddress: string): boolean {\n const {whiteList} = getConfiguration();\n\n if (whiteList) {\n const match = whiteList.includes(ipAddress);\n return match;\n }\n\n return false;\n}\n\n","export const nowMysql = () => new Date().toISOString().slice(0, 19).replace('T', ' ');","import { getData } from '../helpers/getIPInformation.js';\nimport { makeCookie } from '../utils/cookieGenerator.js';\nimport type { Request, Response, NextFunction, RequestHandler } from \"express\";\nimport { randomBytes, randomUUID } from \"crypto\";\nimport parseUA from '../helpers/UAparser.js';\nimport { uaAndGeoBotDetector } from '../../botDetector.js';\nimport { visitorCache } from '../helpers/cache/cannaryCache.js';\nimport { rateCache } from '../helpers/cache/rateLimitarCache.js';\nimport { userReputation } from '../helpers/reputation.js';\nimport { getLogger } from '../utils/logger.js';\nimport type { userValidation } from '../types/fingerPrint.js';\nimport { getConfiguration, getBatchQueue } from '../config/config.js';\nimport { isInWhiteList } from '../utils/whitelist.js';\nimport { nowMysql } from '@utils/nowMysql.js';\nimport consola from 'consola';\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/no-namespace\n namespace Express {\n export interface Request {\n newVisitorId?: string;\n botDetection: {\n success: boolean,\n banned: boolean,\n time: string,\n ipAddress: string\n }\n }\n }\n}\n\n\nexport function validator(\n buildCustomContext?: (req: Request) => unknown,\n): RequestHandler {\n return async (req: Request, res: Response, next: NextFunction): Promise<void> => {\n const {checksTimeRateControl} = getConfiguration();\n let canary: string | undefined = req.cookies.canary_id as string | undefined;\n const ua = req.get(\"User-Agent\") ?? \"\";\n const ip = req.ip ?? '';\n const log = getLogger().child({service: 'BOT DETECTOR', branch: `main`, canary: canary});\n log.info(`Validator entered for ${req.method} ${req.get('X-Forwarded-Host') ?? ''}`);\n log.info({ cookies: req.cookies },`Incoming cookies`);\n const whiteList = isInWhiteList(ip);\n\n if (canary) {\n const cached = await visitorCache.get(canary);\n if (cached) {\n if (cached.banned && !whiteList) {\n res.sendStatus(403);\n return;\n }\n req.newVisitorId = cached.visitor_id;\n if (!checksTimeRateControl.checkEveryRequest){\n next(); return;\n }\n }\n }\n \n if (!canary) {\n log.info(`No canary_id cookie found. Generating a new one.`);\n const cookieValue = randomBytes(32).toString('hex');\n canary = cookieValue;\n \n makeCookie(res,'canary_id', cookieValue, {\n httpOnly: true,\n sameSite: \"lax\", \n maxAge: 1000 * 60 * 60 * 24 * 90,\n secure: true,\n path: \"/\", \n });\n req.cookies.canary_id = canary;\n log.info(`New canary_id cookie set:, ${cookieValue}`);\n }\n\n const geo = getData(ip);\n const parsedUA = parseUA(ua);\n const visitorId = randomUUID();\n\n const userValidation = {\n visitorId,\n cookie: canary,\n userAgent: ua,\n ipAddress: ip,\n device_type: parsedUA.device,\n browser: parsedUA.browser,\n is_bot: false,\n first_seen: nowMysql(), \n last_seen: nowMysql(), \n request_count: 1, \n deviceVendor: parsedUA.deviceVendor,\n deviceModel: parsedUA.deviceModel,\n browserType: parsedUA.browserType,\n browserVersion: parsedUA.browserVersion,\n os: parsedUA.os,\n activity_score: '0',\n ...geo,\n } as userValidation;\n\n void getBatchQueue().addQueue(canary, ip, 'visitor_upsert', { insert: userValidation }, 'deferred');\n req.newVisitorId = visitorId;\n\n if (whiteList) {\n log.info(`${ip} is in white list skipping botDetection checks.`);\n\n visitorCache.set(canary, {\n banned: false,\n visitor_id: visitorId\n }).catch((err: unknown) => { log.error({ err }, 'Failed to save visitorCache in storage'); });\n\n req.botDetection = {\n success: true,\n banned: false,\n time: new Date().toISOString(),\n ipAddress: ip\n };\n\n next(); return;\n };\n\n const brvConfig = getConfiguration().checkers.enableBehaviorRateCheck;\n if (brvConfig.enable) {\n const existing = await rateCache.get(canary);\n if (!existing) {\n const ttlSeconds = Math.ceil(brvConfig.behavioral_window / 1000);\n rateCache.set(canary, { score: 0, timestamp: Date.now(), request_count: 1 }, ttlSeconds)\n .catch((err: unknown) => { log.error({ err }, 'Failed to pre seed rateCache'); });\n }\n }\n\n const isBot = await uaAndGeoBotDetector(req, ip, ua, geo, parsedUA, buildCustomContext);\n\n visitorCache.set(canary, {\n banned: isBot,\n visitor_id: visitorId\n }).catch((err: unknown) => { log.error({ err }, 'Failed to save visitorCache in storage'); });\n\n if (isBot) {\n res.sendStatus(403);\n return;\n }\n\n req.botDetection = {\n success: true,\n banned: isBot,\n time: new Date().toISOString(),\n ipAddress: ip\n };\n \n userReputation(canary).catch((err: unknown) => { consola.error('[BOT DETECTION - MIDDLEWARE] userReputation failed:', err); });\n\n next();\n };\n}\n","import { Router } from 'express';\nimport { validator } from '../middlewares/canaryCookieChecker.js';\n\n\nconst router = Router();\n\nrouter.use('/check', validator(), (req, res) => {\n res.json({results: req.botDetection, message: 'Fingerprint logged successfully' });\n});\n\nexport default router;\n\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 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 consola from 'consola';\nimport { getDb } from '../config/config.js';\nimport { prep } from './dialectUtils.js';\n\nexport async function warmUp() {\nconst db = getDb();\nawait Promise.all(\n Array.from({ length: 10 }, () => db.sql`SELECT 1`)\n);\n\nawait prep(db,\n `SELECT last_seen, request_count\n FROM visitors\n WHERE canary_id = ?\n LIMIT 1`\n).get('00000000‑warm‑up‑row');\n\nconsola.info('botDetector is ready!');\n}","import { getLogger } from \"../utils/logger.js\";\nimport { getDb } from \"../config/config.js\";\nimport { prep } from \"./dialectUtils.js\";\n\nexport interface VisitorFingerPrint {\n userAgent: string;\n ipAddress: string;\n country: string;\n region: string;\n regionName: string;\n city: string;\n district: string;\n lat: string;\n lon: string;\n timezone: string;\n currency: string;\n isp: string;\n org: string;\n as: string;\n device_type: string;\n browser: string;\n proxy: boolean;\n hosting: boolean;\n deviceVendor: string;\n deviceModel: string;\n browserType: string;\n browserVersion: string;\n os: string;\n}\n\n\nexport async function updateVisitors(\n data: VisitorFingerPrint,\n cookie: string,\n visitor_id: string,\n): Promise<{ success: boolean; reason?: string }> {\n const db = getDb();\n const log = getLogger().child({ service: 'BOT DETECTOR', branch: 'customUpdate' });\n\n const params = [\n data.userAgent,\n data.ipAddress,\n data.country,\n data.region,\n data.regionName,\n data.city,\n data.district,\n data.lat,\n data.lon,\n data.timezone,\n data.currency,\n data.isp,\n data.org,\n data.as,\n data.device_type,\n data.browser,\n data.proxy ? 1 : 0,\n data.hosting ? 1 : 0,\n data.deviceVendor,\n data.deviceModel,\n data.browserType,\n data.browserVersion,\n data.os,\n ];\n\n try {\n const result = await prep(db, `\n UPDATE visitors\n SET\n user_agent = ?,\n ip_address = ?,\n country = ?,\n region = ?,\n region_name = ?,\n city = ?,\n district = ?,\n lat = ?,\n lon = ?,\n timezone = ?,\n currency = ?,\n isp = ?,\n org = ?,\n as_org = ?,\n device_type = ?,\n browser = ?,\n proxy = ?,\n hosting = ?,\n deviceVendor = ?,\n deviceModel = ?,\n browserType = ?,\n browserVersion = ?,\n os = ?\n WHERE canary_id = ?\n AND visitor_id = ?\n `).run(...params, cookie, visitor_id);\n\n if (!result.success) {\n log.warn({ cookie, visitor_id }, `updateVisitors: no rows affected`);\n return { success: false, reason: `No visitor found for canary_id=${cookie} visitor_id=${visitor_id}` };\n }\n\n log.info({ visitor_id }, `updateVisitors: visitor updated`);\n return { success: true };\n } catch (err) {\n log.error({ err }, `updateVisitors: query failed`);\n return { success: false, reason: 'DB error — check logs for details' };\n }\n}\n"],"mappings":"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"}
|