@anonympins/fingerprint 0.7.5 → 0.8.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 (60) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/public/anonympins-bot-mitigation-pow.zip +0 -0
  5. package/src/js/fingerprint.client.js +1784 -1772
  6. package/src/js/fingerprint.client.obfuscated.js +1 -1
  7. package/src/js/fingerprint.js +198 -28
  8. package/src/js/fingerprint.utils.js +252 -2
  9. package/src/js/pow.worker.js +2 -2
  10. package/src/js/tests/cross_parity.test.js +3 -3
  11. package/src/js/tests/dns-circuit-breaker.test.js +6 -6
  12. package/src/js/tests/fingerprint.builder.test.js +76 -78
  13. package/src/js/tests/fingerprint.client.test.js +16 -17
  14. package/src/js/tests/fingerprint.test.js +19 -12
  15. package/src/js/tests/ja3AnomalyDetector.test.js +135 -136
  16. package/src/js/tests/library.test.js +94 -95
  17. package/src/js/tests/obfuscation.test.js +8 -8
  18. package/src/js/tests/quicFingerprint.test.js +47 -0
  19. package/src/js/tests/tcpFingerprint.test.js +4 -4
  20. package/src/js/upow-model-task.js +155 -112
  21. package/src/php/Challenge/ChallengeUtils.php +382 -86
  22. package/src/php/Config/SecurityProfiles.php +75 -62
  23. package/src/php/DirectFingerprint.php +55 -8
  24. package/src/php/FingerprintBuilder.php +13 -13
  25. package/src/php/FingerprintClient.php +6 -6
  26. package/src/php/FingerprintEngine.php +2120 -1837
  27. package/src/php/Ja3AnomalyDetector.php +22 -22
  28. package/src/php/Optimization/FunctionRegistry.php +4 -4
  29. package/src/php/Optimization/Optimization.php +6 -6
  30. package/src/php/RequestContext.php +11 -11
  31. package/src/php/Store/InMemoryStore.php +96 -66
  32. package/src/php/Store/MongoDbStore.php +2 -2
  33. package/src/php/Store/RedisStore.php +1 -1
  34. package/src/php/Store/StoreManager.php +48 -35
  35. package/src/php/Tests/ChallengeUtilsTest.php +31 -0
  36. package/src/php/Tests/DnsCircuitBreakerTest.php +105 -105
  37. package/src/php/Tests/FingerprintClientTest.php +70 -70
  38. package/src/php/Tests/PowTest.php +37 -39
  39. package/src/php/Tests/QuicFingerprintTest.php +115 -53
  40. package/src/php/Tests/ThreatIntelTest.php +2 -2
  41. package/src/php/Utils/BigInt.php +202 -202
  42. package/src/php/Utils/BlockList.php +13 -13
  43. package/src/php/Utils/Logger.php +19 -1
  44. package/src/php/Utils/MaliciousPatterns.php +6 -6
  45. package/src/php/Utils/MetricsManager.php +209 -209
  46. package/src/php/Utils/RequestUtils.php +327 -14
  47. package/src/php/Utils/TLSClientHelloParser.php +385 -369
  48. package/src/php/WordPress/WpDbStore.php +7 -7
  49. package/src/php/WordPress/anonympins-bot-mitigation-pow.php +1121 -0
  50. package/src/php/WordPress/fingerprint-anti-bot.php +0 -559
  51. package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.mo +0 -0
  52. package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.po +232 -0
  53. package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
  54. package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +297 -261
  55. package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
  56. package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +348 -267
  57. package/src/php/WordPress/package.php +80 -101
  58. package/src/php/WordPress/readme.txt +21 -5
  59. package/src/php/bin/auto-tune.php +1 -1
  60. package/public/fingerprint-anti-bot.zip +0 -0
@@ -5,8 +5,8 @@ declare(strict_types=1);
5
5
  namespace Anonympins\Fingerprint\Config;
6
6
 
