@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
package/src/php/Utils/BigInt.php
CHANGED
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
<?php
|
|
2
|
-
|
|
3
|
-
declare(strict_types=1);
|
|
4
|
-
|
|
5
|
-
namespace Anonympins\Fingerprint\Utils;
|
|
6
|
-
|
|
7
|
-
class BigInt
|
|
8
|
-
{
|
|
9
|
-
private static ?bool $useGmp = null;
|
|
10
|
-
/** @var \GMP|string */
|
|
11
|
-
private $value;
|
|
12
|
-
|
|
13
|
-
private static function useGmp(): bool
|
|
14
|
-
{
|
|
15
|
-
if (self::$useGmp === null) {
|
|
16
|
-
self::$useGmp = extension_loaded('gmp');
|
|
17
|
-
}
|
|
18
|
-
return self::$useGmp;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param \GMP|string|int $number Le nombre initial.
|
|
23
|
-
*/
|
|
24
|
-
public function __construct($number)
|
|
25
|
-
{
|
|
26
|
-
if (self::useGmp()) {
|
|
27
|
-
if ($number instanceof \GMP) {
|
|
28
|
-
$this->value = $number;
|
|
29
|
-
} else {
|
|
30
|
-
$str = (string)$number;
|
|
31
|
-
if (($dot = strpos($str, '.')) !== false) {
|
|
32
|
-
$str = substr($str, 0, $dot);
|
|
33
|
-
}
|
|
34
|
-
$this->value = gmp_init($str);
|
|
35
|
-
}
|
|
36
|
-
} else {
|
|
37
|
-
if ($number instanceof BigInt) {
|
|
38
|
-
$this->value = $number->value;
|
|
39
|
-
} else {
|
|
40
|
-
$str = (string)$number;
|
|
41
|
-
if (($dot = strpos($str, '.')) !== false) {
|
|
42
|
-
$str = substr($str, 0, $dot);
|
|
43
|
-
}
|
|
44
|
-
$this->value = $str;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Crée une instance à partir d'une chaîne hexadécimale.
|
|
51
|
-
*/
|
|
52
|
-
public static function fromHex(string $hex): BigInt
|
|
53
|
-
{
|
|
54
|
-
$hex = trim(strtolower($hex));
|
|
55
|
-
if (substr($hex, 0, 2) === '0x') {
|
|
56
|
-
$hex = substr($hex, 2);
|
|
57
|
-
}
|
|
58
|
-
if (self::useGmp()) {
|
|
59
|
-
return new self(gmp_init($hex, 16));
|
|
60
|
-
} else {
|
|
61
|
-
$dec = '0';
|
|
62
|
-
$len = strlen($hex);
|
|
63
|
-
for ($i = 0; $i < $len; $i++) {
|
|
64
|
-
$dec = bcadd(bcmul($dec, '16', 0), (string)hexdec($hex[$i]), 0);
|
|
65
|
-
}
|
|
66
|
-
return new self($dec);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Compare cette instance avec une autre.
|
|
72
|
-
* @return int < 0 si this < other, 0 si this == other, > 0 si this > other.
|
|
73
|
-
*/
|
|
74
|
-
public function compareTo(BigInt $other): int
|
|
75
|
-
{
|
|
76
|
-
if (self::useGmp()) {
|
|
77
|
-
return gmp_cmp($this->value, $other->value);
|
|
78
|
-
} else {
|
|
79
|
-
return bccomp($this->value, $other->value, 0);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Effectue un décalage de bits vers la gauche (<<).
|
|
85
|
-
*/
|
|
86
|
-
public function shiftLeft(int $bits): BigInt
|
|
87
|
-
{
|
|
88
|
-
if (self::useGmp()) {
|
|
89
|
-
return new self(gmp_mul($this->value, gmp_pow("2", $bits)));
|
|
90
|
-
} else {
|
|
91
|
-
return new self(bcmul($this->value, bcpow("2", (string)$bits, 0), 0));
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Effectue un décalage de bits vers la droite (>>).
|
|
97
|
-
*/
|
|
98
|
-
public function shiftRight(int $bits): BigInt
|
|
99
|
-
{
|
|
100
|
-
if (self::useGmp()) {
|
|
101
|
-
return new self(gmp_div_q($this->value, gmp_pow("2", $bits)));
|
|
102
|
-
} else {
|
|
103
|
-
return new self(bcdiv($this->value, bcpow("2", (string)$bits, 0), 0));
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Retourne la représentation en chaîne de caractères.
|
|
109
|
-
*/
|
|
110
|
-
public function __toString(): string
|
|
111
|
-
{
|
|
112
|
-
if (self::useGmp()) {
|
|
113
|
-
return gmp_strval($this->value);
|
|
114
|
-
} else {
|
|
115
|
-
return $this->value;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Retourne la représentation hexadécimale.
|
|
121
|
-
*/
|
|
122
|
-
public function toHex(): string
|
|
123
|
-
{
|
|
124
|
-
if (self::useGmp()) {
|
|
125
|
-
return gmp_strval($this->value, 16);
|
|
126
|
-
} else {
|
|
127
|
-
$hex = '';
|
|
128
|
-
$dec = $this->value;
|
|
129
|
-
while (bccomp($dec, '0', 0) > 0) {
|
|
130
|
-
$rem = bcmod($dec, '16', 0);
|
|
131
|
-
$hex = dechex((int)$rem) . $hex;
|
|
132
|
-
$dec = bcdiv($dec, '16', 0);
|
|
133
|
-
}
|
|
134
|
-
return $hex ?: '0';
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Crée une instance à partir d'une puissance de 2.
|
|
140
|
-
*/
|
|
141
|
-
public static function pow(int $base, int $exp): BigInt
|
|
142
|
-
{
|
|
143
|
-
if (self::useGmp()) {
|
|
144
|
-
return new self(gmp_pow((string)$base, $exp));
|
|
145
|
-
} else {
|
|
146
|
-
return new self(bcpow((string)$base, (string)$exp, 0));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Soustrait un autre BigInt.
|
|
152
|
-
*/
|
|
153
|
-
public function sub(BigInt $other): BigInt
|
|
154
|
-
{
|
|
155
|
-
if (self::useGmp()) {
|
|
156
|
-
return new self(gmp_sub($this->value, $other->value));
|
|
157
|
-
} else {
|
|
158
|
-
return new self(bcsub($this->value, $other->value, 0));
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Computes ($this ^ $exponent) % $modulus
|
|
164
|
-
*/
|
|
165
|
-
public function modPow(BigInt $exponent, BigInt $modulus): BigInt
|
|
166
|
-
{
|
|
167
|
-
if (self::useGmp()) {
|
|
168
|
-
return new self(gmp_powm($this->value, $exponent->value, $modulus->value));
|
|
169
|
-
} else {
|
|
170
|
-
return new self(bcpowmod((string)$this->value, (string)$exponent->value, (string)$modulus->value, 0));
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Computes $this % $modulus
|
|
176
|
-
*/
|
|
177
|
-
public function mod(BigInt $modulus): BigInt
|
|
178
|
-
{
|
|
179
|
-
if (self::useGmp()) {
|
|
180
|
-
return new self(gmp_mod($this->value, $modulus->value));
|
|
181
|
-
} else {
|
|
182
|
-
return new self(bcmod((string)$this->value, (string)$modulus->value, 0));
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
public function add(BigInt $other): BigInt
|
|
187
|
-
{
|
|
188
|
-
if (self::useGmp()) {
|
|
189
|
-
return new self(gmp_add($this->value, $other->value));
|
|
190
|
-
} else {
|
|
191
|
-
return new self(bcadd((string)$this->value, (string)$other->value, 0));
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
public function mul(BigInt $other): BigInt
|
|
196
|
-
{
|
|
197
|
-
if (self::useGmp()) {
|
|
198
|
-
return new self(gmp_mul($this->value, $other->value));
|
|
199
|
-
} else {
|
|
200
|
-
return new self(bcmul((string)$this->value, (string)$other->value, 0));
|
|
201
|
-
}
|
|
202
|
-
}
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
declare(strict_types=1);
|
|
4
|
+
|
|
5
|
+
namespace Anonympins\Fingerprint\Utils;
|
|
6
|
+
|
|
7
|
+
class BigInt
|
|
8
|
+
{
|
|
9
|
+
private static ?bool $useGmp = null;
|
|
10
|
+
/** @var \GMP|string */
|
|
11
|
+
private $value;
|
|
12
|
+
|
|
13
|
+
private static function useGmp(): bool
|
|
14
|
+
{
|
|
15
|
+
if (self::$useGmp === null) {
|
|
16
|
+
self::$useGmp = extension_loaded('gmp');
|
|
17
|
+
}
|
|
18
|
+
return self::$useGmp;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param \GMP|string|int $number Le nombre initial.
|
|
23
|
+
*/
|
|
24
|
+
public function __construct($number)
|
|
25
|
+
{
|
|
26
|
+
if (self::useGmp()) {
|
|
27
|
+
if ($number instanceof \GMP) {
|
|
28
|
+
$this->value = $number;
|
|
29
|
+
} else {
|
|
30
|
+
$str = (string)$number;
|
|
31
|
+
if (($dot = strpos($str, '.')) !== false) {
|
|
32
|
+
$str = substr($str, 0, $dot);
|
|
33
|
+
}
|
|
34
|
+
$this->value = gmp_init($str);
|
|
35
|
+
}
|
|
36
|
+
} else {
|
|
37
|
+
if ($number instanceof BigInt) {
|
|
38
|
+
$this->value = $number->value;
|
|
39
|
+
} else {
|
|
40
|
+
$str = (string)$number;
|
|
41
|
+
if (($dot = strpos($str, '.')) !== false) {
|
|
42
|
+
$str = substr($str, 0, $dot);
|
|
43
|
+
}
|
|
44
|
+
$this->value = $str;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Crée une instance à partir d'une chaîne hexadécimale.
|
|
51
|
+
*/
|
|
52
|
+
public static function fromHex(string $hex): BigInt
|
|
53
|
+
{
|
|
54
|
+
$hex = trim(strtolower($hex));
|
|
55
|
+
if (substr($hex, 0, 2) === '0x') {
|
|
56
|
+
$hex = substr($hex, 2);
|
|
57
|
+
}
|
|
58
|
+
if (self::useGmp()) {
|
|
59
|
+
return new self(gmp_init($hex, 16));
|
|
60
|
+
} else {
|
|
61
|
+
$dec = '0';
|
|
62
|
+
$len = strlen($hex);
|
|
63
|
+
for ($i = 0; $i < $len; $i++) {
|
|
64
|
+
$dec = bcadd(bcmul($dec, '16', 0), (string)hexdec($hex[$i]), 0);
|
|
65
|
+
}
|
|
66
|
+
return new self($dec);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Compare cette instance avec une autre.
|
|
72
|
+
* @return int < 0 si this < other, 0 si this == other, > 0 si this > other.
|
|
73
|
+
*/
|
|
74
|
+
public function compareTo(BigInt $other): int
|
|
75
|
+
{
|
|
76
|
+
if (self::useGmp()) {
|
|
77
|
+
return gmp_cmp($this->value, $other->value);
|
|
78
|
+
} else {
|
|
79
|
+
return bccomp($this->value, $other->value, 0);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Effectue un décalage de bits vers la gauche (<<).
|
|
85
|
+
*/
|
|
86
|
+
public function shiftLeft(int $bits): BigInt
|
|
87
|
+
{
|
|
88
|
+
if (self::useGmp()) {
|
|
89
|
+
return new self(gmp_mul($this->value, gmp_pow("2", $bits)));
|
|
90
|
+
} else {
|
|
91
|
+
return new self(bcmul($this->value, bcpow("2", (string)$bits, 0), 0));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Effectue un décalage de bits vers la droite (>>).
|
|
97
|
+
*/
|
|
98
|
+
public function shiftRight(int $bits): BigInt
|
|
99
|
+
{
|
|
100
|
+
if (self::useGmp()) {
|
|
101
|
+
return new self(gmp_div_q($this->value, gmp_pow("2", $bits)));
|
|
102
|
+
} else {
|
|
103
|
+
return new self(bcdiv($this->value, bcpow("2", (string)$bits, 0), 0));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Retourne la représentation en chaîne de caractères.
|
|
109
|
+
*/
|
|
110
|
+
public function __toString(): string
|
|
111
|
+
{
|
|
112
|
+
if (self::useGmp()) {
|
|
113
|
+
return gmp_strval($this->value);
|
|
114
|
+
} else {
|
|
115
|
+
return $this->value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Retourne la représentation hexadécimale.
|
|
121
|
+
*/
|
|
122
|
+
public function toHex(): string
|
|
123
|
+
{
|
|
124
|
+
if (self::useGmp()) {
|
|
125
|
+
return gmp_strval($this->value, 16);
|
|
126
|
+
} else {
|
|
127
|
+
$hex = '';
|
|
128
|
+
$dec = $this->value;
|
|
129
|
+
while (bccomp($dec, '0', 0) > 0) {
|
|
130
|
+
$rem = bcmod($dec, '16', 0);
|
|
131
|
+
$hex = dechex((int)$rem) . $hex;
|
|
132
|
+
$dec = bcdiv($dec, '16', 0);
|
|
133
|
+
}
|
|
134
|
+
return $hex ?: '0';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Crée une instance à partir d'une puissance de 2.
|
|
140
|
+
*/
|
|
141
|
+
public static function pow(int $base, int $exp): BigInt
|
|
142
|
+
{
|
|
143
|
+
if (self::useGmp()) {
|
|
144
|
+
return new self(gmp_pow((string)$base, $exp));
|
|
145
|
+
} else {
|
|
146
|
+
return new self(bcpow((string)$base, (string)$exp, 0));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Soustrait un autre BigInt.
|
|
152
|
+
*/
|
|
153
|
+
public function sub(BigInt $other): BigInt
|
|
154
|
+
{
|
|
155
|
+
if (self::useGmp()) {
|
|
156
|
+
return new self(gmp_sub($this->value, $other->value));
|
|
157
|
+
} else {
|
|
158
|
+
return new self(bcsub($this->value, $other->value, 0));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Computes ($this ^ $exponent) % $modulus
|
|
164
|
+
*/
|
|
165
|
+
public function modPow(BigInt $exponent, BigInt $modulus): BigInt
|
|
166
|
+
{
|
|
167
|
+
if (self::useGmp()) {
|
|
168
|
+
return new self(gmp_powm($this->value, $exponent->value, $modulus->value));
|
|
169
|
+
} else {
|
|
170
|
+
return new self(bcpowmod((string)$this->value, (string)$exponent->value, (string)$modulus->value, 0));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Computes $this % $modulus
|
|
176
|
+
*/
|
|
177
|
+
public function mod(BigInt $modulus): BigInt
|
|
178
|
+
{
|
|
179
|
+
if (self::useGmp()) {
|
|
180
|
+
return new self(gmp_mod($this->value, $modulus->value));
|
|
181
|
+
} else {
|
|
182
|
+
return new self(bcmod((string)$this->value, (string)$modulus->value, 0));
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public function add(BigInt $other): BigInt
|
|
187
|
+
{
|
|
188
|
+
if (self::useGmp()) {
|
|
189
|
+
return new self(gmp_add($this->value, $other->value));
|
|
190
|
+
} else {
|
|
191
|
+
return new self(bcadd((string)$this->value, (string)$other->value, 0));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public function mul(BigInt $other): BigInt
|
|
196
|
+
{
|
|
197
|
+
if (self::useGmp()) {
|
|
198
|
+
return new self(gmp_mul($this->value, $other->value));
|
|
199
|
+
} else {
|
|
200
|
+
return new self(bcmul((string)$this->value, (string)$other->value, 0));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
203
|
}
|
|
@@ -1175,14 +1175,39 @@ class RequestUtils
|
|
|
1175
1175
|
$networkBinary = $ipBinary & $mask;
|
|
1176
1176
|
return inet_ntop($networkBinary) . '/' . $ipv4Prefix;
|
|
1177
1177
|
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
1178
|
-
$
|
|
1179
|
-
if ($
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1178
|
+
$normalized = trim(strtolower($ip));
|
|
1179
|
+
if (str_contains($normalized, '::')) {
|
|
1180
|
+
$parts = explode('::', $normalized, 2);
|
|
1181
|
+
$left = $parts[0] !== '' ? explode(':', $parts[0]) : [];
|
|
1182
|
+
$right = $parts[1] !== '' ? explode(':', $parts[1]) : [];
|
|
1183
|
+
$missing = 8 - (count($left) + count($right));
|
|
1184
|
+
$middle = array_fill(0, $missing, '0000');
|
|
1185
|
+
$groups = array_merge($left, $middle, $right);
|
|
1186
|
+
} else {
|
|
1187
|
+
$groups = explode(':', $normalized);
|
|
1188
|
+
if (count($groups) !== 8) {
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
foreach ($groups as $i => &$g) {
|
|
1193
|
+
$val = hexdec($g);
|
|
1194
|
+
$g = str_pad(dechex($val), 4, '0', STR_PAD_LEFT);
|
|
1195
|
+
}
|
|
1196
|
+
unset($g);
|
|
1197
|
+
for ($i = 0; $i < 8; $i++) {
|
|
1198
|
+
$startBit = $i * 16;
|
|
1199
|
+
if ($ipv6Prefix >= ($i + 1) * 16) {
|
|
1200
|
+
continue;
|
|
1201
|
+
} elseif ($ipv6Prefix <= $startBit) {
|
|
1202
|
+
$groups[$i] = '0000';
|
|
1203
|
+
} else {
|
|
1204
|
+
$bitsToKeep = $ipv6Prefix - $startBit;
|
|
1205
|
+
$val = hexdec($groups[$i]);
|
|
1206
|
+
$mask = (0xffff << (16 - $bitsToKeep)) & 0xffff;
|
|
1207
|
+
$groups[$i] = str_pad(dechex($val & $mask), 4, '0', STR_PAD_LEFT);
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
return implode(':', $groups) . '/' . $ipv6Prefix;
|
|
1186
1211
|
}
|
|
1187
1212
|
return null;
|
|
1188
1213
|
}
|
|
@@ -1382,29 +1407,62 @@ class RequestUtils
|
|
|
1382
1407
|
return [];
|
|
1383
1408
|
}
|
|
1384
1409
|
|
|
1385
|
-
$
|
|
1410
|
+
$suspiciousLogs = [];
|
|
1411
|
+
$passedLogs = [];
|
|
1386
1412
|
$deviceCounts = [];
|
|
1387
1413
|
$ipCounts = [];
|
|
1388
1414
|
$subnetCounts = [];
|
|
1415
|
+
$hardwareClusterCounts = [];
|
|
1416
|
+
$hwClusterCache = [];
|
|
1389
1417
|
|
|
1390
1418
|
$totalCount = count($trafficData);
|
|
1391
1419
|
$maxLogsPerDevice = max(3, (int)floor($totalCount * 0.02)); // Max 2% contribution per device
|
|
1392
1420
|
$maxLogsPerIp = max(3, (int)floor($totalCount * 0.02)); // Max 2% par adresse IP individuelle
|
|
1393
1421
|
$maxLogsPerSubnet = max(5, (int)floor($totalCount * 0.05)); // Max 5% par bloc réseau (anti-proxy-rotation)
|
|
1422
|
+
$maxLogsPerHardwareCluster = max(3, (int)floor($totalCount * 0.02)); // Max 2% par cluster matériel stable
|
|
1423
|
+
|
|
1424
|
+
$getHardwareCluster = function (array $log) use (&$hwClusterCache): string {
|
|
1425
|
+
$fp = $log['deviceHash'] ?? $log['fingerprint'] ?? $log['deviceFingerprint'] ?? '';
|
|
1426
|
+
if (!empty($fp) && is_string($fp)) {
|
|
1427
|
+
if (isset($hwClusterCache[$fp])) {
|
|
1428
|
+
return $hwClusterCache[$fp];
|
|
1429
|
+
}
|
|
1430
|
+
$parts = explode('|', $fp);
|
|
1431
|
+
$hwComponents = [];
|
|
1432
|
+
foreach ($parts as $part) {
|
|
1433
|
+
$pair = explode(':', $part, 2);
|
|
1434
|
+
if (count($pair) === 2 && in_array($pair[0], ['gpu', 'cvs', 'hw'], true)) {
|
|
1435
|
+
$hwComponents[] = $part;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
if (!empty($hwComponents)) {
|
|
1439
|
+
sort($hwComponents);
|
|
1440
|
+
$result = implode('|', $hwComponents);
|
|
1441
|
+
} else {
|
|
1442
|
+
$result = $log['deviceId'] ?? 'anonymous-cluster';
|
|
1443
|
+
}
|
|
1444
|
+
$hwClusterCache[$fp] = $result;
|
|
1445
|
+
return $result;
|
|
1446
|
+
}
|
|
1447
|
+
return $log['deviceId'] ?? 'anonymous-cluster';
|
|
1448
|
+
};
|
|
1394
1449
|
|
|
1395
1450
|
foreach ($trafficData as $log) {
|
|
1396
1451
|
$devId = $log['deviceId'] ?? 'anonymous';
|
|
1397
1452
|
$ip = $log['clientIp'] ?? $log['ip'] ?? 'unknown';
|
|
1398
1453
|
$subnet = self::getIpSubnet($ip) ?? 'unknown-subnet';
|
|
1454
|
+
$hwCluster = $getHardwareCluster($log);
|
|
1399
1455
|
|
|
1400
1456
|
$currentDeviceCount = $deviceCounts[$devId] ?? 0;
|
|
1401
1457
|
$currentIpCount = $ipCounts[$ip] ?? 0;
|
|
1402
1458
|
$currentSubnetCount = $subnetCounts[$subnet] ?? 0;
|
|
1459
|
+
$currentHwClusterCount = $hardwareClusterCounts[$hwCluster] ?? 0;
|
|
1403
1460
|
|
|
1404
1461
|
if (
|
|
1405
1462
|
$currentDeviceCount < $maxLogsPerDevice &&
|
|
1406
1463
|
($ip === 'unknown' || $currentIpCount < $maxLogsPerIp) &&
|
|
1407
|
-
($subnet === 'unknown-subnet' || $currentSubnetCount < $maxLogsPerSubnet)
|
|
1464
|
+
($subnet === 'unknown-subnet' || $currentSubnetCount < $maxLogsPerSubnet) &&
|
|
1465
|
+
$currentHwClusterCount < $maxLogsPerHardwareCluster
|
|
1408
1466
|
) {
|
|
1409
1467
|
$deviceCounts[$devId] = $currentDeviceCount + 1;
|
|
1410
1468
|
if ($ip !== 'unknown') {
|
|
@@ -1413,17 +1471,12 @@ class RequestUtils
|
|
|
1413
1471
|
if ($subnet !== 'unknown-subnet') {
|
|
1414
1472
|
$subnetCounts[$subnet] = $currentSubnetCount + 1;
|
|
1415
1473
|
}
|
|
1416
|
-
$
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
foreach ($tempSanitized as $log) {
|
|
1423
|
-
if (($log['type'] ?? '') === 'request_passed') {
|
|
1424
|
-
$passedLogs[] = $log;
|
|
1425
|
-
} else {
|
|
1426
|
-
$suspiciousLogs[] = $log;
|
|
1474
|
+
$hardwareClusterCounts[$hwCluster] = $currentHwClusterCount + 1;
|
|
1475
|
+
if (($log['type'] ?? '') === 'request_passed') {
|
|
1476
|
+
$passedLogs[] = $log;
|
|
1477
|
+
} else {
|
|
1478
|
+
$suspiciousLogs[] = $log;
|
|
1479
|
+
}
|
|
1427
1480
|
}
|
|
1428
1481
|
}
|
|
1429
1482
|
|