@webdecoy/fcaptcha 1.40.0 → 1.41.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.
Files changed (2) hide show
  1. package/experimental.js +21 -0
  2. package/package.json +1 -1
package/experimental.js CHANGED
@@ -6,6 +6,26 @@ const { calculateCategoryScores, BEHAVIOURAL_CATEGORIES, CORROBORATION_AGREE_AT,
6
6
  // Change this ID whenever the policy's evidence, thresholds, or scoring semantics
7
7
  // change. An old selector must never silently opt an operator into a new policy.
8
8
  const EXPERIMENTAL_POLICY = 'stealth-corroboration-v1';
9
+ const ANIMATION_POLICY = 'animation-consistency-v1';
10
+
11
+ function animationObservation(signals) {
12
+ const probe = signals.environmental?.animationConsistency;
13
+ const realm = (value) => {
14
+ if (value?.status !== 'ok' || !Array.isArray(value.specified) || value.specified.length !== 3 ||
15
+ !value.specified.every((n) => n === 1000) || !Array.isArray(value.durations) || value.durations.length !== 3 ||
16
+ !value.durations.every((row) => Array.isArray(row) && row.length === 4 &&
17
+ row.every((n) => typeof n === 'number' && Number.isFinite(n) && n >= 0 && n <= 1e9))) return null;
18
+ return value.durations.every((row, i) => row.every((n) => n === (i === 2 ? 1000 : 0)));
19
+ };
20
+ const main = probe?.version === 1 ? realm(probe.main) : null;
21
+ const frame = probe?.version === 1 ? realm(probe.iframe) : null;
22
+ const status = main === null || frame === null ? 'unknown' : main && frame ? 'detected' : 'clear';
23
+ // Always observe: existing policy selectors must never enable new evidence.
24
+ return { mode: 'observe', status, detections: status === 'detected' ? [{
25
+ id: 'animation-timing-inconsistency',
26
+ reason: 'Browser API timing inconsistency; experimental observation, not proof of automation',
27
+ }] : [] };
28
+ }
9
29
 
10
30
  // Observe by default. This intentionally measures a known-ambiguous hypothesis:
11
31
  // #87's stealth session and a DevTools hardware override can look identical.
@@ -31,6 +51,7 @@ function evaluateExperimental(signals, productionScore, detections, blocking = f
31
51
  reason: 'Page and Worker disagree on hardwareConcurrency; also possible with DevTools or privacy tools',
32
52
  }] : [],
33
53
  corroboratingCategories,
54
+ observations: { [ANIMATION_POLICY]: animationObservation(signals) },
34
55
  };
35
56
  }
36
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webdecoy/fcaptcha",
3
- "version": "1.40.0",
3
+ "version": "1.41.0",
4
4
  "description": "Open source CAPTCHA with PoW, bot detection, and Vision AI protection",
5
5
  "main": "index.js",
6
6
  "exports": {