7
7
  /**
8
- * Définit les profils de sécurité prédéfinis pour la bibliothèque Fingerprint.
9
- * Ces profils contiennent les poids des scores de suspicion et les seuils de déclenchement.
8
+ * Defines predefined security profiles for the Fingerprint library.
9
+ * These profiles contain suspicion score weights and trigger thresholds.
10
10
  */
11
11
  class SecurityProfiles
12
12
  {
@@ -33,19 +33,21 @@ class SecurityProfiles
33
33
  'crossLayerInconsistencyScore' => 0.4,
34
34
  'timeInconsistencyScore' => 0.9,
35
35
  'tlsSpoofingScore' => 0.8,
36
- 'botScore' => 1.0, // Poids pour le score de bot explicite
37
- 'cookieDroppingScore' => 0.9, // Pénalité élevée pour la suppression de cookies
38
- 'threatIntelScore' => 0.4, // Poids pour le renseignement sur les menaces (ex: IP de proxy connu)
39
- 'clientHintsInconsistencyScore' => 0.7, // Penalizes inconsistency between User-Agent and Client-Hints
40
- 'clickVarianceScore' => 0.6, // Poids pour la variance des clics
41
- 'subnetScore' => 0.5, // Pénalise les sous-réseaux IP avec une activité suspecte agrégée
42
- 'botnetClusterScore' => 0.6, // NOUVEAU: Poids pour le clustering botnet
36
+ 'botScore' => 1.0,
37
+ 'cookieDroppingScore' => 0.4,
38
+ 'threatIntelScore' => 0.4,
39
+ 'clientHintsInconsistencyScore' => 0.7,
40
+ 'clickVarianceScore' => 0.6,
41
+ 'subnetScore' => 0.5,
42
+ 'ipReputationScore' => 0.5,
43
+ 'botnetClusterScore' => 0.6,
43
44
  'tcpAnomalyScore' => 0.8,
44
- 'protocolAnomalyScore' => 0.8, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
45
- 'renderingAnomalyScore' => 0.8, // NEW: Anomalie de rendu
46
- 'mtuAnomalyScore' => 0.9, // NOUVEAU: Poids pour l'anomalie MTU/fragmentation
47
- 'ipReputationScore' => 0.5, // NOUVEAU: Poids pour la réputation IP
45
+ 'protocolAnomalyScore' => 0.8,
46
+ 'http2AnomalyScore' => 0.8,
47
+ 'quicAnomalyScore' => 0.8,
48
+ 'renderingAnomalyScore' => 0.8,
48
49
  'virtualizationScore' => 0.8,
50
+ 'mtuAnomalyScore' => 0.9,
49
51
  ],
50
52
  'thresholds' => ['low' => 20, 'medium' => 45, 'high' => 75, 'block' => 95],
51
53
  'patterns' => [
@@ -64,7 +66,7 @@ class SecurityProfiles
64
66
  'minDifficultyBits' => 8,
65
67
  'maxDifficultyBits' => 22,
66
68
  ],
67
- 'filterWhitelist' => 85.0, // Stratégie d'inspection modérée pour les IP/chemins en liste blanche
69
+ 'filterWhitelist' => 85.0, // Moderate inspection strategy for allowlisted IPs/paths
68
70
  'wasm' => true,
69
71
  ],
70
72
 
@@ -89,17 +91,20 @@ class SecurityProfiles
89
91
  'timeInconsistencyScore' => 1.0,
90
92
  'tlsSpoofingScore' => 1.0,
91
93
  'botScore' => 1.0,
