@anonympins/fingerprint 0.7.0 → 0.7.1

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 (61) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +1 -1
  3. package/composer.json +8 -1
  4. package/package.json +1 -1
  5. package/public/fingerprint-wordpress.zip +0 -0
  6. package/src/js/build-client.js +8 -10
  7. package/src/js/fingerprint.builder.js +37 -38
  8. package/src/js/fingerprint.client.js +1531 -1463
  9. package/src/js/fingerprint.client.obfuscated.js +1 -0
  10. package/src/js/fingerprint.js +152 -10
  11. package/src/js/fingerprint.utils.js +213 -213
  12. package/src/js/library.js +340 -376
  13. package/src/js/mongodb-store.js +1 -1
  14. package/src/js/optimization.worker.js +27 -27
  15. package/src/js/pow.solver.inline.js +154 -56
  16. package/src/js/pow.solver.js +180 -92
  17. package/src/js/pow.worker.js +48 -48
  18. package/src/js/redis-store.js +1 -1
  19. package/src/js/tests/fingerprint.client.init.test.js +146 -143
  20. package/src/js/tests/fingerprint.test.js +34 -7
  21. package/src/js/tests/ip-reputation.test.js +1 -0
  22. package/src/js/upow-model-task.js +14 -15
  23. package/src/php/AutoTuner.php +34 -34
  24. package/src/php/Challenge/ChallengeUtils.php +56 -10
  25. package/src/php/Config/SecurityProfiles.php +20 -0
  26. package/src/php/DirectFingerprint.php +190 -145
  27. package/src/php/FingerprintBuilder.php +29 -30
  28. package/src/php/FingerprintClient.php +147 -148
  29. package/src/php/FingerprintEngine.php +7 -5
  30. package/src/php/Ja3AnomalyDetector.php +33 -32
  31. package/src/php/Optimization/FunctionRegistry.php +7 -7
  32. package/src/php/Optimization/Optimization.php +24 -24
  33. package/src/php/Optimization/OptimizationOperators.php +26 -25
  34. package/src/php/Optimization/ProblemInitializers.php +52 -52
  35. package/src/php/ProblemManager.php +31 -34
  36. package/src/php/RequestContext.php +8 -1
  37. package/src/php/Store/IStore.php +7 -8
  38. package/src/php/Store/InMemoryStore.php +66 -66
  39. package/src/php/Store/MongoDbStore.php +5 -5
  40. package/src/php/Store/RedisStore.php +5 -5
  41. package/src/php/Store/StoreManager.php +35 -35
  42. package/src/php/Tests/ChallengeUtilsTest.php +453 -453
  43. package/src/php/Tests/DnsCircuitBreakerTest.php +105 -105
  44. package/src/php/Tests/FingerprintEngineTest.php +662 -662
  45. package/src/php/Tests/IpReputationTest.php +10 -0
  46. package/src/php/Tests/MaliciousPatternsTest.php +103 -103
  47. package/src/php/Tests/MetricsTest.php +97 -97
  48. package/src/php/Tests/ProblemManagerTest.php +376 -376
  49. package/src/php/Tests/QuicFingerprintTest.php +53 -53
  50. package/src/php/Tests/RequestUtilsTest.php +471 -471
  51. package/src/php/Tests/TLSClientHelloParserTest.php +177 -177
  52. package/src/php/Tests/config/ed25519_key.json +3 -3
  53. package/src/php/Utils/Env.php +49 -49
  54. package/src/php/Utils/MaliciousPatterns.php +74 -74
  55. package/src/php/Utils/MetricsManager.php +209 -209
  56. package/src/php/Utils/RequestUtils.php +129 -7
  57. package/src/php/Utils/TLSClientHelloParser.php +369 -369
  58. package/src/php/WordPress/WpDbStore.php +155 -0
  59. package/src/php/WordPress/fingerprint-wordpress.php +217 -0
  60. package/src/php/WordPress/package.php +123 -0
  61. package/src/php/bin/auto-tune.php +118 -118
