@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.
- package/CHANGELOG.md +18 -0
- package/package.json +1 -1
- package/src/js/fingerprint.client.js +1271 -1191
- package/src/js/fingerprint.js +202 -108
- package/src/js/fingerprint.utils.js +213 -213
- package/src/js/library.js +24 -8
- package/src/js/mongodb-store.js +165 -79
- package/src/js/pow.solver.inline.js +500 -14
- package/src/js/pow.solver.js +323 -14
- package/src/js/problem-manager.js +1 -1
- package/src/js/redis-store.js +114 -42
- package/src/js/tests/dns-circuit-breaker.test.js +55 -0
- package/src/js/tests/fingerprint.client.init.test.js +143 -143
- package/src/js/tests/fingerprint.client.test.js +128 -128
- package/src/js/tests/fingerprint.test.js +32 -2
- package/src/js/tests/ip-reputation.test.js +1 -1
- package/src/js/tests/pow.solver.test.js +5 -2
- package/src/js/tests/usefulWorkSolver.test.js +162 -0
- package/src/php/Challenge/ChallengeUtils.php +21 -8
- package/src/php/FingerprintClient.php +22 -5
- package/src/php/FingerprintEngine.php +232 -56
- package/src/php/Optimization/Optimization.php +23 -16
- package/src/php/Optimization/OptimizationOperators.php +27 -0
- package/src/php/ProblemManager.php +1 -1
- package/src/php/Store/MongoDbStore.php +184 -104
- package/src/php/Store/RedisStore.php +91 -11
- package/src/php/Tests/ChallengeUtilsTest.php +285 -285
- package/src/php/Tests/DnsCircuitBreakerTest.php +106 -0
- package/src/php/Tests/IpReputationTest.php +1 -1
- package/src/php/Tests/PowTest.php +1 -1
- package/src/php/Tests/RequestUtilsTest.php +29 -0
- package/src/php/Tests/TLSClientHelloParserTest.php +177 -117
- package/src/php/Utils/BigInt.php +202 -202
- package/src/php/Utils/RequestUtils.php +74 -21
- 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
|
-
* @
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
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
|
-
$
|
|
29
|
-
if ($
|
|
30
|
-
return
|
|
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
|
-
$
|
|
38
|
-
if ($
|
|
39
|
-
$this->
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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->
|
|
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
|
}
|