92
- 'cookieDroppingScore' => 1.0, // Pénalité maximale
93
- 'threatIntelScore' => 0.7, // Poids élevé pour les menaces connues (Tor, etc.)
94
- 'clientHintsInconsistencyScore' => 0.9, // Very high penalty in strict mode
95
- 'clickVarianceScore' => 0.7, // High weight for click variance
96
- 'subnetScore' => 0.7, // Poids plus élevé en mode strict
97
- 'botnetClusterScore' => 0.8, // NOUVEAU: Poids pour le clustering botnet
98
- 'tcpAnomalyScore' => 1.0, // NEW: Anomalie de pile TCP/IP
99
- 'protocolAnomalyScore' => 1.0, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
100
- 'renderingAnomalyScore' => 1.0, // NEW: Anomalie de rendu
94
+ 'cookieDroppingScore' => 0.6,
95
+ 'threatIntelScore' => 0.7,
96
+ 'clientHintsInconsistencyScore' => 0.9,
97
+ 'clickVarianceScore' => 0.7,
98
+ 'subnetScore' => 0.7,
99
+ 'ipReputationScore' => 0.7,
100
+ 'botnetClusterScore' => 0.8,
101
+ 'tcpAnomalyScore' => 1.0,
102
+ 'protocolAnomalyScore' => 1.0,
103
+ 'http2AnomalyScore' => 1.0,
104
+ 'quicAnomalyScore' => 1.0,
105
+ 'renderingAnomalyScore' => 1.0,
106
+ 'virtualizationScore' => 1.0,
101
107
  'mtuAnomalyScore' => 0.9,
102
-
103
108
  ],
104
109
  'thresholds' => ['low' => 10, 'medium' => 35, 'high' => 65, 'block' => 90],
105
110
  'patterns' => [
@@ -120,7 +125,7 @@ class SecurityProfiles
120
125
  ],
121
126
  'challengeNewDevices' => true, // Challenge all new devices
122
127
  'wasm' => true,
123
- 'filterWhitelist' => true, // Tout comportement d'attaque certain bypass immédiatement la liste blanche
128
+ 'filterWhitelist' => true, // Any definite attack behavior immediately bypasses the allowlist
124
129
  ],
125
130
 
