@anonympins/fingerprint 0.5.2 → 0.5.4

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 (35) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/package.json +1 -1
  3. package/src/js/fingerprint.client.js +1271 -1191
  4. package/src/js/fingerprint.js +202 -108
  5. package/src/js/fingerprint.utils.js +213 -213
  6. package/src/js/library.js +24 -8
  7. package/src/js/mongodb-store.js +165 -79
  8. package/src/js/pow.solver.inline.js +500 -14
  9. package/src/js/pow.solver.js +323 -14
  10. package/src/js/problem-manager.js +1 -1
  11. package/src/js/redis-store.js +114 -42
  12. package/src/js/tests/dns-circuit-breaker.test.js +55 -0
  13. package/src/js/tests/fingerprint.client.init.test.js +143 -143
  14. package/src/js/tests/fingerprint.client.test.js +128 -128
  15. package/src/js/tests/fingerprint.test.js +32 -2
  16. package/src/js/tests/ip-reputation.test.js +1 -1
  17. package/src/js/tests/pow.solver.test.js +5 -2
  18. package/src/js/tests/usefulWorkSolver.test.js +162 -0
  19. package/src/php/Challenge/ChallengeUtils.php +21 -8
  20. package/src/php/FingerprintClient.php +22 -5
  21. package/src/php/FingerprintEngine.php +232 -56
  22. package/src/php/Optimization/Optimization.php +23 -16
  23. package/src/php/Optimization/OptimizationOperators.php +27 -0
  24. package/src/php/ProblemManager.php +1 -1
  25. package/src/php/Store/MongoDbStore.php +184 -104
  26. package/src/php/Store/RedisStore.php +91 -11
  27. package/src/php/Tests/ChallengeUtilsTest.php +285 -285
  28. package/src/php/Tests/DnsCircuitBreakerTest.php +106 -0
  29. package/src/php/Tests/IpReputationTest.php +1 -1
  30. package/src/php/Tests/PowTest.php +1 -1
  31. package/src/php/Tests/RequestUtilsTest.php +29 -0
  32. package/src/php/Tests/TLSClientHelloParserTest.php +177 -117
  33. package/src/php/Utils/BigInt.php +202 -202
  34. package/src/php/Utils/RequestUtils.php +74 -21
  35. package/src/php/Utils/TLSClientHelloParser.php +212 -116
