is-antibot 1.3.4 → 1.3.6
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 +1 -1
- package/src/index.js +53 -56
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.
|
|
5
|
+
"version": "1.3.6",
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) ||
|
|
@@ -237,83 +237,80 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
|
|
|
237
237
|
return createResult(true, 'recaptcha')
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
// reCAPTCHA: Check for grecaptcha
|
|
241
|
-
//
|
|
242
|
-
if (
|
|
240
|
+
// reCAPTCHA: Check for grecaptcha API usage in html (JavaScript indicator)
|
|
241
|
+
// Note: plain "grecaptcha" is too broad (e.g. ".grecaptcha-badge" CSS appears on normal YouTube pages)
|
|
242
|
+
if (
|
|
243
|
+
htmlHas(
|
|
244
|
+
'\\b(?:window\\.)?grecaptcha\\s*\\.(?:execute|render|ready|getResponse|enterprise)\\b',
|
|
245
|
+
true
|
|
246
|
+
) ||
|
|
247
|
+
htmlHas('\\b(?:window\\.)?grecaptcha\\s*\\(', true) ||
|
|
248
|
+
htmlHas('\\b__grecaptcha_cfg\\b', true)
|
|
249
|
+
) {
|
|
243
250
|
return createResult(true, 'recaptcha')
|
|
244
251
|
}
|
|
245
252
|
|
|
246
253
|
// reCAPTCHA: Check for g-recaptcha container class in html
|
|
247
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/recaptcha.json
|
|
254
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-recaptcha.json
|
|
248
255
|
if (htmlHas('g-recaptcha')) {
|
|
249
256
|
return createResult(true, 'recaptcha')
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
// hCaptcha: Check for hcaptcha.com domain in URL
|
|
253
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/hcaptcha.json
|
|
260
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-hcaptcha.json
|
|
254
261
|
if (urlHas('hcaptcha\\.com', true)) {
|
|
255
262
|
return createResult(true, 'hcaptcha')
|
|
256
263
|
}
|
|
257
264
|
|
|
258
|
-
// hCaptcha: Check for hcaptcha
|
|
259
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/hcaptcha.json
|
|
260
|
-
|
|
261
|
-
|
|
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')) {
|
|
265
|
+
// hCaptcha: Check for hcaptcha.com API domain or h-captcha container class in html
|
|
266
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-hcaptcha.json
|
|
267
|
+
// Note: bare 'hcaptcha' matches too broadly (could appear in articles discussing hCaptcha)
|
|
268
|
+
if (htmlHas('hcaptcha.com') || htmlHas('h-captcha')) {
|
|
267
269
|
return createResult(true, 'hcaptcha')
|
|
268
270
|
}
|
|
269
271
|
|
|
270
272
|
// 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
|
|
273
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-funcaptcha.json
|
|
272
274
|
if (urlHas('arkoselabs\\.com', true) || urlHas('funcaptcha')) {
|
|
273
275
|
return createResult(true, 'funcaptcha')
|
|
274
276
|
}
|
|
275
277
|
|
|
276
|
-
// FunCaptcha (Arkose Labs): Check for
|
|
277
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/funcaptcha.json
|
|
278
|
-
|
|
278
|
+
// FunCaptcha (Arkose Labs): Check for arkoselabs.com API domain or funcaptcha in html
|
|
279
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-funcaptcha.json
|
|
280
|
+
// Note: bare 'arkose' matches too broadly (e.g. Facebook bundles Arkose SDK for login without blocking content)
|
|
281
|
+
if (htmlHas('arkoselabs.com') || htmlHas('funcaptcha')) {
|
|
279
282
|
return createResult(true, 'funcaptcha')
|
|
280
283
|
}
|
|
281
284
|
|
|
282
285
|
// GeeTest: Check for geetest.com domain in URL
|
|
283
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/geetest.json
|
|
286
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-geetest.json
|
|
284
287
|
if (urlHas('geetest\\.com', true)) {
|
|
285
288
|
return createResult(true, 'geetest')
|
|
286
289
|
}
|
|
287
290
|
|
|
288
291
|
// GeeTest: Check for geetest object or text in html
|
|
289
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/geetest.json
|
|
292
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-geetest.json
|
|
293
|
+
// Note: bare 'gt.js' removed (too generic, any script named gt.js would match)
|
|
290
294
|
if (htmlHas('geetest')) {
|
|
291
295
|
return createResult(true, 'geetest')
|
|
292
296
|
}
|
|
293
297
|
|
|
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
298
|
// Cloudflare Turnstile: Check for challenges.cloudflare.com/turnstile in URL
|
|
301
299
|
if (urlHas('challenges\\.cloudflare\\.com/turnstile', true)) {
|
|
302
300
|
return createResult(true, 'cloudflare-turnstile')
|
|
303
301
|
}
|
|
304
302
|
|
|
305
|
-
// Cloudflare Turnstile: Check for cf-turnstile class in html
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (htmlHas('turnstile')) {
|
|
303
|
+
// Cloudflare Turnstile: Check for cf-turnstile class or turnstile API script in html
|
|
304
|
+
// Note: bare 'turnstile' matches too broadly (common English word)
|
|
305
|
+
if (
|
|
306
|
+
htmlHas('cf-turnstile') ||
|
|
307
|
+
htmlHas('challenges.cloudflare.com/turnstile')
|
|
308
|
+
) {
|
|
312
309
|
return createResult(true, 'cloudflare-turnstile')
|
|
313
310
|
}
|
|
314
311
|
|
|
315
312
|
// Friendly Captcha: Check for friendlycaptcha.com in URL
|
|
316
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/friendlycaptcha.json
|
|
313
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-friendlycaptcha.json
|
|
317
314
|
if (urlHas('friendlycaptcha\\.com', true)) {
|
|
318
315
|
return createResult(true, 'friendly-captcha')
|
|
319
316
|
}
|
|
@@ -324,7 +321,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
|
|
|
324
321
|
}
|
|
325
322
|
|
|
326
323
|
// Captcha.eu: Check for captcha.eu in URL
|
|
327
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/captchaeu.json
|
|
324
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-captchaeu.json
|
|
328
325
|
if (urlHas('captcha\\.eu', true)) {
|
|
329
326
|
return createResult(true, 'captcha-eu')
|
|
330
327
|
}
|
|
@@ -335,7 +332,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
|
|
|
335
332
|
}
|
|
336
333
|
|
|
337
334
|
// 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
|
|
335
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-qcloud.json
|
|
339
336
|
if (urlHas('turing\\.captcha\\.qcloud\\.com', true)) {
|
|
340
337
|
return createResult(true, 'qcloud-captcha')
|
|
341
338
|
}
|
|
@@ -346,7 +343,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
|
|
|
346
343
|
}
|
|
347
344
|
|
|
348
345
|
// AliExpress CAPTCHA: Check for punish?x5secdata in URL
|
|
349
|
-
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/aliexpress.json
|
|
346
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/captcha/detect-aliexpress.json
|
|
350
347
|
if (urlHas('punish\\?x5secdata', true)) {
|
|
351
348
|
return createResult(true, 'aliexpress-captcha')
|
|
352
349
|
}
|
|
@@ -368,7 +365,7 @@ const detect = ({ headers = {}, html = '', url = '' } = {}) => {
|
|
|
368
365
|
}
|
|
369
366
|
|
|
370
367
|
// 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
|
|
368
|
+
// Reference: https://github.com/scrapfly/Antibot-Detector/blob/main/detectors/antibot/detect-aws-waf.json
|
|
372
369
|
if (getHeader('x-amzn-waf-action') || getHeader('x-amzn-requestid')) {
|
|
373
370
|
return createResult(true, 'aws-waf')
|
|
374
371
|
}
|