126
131
  /**
@@ -143,16 +148,20 @@ class SecurityProfiles
143
148
  'timeInconsistencyScore' => 0.8,
144
149
  'tlsSpoofingScore' => 0.7,
145
150
  'botScore' => 0.5,
146
- 'cookieDroppingScore' => 0.8, // Important pour les clients API qui doivent maintenir un état
151
+ 'cookieDroppingScore' => 0.5, // Important for API clients that need to maintain state
147
152
  'threatIntelScore' => 0.5, // APIs are often targeted by malicious IPs
148
153
  'clientHintsInconsistencyScore' => 0.6, // Relevant signal for APIs
149
154
  'clickVarianceScore' => 0.3, // Low weight as not applicable to APIs
150
- 'subnetScore' => 0.8, // Très important pour les API pour détecter les botnets
151
- 'botnetClusterScore' => 0.7, // NOUVEAU: Poids pour le clustering botnet
152
- 'tcpAnomalyScore' => 0.8, // NEW: Anomalie de pile TCP/IP
153
- 'protocolAnomalyScore' => 0.8, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
155
+ 'subnetScore' => 0.8, // Highly important for APIs to detect botnets
156
+ 'ipReputationScore' => 0.6,
157
+ 'botnetClusterScore' => 0.7,
158
+ 'tcpAnomalyScore' => 0.8,
159
+ 'protocolAnomalyScore' => 0.8,
160
+ 'http2AnomalyScore' => 0.8,
161
+ 'quicAnomalyScore' => 0.8,
162
+ 'renderingAnomalyScore' => 0.2,
163
+ 'virtualizationScore' => 0.5,
154
164
  'mtuAnomalyScore' => 0.9,
155
-
156
165
  ],
157
166
  'thresholds' => ['low' => 25, 'medium' => 50, 'high' => 80, 'block' => 95],
158
167
  'patterns' => [
@@ -173,7 +182,7 @@ class SecurityProfiles
173
182
  ],
174
183
  // This would be a callable in PHP, but for now, we represent its intent.
175
184
  'isApiRequest' => 'req.path.startsWith("/api/") || req.headers.accept?.includes("application/json")',
176
- 'filterWhitelist' => 75.0, // Seuil bas pour parer au vol de clés/tokens API légitimes
185
+ 'filterWhitelist' => 75.0, // Low threshold to defend against stolen legitimate API keys/tokens
177
186
  'wasm' => true,
178
187
  ],
179
188
 
@@ -196,20 +205,22 @@ class SecurityProfiles
196
205
  'honeypotScore' => 1.0, // Crucial for comment spam
197
206
  'crossLayerInconsistencyScore' => 0.4,
198
207
  'timeInconsistencyScore' => 0.8,
199
- 'tlsSpoofingScore' => 0.6, // Moins critique pour les blogs
208
+ 'tlsSpoofingScore' => 0.6,
200
209
  'botScore' => 0.8,
201
- 'cookieDroppingScore' => 0.7, // Moins critique, mais toujours un signal
202
- 'threatIntelScore' => 0.3, // Lower priority for a blog
210
+ 'cookieDroppingScore' => 0.3,
211
+ 'threatIntelScore' => 0.3,
203
212
  'clientHintsInconsistencyScore' => 0.5,
204
- 'clickVarianceScore' => 0.5, // Moderate weight for click variance
205
- 'subnetScore' => 0.4, // Utile contre le spam de commentaires coordonné
206
- 'ipReputationScore' => 0.3, // NOUVEAU: Poids pour la réputation IP
207
- 'botnetClusterScore' => 0.5, // NOUVEAU: Poids pour le clustering botnet
208
- 'tcpAnomalyScore' => 0.5, // NEW: Anomalie de pile TCP/IP
209
- 'protocolAnomalyScore' => 0.5, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
210
- 'renderingAnomalyScore' => 0.5, // NEW: Anomalie de rendu
213
+ 'clickVarianceScore' => 0.5,
214
+ 'subnetScore' => 0.4,
215
+ 'ipReputationScore' => 0.3,
216
+ 'botnetClusterScore' => 0.5,
217
+ 'tcpAnomalyScore' => 0.5,
218
+ 'protocolAnomalyScore' => 0.5,
219
+ 'http2AnomalyScore' => 0.5,
220
+ 'quicAnomalyScore' => 0.5,
221
+ 'renderingAnomalyScore' => 0.5,
222
+ 'virtualizationScore' => 0.6,
211
223
  'mtuAnomalyScore' => 0.9,
212
-
213
224
  ],
214
225
  'thresholds' => ['low' => 25, 'medium' => 55, 'high' => 80, 'block' => 95],
215
226
  'patterns' => [
@@ -228,7 +239,7 @@ class SecurityProfiles
228
239
  'minDifficultyBits' => 8,
229
240
  'maxDifficultyBits' => 20,
230
241
  ],
231
- 'filterWhitelist' => 90.0, // Très tolérant, n'inspecte que si le score est presque au blocage
242
+ 'filterWhitelist' => 90.0, // Highly lenient, only inspects if the score is near blocking
232
243
  'wasm' => true,
233
244
  ],
234
245
 
@@ -245,26 +256,28 @@ class SecurityProfiles
245
256
  'historyScore' => 0.4,
246
257
  'rotationScore' => 0.6,
247
258
  'headerAnomalyScore' => 0.2,
259
+ 'requestPatternScore' => 0.9,
248
260
  'inconsistencyScore' => 1.0, // Crucial for preventing account takeover
249
261
  'behaviorScore' => 0.8, // Important for checkout/login forms
250
262
  'honeypotScore' => 1.0,
251
263
  'crossLayerInconsistencyScore' => 0.7,
252
- // NOUVEAU: Ajout des scores manquants pour une configuration complète
253
- 'requestPatternScore' => 0.9, // Poids unifié pour les patterns, remplace les scores scindés
254
264
  'timeInconsistencyScore' => 0.9,
255
265
  'tlsSpoofingScore' => 0.9,
256
266
  'botScore' => 1.0,
257
- 'cookieDroppingScore' => 1.0, // Crucial pour la détection de bots e-commerce
267
+ 'cookieDroppingScore' => 0.6, // Crucial for e-commerce bot detection
258
268
  'threatIntelScore' => 0.8, // Very important for e-commerce (scalping proxies)
259
269
  'clientHintsInconsistencyScore' => 0.9, // Very important for e-commerce
260
270
  'clickVarianceScore' => 0.8, // Very high weight for click variance
261
- 'subnetScore' => 0.9, // Crucial contre les attaques de scalping distribuées
262
- 'botnetClusterScore' => 0.9, // NOUVEAU: Poids pour le clustering botnet
263
- 'tcpAnomalyScore' => 0.9, // NEW: Anomalie de pile TCP/IP
264
- 'protocolAnomalyScore' => 0.9, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
265
- 'renderingAnomalyScore' => 0.9, // NEW: Anomalie de rendu
271
+ 'subnetScore' => 0.9, // Crucial against distributed scalping attacks
272
+ 'ipReputationScore' => 0.8,
273
+ 'botnetClusterScore' => 0.9,
274
+ 'tcpAnomalyScore' => 0.9,
275
+ 'protocolAnomalyScore' => 0.9,
276
+ 'http2AnomalyScore' => 0.9,
277
+ 'quicAnomalyScore' => 0.9,
278
+ 'renderingAnomalyScore' => 0.9,
279
+ 'virtualizationScore' => 0.9,
266
280
  'mtuAnomalyScore' => 0.9,
267
-
268
281
  ],
269
282
  'thresholds' => ['low' => 15, 'medium' => 40, 'high' => 70, 'block' => 90],
270
283
  'patterns' => [
@@ -287,16 +300,16 @@ class SecurityProfiles
287
300
  // This would be a callable in PHP, but for now, we represent its intent.
288
301
  'isApiRequest' => 'req.path.startsWith("/api/cart") || req.path.startsWith("/api/stock") || req.path.startsWith("/api/checkout")',
289
302
  'wasm' => true,
290
- 'filterWhitelist' => true, // Tolérance zéro pour le scraping / scalping distribué
303
+ 'filterWhitelist' => true, // Zero tolerance for scraping / distributed scalping
291
304
  ],
292
305
  ];
293
306
 
294
307
  /**
295
- * Crée une configuration de sécurité basée sur un profil nommé, avec des surcharges optionnelles.
308
+ * Creates a security configuration based on a named profile, with optional overrides.
296
309
  *
297
- * @param string $profileName Le nom du profil à utiliser ('balanced', 'strict', 'api', etc.).
298
- * @param array<string, mixed> $overrides Un tableau pour fusionner profondément avec le profil, permettant la personnalisation.
299
- * @return array<string, mixed> L'objet de configuration de sécurité final.
310
+ * @param string $profileName The profile name to use ('balanced', 'strict', 'api', etc.).
311
+ * @param array<string, mixed> $overrides An array to deep-merge with the profile, allowing customization.
312
+ * @return array<string, mixed> The final security configuration object.
300
313
  */
