@anonympins/fingerprint 0.7.4 → 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 (64) hide show
  1. package/CHANGELOG.md +59 -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/dynamic-wasm.js +218 -218
  6. package/src/js/fingerprint.client.js +1784 -1738
  7. package/src/js/fingerprint.client.obfuscated.js +1 -1
  8. package/src/js/fingerprint.js +489 -99
  9. package/src/js/fingerprint.utils.js +252 -2
  10. package/src/js/pow.worker.js +2 -2
  11. package/src/js/tests/cross_parity.test.js +3 -3
  12. package/src/js/tests/dns-circuit-breaker.test.js +6 -6
  13. package/src/js/tests/dynamic-wasm.test.js +77 -77
  14. package/src/js/tests/fingerprint.builder.test.js +76 -78
  15. package/src/js/tests/fingerprint.client.init.test.js +78 -0
  16. package/src/js/tests/fingerprint.client.test.js +16 -17
  17. package/src/js/tests/fingerprint.test.js +37 -12
  18. package/src/js/tests/ja3AnomalyDetector.test.js +135 -136
  19. package/src/js/tests/library.test.js +94 -95
  20. package/src/js/tests/obfuscation.test.js +8 -8
  21. package/src/js/tests/quicFingerprint.test.js +47 -0
  22. package/src/js/tests/tcpFingerprint.test.js +4 -4
  23. package/src/js/tests/threatIntel.test.js +40 -1
  24. package/src/js/upow-model-task.js +155 -112
  25. package/src/php/Challenge/ChallengeUtils.php +392 -86
  26. package/src/php/Config/SecurityProfiles.php +79 -61
  27. package/src/php/DirectFingerprint.php +55 -8
  28. package/src/php/FingerprintBuilder.php +13 -13
  29. package/src/php/FingerprintClient.php +6 -6
  30. package/src/php/FingerprintEngine.php +2122 -1690
  31. package/src/php/Ja3AnomalyDetector.php +22 -22
  32. package/src/php/Optimization/FunctionRegistry.php +4 -4
  33. package/src/php/Optimization/Optimization.php +6 -6
  34. package/src/php/RequestContext.php +11 -11
  35. package/src/php/Store/InMemoryStore.php +96 -66
  36. package/src/php/Store/MongoDbStore.php +2 -2
  37. package/src/php/Store/RedisStore.php +1 -1
  38. package/src/php/Store/StoreManager.php +48 -35
  39. package/src/php/Tests/ChallengeUtilsTest.php +31 -0
  40. package/src/php/Tests/DnsCircuitBreakerTest.php +105 -105
  41. package/src/php/Tests/FingerprintClientTest.php +70 -70
  42. package/src/php/Tests/PowTest.php +37 -39
  43. package/src/php/Tests/QuicFingerprintTest.php +115 -53
  44. package/src/php/Tests/ThreatIntelTest.php +34 -0
  45. package/src/php/Utils/BigInt.php +202 -202
  46. package/src/php/Utils/BlockList.php +13 -13
  47. package/src/php/Utils/Logger.php +19 -1
  48. package/src/php/Utils/MaliciousPatterns.php +6 -6
  49. package/src/php/Utils/MetricsManager.php +209 -209
  50. package/src/php/Utils/RequestUtils.php +362 -1
  51. package/src/php/Utils/TLSClientHelloParser.php +385 -369
  52. package/src/php/WordPress/WpDbStore.php +7 -7
  53. package/src/php/WordPress/anonympins-bot-mitigation-pow.php +1121 -0
  54. package/src/php/WordPress/fingerprint-anti-bot.php +0 -559
  55. package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.mo +0 -0
  56. package/src/php/WordPress/languages/anonympins-bot-mitigation-pow-fr_FR.po +232 -0
  57. package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
  58. package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +297 -261
  59. package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
  60. package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +348 -267
  61. package/src/php/WordPress/package.php +80 -101
  62. package/src/php/WordPress/readme.txt +21 -5
  63. package/src/php/bin/auto-tune.php +1 -1
  64. 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,18 +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
- '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,
47
49
  'virtualizationScore' => 0.8,
50
+ 'mtuAnomalyScore' => 0.9,
48
51
  ],
49
52
  'thresholds' => ['low' => 20, 'medium' => 45, 'high' => 75, 'block' => 95],
50
53
  'patterns' => [
@@ -63,7 +66,7 @@ class SecurityProfiles
63
66
  'minDifficultyBits' => 8,
64
67
  'maxDifficultyBits' => 22,
65
68
  ],
