is-antibot 1.3.4 → 1.3.5

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +44 -54
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.3.4",
5
+ "version": "1.3.5",
6
6
  "exports": {
7
7
  ".": "./src/index.js"
8
8
  },
package/src/index.js CHANGED
@@ -66,7 +66,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
66
66
  }
67
67
 
68
68
  // Akamai: Check for additional identifying headers (akamai-grn, x-akamai-session-info)
69
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/akamai.json
69
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-akamai.json
70
70
  if (getHeader('akamai-grn') || getHeader('x-akamai-session-info')) {
71
71
  return createResult(true, 'akamai')
72
72
  }
@@ -88,7 +88,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
88
88
  }
89
89
 
90
90
  // DataDome: Check for x-datadome or x-datadome-cid header presence
91
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/datadome.json
91
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-datadome.json
92
92
  if (getHeader('x-datadome') || getHeader('x-datadome-cid')) {
93
93
  return createResult(true, 'datadome')
94
94
  }
@@ -99,13 +99,13 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
99
99
  }
100
100
 
101
101
  // PerimeterX: Check for X-PX-Authorization header (primary indicator)
102
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/perimeterx.json#L71-L84
102
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-perimeterx.json
103
103
  if (getHeader('x-px-authorization')) {
104
104
  return createResult(true, 'perimeterx')
105
105
  }
106
106
 
107
107
  // PerimeterX: Check for window._pxAppId, pxInit, or _pxAction in html
108
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/perimeterx.json#L130-L137
108
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-perimeterx.json
109
109
  if (htmlHas('window._pxAppId') || htmlHas('pxInit') || htmlHas('_pxAction')) {
110
110
  return createResult(true, 'perimeterx')
111
111
  }
@@ -117,7 +117,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
117
117
 
118
118
  // Shape Security: Check for dynamic header patterns x-[8chars]-[abcdfz]
119
119
  // These headers use 8 random characters followed by suffixes like -a, -b, -c, -d, -f, or -z
120
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/shapesecurity.json#L30-L113
120
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-shapesecurity.json
121
121
  const headerNames = Object.keys(headers)
122
122
  for (const name of headerNames) {
123
123
  if (/^x-[a-z0-9]{8}-[abcdfz]$/i.test(name)) {
@@ -126,37 +126,37 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
126
126
  }
127
127
 
128
128
  // Shape Security: Check for 'shapesecurity' text in response html
129
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/shapesecurity.json#L136-L142
129
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-shapesecurity.json
130
130
  if (htmlHas('shapesecurity')) {
131
131
  return createResult(true, 'shapesecurity')
132
132
  }
133
133
 
134
134
  // Kasada: Check for x-kasada or x-kasada-challenge headers
135
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/kasada.json#L57-L85
135
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-kasada.json
136
136
  if (getHeader('x-kasada') || getHeader('x-kasada-challenge')) {
137
137
  return createResult(true, 'kasada')
138
138
  }
139
139
 
140
140
  // Kasada: Check for __kasada global object or kasada.js script in html
141
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/kasada.json#L117-L144
141
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-kasada.json
142
142
  if (htmlHas('__kasada') || htmlHas('kasada.js')) {
143
143
  return createResult(true, 'kasada')
144
144
  }
145
145
 
146
146
  // Imperva/Incapsula: Check for x-cdn header with 'Incapsula' value or x-iinfo header
147
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/incapsula.json#L86-L109
147
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-incapsula.json
148
148
  if (getHeader('x-cdn') === 'Incapsula' || getHeader('x-iinfo')) {
149
149
  return createResult(true, 'imperva')
150
150
  }
151
151
 
152
152
  // Imperva/Incapsula: Check for 'incapsula' or 'imperva' text in response html
153
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/incapsula.json#L111-L124
153
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-incapsula.json
154
154
  if (htmlHas('incapsula') || htmlHas('imperva')) {
155
155
  return createResult(true, 'imperva')
156
156
  }
157
157
 
158
158
  // Imperva/Incapsula: incap_ses_, visid_incap_, or reese84 cookies
159
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/incapsula.json
159
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-incapsula.json
160
160
  if (
161
161
  hasCookie('incap_ses_') ||
162
162
  hasCookie('visid_incap_') ||
@@ -166,7 +166,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
166
166
  }
167
167
 
168
168
  // Reblaze: rbzid or rbzsessionid cookies
169
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/reblaze.json
169
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-reblaze.json
170
170
  if (hasCookie('rbzid=') || hasCookie('rbzsessionid=')) {
171
171
  return createResult(true, 'reblaze')
172
172
  }
@@ -177,7 +177,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
177
177
  }