301
314
  public static function createSecurityProfile(string $profileName = 'balanced', array $overrides = []): array
302
315
  {
@@ -305,11 +318,11 @@ class SecurityProfiles
305
318
  }
306
319
 
307
320
  /**
308
- * Fusionne profondément deux tableaux. Les propriétés du tableau `$source` écrasent celles du tableau `$target`.
321
+ * Deep-merges two arrays. Properties of the `$source` array overwrite those of `$target`.
309
322
  *
310
- * @param array<string, mixed> $target Le tableau cible.
311
- * @param array<string, mixed> $source Le tableau source.
312
- * @return array<string, mixed> Le tableau fusionné.
323
+ * @param array<string, mixed> $target The target array.
324
+ * @param array<string, mixed> $source The source array.
325
+ * @return array<string, mixed> The merged array.
313
326
  */
314
327
  public static function deepMerge(array $target, array $source): array
315
328
  {
@@ -25,15 +25,10 @@ class DirectFingerprint
25
25
  }
26
26
 
27
27
  /**
28
- * Protects the current entry point.
29
- * Analyzes the incoming request and issues challenges or block responses, exiting the script if necessary.
30
- * If the request is allowed, returns the fingerprint data.
31
- *
32
- * @return array{score: float, vector: array}|null Fingerprint data if allowed, null otherwise.
28
+ * Builds request context from PHP superglobals.
33
29
  */
