@webdecoy/fcaptcha 1.28.1 → 1.28.2
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/index.js +13 -2
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -246,6 +246,7 @@ class ScoringEngine {
|
|
|
246
246
|
// Verify signals and return score
|
|
247
247
|
verify(signals, ip, siteKey, userAgent, headers = {}, powSolution = null) {
|
|
248
248
|
const detections = [];
|
|
249
|
+
let powSatisfied = false;
|
|
249
250
|
|
|
250
251
|
// Run all detection modules
|
|
251
252
|
detections.push(...this._detectVisionAI(signals));
|
|
@@ -272,6 +273,7 @@ class ScoringEngine {
|
|
|
272
273
|
reason: `PoW verification failed: ${powResult.reason}`
|
|
273
274
|
});
|
|
274
275
|
} else if (powResult.serverElapsed < BASE_MIN_AGE_MS) {
|
|
276
|
+
powSatisfied = true;
|
|
275
277
|
// Under the universal baseline nothing legitimate can have happened —
|
|
276
278
|
// no human completes an interaction that fast.
|
|
277
279
|
detections.push({
|
|
@@ -281,6 +283,7 @@ class ScoringEngine {
|
|
|
281
283
|
reason: `Challenge solved too fast (${powResult.serverElapsed}ms server-side)`
|
|
282
284
|
});
|
|
283
285
|
} else if (powResult.serverElapsed < powResult.minAgeMs) {
|
|
286
|
+
powSatisfied = true;
|
|
284
287
|
// Between the baseline and this source's own elevated floor is weaker
|
|
285
288
|
// evidence: a client predating adaptive cost, or one served from a
|
|
286
289
|
// stale cache, does not know to wait. It contributes rather than
|
|
@@ -291,6 +294,8 @@ class ScoringEngine {
|
|
|
291
294
|
confidence: 0.5,
|
|
292
295
|
reason: `Challenge submitted before the required delay for this source (${powResult.serverElapsed}ms of ${powResult.minAgeMs}ms)`
|
|
293
296
|
});
|
|
297
|
+
} else {
|
|
298
|
+
powSatisfied = true;
|
|
294
299
|
}
|
|
295
300
|
} else {
|
|
296
301
|
detections.push({
|
|
@@ -336,7 +341,12 @@ class ScoringEngine {
|
|
|
336
341
|
else if (finalScore < 0.6) recommendation = 'challenge';
|
|
337
342
|
else recommendation = 'block';
|
|
338
343
|
|
|
339
|
-
|
|
344
|
+
// PoW is a precondition, not weighted evidence. Expressing a missing or
|
|
345
|
+
// invalid solution only as a bot-category score lets the category weight
|
|
346
|
+
// dilute it below the allow threshold and used to mint a token for an empty
|
|
347
|
+
// request. Keep this gate independent of scoring so weight changes cannot
|
|
348
|
+
// reopen the bypass.
|
|
349
|
+
const success = finalScore < 0.5 && powSatisfied;
|
|
340
350
|
const token = success ? this._generateToken(ip, siteKey, finalScore) : null;
|
|
341
351
|
|
|
342
352
|
// Feed the ledger so the next challenge this source asks for is priced on
|
|
@@ -350,7 +360,8 @@ class ScoringEngine {
|
|
|
350
360
|
timestamp: Math.floor(Date.now() / 1000),
|
|
351
361
|
recommendation,
|
|
352
362
|
categoryScores,
|
|
353
|
-
detections
|
|
363
|
+
detections,
|
|
364
|
+
...(!powSatisfied ? { reason: 'pow_not_satisfied' } : {})
|
|
354
365
|
};
|
|
355
366
|
}
|
|
356
367
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webdecoy/fcaptcha",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.2",
|
|
4
4
|
"description": "Open source CAPTCHA with PoW, bot detection, and Vision AI protection",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"exports": {
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"test:clientip": "node clientip.test.js",
|
|
16
16
|
"test:limits": "node limits.test.js",
|
|
17
17
|
"test:detection": "node detection.test.js",
|
|
18
|
-
"test": "node clientip.test.js && node limits.test.js && node detection.test.js && node inputforensics.test.js && node webbotauth.test.js && node siteverify.test.js && node --test suspicion.test.js",
|
|
18
|
+
"test": "node clientip.test.js && node limits.test.js && node detection.test.js && node inputforensics.test.js && node webbotauth.test.js && node siteverify.test.js && node index.test.js && node --test suspicion.test.js",
|
|
19
19
|
"test:siteverify": "node siteverify.test.js",
|
|
20
20
|
"test:forensics": "node inputforensics.test.js",
|
|
21
21
|
"test:suspicion": "node --test suspicion.test.js"
|