178
178
 
179
179
  // Cheq: Check for CheqSdk or cheqzone.com in html
180
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/cheq.json
180
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-cheq.json
181
181
  if (htmlHas('CheqSdk') || htmlHas('cheqzone.com')) {
182
182
  return createResult(true, 'cheq')
183
183
  }
@@ -188,13 +188,13 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
188
188
  }
189
189
 
190
190
  // Sucuri: Check for 'sucuri' text in response html
191
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/sucuri.json
191
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-sucuri.json
192
192
  if (htmlHas('sucuri')) {
193
193
  return createResult(true, 'sucuri')
194
194
  }
195
195
 
196
196
  // ThreatMetrix: Check for 'ThreatMetrix' in html
197
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/threatmetrix.json
197
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-threatmetrix.json
198
198
  if (htmlHas('ThreatMetrix')) {
199
199
  return createResult(true, 'threatmetrix')
200
200
  }
@@ -205,7 +205,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
205
205
  }
206
206
 
207
207
  // Meetrics: Check for 'meetrics' text in response html
208
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/meetrics.json
208
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-meetrics.json
209
209
  if (htmlHas('meetrics')) {
210
210
  return createResult(true, 'meetrics')
211
211
  }
@@ -216,7 +216,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
216
216
  }
217
217
 
218
218
  // Ocule: Check for ocule.co.uk in html
219
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/ocule.json
219
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-ocule.json
220
220
  if (htmlHas('ocule.co.uk')) {
221
221
  return createResult(true, 'ocule')
222
222
  }
@@ -227,7 +227,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
227
227
  }
228
228
 
229
229
  // reCAPTCHA: Check for recaptcha/api, google.com/recaptcha, gstatic.com/recaptcha, or recaptcha.net in URL
230
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/recaptcha.json#L13-L48
230
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-recaptcha.json
231
231
  if (
232
232
  urlHas('recaptcha/api') ||
233
233
  urlHas('google\\.com/recaptcha', true) ||
@@ -238,82 +238,72 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
238
238
  }
239
239
 
240
240
  // reCAPTCHA: Check for grecaptcha global object in html (primary JavaScript indicator)
241
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/recaptcha.json#L51-L58
241
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-recaptcha.json
242
242
  if (htmlHas('grecaptcha')) {
243
243
  return createResult(true, 'recaptcha')
244
244
  }
245
245
 
246
246
  // reCAPTCHA: Check for g-recaptcha container class in html
247
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/recaptcha.json#L66-L73
247
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-recaptcha.json
248
248
  if (htmlHas('g-recaptcha')) {
249
249
  return createResult(true, 'recaptcha')
250
250
  }
251
251
 
252
252
  // hCaptcha: Check for hcaptcha.com domain in URL
253
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/hcaptcha.json#L13-L22
253
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-hcaptcha.json
254
254
  if (urlHas('hcaptcha\\.com', true)) {
255
255
  return createResult(true, 'hcaptcha')
256
256
  }
257
257
 