34
- public function protect(): ?array
30
+ public function buildRequestContext(): RequestContext
35
31
  {
36
- // 1. Build request context from PHP superglobals
37
32
  // phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.NonceVerification.Recommended -- Direct WAF inspection firewall before WP core logic
38
33
  $body = $_POST ?: json_decode(file_get_contents('php://input'), true);
39
34
  $headers = function_exists('getallheaders') ? getallheaders() : [];
@@ -44,7 +39,7 @@ class DirectFingerprint
44
39
  $path = function_exists('wp_parse_url') ? (string)wp_parse_url($rawUri, PHP_URL_PATH) : (string)parse_url($rawUri, PHP_URL_PATH);
45
40
  $serverProtocol = isset($_SERVER['SERVER_PROTOCOL']) ? sanitize_text_field(wp_unslash($_SERVER['SERVER_PROTOCOL'])) : '1.1';
46
41
 
47
- $context = new RequestContext(
42
+ return new RequestContext(
48
43
  $remoteAddr,
49
44
  !empty($path) ? $path : '/',
50
45
  $headers,
@@ -54,10 +49,62 @@ class DirectFingerprint
54
49
  $_COOKIE,
55
50
  $serverProtocol
56
51
  );
52
+ }
53
+
54
+ /**
55
+ * Inspects the incoming request without terminating execution or issuing redirects/exits.
56
+ *
57
+ * @param RequestContext|null $context
58
+ * @return array
59
+ */
60
+ public function inspect(?RequestContext $context = null): array
61
+ {
62
+ $context = $context ?? $this->buildRequestContext();
63
+ $decision = $this->engine->processRequest($context);
64
+
65
+ return [
66
+ 'action' => $decision['action'] ?? 'next',
67
+ 'intendedAction' => $decision['intendedAction'] ?? null,
68
+ 'score' => (float)($decision['score'] ?? 0.0),
69
+ 'suspicionScore' => (float)($decision['score'] ?? 0.0),
70
+ 'vector' => $decision['vector'] ?? [],
71
+ 'status' => $decision['status'] ?? 200,
72
+ 'body' => $decision['body'] ?? null,
73
+ 'context' => $context,
74
+ ];
75
+ }
76
+
77
+ /**
78
+ * Alias for inspect().
79
+ *
80
+ * @param RequestContext|null $context
81
+ * @return array
82
+ */
83
+ public function evaluate(?RequestContext $context = null): array
84
+ {
85
+ return $this->inspect($context);
86
+ }
87
+
88
+ /**
89
+ * Protects the current entry point.
90
+ * Analyzes the incoming request and issues challenges or block responses, exiting the script if necessary.
91
+ * If the request is allowed, returns the fingerprint data.
92
+ *
93
+ * @return array{score: float, vector: array}|null Fingerprint data if allowed, null otherwise.
94
+ */
95
+ public function protect(): ?array
96
+ {
97
+ // 1. Build request context from PHP superglobals
98
+ $context = $this->buildRequestContext();
57
99
 
58
100
  // 2. Process request with engine
59
101
  $decision = $this->engine->processRequest($context);
60
102
 
103
+ // 3. Callback hook before acting on decision (allows logging, telemetry, SSE recording)
104
+ if (isset($this->securityConfig['onDecision']) && is_callable($this->securityConfig['onDecision'])) {
105
+ call_user_func($this->securityConfig['onDecision'], $decision, $context);
106
+ }
107
+
61
108
  // 3. Act on decision
62
109
  if (isset($context->newCookieForResponse)) {
63
110
  $cookie = $context->newCookieForResponse;
@@ -5,7 +5,7 @@ declare(strict_types=1);
5
5
  namespace Anonympins\Fingerprint;
6
6
 
7
7
  /**
8
- * Class to build a composite fingerprint (Multi-Hash).
8
+ * Builds a composite fingerprint (Multi-Hash).
9
9
  * Output format: "grp1:hash1|grp2:hash2|grp3:hash3"
10
10
  */
11
11
  class FingerprintBuilder
@@ -17,7 +17,7 @@ class FingerprintBuilder
17
17
 
18
18
  /**
19
19
  * Adds a component to the fingerprint.
20
- *
20
+ *
21
21
  * @param string $group Group name (e.g. 'hw', 'screen', 'geo').
22
22
  * @param string|int|bool|null $value Raw value to hash.
23
23
  * @return self
@@ -27,14 +27,14 @@ class FingerprintBuilder
27
27
  if ($value === null || $value === '') {
28
28
  return $this;
29
29
  }
30
- // Hash the value individually
30
+ // Hash the value individually to anonymize and normalize its length.
31
31
  $this->components[$group] = self::cyrb53((string)$value);
32
32
  return $this;
33
33
  }
34
34
 
35
35
  /**
36
36
  * Adds a raw component without hashing it.
37
- * Useful for metrics that need to be read as-is on the server.
37
+ * Useful for metrics that need to be read as-is on the server side.
38
38
  *
39
39
  * @param string $group Group name.
40
40
  * @param string|int|null $value Raw value.
@@ -51,13 +51,13 @@ class FingerprintBuilder
51
51
 
52
52
  /**
53
53
  * Generates the final fingerprint string.
54
- * Components are sorted by key to guarantee deterministic ordering.
54
+ * Components are sorted by key to ensure deterministic ordering.
55
55
  *
56
56
  * @return string
57
57
  */
58
58
  public function __toString(): string
59
59
  {
60
- // Sort array by key
60
+ // Sort array by key.
61
61
  ksort($this->components);
62
62
 
63
63
  $parts = [];
@@ -70,7 +70,7 @@ class FingerprintBuilder
70
70
 
71
71
  /**
72
72
  * Compares two fingerprints and returns a similarity score (0 to 1).
73
- * Uses weights to emphasize strong invariants (Canvas, GPU, JA3).
73
+ * Uses weights to emphasize strong invariants (e.g., Canvas, GPU, JA3).
74
74
  *
75
75
  * @param string|null $fpString1 Fingerprint A.
76
76
  * @param string|null $fpString2 Fingerprint B.
@@ -137,7 +137,7 @@ class FingerprintBuilder
137
137
 
138
138
  /**
139
139
  * cyrb53 hashing algorithm (fast and low collision rate).
140
- * Ported from the JavaScript version.
140
+ * This is a direct port of the JavaScript version.
141
141
  *
142
142
  * @param string $str String to hash.
143
143
  * @param int $seed Optional seed.
@@ -157,8 +157,8 @@ class FingerprintBuilder
157
157
  $h1 = self::imul($h1 ^ ($h1 >> 16), 2246822507) ^ self::imul($h2 ^ ($h2 >> 13), 3266489909);
158
158
  $h2 = self::imul($h2 ^ ($h2 >> 16), 2246822507) ^ self::imul($h1 ^ ($h1 >> 13), 3266489909);
159
159
 
160
- // On 64-bit platforms, PHP handles 64-bit signed ints natively.
161
- // Use native shifts instead of bcmath for better performance.
160
+ // On 64-bit platforms, PHP handles 64-bit signed integers natively.
161
+ // Use native shifts instead of bcmath for improved performance.
162
162
  if (PHP_INT_SIZE === 8) {
163
163
  $h1_u = $h1 & 0xffffffff;
164
164
  $h2_u = $h2 & 0xffffffff;
@@ -166,7 +166,7 @@ class FingerprintBuilder
166
166
  return (string)$val_h2;
167
167
  }
168
168
 
169
- // Fallback to bcmath on 32-bit platforms
169
+ // Fallback to bcmath on 32-bit platforms.
170
170
  $val_h2 = bcadd(bcmul((string)(2097151 & $h2), '4294967296'), (string)($h1 >= 0 ? $h1 : $h1 + 4294967296));
171
171
  return $val_h2;
172
172
  }
@@ -180,8 +180,8 @@ class FingerprintBuilder
180
180
  */
181
181
  private static function imul(int $a, int $b): int
182
182
  {
183
- // Emulation of JavaScript's Math.imul for signed 32-bit integer multiplication.
184
- // This version correctly handles overflows on 64-bit systems.
183
+ // Emulates JavaScript's Math.imul for signed 32-bit integer multiplication.
184
+ // This implementation correctly handles overflows on 64-bit systems.
185
185
  $ah = ($a >> 16) & 0xffff;
186
186
  $al = $a & 0xffff;
187
187
  $bh = ($b >> 16) & 0xffff;
@@ -6,8 +6,8 @@ namespace Anonympins\Fingerprint;
6
6
  use Anonympins\Fingerprint\Config\SecurityProfiles;
7
7
 
8
8
  /**
9
- * FingerprintClient - PHP wrapper for the client-side fingerprinting library.
10
- *
9
+ * PHP wrapper for the client-side fingerprinting library.
10
+ *
11
11
  * Handles script injection and generation of polymorphic honeypot fields
12
12
  * inside HTML forms.
13
13
  */
@@ -64,7 +64,7 @@ class FingerprintClient
64
64
 
65
65
  /**
66
66
  * Generates a hidden honeypot form field.
67
- * Traps automated bots while remaining invisible to human users.
67
+ * Traps automated bots while remaining invisible to human users and screen readers.
68
68
  *
69
69
  * @param string $fieldName Field name (must match client honeypot registration).
70
70
  * @return string Generated HTML markup.
@@ -76,7 +76,7 @@ class FingerprintClient
76
76
  $this->clientConfig['honeypots'][] = $fieldName;
77
77
  }
78
78
 
79
- // Polymorphic CSS styling to robustly obscure honeypots
79
+ // Polymorphic CSS styling to robustly obscure honeypot fields
80
80
  $styleOptions = [
81
81
  'position:absolute; left:-9999px; top:-9999px; transform:scale(0); opacity:0; pointer-events:none;',
82
82
  'position:fixed; left:-8888px; top:-8888px; width:0; height:0; overflow:hidden; opacity:0; pointer-events:none;',
@@ -112,7 +112,7 @@ class FingerprintClient
112
112
  $configJson = json_encode($this->clientConfig);
113
113
  $nonceAttr = $this->nonce ? ' nonce="' . $this->nonce . '"' : '';
114
114
 
115
- // Inline initialization script embedded in HTML
115
+ // Inline initialization script to be embedded in HTML
116
116
  $initScript = "document.addEventListener('DOMContentLoaded', function() {\n"
117
117
  . " const config = " . $configJson . ";\n"
118
118
  . " if (window.ClientLibrary) {\n"
@@ -129,7 +129,7 @@ class FingerprintClient
129
129
  . " }\n"
130
130
  . "});";
131
131
 
132
- // Combine library loader script and inline initialization
132
+ // Combine the main library loader script and the inline initialization script
133
133
  // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Polymorphic dynamic client script tag generation
134
134
  return '<script src="' . htmlspecialchars($this->clientScriptPath) . '"' . $nonceAttr . '></script>'
135
135
  . '<script' . $nonceAttr . '>' . $initScript . '</script>';