66
- '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
67
70
  'wasm' => true,
68
71
  ],
69
72
 
@@ -88,16 +91,20 @@ class SecurityProfiles
88
91
  'timeInconsistencyScore' => 1.0,
89
92
  'tlsSpoofingScore' => 1.0,
90
93
  'botScore' => 1.0,
91
- 'cookieDroppingScore' => 1.0, // Pénalité maximale
92
- 'threatIntelScore' => 0.7, // Poids élevé pour les menaces connues (Tor, etc.)
93
- 'clientHintsInconsistencyScore' => 0.9, // Very high penalty in strict mode
94
- 'clickVarianceScore' => 0.7, // High weight for click variance
95
- 'subnetScore' => 0.7, // Poids plus élevé en mode strict
96
- 'botnetClusterScore' => 0.8, // NOUVEAU: Poids pour le clustering botnet
97
- 'tcpAnomalyScore' => 1.0, // NEW: Anomalie de pile TCP/IP
98
- 'protocolAnomalyScore' => 1.0, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
99
- 'renderingAnomalyScore' => 1.0, // NEW: Anomalie de rendu
100
-
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,
107
+ 'mtuAnomalyScore' => 0.9,
101
108
  ],
102
109
  'thresholds' => ['low' => 10, 'medium' => 35, 'high' => 65, 'block' => 90],
103
110
  'patterns' => [
@@ -118,7 +125,7 @@ class SecurityProfiles
118
125
  ],
119
126
  'challengeNewDevices' => true, // Challenge all new devices
120
127
  'wasm' => true,
121
- 'filterWhitelist' => true, // Tout comportement d'attaque certain bypass immédiatement la liste blanche
128
+ 'filterWhitelist' => true, // Any definite attack behavior immediately bypasses the allowlist
122
129
  ],
123
130
 
