is-antibot 1.5.0 → 1.6.0

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/LICENSE.md CHANGED
File without changes
package/README.md CHANGED
@@ -60,7 +60,7 @@ $ npm install is-antibot --save
60
60
 
61
61
  ## Usage
62
62
 
63
- Just pass `headers`, `html`, and `url` from any HTTP response:
63
+ Just pass `headers`, `html`, `url`, and `statusCode` from any HTTP response:
64
64
 
65
65
  ```js
66
66
  const isAntibot = require('is-antibot')
@@ -70,6 +70,7 @@ const html = await response.text()
70
70
 
71
71
  const { detected, provider, detection } = isAntibot({
72
72
  headers: response.headers,
73
+ statusCode: response.status,
73
74
  html,
74
75
  url: response.url
75
76
  })
@@ -96,7 +97,7 @@ The library returns an object with the following properties:
96
97
 
97
98
  - `detected` (boolean): Whether an antibot challenge was detected
98
99
  - `provider` (string|null): The name of the detected provider (e.g., 'cloudflare', 'recaptcha')
99
- - `detection` (string|null): Where the signal came from: `'headers'`, `'cookies'`, `'html'`, or `'url'`
100
+ - `detection` (string|null): Where the signal came from: `'headers'`, `'cookies'`, `'html'`, `'url'`, or `'statusCode'`
100
101
 
101
102
  ## License
102
103
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "is-antibot",
3
3
  "description": "Identify if a response is an antibot challenge from CloudFlare, Akamai, DataDome, Vercel, PerimeterX, Shape Security, and more, including CAPTCHA providers like reCAPTCHA and hCaptcha.",
4
4
  "homepage": "https://github.com/microlinkhq/is-antibot",
5
- "version": "1.5.0",
5
+ "version": "1.6.0",
6
6
  "exports": {
7
7
  ".": "./src/index.js"
8
8
  },
@@ -82,6 +82,22 @@
82
82
  "files": [
83
83
  "src"
84
84
  ],
85
+ "scripts": {
86
+ "clean": "rm -rf node_modules",
87
+ "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
88
+ "coverage": "c8 report --reporter=text-lcov > coverage/lcov.info",
89
+ "lint": "standard",
90
+ "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
91
+ "pretest": "npm run lint",
92
+ "release": "pnpm run release:version && pnpm run release:changelog && pnpm run release:commit && pnpm run release:tag",
93
+ "release:changelog": "conventional-changelog -p conventionalcommits -i CHANGELOG.md -s",
94
+ "release:commit": "git add package.json CHANGELOG.md && git commit -m \"chore(release): $(node -p \"require('./package.json').version\")\"",
95
+ "release:github": "github-generate-release",
96
+ "release:tag": "git tag -a v$(node -p \"require('./package.json').version\") -m \"v$(node -p \"require('./package.json').version\")\"",
97
+ "release:tags": "git push origin HEAD:master --follow-tags",
98
+ "release:version": "standard-version --skip.changelog --skip.commit --skip.tag",
99
+ "test": "c8 ava"
100
+ },
85
101
  "license": "MIT",
86
102
  "ava": {
87
103
  "files": [
@@ -111,21 +127,5 @@
111
127
  "simple-git-hooks": {
112
128
  "commit-msg": "npx commitlint --edit",
113
129
  "pre-commit": "npx nano-staged"
114
- },
115
- "scripts": {
116
- "clean": "rm -rf node_modules",
117
- "contributors": "(npx git-authors-cli && npx finepack && git add package.json && git commit -m 'build: contributors' --no-verify) || true",
118
- "coverage": "c8 report --reporter=text-lcov > coverage/lcov.info",
119
- "lint": "standard",
120
- "postrelease": "npm run release:tags && npm run release:github && (ci-publish || npm publish --access=public)",
121
- "pretest": "npm run lint",
122
- "release": "pnpm run release:version && pnpm run release:changelog && pnpm run release:commit && pnpm run release:tag",
123
- "release:changelog": "conventional-changelog -p conventionalcommits -i CHANGELOG.md -s",
124
- "release:commit": "git add package.json CHANGELOG.md && git commit -m \"chore(release): $(node -p \"require('./package.json').version\")\"",
125
- "release:github": "github-generate-release",
126
- "release:tag": "git tag -a v$(node -p \"require('./package.json').version\") -m \"v$(node -p \"require('./package.json').version\")\"",
127
- "release:tags": "git push origin HEAD:master --follow-tags",
128
- "release:version": "standard-version --skip.changelog --skip.commit --skip.tag",
129
- "test": "c8 ava"
130
130
  }
131
- }
131
+ }
package/src/index.js CHANGED
@@ -8,7 +8,8 @@ const DETECTION = {
8
8
  HEADERS: 'headers',
9
9
  COOKIES: 'cookies',
10
10
  HTML: 'html',
11
- URL: 'url'
11
+ URL: 'url',
12
+ STATUS_CODE: 'statusCode'
12
13
  }
13
14
 
14
15
  const createGetHeader = headers =>
@@ -57,7 +58,7 @@ const getHeaderNames = headers =>
57
58
  ? Array.from(headers.keys())
58
59
  : Object.keys(headers)
59
60
 
60
- const detect = ({ headers = {}, html = '', url = '' } = {}) => {
61
+ const detect = ({ headers = {}, html = '', url = '', statusCode } = {}) => {
61
62
  const getHeader = createGetHeader(headers)
62
63
  const hasCookie = createHasCookie(headers)
63
64
  const htmlHas = createTestPattern(html)
@@ -81,6 +82,9 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
81
82
 
82
83
  const byUrl = provider => createResult(true, provider, DETECTION.URL)
83
84
 
85
+ const byStatusCode = provider =>
86
+ createResult(true, provider, DETECTION.STATUS_CODE)
87
+
84
88
  // CloudFlare: Check for cf-mitigated header with 'challenge' value
85
89
  // Official docs: https://developers.cloudflare.com/cloudflare-challenges/challenge-types/challenge-pages/detect-response/
86
90
  if (getHeader('cf-mitigated') === 'challenge') {
@@ -397,9 +401,9 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
397
401
  return byHtml('reddit')
398
402
  }
399
403
 
400
- // LinkedIn: trkCode=bf cookie ("bot filter") is set when LinkedIn blocks a request
401
- if (hasAnyCookie(['trkCode=bf'])) {
402
- return byCookies('linkedin')
404
+ // LinkedIn: status 999 is LinkedIn's dedicated bot-detection response
405
+ if (parseUrl(url).domain === 'linkedin.com' && statusCode === 999) {
406
+ return byStatusCode('linkedin')
403
407
  }
404
408
 
405
409
  // YouTube: empty title pattern indicates a degraded response requiring BotGuard JS attestation
@@ -428,8 +432,13 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
428
432
  }
429
433
 
430
434
  const isAntibot = (input = {}) => {
431
- const { headers, html, body, url } = input
432
- return detect({ headers, html: html || body, url })
435
+ const { headers, html, body, url, statusCode, status } = input
436
+ return detect({
437
+ headers,
438
+ html: html || body,
439
+ url,
440
+ statusCode: statusCode ?? status
441
+ })
433
442
  }
434
443
 
435
444
  module.exports = isAntibot