@webdecoy/fcaptcha 1.12.0 → 1.13.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/package.json +1 -1
  2. package/server.js +39 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webdecoy/fcaptcha",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Open source CAPTCHA with PoW, bot detection, and Vision AI protection",
5
5
  "main": "index.js",
6
6
  "exports": {
package/server.js CHANGED
@@ -18,6 +18,43 @@ const SECRET_KEY = process.env.FCAPTCHA_SECRET || 'dev-secret-change-in-producti
18
18
  const PORT = process.env.PORT || 3000;
19
19
  const TRUSTED_JA4_HEADERS = detection.getTrustedJA4HeaderNames();
20
20
 
21
+ // Verdict logging is off by default: a self-hosted FCaptcha emits no per-request
22
+ // logs unless the operator opts in via FCAPTCHA_LOG_VERDICTS (1/true/yes/on).
23
+ // When on, each /api/verify and /api/score logs one privacy-safe JSON line
24
+ // (score, recommendation, category scores, and per-hit category/score/confidence)
25
+ // for observability and tuning. It deliberately omits IP, user agent, raw
26
+ // signals, and the free-text detection `reason`, which can interpolate
27
+ // visitor-derived data (reverse-DNS hostname, UA/header fragments, field ids).
28
+ //
29
+ // FCAPTCHA_LOG_VERDICTS_INCLUDE_RAW additionally includes that free-text reason.
30
+ // Separate and off by default because reasons can carry visitor-derived data —
31
+ // only enable in trusted debugging contexts with no privacy obligations.
32
+ const envFlag = (name) => ['1', 'true', 'yes', 'on']
33
+ .includes(String(process.env[name] || '').trim().toLowerCase());
34
+ const VERDICT_LOGGING_ENABLED = envFlag('FCAPTCHA_LOG_VERDICTS');
35
+ const VERDICT_LOG_INCLUDE_RAW = envFlag('FCAPTCHA_LOG_VERDICTS_INCLUDE_RAW');
36
+ if (VERDICT_LOGGING_ENABLED && VERDICT_LOG_INCLUDE_RAW) {
37
+ console.warn('WARNING: FCAPTCHA_LOG_VERDICTS_INCLUDE_RAW enabled — verdict logs include free-text detection reasons that may contain visitor-derived data (hostnames, UA/header fragments, field ids). Do not enable where you have privacy obligations.');
38
+ }
39
+
40
+ function logVerdict(endpoint, siteKey, result) {
41
+ if (!VERDICT_LOGGING_ENABLED || !result) return;
42
+ console.log(JSON.stringify({
43
+ event: 'verdict',
44
+ endpoint,
45
+ siteKey,
46
+ success: result.success,
47
+ score: result.score,
48
+ recommendation: result.recommendation,
49
+ categoryScores: result.categoryScores,
50
+ detections: (result.detections || []).map((d) => {
51
+ const det = { category: d.category, score: d.score, confidence: d.confidence };
52
+ if (VERDICT_LOG_INCLUDE_RAW) det.reason = d.reason;
53
+ return det;
54
+ })
55
+ }));
56
+ }
57
+
21
58
  // Serve the browser widget alongside the API so deployments expose a single
22
59
  // origin to integrators (the implicit contract behind <serverUrl>/fcaptcha.js).
23
60
  // Set FCAPTCHA_SERVE_CLIENT=false to opt out — useful when hosting the widget
@@ -1168,6 +1205,7 @@ app.post('/api/verify', (req, res) => {
1168
1205
  }
1169
1206
 
1170
1207
  const result = runVerification(signals, ip, siteKey, userAgent, headers, ja3Hash, powSolution, signalsJson, powTiming);
1208
+ logVerdict('verify', siteKey, result);
1171
1209
  res.json(result);
1172
1210
  });
1173
1211
 
@@ -1191,6 +1229,7 @@ app.post('/api/score', (req, res) => {
1191
1229
  }
1192
1230
 
1193
1231
  const result = runVerification(signals, ip, siteKey, userAgent, headers, ja3Hash, powSolution, signalsJson, powTiming);
1232
+ logVerdict('score', siteKey, result);
1194
1233
  res.json({
1195
1234
  success: result.success,
1196
1235
  score: result.score,