{"_id":"nestjs-request-protector","_rev":"28-1ffd9d19e2cbbf9a95236428e8fd2730","name":"nestjs-request-protector","dist-tags":{"latest":"1.3.0"},"versions":{"1.1.8":{"name":"nestjs-request-protector","version":"1.1.8","license":"MIT","_id":"nestjs-request-protector@1.1.8","maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"dist":{"shasum":"c2935ee58eca8440425c43482de2469168abfe1b","tarball":"https://registry.npmjs.org/nestjs-request-protector/-/nestjs-request-protector-1.1.8.tgz","fileCount":10,"integrity":"sha512-OKAz1XwpDe8iqfcHFR9ugCgN50c1v5YQN0psV+EH4PiuRM//HHKTnjZQidZm4NRwALy/110YtuZkCv9woPbBEg==","signatures":[{"sig":"MEQCIAVkDSapHAcMEFumIVe7EaNqbvC4h/bGz173Zbuah8dQAiAVTd67BwDJHFt+xNoyjmz9J6L4y4V83Mu1cQowUZ408g==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":17840},"main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc"},"_npmUser":{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"},"_npmVersion":"10.8.2","description":"A configurable NestJS middleware to block unauthorized API requests (Postman, curl, etc.)","directories":{},"_nodeVersion":"20.19.0","dependencies":{"express-useragent":"^1.0.15"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3","@types/express":"^5.0.4","@types/express-useragent":"^1.0.5"},"peerDependencies":{"express":"^4.0.0","@nestjs/common":"^10.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-request-protector_1.1.8_1761444630889_0.5383097841815381","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"nestjs-request-protector","version":"1.2.1","keywords":["nestjs","typescript","guard","request-protector","security","nestjs-security","nestjs-guard","nestjs-request-protector"],"author":{"name":"Vahe Hakobyan"},"license":"MIT","_id":"nestjs-request-protector@1.2.1","maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"homepage":"https://github.com/VaheHak/nestjs-request-protector#readme","bugs":{"url":"https://github.com/VaheHak/nestjs-request-protector/issues"},"dist":{"shasum":"6d5966dcd575641d6b17ed9d3ae50ed9ca84cb33","tarball":"https://registry.npmjs.org/nestjs-request-protector/-/nestjs-request-protector-1.2.1.tgz","fileCount":19,"integrity":"sha512-fYbKrCwcuDEMVkf6GCM2QmPJDfqATLG99jKdnGNDgTheRcA87oEaJEkrmz2nA2Xwp+ROBAh/RMNg/iTgCiKAIg==","signatures":[{"sig":"MEUCIC3gScszvsHHdzT397G2nnwO9TpKGhmY7uk/K2/Wrz05AiEAnPxMLJ9ybcFvo4jHwbKRc1O4s3WErG6zRHioRrDt5bo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26967},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"f328b7fc116edfb5b786f9240d6112b3806c18b4","scripts":{"build":"tsc"},"_npmUser":{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"},"repository":{"url":"git+https://github.com/VaheHak/nestjs-request-protector.git","type":"git"},"_npmVersion":"10.8.2","description":"A configurable NestJS guard to block unauthorized API requests (Postman, curl, etc.)","directories":{},"_nodeVersion":"20.19.0","dependencies":{"express-useragent":"^1.0.15"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3","@types/express":"^5.0.4","@types/express-useragent":"^1.0.5"},"peerDependencies":{"express":"^4.0.0","@nestjs/common":"^10.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-request-protector_1.2.1_1761521232283_0.2580970742644033","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"nestjs-request-protector","version":"1.2.2","keywords":["nestjs","backend","typescript","guard","request-protector","security","nestjs-security","nestjs-guard","nestjs-request-protector"],"author":{"name":"Vahe Hakobyan"},"license":"MIT","_id":"nestjs-request-protector@1.2.2","maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"homepage":"https://github.com/VaheHak/nestjs-request-protector#readme","bugs":{"url":"https://github.com/VaheHak/nestjs-request-protector/issues"},"dist":{"shasum":"ee6dc4d63d728e85580a1ba530da6c092a01e284","tarball":"https://registry.npmjs.org/nestjs-request-protector/-/nestjs-request-protector-1.2.2.tgz","fileCount":14,"integrity":"sha512-fQqT0ujDQ7iKUX0Y+tH93eFjnfNEwGK5EU4ZNcnL68hU9eIoYYLZf5swx5RFZq7qSZgsZKCEHLzhjKk6LXlRmA==","signatures":[{"sig":"MEUCIArg2QAdtjeH9HN5LiwmKTLGn8RcVV5PMoLXX0kQ5vBtAiEAz/bWpRDMKW4Ug7/9XD0UNYVtjCHN0v8H08M2GcFvwPc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":37902},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"3cbde4a376c76dd56dce76fa50038786def31877","scripts":{"build":"tsc"},"_npmUser":{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"},"repository":{"url":"git+https://github.com/VaheHak/nestjs-request-protector.git","type":"git"},"_npmVersion":"10.8.2","description":"A configurable NestJS guard to block unauthorized API requests (Postman, curl, etc.)","directories":{},"_nodeVersion":"20.19.0","dependencies":{"express-useragent":"^1.0.15"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3","@types/express":"^5.0.4","@types/express-useragent":"^1.0.5"},"peerDependencies":{"express":"^4.0.0","@nestjs/common":"^10.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-request-protector_1.2.2_1761584585181_0.295839888409291","host":"s3://npm-registry-packages-npm-production"}},"1.2.5":{"name":"nestjs-request-protector","version":"1.2.5","keywords":["nestjs","backend","typescript","guard","request-protector","security","nestjs-security","nestjs-guard","nestjs-request-protector"],"author":{"name":"Vahe Hakobyan"},"license":"MIT","_id":"nestjs-request-protector@1.2.5","maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"homepage":"https://github.com/VaheHak/nestjs-request-protector#readme","bugs":{"url":"https://github.com/VaheHak/nestjs-request-protector/issues"},"dist":{"shasum":"542f0669140630cae616f2930aca043500ed3dba","tarball":"https://registry.npmjs.org/nestjs-request-protector/-/nestjs-request-protector-1.2.5.tgz","fileCount":16,"integrity":"sha512-ddcTUCSoJVMXuzeuRgkyth1WbyVy12s14tMhUIHGxqAWI3n7c8ypff2s/FO2Fw9zhEFbw/shh7YS3sQiQM4nMg==","signatures":[{"sig":"MEYCIQCRmItUlo0jbDy46BWyaPaFX2R1bH2DEY0qAnO9aJ9OQwIhAKIVzdatZkACXj2SLrkTsOlbAt0APIl863nwhQAvN1Kg","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":40601},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"563fe183135f862f8495d1b5db2f3fde475b00e0","scripts":{"build":"tsc"},"_npmUser":{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"},"repository":{"url":"git+https://github.com/VaheHak/nestjs-request-protector.git","type":"git"},"_npmVersion":"10.8.2","description":"A configurable NestJS guard to block unauthorized API requests (Postman, curl, etc.)","directories":{},"_nodeVersion":"20.19.0","dependencies":{"express-useragent":"^1.0.15"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3","@types/express":"^5.0.4","@types/express-useragent":"^1.0.5"},"peerDependencies":{"express":"^4.0.0","@nestjs/common":"^10.0.0"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-request-protector_1.2.5_1761654179320_0.6554315634096439","host":"s3://npm-registry-packages-npm-production"}},"1.2.6":{"name":"nestjs-request-protector","version":"1.2.6","keywords":["nestjs","backend","typescript","guard","request-protector","security","nestjs-security","nestjs-guard","nestjs-request-protector"],"author":{"name":"Vahe Hakobyan"},"license":"MIT","_id":"nestjs-request-protector@1.2.6","maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"homepage":"https://github.com/VaheHak/nestjs-request-protector#readme","bugs":{"url":"https://github.com/VaheHak/nestjs-request-protector/issues"},"dist":{"shasum":"2cfe13de577f2eab676fedaaf976cacec4b57da1","tarball":"https://registry.npmjs.org/nestjs-request-protector/-/nestjs-request-protector-1.2.6.tgz","fileCount":16,"integrity":"sha512-9GTkc5k7zazLjr3JEV3FYiQfZDOzBljr8h7UJKtZ82M134Ixq8Qr6dTBRiUY6ggAhNuR+7mToDSW0AdkIy0EjQ==","signatures":[{"sig":"MEUCIBLQG95+H0Vh+wf2b24ULu2ntWAWfbY0dF6CNh7XN6eOAiEAwj9RI8bf4Pu2sE9/YyrFV3l6v9LTlJzWAabGDD/SpvU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":39412},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=16.0.0"},"gitHead":"883c5d90ac0ccdf94442803721154132e5353ce5","scripts":{"build":"tsc"},"_npmUser":{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"},"repository":{"url":"git+https://github.com/VaheHak/nestjs-request-protector.git","type":"git"},"_npmVersion":"10.8.2","description":"A configurable NestJS guard to block unauthorized API requests (Postman, curl, etc.)","directories":{},"_nodeVersion":"20.19.0","dependencies":{"express-useragent":"^2.1.0"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.9.3","@types/express":"^5.0.6","@types/express-useragent":"^1.0.5"},"peerDependencies":{"express":"^5.2.1","@nestjs/common":"^11.1.12"},"_npmOperationalInternal":{"tmp":"tmp/nestjs-request-protector_1.2.6_1770030380425_0.2811833179479819","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"nestjs-request-protector","version":"1.3.0","author":{"name":"Vahe Hakobyan"},"description":"A configurable NestJS guard to block unauthorized API requests (Postman, curl, etc.)","main":"dist/index.js","types":"dist/index.d.ts","exports":{".":{"require":"./dist/index.js","import":"./dist/index.js","types":"./dist/index.d.ts"}},"license":"MIT","scripts":{"build":"tsc --project tsconfig.json","build:check":"tsc --project tsconfig.json --noEmit","typecheck":"tsc --noEmit","lint":"eslint \"src/**/*.ts\" \"tests/**/*.ts\"","lint:fix":"eslint \"src/**/*.ts\" \"tests/**/*.ts\" --fix","test":"jest","test:watch":"jest --watch","test:cov":"jest --coverage","test:ci":"jest --ci --coverage --runInBand","prepublishOnly":"npm run lint && npm test && npm run build:check && npm run build"},"engines":{"node":">=18.0.0"},"keywords":["nestjs","backend","typescript","guard","request-protector","security","nestjs-security","nestjs-guard","nestjs-request-protector","rate-limit","bot-detection"],"bugs":{"url":"https://github.com/VaheHak/nestjs-request-protector/issues"},"homepage":"https://github.com/VaheHak/nestjs-request-protector#readme","repository":{"type":"git","url":"git+https://github.com/VaheHak/nestjs-request-protector.git"},"dependencies":{"express-useragent":"^2.1.0"},"peerDependencies":{"@nestjs/common":">=9.0.0","express":">=4.0.0"},"devDependencies":{"@eslint/js":"^9.13.0","@nestjs/common":"^11.1.12","@types/express":"^5.0.6","@types/express-useragent":"^1.0.5","@types/jest":"^29.5.12","@types/node":"^20.11.0","eslint":"^9.13.0","jest":"^29.7.0","ts-jest":"^29.1.2","typescript":"^5.9.3","typescript-eslint":"^8.12.0"},"_id":"nestjs-request-protector@1.3.0","_nodeVersion":"20.19.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-WdEQpEowYk6XT+S+06P1zaN1NPZkIGOspgKH+vEl3WvG0bZDyQ3svq8YiTXaopabUFxs7+yYw4eOs49zceGRQw==","shasum":"ce60b7fb59f5b1077a3f2ed7626733ce9df1e4d8","tarball":"https://registry.npmjs.org/nestjs-request-protector/-/nestjs-request-protector-1.3.0.tgz","fileCount":17,"unpackedSize":64252,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBOVjsAsYE+pvnexWqYmYl3v7bXB6GB/dEPiaoBRH/0WAiEA954JVk3/rOFKRWJ4MkLCa12HcbNWsUmY58ZaemXScSA="}]},"_npmUser":{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"},"directories":{},"maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs-request-protector_1.3.0_1780022423706_0.7705809693382137"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-24T23:15:37.485Z","modified":"2026-05-29T02:40:23.956Z","1.1.0":"2025-10-24T23:15:37.746Z","1.1.1":"2025-10-24T23:21:45.434Z","1.1.2":"2025-10-24T23:27:44.047Z","1.1.3":"2025-10-24T23:58:52.701Z","1.1.4":"2025-10-25T00:39:10.818Z","1.1.5":"2025-10-25T00:50:23.045Z","1.1.6":"2025-10-25T17:58:57.569Z","1.1.7":"2025-10-25T20:18:05.674Z","1.1.8":"2025-10-26T02:10:31.091Z","1.2.0":"2025-10-26T23:05:30.775Z","1.2.1":"2025-10-26T23:27:12.474Z","1.2.2":"2025-10-27T17:03:05.371Z","1.2.3":"2025-10-28T10:45:22.504Z","1.2.4":"2025-10-28T10:51:22.850Z","1.2.5":"2025-10-28T12:22:59.496Z","1.2.6":"2026-02-02T11:06:20.554Z","1.3.0":"2026-05-29T02:40:23.857Z"},"bugs":{"url":"https://github.com/VaheHak/nestjs-request-protector/issues"},"author":{"name":"Vahe Hakobyan"},"license":"MIT","homepage":"https://github.com/VaheHak/nestjs-request-protector#readme","keywords":["nestjs","backend","typescript","guard","request-protector","security","nestjs-security","nestjs-guard","nestjs-request-protector","rate-limit","bot-detection"],"repository":{"type":"git","url":"git+https://github.com/VaheHak/nestjs-request-protector.git"},"description":"A configurable NestJS guard to block unauthorized API requests (Postman, curl, etc.)","maintainers":[{"name":"vahe14","email":"vahe.hakobyan.1997@mail.ru"}],"readme":"![](https://img.shields.io/npm/v/nestjs-request-protector.svg)\n![](https://img.shields.io/npm/dy/nestjs-request-protector.svg)\n![](https://img.shields.io/npm/l/nestjs-request-protector.svg)\n![](https://img.shields.io/github/issues/VaheHak/nestjs-request-protector.svg)\n![](https://img.shields.io/github/contributors/VaheHak/nestjs-request-protector.svg)\n![](https://img.shields.io/github/last-commit/VaheHak/nestjs-request-protector.svg)\n![](https://img.shields.io/github/forks/VaheHak/nestjs-request-protector.svg)\n![](https://img.shields.io/github/stars/VaheHak/nestjs-request-protector.svg)\n![](https://img.shields.io/github/watchers/VaheHak/nestjs-request-protector.svg)\n\n# 🛡️ NestJS Request Protector Guard\n\nA powerful **NestJS Guard** that protects your API from unauthorized, scripted, or automated requests.  \nIt validates **clients**, **devices**, and **platforms** using `User-Agent` analysis powered by [`express-useragent`](https://www.npmjs.com/package/express-useragent).\n\n---\n\n<a id=\"toc\"></a>\n## 📚 Table of Contents\n\n- [🚀 Installation](#installation)\n- [⚙ Features](#features)\n- [⚙️ Setup Options](#setup-options)\n  - [1️⃣ Global Registration (Recommended)](#setup-global)\n  - [2️⃣ Using `useClass`](#setup-useclass)\n  - [3️⃣ Using `useFactory`](#setup-usefactory)\n- [🧩 Full Example](#full-example)\n- [🌍 Platform or Client Detection (Full List)](#detection)\n- [⚙️ Behavior Notes](#behavior-notes)\n- [🚦 IP & User-Agent Whitelist / Blacklist](#whitelist-blacklist)\n  - [Evaluation order](#evaluation-order)\n  - [Notes](#whitelist-notes)\n- [🧠 How It Works](#how-it-works)\n  - [🔐 Device Token Validation](#device-token-validation)\n  - [🧩 Examples](#examples)\n- [🧱 Example Request Flow](#example-request-flow)\n- [⚙️ Optional Flags](#optional-flags)\n- [📜 License](#license)\n\n---\n\n<a id=\"installation\"></a>\n## 🚀 Installation\n\n```bash\nnpm install nestjs-request-protector\n```\n\n---\n\n<a id=\"features\"></a>\n## ⚙ Features\n\n- ✅ Block non-browser and script-based requests (`curl`, `wget`, `axios`, etc.)\n- 🔐 Allow only trusted devices via `x-device-token` or `<custom key>` \n- 📱 Detect devices: browser, desktop, mobile, tablet, console, IoT\n- 🤖 Detect bots (Googlebot, ChatGPT, TelegramBot, etc.)\n- 🧩 Support for `*` wildcard (allow all)\n- 🧠 Customizable rules for both **platforms** and **clients**\n\n---\n\n<a id=\"setup-options\"></a>\n## ⚙️ Setup Options\n\n<a id=\"setup-global\"></a>\n### 1️⃣ Global Registration (Recommended)\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { RequestProtectorModule, RequestProtectorGuard, RequestProtectorOptions } from 'nestjs-request-protector';\n\nconst protectorOptions: RequestProtectorOptions = {\n  allowedDeviceTokens: ['device123', 'device456'],\n  allowedClients: {\n    browser: ['chrome', 'firefox', 'safari'],\n    scripts: false,\n    bots: ['googlebot', 'telegrambot'],\n  },\n  allowedPlatforms: {\n    desktop: true,\n    mobile: false,\n    smartTV: false,\n    smartGadgets: ['alexa', 'googlehome'],\n    gameConsoles: ['playstation', 'xbox'],\n    customs: ['internal-monitor'],\n  },\n};\n\n@Module({\n  imports: [RequestProtectorModule.forRoot(protectorOptions)],\n  providers: [\n    { provide: APP_GUARD, useClass: RequestProtectorGuard },\n  ],\n})\nexport class AppModule {}\n```\n\n---\n\n<a id=\"setup-useclass\"></a>\n### 2️⃣ Using `useClass`\n\n```ts\nimport { Module } from '@nestjs/common';\nimport { APP_GUARD } from '@nestjs/core';\nimport { RequestProtectorGuard, REQUEST_PROTECTOR_OPTIONS, RequestProtectorOptions } from 'nestjs-request-protector';\n\nconst protectorOptions: RequestProtectorOptions = {\n  allowedDeviceTokens: ['secure-token'],\n  allowedClients: '*',\n  allowedPlatforms: '*',\n};\n\n@Module({\n  providers: [\n    {\n      provide: REQUEST_PROTECTOR_OPTIONS,\n      useValue: protectorOptions,\n    },\n    {\n      provide: APP_GUARD,\n      useClass: RequestProtectorGuard,\n    },\n  ],\n})\nexport class AppModule {}\n```\n\n---\n\n<a id=\"setup-usefactory\"></a>\n### 3️⃣ Using `useFactory`\n\n```ts\n@Module({\n  providers: [\n    {\n      provide: APP_GUARD,\n      useFactory: () =>\n        new RequestProtectorGuard({\n          allowedDeviceTokens: '*',\n          allowedClients: {\n            browser: ['chrome', 'firefox'],\n            scripts: ['axios'],\n          },\n          allowedPlatforms: {\n            browser: ['chrome'],\n            desktop: true,\n          },\n        }),\n    },\n  ],\n})\nexport class AppModule {}\n```\n\n---\n\n<a id=\"full-example\"></a>\n## 🧩 Full Example\n\n```ts\nconst options: RequestProtectorOptions = {\n  allowedDeviceTokens: ['abc123'],\n  fetchAllowedTokens: async () => ['tokenFromDB'],\n  allowedClients: {\n    browser: true,\n    bots: ['googlebot', 'telegrambot', 'chatgpt-user'],\n    scripts: ['postman'],\n    apps: ['messenger'],\n    customs: ['iot']\n  },\n  allowedPlatforms: {\n    desktop: ['mac', 'windows'],\n    mobile: true,\n    smartGadgets: ['alexa'],\n    gameConsoles: ['playstation', 'xbox'],\n    smartTV: true,\n    tablet: true,\n    customs: ['postman'],\n  }\n};\n```\n\n---\n\n<a id=\"detection\"></a>\n## 🌍 Platform or Client Detection (Full List)\n\n🖥️ `allowedPlatforms` lets you control access by detected platform or User-Agent flags.\n\n| **Category** | **Type** | **Supported Keywords** | **Description** |\n|--------------|-----------|------------------------|------------------|\n| 📱 **mobile** | `boolean` / `Mobile[]` | iphone, ipod, ipad, android, androidtablet, windowsphone, bada, samsung, kindlefire, silk | Mobile devices |\n| 💻 **tablet** | `boolean` / `Tablet[]` | ipad, androidtablet, kindle, windowstablet | Tablet devices |\n| 🖥 **desktop** | `boolean` / `Desktop[]` | windows, mac, linux, chromeos, raspberry | Desktop & laptop OS |\n| 🧠 **smartGadgets** | `boolean` / `SmartGadgets[]` | alexa, googlehome, echo, nest, smarthub, iot | IoT & smart devices |\n| 🎮 **gameConsoles** | `boolean` / `GameConsoles[]` | playstation, xbox, nintendo, switch, wii, ps5, ps4 | Gaming consoles |\n| 📺 **smartTV** | `boolean` | — | Smart TVs |\n| 🧩 **customs** | `string[]` | custom UA substrings | Custom rules |\n\n---\n\n🤝 `allowedClients` lets you control access by detected clients or User-Agent flags.\n\n| **Category** | **Type** | **Supported Keywords** | **Description** |\n|--------------|-----------|------------------------|------------------|\n| 🌐 **browser** | `boolean` / `Browser[]` | chrome, firefox, safari, edge, opera, ie, konqueror, omniweb, seamonkey, flock, amaya, epiphany | Web browsers |\n| ⚙️ **scripts** | `boolean` / `Scripts[]` | curl, wget, postman, httpie, powershell, java, go-http-client, php, ruby, perl, python-requests, python-httpx, urllib, aiohttp, axios, node-fetch, superagent, got, okhttp, apache-httpclient, unity | Command-line tools or libraries |\n| 🤖 **bots** | `boolean` / `Bots[]` | googlebot, bingbot, duckduckbot, yandexbot, telegrambot, facebookbot, whatsappbot, discordbot, slackbot, linkedinbot, twitterbot, applebot, pinterestbot, yahoo-slurp, baiduspider, exabot, ahrefsbot, semrushbot, accoona, gptbot, oai-searchbot, chatgpt-user | Crawlers, social bots, AI agents |\n| 📲 **apps** | `boolean` / `Apps[]` | telegram, instagram, facebook, messenger, whatsapp, tiktok, discord, slack, spotify, electron, zoom, skype, viber, youtube, googleapp, googleassistant, gmail, googledrive, googlephotos, googlecalendar, googleplay, googlemaps | Native or desktop applications |\n| 🧩 **customs** | `string[]` | Any substring | Custom client matchers |\n\n---\n\n<a id=\"behavior-notes\"></a>\n## ⚙️ Behavior Notes\n\n- If `allowedPlatforms === '*'` or `allowedClients === '*'` or `allowedDeviceTokens === '*'`, all platforms/clients/tokens are accepted.\n- Both `allowedDeviceTokens` **and** `allowedPlatforms` are checked before client detection.\n- Scripts like `curl`, `axios`, or `wget` are automatically blocked unless `scripts: true`.\n- `customs` allows substring matching inside User-Agent (case-insensitive).\n\n---\n\n<a id=\"whitelist-blacklist\"></a>\n## 🚦 IP & User-Agent Whitelist / Blacklist\n\nIn addition to platform/client matchers, the guard supports first-class\n**allow / deny lists** for IPs and User-Agents. They run **before** the\nexpensive UA parsing, so denied traffic is rejected almost for free.\n\n```ts\nconst options: RequestProtectorOptions = {\n  allowedClients: '*',\n\n  // ── IP rules ─────────────────────────────────────────────────────────────\n  // Exact IPv4/IPv6 or IPv4 CIDR blocks are supported.\n  ipBlacklist: ['203.0.113.7', '198.51.100.0/24'],\n  ipWhitelist: ['10.0.0.0/8', '192.168.1.0/24'],\n\n  // When running behind a load-balancer/CDN, tell the guard which header\n  // contains the original client IP. The first entry of a comma-separated\n  // list is used.\n  trustedProxyIpHeader: 'x-forwarded-for', // or 'cf-connecting-ip', etc.\n\n  // ── User-Agent rules ─────────────────────────────────────────────────────\n  // Each entry may be a case-insensitive substring or a RegExp.\n  userAgentBlacklist: ['EvilScanner', /^badbot/i],\n\n  // A match in `userAgentWhitelist` marks the request as *trusted* and skips\n  // the platform/client allow-list checks (token + IP checks still run).\n  userAgentWhitelist: ['MyInternalMonitor', /^uptime-robot\\//i],\n};\n```\n\n<a id=\"evaluation-order\"></a>\n### Evaluation order\n\nFor every request the guard runs these checks, in order, and short-circuits on the first failure:\n\n1. `maxUserAgentLength` / `denyEmptyUserAgent`\n2. `ipBlacklist` → **deny** on match\n3. `ipWhitelist` → **deny** when set and *not* matched\n4. `userAgentBlacklist` → **deny** on match\n5. `userAgentWhitelist` → if matched, mark request as *trusted*\n6. `allowedDeviceTokens` (+ optional `fetchAllowedTokens`)\n7. `allowedPlatforms` / `allowedClients` — **skipped entirely** when the request is trusted\n\n<a id=\"whitelist-notes\"></a>\n### Notes\n\n- **Blacklist always wins over whitelist** (both for IPs and UAs).\n- IPv4 CIDR is fully supported (e.g. `10.0.0.0/8`, `1.2.3.4/32`, `0.0.0.0/0`).\n  IPv6 must be matched exactly — open an issue if you need IPv6 CIDR.\n- `::ffff:1.2.3.4` (IPv4-mapped IPv6) is normalised to `1.2.3.4`, so a single\n  rule covers both forms.\n- Without `trustedProxyIpHeader`, the guard reads `req.ip` and then falls\n  back to `req.socket.remoteAddress`. Make sure Express's `trust proxy`\n  setting is configured if you rely on `req.ip`.\n\n---\n\n<a id=\"how-it-works\"></a>\n## 🧠 How It Works\n\n<a id=\"device-token-validation\"></a>\n### 🔐 Device Token Validation\n\nRequests must include a valid token if specified:\n\n```http\nGET /api/data\nx-device-token: device123\nUser-Agent: MyIOTDevice/1.0\n```\n\nIf `allowedDeviceTokens` is `'*'`, all tokens are accepted.\n\n---\n\n<a id=\"examples\"></a>\n### 🧩 Examples\n\n#### ✅ Allow everything\n```ts\nallowedPlatforms: '*'\nallowedClients: '*'\nallowedDeviceTokens: '*'\n```\n\n#### ✅ Allow specific browsers only\n```ts\nallowedPlatforms: {\n    browser: ['chrome', 'firefox']\n}\n```\n\n#### ✅ Allow custom trusted UA\n```ts\nallowedPlatforms: {\n    customs: ['myiotdevice']\n}\n```\n\n#### ✅ Allow bots or scripts (for monitoring)\n```ts\nallowedClients: {\n    bots: true\n    scripts: true\n}\n```\n\n#### ✅ Dynamic token fetch\n```ts\nfetchAllowedTokens: async () => {\n  const tokensFromDb = await TokenService.getActiveTokens();\n  return tokensFromDb.map(t => t.token);\n}\n```\n\n---\n\n<a id=\"example-request-flow\"></a>\n## 🧱 Example Request Flow\n\n✅ Allowed:\n```http\nGET /api/data\nx-device-token: device123\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/122.0\n```\n\n❌ Blocked (untrusted client):\n```http\nGET /api/data\nx-device-token: invalidToken\nUser-Agent: curl/8.0\n```\n\n❌ Blocked (not allowed platform):\n```http\nGET /api/data\nUser-Agent: PostmanRuntime/7.49.0\n```\n\n---\n\n<a id=\"optional-flags\"></a>\n## ⚙️ Optional Flags\n\n| Rule | Description |\n|------|--------------|\n| `allowedDeviceTokens` | Must match header token (or be `*` to allow all) |\n| `fetchAllowedTokens` | Async dynamic token fetch support |\n| `allowedClients` | Controls app/browser/script access |\n| `allowedPlatforms` | Controls device or OS access |\n| `'*'` (wildcard) | Allows everything for that rule |\n| `customs` | Partial case-insensitive match on UA |\n| `ipWhitelist` | Allow-list of exact IPs / IPv4 CIDR blocks |\n| `ipBlacklist` | Deny-list of exact IPs / IPv4 CIDR blocks (wins over whitelist) |\n| `userAgentWhitelist` | Substrings / RegExps that mark a request as trusted (skips client/platform checks) |\n| `userAgentBlacklist` | Substrings / RegExps that immediately deny a request |\n| `trustedProxyIpHeader` | Header (e.g. `x-forwarded-for`) used to read the real client IP behind a proxy |\n| `maxUserAgentLength` | Max accepted UA length (default `512`) |\n| `denyEmptyUserAgent` | Reject requests with no `User-Agent` header |\n\n---\n\n<a id=\"license\"></a>\n## 📜 License\n\nMIT © 2025\n\n[⬆ Back to top](#toc)\n\n","readmeFilename":"README.md"}