@@ -8,18 +8,18 @@ use Anonympins\Fingerprint\Optimization\OptimizationOperators;
8
8
  use Anonympins\Fingerprint\Utils\RequestUtils;
9
9
 
10
10
  /**
11
- * Gère le processus d'auto-ajustement en arrière-plan pour les seuils et poids de sécurité.
12
- * Conçu pour être exécuté périodiquement (par exemple, via une tâche cron).
11
+ * Manages the background auto-tuning process for security thresholds and weights.
12
+ * Designed to be executed periodically (e.g. via a cron job).
13
13
  */
14
14
  class AutoTuner
15
15
  {
16
16
  /**
17
- * @var array<string, mixed> La configuration de sécurité en direct qui sera mutée.
17
+ * @var array<string, mixed> Live security configuration that will be mutated.
18
18
  */
19
19
  private array $securityConfig;
20
20
 
21
21
  /**
22
- * @var array<int, array<string, mixed>> Les données de trafic collectées.
22
+ * @var array<int, array<string, mixed>> Collected traffic data log.
23
23
  */
24
24
  private array $trafficData;
25
25
 
@@ -33,14 +33,14 @@ class AutoTuner
33
33
  private float $validationTolerance;
34
34
 
35
35
  /**
36
- * @var ?array<string, mixed> La dernière meilleure solution trouvée par l'optimiseur.
36
+ * @var ?array<string, mixed> Last best solution found by the optimizer.
37
37
  */
38
38
  private static ?array $lastBestSolution = null;
39
39
 
40
40
  /**
41
- * @param array<string, mixed> &$securityConfig La configuration de sécurité (passée par référence).
42
- * @param array<int, array<string, mixed>> &$trafficData Les données de trafic (passées par référence).
43
- * @param array<string, int> $options Options pour l'auto-ajustement.
41
+ * @param array<string, mixed> &$securityConfig Security configuration passed by reference.
42
+ * @param array<int, array<string, mixed>> &$trafficData Traffic logs passed by reference.
43
+ * @param array<string, int> $options Auto-tuning options.
44
44
  */
45
45
  public function __construct(array &$securityConfig, array &$trafficData, array $options = [])
46
46
  {
@@ -104,7 +104,7 @@ class AutoTuner
104
104
  $now = (int)(microtime(true) * 1000);
105
105
  $removed = [];
106
106
 
107
- // 1. Expire par temps (maxAgeMs)
107
+ // 1. Time-based expiration (maxAgeMs)
108
108
  if ($this->maxAgeMs !== null && $this->maxAgeMs > 0) {
109
109
  $threshold = $now - $this->maxAgeMs;
110
110
  foreach ($this->trafficData as $key => $log) {
@@ -117,14 +117,14 @@ class AutoTuner
117
117
  $this->trafficData = array_values($this->trafficData);
118
118
  }
119
119
 
120
- // 2. Politique de taille maximale (maxDataPoints)
120
+ // 2. Maximum dataset size enforcement (maxDataPoints)
121
121
  if ($this->maxDataPoints > 0 && count($this->trafficData) > $this->maxDataPoints) {
122
122
  $overflowCount = count($this->trafficData) - $this->maxDataPoints;
123
123
  $spliced = array_splice($this->trafficData, 0, $overflowCount);
124
124
  $removed = array_merge($removed, $spliced);
125
125
  }
126
126
 
127
- // 3. Invocation du callback onCleanup
127
+ // 3. Execute cleanup callback
128
128
  if ($this->onCleanup !== null && is_callable($this->onCleanup) && !empty($removed)) {
129
129
  try {
130
130
  call_user_func($this->onCleanup, $removed);
@@ -135,7 +135,7 @@ class AutoTuner
135
135
  }
136
136
 
137
137
  /**
138
- * Exécute un cycle d'optimisation des seuils.
138
+ * Executes a threshold optimization cycle.
139
139
  */
140
140
  public function runOptimizationCycle(): void
141
141
  {
@@ -148,35 +148,35 @@ class AutoTuner
148
148
  fn ($log) => in_array($log['type'] ?? '', ['challenge_solved', 'trap_triggered'])
149
149
  ));
150
150
  $highConfidenceRatio = count($sanitizedData) > 0 ? $highConfidenceLogs / count($sanitizedData) : 0;
151
- $minConfidenceRatio = 0.05; // Exiger au moins 5% de signaux forts.
152
- $minHighConfidenceCount = 10; // Absolu de secours pour éviter le gel lors de floods
151
+ $minConfidenceRatio = 0.05; // Require at least 5% high-confidence signals
152
+ $minHighConfidenceCount = 10; // Fallback absolute count to avoid starvation during floods
153
153
 
154
154
  $hasEnoughSignal = $highConfidenceRatio >= $minConfidenceRatio || $highConfidenceLogs >= $minHighConfidenceCount;
155
155
 
156
156
  if (count($sanitizedData) < $this->minDataPoints || !$hasEnoughSignal) {
157
157
  if (count($sanitizedData) < $this->minDataPoints) {
158
- echo sprintf("[AutoTuning] Reporté : %d/%d points de données.\n", count($sanitizedData), $this->minDataPoints);
158
+ echo sprintf("[AutoTuning] Postponed: %d/%d data points collected.\n", count($sanitizedData), $this->minDataPoints);
159
159
  } else {
160
- echo sprintf("[AutoTuning] Reporté : Signaux de confiance insuffisants (Ratio: %.2f%% < %.2f%% et absolu: %d < %d).\n", $highConfidenceRatio * 100, $minConfidenceRatio * 100, $highConfidenceLogs, $minHighConfidenceCount);
160
+ echo sprintf("[AutoTuning] Postponed: Insufficient confidence signals (Ratio: %.2f%% < %.2f%% and count: %d < %d).\n", $highConfidenceRatio * 100, $minConfidenceRatio * 100, $highConfidenceLogs, $minHighConfidenceCount);
161
161
  }
162
162
  return;
163
163
  }
164
164
 
165
165
  if (count($this->trafficData) > $this->maxDataPoints) {
166
- echo sprintf("[AutoTuning] Le journal de trafic a atteint %d entrées (max: %d). Troncation des données les plus anciennes.\n", count($this->trafficData), $this->maxDataPoints);
166
+ echo sprintf("[AutoTuning] Traffic log reached %d entries (max: %d). Truncating oldest logs.\n", count($this->trafficData), $this->maxDataPoints);
167
167
  $this->trafficData = array_slice($this->trafficData, count($this->trafficData) - $this->maxDataPoints);
168
168
  }
169
169
 
170
- echo sprintf("[AutoTuning] Démarrage du cycle d'optimisation complet avec %d points de données assainis.\n", count($sanitizedData));
170
+ echo sprintf("[AutoTuning] Starting complete optimization cycle with %d sanitized data points.\n", count($sanitizedData));
171
171
 
172
172
  $paretoFront = OptimizationOperators::solveFullSecurityTuning(['trafficData' => $sanitizedData, 'currentConfig' => $this->securityConfig], []);
173
173
 
174
174
  if (empty($paretoFront)) {
175
- echo "[AutoTuning] L'optimisation n'a retourné aucune solution.\n";
175
+ echo "[AutoTuning] Optimization returned no solutions.\n";
176
176
  return;
177
177
  }
178
178
 
179
- // Règles de gardiennage (Sanity Guardrails) pour filtrer le front de Pareto
179
+ // Sanity guardrails to filter candidate Pareto solutions
180
180
  $isValidSecurityConfig = function (array $config): bool {
181
181
  if (!isset($config['weights']) || !isset($config['thresholds'])) return false;
182
182
  $w = $config['weights'];
@@ -192,13 +192,13 @@ class AutoTuner
192
192
 
193
193
  $filteredFront = array_filter($paretoFront, fn ($p) => $isValidSecurityConfig($p['solution']));
194
194
  if (empty($filteredFront)) {
195
- echo "[AutoTuning] Attention : Toutes les solutions ont été rejetées par les règles de gardiennage. Rétablissement du front brut.\n";
195
+ echo "[AutoTuning] Warning: All Pareto solutions violated sanity guardrails. Restoring raw front.\n";
196
196
  $filteredFront = $paretoFront;
197
197
  } else {
198
198
  $filteredFront = array_values($filteredFront);
199
199
  }
200
200
 
201
- // Stratégie de sélection : choisir la solution la plus équilibrée (la plus proche de l'origine).
201
+ // Selection strategy: pick the most balanced solution (closest to origin in objective space)
202
202
  $bestSolution = $filteredFront[0];
203
203
  $minDistance = sqrt(pow($bestSolution['objectives'][0], 2) + pow($bestSolution['objectives'][1], 2));
204
204
 
@@ -210,7 +210,7 @@ class AutoTuner
210
210
  }
211
211
  }
212
212
 
213
- // Logique d'inertie pour l'application de la configuration.
213
+ // Inertial update logic to prevent drastic parameter jumps
214
214
  $newConfig = $bestSolution['solution'];
215
215
  $trafficConfidence = min(1.5, max(0.3, $highConfidenceRatio * 4));
216
216
 
@@ -254,7 +254,7 @@ class AutoTuner
254
254
  }
255
255
  };