@@ -1,105 +1,185 @@
1
- <?php
2
-
3
- declare(strict_types=1);
4
-
5
- namespace Anonympins\Fingerprint\Store;
6
-
7
- /**
8
- * Adaptateur de stockage MongoDB pour le moteur Fingerprint.
9
- * Utilise la bibliothèque officielle mongodb/mongodb.
10
- */
11
- class MongoDbStore implements IStore
12
- {
13
- /**
14
- * @var \MongoDB\Collection
15
- */
16
- private $collection;
17
-
18
- /**
19
- * @param \MongoDB\Collection $collection Collection dédiée au stockage des empreintes
20
- */
21
- public function __construct($collection)
22
- {
23
- $this->collection = $collection;
24
- }
25
-
26
- public function get(string $key)
27
- {
28
- $doc = $this->collection->findOne(['_id' => $key]);
29
- if (!$doc) {
30
- return null;
31
- }
32
-
33
- // Vérification d'expiration active pour bypasser le délai de 60s du démon de MongoDB
34
- if (isset($doc['expiresAt'])) {
35
- $expiresAt = $doc['expiresAt'];
36
- if ($expiresAt instanceof \MongoDB\BSON\UTCDateTime) {
37
- $expiresAtMs = $expiresAt->toDateTime()->getTimestamp() * 1000;
38
- $nowMs = (int)(microtime(true) * 1000);
39
- if ($expiresAtMs < $nowMs) {
40
- $this->delete($key);
41
- return null;
42
- }
43
- }
44
- }
45
-
46
- return isset($doc['value']) ? json_decode($doc['value'], true) : null;
47
- }
48
-
49
- public function set(string $key, $value, ?int $ttl = null): void
50
- {
51
- $doc = [
52
- '_id' => $key,
53
- 'value' => json_encode($value),
54
- ];
55
-
56
- if ($ttl !== null && $ttl > 0) {
57
- $doc['expiresAt'] = new \MongoDB\BSON\UTCDateTime((time() + $ttl) * 1000);
58
- }
59
-
60
- $this->collection->replaceOne(
61
- ['_id' => $key],
62
- $doc,
63
- ['upsert' => true]
64
- );
65
- }
66
-
67
- public function has(string $key): bool
68
- {
69
- $doc = $this->collection->findOne(
70
- ['_id' => $key],
71
- ['projection' => ['expiresAt' => 1]]
72
- );
73
-
74
- if (!$doc) {
75
- return false;
76
- }
77
-
78
- if (isset($doc['expiresAt']) && $doc['expiresAt'] instanceof \MongoDB\BSON\UTCDateTime) {
79
- $expiresAtMs = $doc['expiresAt']->toDateTime()->getTimestamp() * 1000;
80
- $nowMs = (int)(microtime(true) * 1000);
81
- if ($expiresAtMs < $nowMs) {
82
- $this->delete($key);
83
- return false;
84
- }
85
- }
86
-
87
- return true;
88
- }
89
-
90
- public function delete(string $key): void
91
- {
92
- $this->collection->deleteOne(['_id' => $key]);
93
- }
94
-
95
- /**
96
- * Automatise la configuration de l'index TTL nécessaire dans MongoDB.
97
- */
98
- public function init(): void
99
- {
100
- $this->collection->createIndex(
101
- ['expiresAt' => 1],
102
- ['expireAfterSeconds' => 0]
103
- );
104
- }
1
+ <?php
2
+
3
+ declare(strict_types=1);
4
+
5
+ namespace Anonympins\Fingerprint\Store;
6
+
7
+ /**
8
+ * Adaptateur de stockage MongoDB pour le moteur Fingerprint.
9
+ * Utilise la bibliothèque officielle mongodb/mongodb.
10
+ */
11
+ class MongoDbStore implements IStore
12
+ {
13
+ /**
14
+ * @var \MongoDB\Collection
15
+ */
16
+ private $collection;
17
+
18
+ /**
19
+ * @var InMemoryStore
20
+ */
21
+ private InMemoryStore $fallbackStore;
22
+
23
+ /**
24
+ * @var bool
25
+ */
26
+ private bool $isDown = false;
27
+
28
+ /**
29
+ * @var float
30
+ */
31
+ private float $lastReconnectAttempt = 0.0;
32
+
33
+ /**
34
+ * @param \MongoDB\Collection $collection Collection dédiée au stockage des empreintes
35
+ */
36
+ public function __construct($collection)
37
+ {
38
+ $this->collection = $collection;
39
+ $this->fallbackStore = new InMemoryStore();
40
+ }
41
+
42
+ private function checkConnection(): void
43
+ {
44
+ if (!$this->isDown) {
45
+ return;
46
+ }
47
+
48
+ $now = microtime(true);
49
+ if ($now - $this->lastReconnectAttempt > 5.0) {
50
+ $this->lastReconnectAttempt = $now;
51
+ try {
52
+ $this->collection->findOne([], ['projection' => ['_id' => 1]]);
53
+ $this->isDown = false;
54
+ } catch (\Throwable $e) {
55
+ $this->isDown = true;
56
+ }
57
+ }
58
+ }
59
+
60
+ public function get(string $key)
61
+ {
62
+ $this->checkConnection();
63
+ if ($this->isDown) {
64
+ return $this->fallbackStore->get($key);
65
+ }
66
+ try {
67
+ $doc = $this->collection->findOne(['_id' => $key]);
68
+ if (!$doc) {
69
+ return null;
70
+ }
71
+
72
+ // Vérification d'expiration active pour bypasser le délai de 60s du démon de MongoDB
73
+ if (isset($doc['expiresAt'])) {
74
+ $expiresAt = $doc['expiresAt'];
75
+ if ($expiresAt instanceof \MongoDB\BSON\UTCDateTime) {
76
+ $expiresAtMs = $expiresAt->toDateTime()->getTimestamp() * 1000;
77
+ $nowMs = (int)(microtime(true) * 1000);
78
+ if ($expiresAtMs < $nowMs) {
79
+ $this->delete($key);
80
+ return null;
81
+ }
82
+ }
83
+ }
84
+
85
+ return isset($doc['value']) ? json_decode($doc['value'], true) : null;
86
+ } catch (\Throwable $e) {
87
+ $this->isDown = true;
88
+ $this->lastReconnectAttempt = microtime(true);
89
+ return $this->fallbackStore->get($key);
90
+ }
91
+ }
92
+
93
+ public function set(string $key, $value, ?int $ttl = null): void
94
+ {
95
+ $this->checkConnection();
96
+ if ($this->isDown) {
97
+ $this->fallbackStore->set($key, $value, $ttl);
98
+ return;
99
+ }
100
+ try {
101
+ $doc = [
102
+ '_id' => $key,
103
+ 'value' => json_encode($value),
104
+ ];
105
+
106
+ if ($ttl !== null && $ttl > 0) {
107
+ $doc['expiresAt'] = new \MongoDB\BSON\UTCDateTime((time() + $ttl) * 1000);
108
+ }
109
+
110
+ $this->collection->replaceOne(
111
+ ['_id' => $key],
112
+ $doc,
113
+ ['upsert' => true]
114
+ );
115
+ } catch (\Throwable $e) {
116
+ $this->isDown = true;
117
+ $this->lastReconnectAttempt = microtime(true);
118
+ $this->fallbackStore->set($key, $value, $ttl);
119
+ }
120
+ }
121
+
122
+ public function has(string $key): bool
123
+ {
124
+ $this->checkConnection();
125
+ if ($this->isDown) {
126
+ return $this->fallbackStore->has($key);
127
+ }
128
+ try {
129
+ $doc = $this->collection->findOne(
130
+ ['_id' => $key],
131
+ ['projection' => ['expiresAt' => 1]]
132
+ );
133
+
134
+ if (!$doc) {
135
+ return false;
136
+ }
137
+
138
+ if (isset($doc['expiresAt']) && $doc['expiresAt'] instanceof \MongoDB\BSON\UTCDateTime) {
139
+ $expiresAtMs = $doc['expiresAt']->toDateTime()->getTimestamp() * 1000;
140
+ $nowMs = (int)(microtime(true) * 1000);
141
+ if ($expiresAtMs < $nowMs) {
142
+ $this->delete($key);
143
+ return false;
144
+ }
145
+ }
146
+
147
+ return true;
148
+ } catch (\Throwable $e) {
149
+ $this->isDown = true;
150
+ $this->lastReconnectAttempt = microtime(true);
151
+ return $this->fallbackStore->has($key);
152
+ }
153
+ }
154
+
155
+ public function delete(string $key): void
156
+ {
157
+ $this->fallbackStore->delete($key);
158
+ $this->checkConnection();
159
+ if ($this->isDown) {
160
+ return;
161
+ }
162
+ try {
163
+ $this->collection->deleteOne(['_id' => $key]);
164
+ } catch (\Throwable $e) {
165
+ $this->isDown = true;
166
+ $this->lastReconnectAttempt = microtime(true);
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Automatise la configuration de l'index TTL nécessaire dans MongoDB.
172
+ */
173
+ public function init(): void
174
+ {
175
+ try {
176
+ $this->collection->createIndex(
177
+ ['expiresAt' => 1],
178
+ ['expireAfterSeconds' => 0]
179
+ );
180
+ } catch (\Throwable $e) {
181
+ $this->isDown = true;
182
+ $this->lastReconnectAttempt = microtime(true);
183
+ }
184
+ }
105
185
  }
@@ -15,40 +15,120 @@ class RedisStore implements IStore
15
15
  */
16
16
  private $redis;
17
17
 
18
+ /**
19
+ * @var InMemoryStore
20
+ */
21
+ private InMemoryStore $fallbackStore;
22
+
23
+ /**
24
+ * @var bool
25
+ */
26
+ private bool $isDown = false;
27
+
28
+ /**
29
+ * @var float
30
+ */
31
+ private float $lastReconnectAttempt = 0.0;
32
+
18
33
  /**
19
34
  * @param mixed $redis Client Redis déjà configuré et connecté
20
35
  */
21
36
  public function __construct($redis)
22
37
  {
23
38
  $this->redis = $redis;
39
+ $this->fallbackStore = new InMemoryStore();
40
+ }
41
+
42
+ private function checkConnection(): void
43
+ {
44
+ if (!$this->isDown) {
45
+ return;
46
+ }
47
+
48
+ $now = microtime(true);
49
+ // Tentative de reconnexion toutes les 5 secondes
50
+ if ($now - $this->lastReconnectAttempt > 5.0) {
51
+ $this->lastReconnectAttempt = $now;
52
+ try {
53
+ if (method_exists($this->redis, 'ping')) {
54
+ $this->redis->ping();
55
+ } else {
56
+ $this->redis->exists('connection_test');
57
+ }
58
+ $this->isDown = false;
59
+ } catch (\Throwable $e) {
60
+ $this->isDown = true;
61
+ }
62
+ }
24
63
  }
25
64
 
26
65
  public function get(string $key)
27
66
  {
28
- $value = $this->redis->get($key);
29
- if ($value === false || $value === null) {
30
- return null;
67
+ $this->checkConnection();
68
+ if ($this->isDown) {
69
+ return $this->fallbackStore->get($key);
70
+ }
71
+ try {
72
+ $value = $this->redis->get($key);
73
+ if ($value === false || $value === null) {
74
+ return null;
75
+ }
76
+ return json_decode($value, true);
77
+ } catch (\Throwable $e) {
78
+ $this->isDown = true;
79
+ $this->lastReconnectAttempt = microtime(true);
80
+ return $this->fallbackStore->get($key);
31
81
  }
32
- return json_decode($value, true);
33
82
  }
34
83
 
35
84
  public function set(string $key, $value, ?int $ttl = null): void
36
85
  {
37
- $stringValue = json_encode($value);
38
- if ($ttl !== null && $ttl > 0) {
39
- $this->redis->setex($key, $ttl, $stringValue);
40
- } else {
41
- $this->redis->set($key, $stringValue);
86
+ $this->checkConnection();
87
+ if ($this->isDown) {
88
+ $this->fallbackStore->set($key, $value, $ttl);
89
+ return;
90
+ }
91
+ try {
92
+ $stringValue = json_encode($value);
93
+ if ($ttl !== null && $ttl > 0) {
94
+ $this->redis->setex($key, $ttl, $stringValue);
95
+ } else {
96
+ $this->redis->set($key, $stringValue);
97
+ }
98
+ } catch (\Throwable $e) {
99
+ $this->isDown = true;
100
+ $this->lastReconnectAttempt = microtime(true);
101
+ $this->fallbackStore->set($key, $value, $ttl);
42
102
  }
43
103
  }
44
104
 
45
105
  public function has(string $key): bool
46
106
  {
47
- return (bool)$this->redis->exists($key);
107
+ $this->checkConnection();
108
+ if ($this->isDown) {
109
+ return $this->fallbackStore->has($key);
110
+ }
111
+ try {
112
+ return (bool)$this->redis->exists($key);
113
+ } catch (\Throwable $e) {
114
+ $this->isDown = true;
115
+ $this->lastReconnectAttempt = microtime(true);
116
+ return $this->fallbackStore->has($key);
117
+ }
48
118
  }
49
119
 
50
120
  public function delete(string $key): void
51
121
  {
52
- $this->redis->del($key);
122
+ $this->fallbackStore->delete($key);
123
+ $this->checkConnection();
124
+ if ($this->isDown) {
125
+ return;
126
+ }
127
+ try {
128
+ $this->redis->del($key);
129
+ } catch (\Throwable $e) {
130
+ $this->isDown = true;
131
+ $this->lastReconnectAttempt = microtime(true);
132
+ }
53
133
  }
54
134
  }