124
131
  /**
@@ -141,15 +148,20 @@ class SecurityProfiles
141
148
  'timeInconsistencyScore' => 0.8,
142
149
  'tlsSpoofingScore' => 0.7,
143
150
  'botScore' => 0.5,
144
- '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
145
152
  'threatIntelScore' => 0.5, // APIs are often targeted by malicious IPs
146
153
  'clientHintsInconsistencyScore' => 0.6, // Relevant signal for APIs
147
154
  'clickVarianceScore' => 0.3, // Low weight as not applicable to APIs
148
- 'subnetScore' => 0.8, // Très important pour les API pour détecter les botnets
149
- 'botnetClusterScore' => 0.7, // NOUVEAU: Poids pour le clustering botnet
150
- 'tcpAnomalyScore' => 0.8, // NEW: Anomalie de pile TCP/IP
151
- 'protocolAnomalyScore' => 0.8, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
152
-
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,
164
+ 'mtuAnomalyScore' => 0.9,
153
165
  ],
154
166
  'thresholds' => ['low' => 25, 'medium' => 50, 'high' => 80, 'block' => 95],
155
167
  'patterns' => [
@@ -170,7 +182,7 @@ class SecurityProfiles
170
182
  ],
171
183
  // This would be a callable in PHP, but for now, we represent its intent.
172
184
  'isApiRequest' => 'req.path.startsWith("/api/") || req.headers.accept?.includes("application/json")',
173
- '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
174
186
  'wasm' => true,
175
187
  ],
176
188
 
@@ -193,19 +205,22 @@ class SecurityProfiles
193
205
  'honeypotScore' => 1.0, // Crucial for comment spam
194
206
  'crossLayerInconsistencyScore' => 0.4,
195
207
  'timeInconsistencyScore' => 0.8,
196
- 'tlsSpoofingScore' => 0.6, // Moins critique pour les blogs
208
+ 'tlsSpoofingScore' => 0.6,
197
209
  'botScore' => 0.8,
198
- 'cookieDroppingScore' => 0.7, // Moins critique, mais toujours un signal
199
- 'threatIntelScore' => 0.3, // Lower priority for a blog
210
+ 'cookieDroppingScore' => 0.3,
211
+ 'threatIntelScore' => 0.3,
200
212
  'clientHintsInconsistencyScore' => 0.5,
201
- 'clickVarianceScore' => 0.5, // Moderate weight for click variance
202
- 'subnetScore' => 0.4, // Utile contre le spam de commentaires coordonné
203
- 'ipReputationScore' => 0.3, // NOUVEAU: Poids pour la réputation IP
204
- 'botnetClusterScore' => 0.5, // NOUVEAU: Poids pour le clustering botnet
205
- 'tcpAnomalyScore' => 0.5, // NEW: Anomalie de pile TCP/IP
206
- 'protocolAnomalyScore' => 0.5, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
207
- 'renderingAnomalyScore' => 0.5, // NEW: Anomalie de rendu
208
-
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,
223
+ 'mtuAnomalyScore' => 0.9,
209
224
  ],
210
225
  'thresholds' => ['low' => 25, 'medium' => 55, 'high' => 80, 'block' => 95],
211
226
  'patterns' => [
@@ -224,7 +239,7 @@ class SecurityProfiles
224
239
  'minDifficultyBits' => 8,
225
240
  'maxDifficultyBits' => 20,
226
241
  ],
227
- '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
228
243
  'wasm' => true,
229
244
  ],
230
245
 
@@ -241,25 +256,28 @@ class SecurityProfiles
241
256
  'historyScore' => 0.4,
242
257
  'rotationScore' => 0.6,
243
258
  'headerAnomalyScore' => 0.2,
259
+ 'requestPatternScore' => 0.9,
244
260
  'inconsistencyScore' => 1.0, // Crucial for preventing account takeover
245
261
  'behaviorScore' => 0.8, // Important for checkout/login forms
246
262
  'honeypotScore' => 1.0,
247
263
  'crossLayerInconsistencyScore' => 0.7,
248
- // NOUVEAU: Ajout des scores manquants pour une configuration complète
249
- 'requestPatternScore' => 0.9, // Poids unifié pour les patterns, remplace les scores scindés
250
264
  'timeInconsistencyScore' => 0.9,
251
265
  'tlsSpoofingScore' => 0.9,
252
266
  'botScore' => 1.0,
253
- 'cookieDroppingScore' => 1.0, // Crucial pour la détection de bots e-commerce
267
+ 'cookieDroppingScore' => 0.6, // Crucial for e-commerce bot detection
254
268
  'threatIntelScore' => 0.8, // Very important for e-commerce (scalping proxies)
255
269
  'clientHintsInconsistencyScore' => 0.9, // Very important for e-commerce
256
270
  'clickVarianceScore' => 0.8, // Very high weight for click variance
257
- 'subnetScore' => 0.9, // Crucial contre les attaques de scalping distribuées
258
- 'botnetClusterScore' => 0.9, // NOUVEAU: Poids pour le clustering botnet
259
- 'tcpAnomalyScore' => 0.9, // NEW: Anomalie de pile TCP/IP
260
- 'protocolAnomalyScore' => 0.9, // NEW: Anomalie de protocole (HTTP/2 et QUIC)
261
- 'renderingAnomalyScore' => 0.9, // NEW: Anomalie de rendu
262
-
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,
280
+ 'mtuAnomalyScore' => 0.9,
263
281
  ],
264
282
  'thresholds' => ['low' => 15, 'medium' => 40, 'high' => 70, 'block' => 90],
265
283
  'patterns' => [
@@ -282,16 +300,16 @@ class SecurityProfiles
282
300
  // This would be a callable in PHP, but for now, we represent its intent.
283
301
  'isApiRequest' => 'req.path.startsWith("/api/cart") || req.path.startsWith("/api/stock") || req.path.startsWith("/api/checkout")',
284
302
  'wasm' => true,
285
- 'filterWhitelist' => true, // Tolérance zéro pour le scraping / scalping distribué
303
+ 'filterWhitelist' => true, // Zero tolerance for scraping / distributed scalping
286
304
  ],
287
305
  ];
288
306
 
289
307
  /**
290
- * 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.
291
309
  *
292
- * @param string $profileName Le nom du profil à utiliser ('balanced', 'strict', 'api', etc.).
293
- * @param array<string, mixed> $overrides Un tableau pour fusionner profondément avec le profil, permettant la personnalisation.
294
- * @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.
295
313
  */
296
314
  public static function createSecurityProfile(string $profileName = 'balanced', array $overrides = []): array
297
315
  {
@@ -300,11 +318,11 @@ class SecurityProfiles
300
318
  }
301
319
 
302
320
  /**
303
- * 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`.
304
322
  *
305
- * @param array<string, mixed> $target Le tableau cible.
306
- * @param array<string, mixed> $source Le tableau source.
307
- * @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.
308
326
  */
309
327
  public static function deepMerge(array $target, array $source): array
310
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>';