256
256
 
257
- // --- VALIDATION POST-CALCUL (PHP Rollback & Seuil de Tolérance) ---
257
+ // --- POST-COMPUTATION VALIDATION (Rollback guard & tolerance threshold) ---
258
258
  $tempConfig = [
259
259
  'thresholds' => $this->securityConfig['thresholds'],
260
260
  'weights' => $this->securityConfig['weights'],
@@ -300,22 +300,22 @@ class AutoTuner
300
300
 
301
301
  self::$lastBestSolution = $bestSolution;
302
302
 
303
- echo "[AutoTuning] Nouvelle configuration de sécurité optimisée appliquée.\n";
304
- echo "[AutoTuning] Objectifs atteints : " . json_encode([
303
+ echo "[AutoTuning] New optimized security configuration applied.\n";
304
+ echo "[AutoTuning] Objectives achieved: " . json_encode([
305
305
  'falsePositiveRate' => round($bestSolution['objectives'][0], 4),
306
306
  'falseNegativeRate' => round($bestSolution['objectives'][1], 4)
307
307
  ]) . "\n";
308
- echo "[AutoTuning] Nouveaux seuils : " . json_encode($this->securityConfig['thresholds']) . "\n";
309
- echo "[AutoTuning] Nouveaux poids : " . json_encode($this->securityConfig['weights']) . "\n";
310
- echo "[AutoTuning] Nouveaux patterns : " . json_encode($this->securityConfig['patterns']) . "\n";
308
+ echo "[AutoTuning] New thresholds: " . json_encode($this->securityConfig['thresholds']) . "\n";
309
+ echo "[AutoTuning] New weights: " . json_encode($this->securityConfig['weights']) . "\n";
310
+ echo "[AutoTuning] New patterns: " . json_encode($this->securityConfig['patterns']) . "\n";
311
311
 
312
- // NOUVEAU: Sauvegarder la meilleure configuration si un chemin est fourni.
312
+ // Persist best configuration if savePath is configured
313
313
  if ($this->savePath !== null) {
314
314
  try {
315
315
  file_put_contents($this->savePath, json_encode($bestSolution['solution'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
316
- echo "[AutoTuning] Meilleure configuration sauvegardée dans : {$this->savePath}\n";
316
+ echo "[AutoTuning] Best configuration saved to: {$this->savePath}\n";
317
317
  } catch (\Throwable $e) {
318
- error_log("[AutoTuning] Erreur lors de la sauvegarde de la configuration optimisée : " . $e->getMessage());
318
+ error_log("[AutoTuning] Error saving optimized configuration: " . $e->getMessage());
319
319
  }
320
320
  }
321
321
 
@@ -333,7 +333,7 @@ class AutoTuner
333
333
  }
334
334
 
335
335
  /**
336
- * Retourne la dernière meilleure solution trouvée par l'auto-tuner.
336
+ * Returns the latest best solution found by the auto-tuner.
337
337
  * @return array<string, mixed>|null
338
338
  */
339
339
  public static function getBestTuningSolution(): ?array
@@ -342,7 +342,7 @@ class AutoTuner
342
342
  }
343
343
 
344
344
  /**
345
- * Réinitialise la meilleure solution statique. Utile pour les tests.
345
+ * Resets the static best solution. Intended for testing.
346
346
  * @internal
347
347
  */
348
348
  public static function resetBestTuningSolution(): void
@@ -695,8 +695,8 @@ class ChallengeUtils
695
695
  public static function calculateCpuTarget(float $suspicionFactor, array $securityConfig): string
696
696
  {
697
697
  $cpuConfig = $securityConfig['cpu'] ?? [];
698
- $minDifficultyBits = $cpuConfig['minDifficultyBits'] ?? 8;
699
- $maxDifficultyBits = $cpuConfig['maxDifficultyBits'] ?? 24;
698
+ $minDifficultyBits = (float)($cpuConfig['minDifficultyBits'] ?? 4);
699
+ $maxDifficultyBits = (float)($cpuConfig['maxDifficultyBits'] ?? 22);
700
700
 
701
701
  $totalDifficultyBits = $minDifficultyBits + $suspicionFactor * ($maxDifficultyBits - $minDifficultyBits);
702
702
 
@@ -735,6 +735,18 @@ class ChallengeUtils
735
735
  string $deviceId = '',
736
736
  string $deviceHash = ''
737
737
  ): ?string {
738
+ // En mode HTTP (non sécurisé), aucun calcul SHA-256 n'est exigé
739
+ if (!empty($challengeContext['isHttp'])) {
740
+ error_log('[FP Server Verify] Mode HTTP détecté (insecure policy) : validation sans SHA-256 acceptée.');
741
+ $expiry = (int)floor(microtime(true) * 1000) + $ticketTtl;
742
+ return self::generateStatelessTicket([
743
+ 'expiry' => $expiry,
744
+ 'originalIp' => $clientIp,
745
+ 'deviceId' => $deviceId,
746
+ 'deviceHash' => $deviceHash
747
+ ]);
748
+ }
749
+
738
750
  $cpuTargetHex = $challengeContext['cpuTarget'] ?? null;
739
751
  $baseBlock = $challengeContext['baseBlock'] ?? null;
740
752
 
@@ -871,6 +883,9 @@ class ChallengeUtils
871
883
  int $difficulty,
872
884
  string $clientSecret
873
885
  ): bool {
886
+ if ($difficulty === 0) {
887
+ return true;
888
+ }
874
889
  $maxAllowedMemDifficulty = 128; // 128MB
875
890
  if ($difficulty > $maxAllowedMemDifficulty) {
876
891
  error_log("[Security] Memory PoW verification attempt with excessive difficulty: {$difficulty}MB. Denied.");
@@ -996,13 +1011,27 @@ class ChallengeUtils
996
1011
  */
997
1012
  private static function getPowSolverCode(): string
998
1013
  {
999
- // Le chemin doit être relatif à ce fichier ou absolu.
1000
- $solverPath = __DIR__ . '/../../js/pow.solver.inline.js';
1001
- if (!file_exists($solverPath)) {
1002
- error_log("[ChallengeUtils] Erreur: Le fichier pow.solver.inline.js n'a pas été trouvé à l'emplacement attendu.");
1003
- return '';
1014
+ $candidates = [
1015
+ __DIR__ . '/../../js/pow.solver.inline.js',
1016
+ __DIR__ . '/../assets/pow.solver.inline.js',
1017
+ __DIR__ . '/../js/pow.solver.inline.js',
1018
+ dirname(__DIR__, 2) . '/assets/pow.solver.inline.js',
1019
+ dirname(__DIR__, 2) . '/js/pow.solver.inline.js',
1020
+ dirname(__DIR__, 1) . '/assets/pow.solver.inline.js',
1021
+ ];
1022
+ if (defined('ABSPATH')) {
1023
+ $wpPluginSolver = ABSPATH . 'wp-content/plugins/fingerprint-wordpress/assets/pow.solver.inline.js';
1024
+ if (file_exists($wpPluginSolver)) {
1025
+ return file_get_contents($wpPluginSolver) ?: '';
1026
+ }
1027
+ }
1028
+ foreach ($candidates as $solverPath) {
1029
+ if (file_exists($solverPath)) {
1030
+ return file_get_contents($solverPath) ?: '';
1031
+ }
1004
1032
  }
1005
- return file_get_contents($solverPath) ?: '';
1033
+ error_log("[ChallengeUtils] Erreur: Le fichier pow.solver.inline.js n'a pas été trouvé à l'emplacement attendu.");
1034
+ return '';
1006
1035
  }
1007
1036
 
1008
1037
  public static function generateSpaceChallengePage(array $challengeDetails, string $clientSecret, array $securityConfig): string
@@ -1210,14 +1239,21 @@ JS;
1210
1239
  string $clientSecret,
1211
1240
  array $securityConfig,
1212
1241
  array $trapUrls,
1213
- string $originalFingerprint
1242
+ string $originalFingerprint,
1243
+ string $clientIp = '',
1244
+ string $tlsSessionId = '',
1245
+ ?string $baseBlock = null,
1246
+ bool $isHttps = true
1214
1247
  ): string {
1215
1248
  $nonce = $cpuChallengeDetails['nonce'];
1216
1249
  $target = $cpuChallengeDetails['target']; // @phpstan-ignore-line
1217
1250
  $path = $cpuChallengeDetails['path'];
1251
+ $isHttp = !$isHttps;
1218
1252
 
1219
1253
  $solverCode = self::getPowSolverCode();
1220
- $baseBlock = self::createCpuChallengeBaseBlock($nonce, $clientSecret, $originalFingerprint);
1254
+ if ($baseBlock === null || $baseBlock === '') {
1255
+ $baseBlock = self::createCpuChallengeBaseBlock($nonce, $clientSecret, $originalFingerprint, $clientIp, $tlsSessionId);
1256
+ }
1221
1257
  $baseBlockBytes = '[' . implode(',', array_values(unpack('C*', $baseBlock))) . ']';
1222
1258
 
1223
1259
  $trapTags = ['div', 'span', 'p', 'section'];
@@ -1241,16 +1277,26 @@ JS;
1241
1277
  $safePath = json_encode($path, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES);
1242
1278
  $safeNonce = json_encode($nonce, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES);
1243
1279
  $safeClientSecret = json_encode($clientSecret, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES);
1280
+ $isHttpJs = $isHttp ? 'true' : 'false';
1244
1281
 
1245
1282
  $challengeScript = <<<JS
1246
1283
  async function solve() {
1247
1284
  const nonce = {$safeNonce};
1248
1285
  const path = {$safePath};
1249
1286
  const clientSecret = {$safeClientSecret};
1287
+ const isHttp = {$isHttpJs};
1250
1288
  const cpuTarget = BigInt("0x" + "{$target}");
1251
1289
  const memDifficulty = {$memoryDifficulty};
1252
1290
  const baseBlock = new Uint8Array({$baseBlockBytes});
1253
1291
 
1292
+ if (isHttp) {
1293
+ document.getElementById('loader').innerText = '⚠️ Connexion HTTP non sécurisée : validation simplifiée en cours...';
1294
+ await new Promise(r => setTimeout(r, 150));
1295
+ const finalUrl = path + "?pow_type=cpu_mem&pow_nonce=" + nonce + "&pow_solution_cpu=http_simulacre_ack&pow_solution_mem=0";
1296
+ window.location.href = finalUrl;
1297
+ return;
1298
+ }
1299
+
1254
1300
  document.getElementById('loader').innerText = '⚙️ Performing CPU security calculation...';
1255
1301
  const cpuSolution = await window.solveCpuChallengeInline(baseBlock, cpuTarget, (progress) => {});
1256
1302
 
@@ -59,6 +59,10 @@ class SecurityProfiles
59
59
  'decayFactor' => 0.9,
60
60
  'inactivityReset' => 5000,
61
61
  ],
62
+ 'cpu' => [
63
+ 'minDifficultyBits' => 8,
64
+ 'maxDifficultyBits' => 22,
65
+ ],
62
66
  'filterWhitelist' => 85.0, // Stratégie d'inspection modérée pour les IP/chemins en liste blanche
63
67
  'wasm' => true,
64
68
  ],
@@ -108,6 +112,10 @@ class SecurityProfiles
108
112
  'decayFactor' => 0.85,
109
113
  'inactivityReset' => 4000,
110
114
  ],
115
+ 'cpu' => [
116
+ 'minDifficultyBits' => 10,
117
+ 'maxDifficultyBits' => 24,
118
+ ],
111
119
  'challengeNewDevices' => true, // Challenge all new devices
112
120
  'wasm' => true,
113
121
  'filterWhitelist' => true, // Tout comportement d'attaque certain bypass immédiatement la liste blanche
@@ -156,6 +164,10 @@ class SecurityProfiles
156
164
  'decayFactor' => 0.9,
157
165
  'inactivityReset' => 10000,
158
166
  ],
167
+ 'cpu' => [
168
+ 'minDifficultyBits' => 8,
169
+ 'maxDifficultyBits' => 20,
170
+ ],
159
171
  // This would be a callable in PHP, but for now, we represent its intent.
160
172
  'isApiRequest' => 'req.path.startsWith("/api/") || req.headers.accept?.includes("application/json")',
161
173
  'filterWhitelist' => 75.0, // Seuil bas pour parer au vol de clés/tokens API légitimes
@@ -208,6 +220,10 @@ class SecurityProfiles
208
220
  'decayFactor' => 0.92,
209
221
  'inactivityReset' => 10000,
210
222
  ],
223
+ 'cpu' => [
224
+ 'minDifficultyBits' => 8,
225
+ 'maxDifficultyBits' => 20,
226
+ ],
211
227
  'filterWhitelist' => 90.0, // Très tolérant, n'inspecte que si le score est presque au blocage
212
228
  'wasm' => true,
213
229
  ],
@@ -258,6 +274,10 @@ class SecurityProfiles
258
274
  'decayFactor' => 0.88,
259
275
  'inactivityReset' => 3000,
260
276
  ],
277
+ 'cpu' => [
278
+ 'minDifficultyBits' => 10,
279
+ 'maxDifficultyBits' => 24,
280
+ ],
261
281
  'challengeNewDevices' => true, // New devices are suspicious in e-commerce
262
282
  // This would be a callable in PHP, but for now, we represent its intent.
263
283
  'isApiRequest' => 'req.path.startsWith("/api/cart") || req.path.startsWith("/api/stock") || req.path.startsWith("/api/checkout")',