is-antibot 2.0.2 → 2.0.4

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/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "is-antibot",
3
3
  "description": "Detect antibot protection from 30+ providers — Cloudflare, Akamai, DataDome, PerimeterX, Kasada, Imperva, reCAPTCHA, hCaptcha, Turnstile, and more.",
4
4
  "homepage": "https://antibot.microlink.io/",
5
- "version": "2.0.2",
5
+ "version": "2.0.4",
6
6
  "exports": {
7
7
  ".": "./src/index.js",
8
8
  "./providers.json": "./src/providers.json",
@@ -72,7 +72,7 @@
72
72
  "devDependencies": {
73
73
  "@commitlint/cli": "latest",
74
74
  "@commitlint/config-conventional": "latest",
75
- "ava": "latest",
75
+ "ava": "7",
76
76
  "browser-sync": "latest",
77
77
  "c8": "latest",
78
78
  "ci-publish": "latest",
@@ -142,6 +142,7 @@
142
142
  },
143
143
  "nano-staged": {
144
144
  "*.js": [
145
+ "npx -y @kikobeats/prettier-standard",
145
146
  "standard --fix"
146
147
  ],
147
148
  "package.json": [
@@ -0,0 +1,88 @@
1
+ {
2
+ "log": {
3
+ "version": "1.2",
4
+ "creator": {
5
+ "name": "curl+node",
6
+ "version": "24.11.1"
7
+ },
8
+ "pages": [
9
+ {
10
+ "id": "page_1",
11
+ "title": "https://www.reddit.com/r/ProductivityApps/comments/1sr2f0w/nocal_is_a_calendar_app_that_turns_your_calendar/",
12
+ "startedDateTime": "2026-04-23T15:55:52.000Z",
13
+ "pageTimings": {
14
+ "onContentLoad": -1,
15
+ "onLoad": 150.0
16
+ }
17
+ }
18
+ ],
19
+ "entries": [
20
+ {
21
+ "pageref": "page_1",
22
+ "startedDateTime": "2026-04-23T15:55:52.000Z",
23
+ "time": 150.0,
24
+ "serverIPAddress": "",
25
+ "connection": "443",
26
+ "request": {
27
+ "method": "GET",
28
+ "url": "https://www.reddit.com/r/ProductivityApps/comments/1sr2f0w/nocal_is_a_calendar_app_that_turns_your_calendar/",
29
+ "httpVersion": "http/2.0",
30
+ "headers": [
31
+ {
32
+ "name": "host",
33
+ "value": "www.reddit.com"
34
+ },
35
+ {
36
+ "name": "user-agent",
37
+ "value": "Slackbot 1.0 (+https://api.slack.com/robots)"
38
+ },
39
+ {
40
+ "name": "accept",
41
+ "value": "*/*"
42
+ }
43
+ ],
44
+ "queryString": [],
45
+ "cookies": [],
46
+ "headersSize": -1,
47
+ "bodySize": 0
48
+ },
49
+ "response": {
50
+ "status": 429,
51
+ "statusText": "Too Many Requests",
52
+ "httpVersion": "http/2.0",
53
+ "headers": [
54
+ {
55
+ "name": "x-ratelimit-remaining",
56
+ "value": "0.0"
57
+ },
58
+ {
59
+ "name": "x-ratelimit-reset",
60
+ "value": "247"
61
+ },
62
+ {
63
+ "name": "x-ratelimit-used",
64
+ "value": "45000"
65
+ },
66
+ {
67
+ "name": "server",
68
+ "value": "snooserv"
69
+ },
70
+ {
71
+ "name": "content-length",
72
+ "value": "0"
73
+ }
74
+ ],
75
+ "cookies": [],
76
+ "content": {
77
+ "size": 0,
78
+ "mimeType": "text/html",
79
+ "text": ""
80
+ },
81
+ "redirectURL": "",
82
+ "headersSize": -1,
83
+ "bodySize": -1
84
+ }
85
+ }
86
+ ]
87
+ }
88
+ }
package/src/index.js CHANGED
@@ -176,6 +176,7 @@ const createRegExp = (pattern, flags = '') => new RegExp(pattern, flags)
176
176
  const createCompiledDetection = (detection, matches) => ({
177
177
  type: detection.type,
178
178
  domain: detection.domain,
179
+ domainWithoutSuffix: detection.domainWithoutSuffix,
179
180
  matches
180
181
  })
181
182
 
@@ -259,8 +260,19 @@ const DETECTION_COMPILERS = {
259
260
  }
260
261
  }
261
262
 
262
- const compileDetection = detection =>
263
- DETECTION_COMPILERS[detection.type](detection)
263
+ const compileDetection = detection => {
264
+ const compiled = DETECTION_COMPILERS[detection.type](detection)
265
+ const statusCodes = detection.statusCodes
266
+ if (!Array.isArray(statusCodes) || statusCodes.length === 0) {
267
+ return compiled
268
+ }
269
+ const allowed = new Set(statusCodes)
270
+ const innerMatches = compiled.matches
271
+ return {
272
+ ...compiled,
273
+ matches: context => allowed.has(context.statusCode) && innerMatches(context)
274
+ }
275
+ }
264
276
 
265
277
  const compileProviders = ({ providers = [] } = {}) =>
266
278
  providers.map(provider => ({
@@ -285,7 +297,13 @@ const detectWithProviders = (
285
297
  const headerNames = getHeaderNames(headers)
286
298
  const hasUrl = Boolean(url)
287
299
 
288
- let domain
300
+ let parsedUrl
301
+ const getParsedUrl = () => {
302
+ if (!hasUrl) return null
303
+ if (!parsedUrl) parsedUrl = parseUrl(url)
304
+ return parsedUrl
305
+ }
306
+
289
307
  const context = {
290
308
  getHeader,
291
309
  headerNames,
@@ -297,10 +315,16 @@ const detectWithProviders = (
297
315
 
298
316
  for (const provider of compiledProviders) {
299
317
  for (const detection of provider.detections) {
300
- if (detection.domain) {
301
- if (!hasUrl) continue
302
- if (domain === undefined) domain = parseUrl(url).domain
303
- if (detection.domain !== domain) continue
318
+ if (detection.domain || detection.domainWithoutSuffix) {
319
+ const parsed = getParsedUrl()
320
+ if (!parsed) continue
321
+ if (detection.domain && detection.domain !== parsed.domain) continue
322
+ if (
323
+ detection.domainWithoutSuffix &&
324
+ detection.domainWithoutSuffix !== parsed.domainWithoutSuffix
325
+ ) {
326
+ continue
327
+ }
304
328
  }
305
329
  if (!detection.matches(context)) continue
306
330
  return createResult(
@@ -625,6 +625,9 @@
625
625
  "rules": [
626
626
  {
627
627
  "status": 403
628
+ },
629
+ {
630
+ "status": 429
628
631
  }
629
632
  ]
630
633
  },
@@ -683,6 +686,22 @@
683
686
  }
684
687
  ]
685
688
  },
689
+ {
690
+ "name": "amazon",
691
+ "detections": [
692
+ {
693
+ "type": "headers",
694
+ "domainWithoutSuffix": "amazon",
695
+ "statusCodes": [500],
696
+ "rules": [
697
+ {
698
+ "header": "x-cache",
699
+ "startsWith": "Error from cloudfront"
700
+ }
701
+ ]
702
+ }
703
+ ]
704
+ },
686
705
  {
687
706
  "name": "anubis",
688
707
  "detections": [
package/src/schema.json CHANGED
@@ -57,6 +57,18 @@
57
57
  "type": "string",
58
58
  "description": "When set, this detection only applies if the request URL's registrable domain matches (e.g. 'reddit.com')."
59
59
  },
60
+ "domainWithoutSuffix": {
61
+ "type": "string",
62
+ "description": "When set, this detection only applies if the request URL's registrable domain without public suffix matches (e.g. 'amazon' for amazon.es, amazon.co.uk, amazon.com)."
63
+ },
64
+ "statusCodes": {
65
+ "type": "array",
66
+ "items": {
67
+ "type": "integer"
68
+ },
69
+ "minItems": 1,
70
+ "description": "When set, the detection matches only if the response status code equals one of these values (AND with the detection's rules)."
71
+ },
60
72
  "rules": {
61
73
  "type": "array",
62
74
  "minItems": 1,