258
- // hCaptcha: Check for hcaptcha object in html
259
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/hcaptcha.json#L42-L50
260
- if (htmlHas('hcaptcha')) {
261
- return createResult(true, 'hcaptcha')
262
- }
263
-
264
- // hCaptcha: Check for h-captcha container class in html
265
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/hcaptcha.json#L51-L58
266
- if (htmlHas('h-captcha')) {
258
+ // hCaptcha: Check for hcaptcha.com API domain or h-captcha container class in html
259
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-hcaptcha.json
260
+ // Note: bare 'hcaptcha' matches too broadly (could appear in articles discussing hCaptcha)
261
+ if (htmlHas('hcaptcha.com') || htmlHas('h-captcha')) {
267
262
  return createResult(true, 'hcaptcha')
268
263
  }
269
264
 
270
265
  // FunCaptcha (Arkose Labs): Check for arkoselabs.com or funcaptcha in URL
271
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/funcaptcha.json#L13-L40
266
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-funcaptcha.json
272
267
  if (urlHas('arkoselabs\\.com', true) || urlHas('funcaptcha')) {
273
268
  return createResult(true, 'funcaptcha')
274
269
  }
275
270
 
276
- // FunCaptcha (Arkose Labs): Check for funcaptcha or arkose text in html
277
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/funcaptcha.json#L42-L55
278
- if (htmlHas('funcaptcha') || htmlHas('arkose')) {
271
+ // FunCaptcha (Arkose Labs): Check for arkoselabs.com API domain or funcaptcha in html
272
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-funcaptcha.json
273
+ // Note: bare 'arkose' matches too broadly (e.g. Facebook bundles Arkose SDK for login without blocking content)
274
+ if (htmlHas('arkoselabs.com') || htmlHas('funcaptcha')) {
279
275
  return createResult(true, 'funcaptcha')
280
276
  }
281
277
 
282
278
  // GeeTest: Check for geetest.com domain in URL
283
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/geetest.json#L13-L43
279
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-geetest.json
284
280
  if (urlHas('geetest\\.com', true)) {
285
281
  return createResult(true, 'geetest')
286
282
  }
287
283
 
288
284
  // GeeTest: Check for geetest object or text in html
289
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/geetest.json#L45-L52
285
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-geetest.json
286
+ // Note: bare 'gt.js' removed (too generic, any script named gt.js would match)
290
287
  if (htmlHas('geetest')) {
291
288
  return createResult(true, 'geetest')
292
289
  }
293
290
 
294
- // GeeTest: Check for gt.js script in html
295
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/geetest.json#L53-L60
296
- if (htmlHas('gt.js')) {
297
- return createResult(true, 'geetest')
298
- }
299
-
300
291
  // Cloudflare Turnstile: Check for challenges.cloudflare.com/turnstile in URL
301
292
  if (urlHas('challenges\\.cloudflare\\.com/turnstile', true)) {
302
293
  return createResult(true, 'cloudflare-turnstile')
303
294
  }
304
295
 
305
- // Cloudflare Turnstile: Check for cf-turnstile class in html
306
- if (htmlHas('cf-turnstile')) {
307
- return createResult(true, 'cloudflare-turnstile')
308
- }
309
-
310
- // Cloudflare Turnstile: Check for turnstile text in html
311
- if (htmlHas('turnstile')) {
296
+ // Cloudflare Turnstile: Check for cf-turnstile class or turnstile API script in html
297
+ // Note: bare 'turnstile' matches too broadly (common English word)
298
+ if (
299
+ htmlHas('cf-turnstile') ||
300
+ htmlHas('challenges.cloudflare.com/turnstile')
301
+ ) {
312
302
  return createResult(true, 'cloudflare-turnstile')
313
303
  }
314
304
 
315
305
  // Friendly Captcha: Check for friendlycaptcha.com in URL
316
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/friendlycaptcha.json
306
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-friendlycaptcha.json
317
307
  if (urlHas('friendlycaptcha\\.com', true)) {
318
308
  return createResult(true, 'friendly-captcha')
319
309
  }
@@ -324,7 +314,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
324
314
  }
325
315
 
326
316
  // Captcha.eu: Check for captcha.eu in URL
327
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/captchaeu.json
317
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-captchaeu.json
328
318
  if (urlHas('captcha\\.eu', true)) {
329
319
  return createResult(true, 'captcha-eu')
330
320
  }
@@ -335,7 +325,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
335
325
  }
336
326
 
337
327
  // QCloud Captcha (Tencent): Check for turing.captcha.qcloud.com in URL
338
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/qcloud.json
328
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-qcloud.json
339
329
  if (urlHas('turing\\.captcha\\.qcloud\\.com', true)) {
340
330
  return createResult(true, 'qcloud-captcha')
341
331
  }
@@ -346,7 +336,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
346
336
  }
347
337
 
348
338
  // AliExpress CAPTCHA: Check for punish?x5secdata in URL
349
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/aliexpress.json
339
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-aliexpress.json
350
340
  if (urlHas('punish\\?x5secdata', true)) {
351
341
  return createResult(true, 'aliexpress-captcha')
352
342
  }
@@ -368,7 +358,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
368
358
  }
369
359
 
370
360
  // AWS WAF: Check for x-amzn-waf-action or x-amzn-requestid headers
371
- // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/aws-waf.json
361
+ // Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-aws-waf.json
372
362
  if (getHeader('x-amzn-waf-action') || getHeader('x-amzn-requestid')) {
373
363
  return createResult(true, 'aws-waf')
374
364
  }