@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
@@ -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 Initial number.
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
+ * Creates an instance from a hexadecimal string.
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
+ * Compares this instance with another.
72
+ * @return int < 0 if this < other, 0 if this == other, > 0 if 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
+ * Performs bitwise left shift (<<).
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
+ * Performs bitwise right shift (>>).
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
+ * Returns the string representation.
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
+ * Returns the hexadecimal representation.
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
+ * Creates an instance from a power of two.
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
+ * Subtracts another 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
  }
@@ -5,18 +5,18 @@ declare(strict_types=1);
5
5
  namespace Anonympins\Fingerprint\Utils;
6
6
 
7
7
  /**
8
- * Implémentation PHP d'une liste de blocage IP/CIDR, similaire à Node.js `net.BlockList`.
8
+ * PHP implementation of an IP/CIDR blocklist, similar to Node.js `net.BlockList`.
9
9
  */
10
10
  class BlockList
11
11
  {
12
12
  /**
13
- * @var array<string> Liste des IPs ou CIDR à bloquer.
13
+ * @var array<string> List of IPs or CIDR blocks to filter.
14
14
  */
15
15
  private array $entries = [];
16
16
 
17
17
  /**
18
- * Ajoute une adresse IP ou une plage CIDR à la liste.
19
- * @param string $entry Une adresse IP (ex: '192.168.1.1') ou une plage CIDR (ex: '192.168.1.0/24').
18
+ * Adds an IP address or CIDR range to the list.
19
+ * @param string $entry An IP address (e.g. '192.168.1.1') or CIDR range (e.g. '192.168.1.0/24').
20
20
  * @return void
21
21
  */
22
22
  public function add(string $entry): void
@@ -25,20 +25,20 @@ class BlockList
25
25
  }
26
26
 
27
27
  /**
28
- * Vérifie si une adresse IP est présente dans la liste de blocage.
29
- * @param string $ip L'adresse IP à vérifier.
30
- * @return bool True si l'IP est bloquée, false sinon.
28
+ * Checks if an IP address exists in the blocklist.
29
+ * @param string $ip The IP address to verify.
30
+ * @return bool True if the IP matches, false otherwise.
31
31
  */
32
32
  public function check(string $ip): bool
33
33
  {
34
34
  foreach ($this->entries as $entry) {
35
35
  if (str_contains($entry, '/')) {
36
- // C'est une plage CIDR
36
+ // CIDR range
37
37
  if ($this->ipInCidr($ip, $entry)) {
38
38
  return true;
39
39
  }
40
40
  } else {
41
- // C'est une IP directe
41
+ // Direct IP match
42
42
  if ($ip === $entry) {
43
43
  return true;
44
44
  }
@@ -48,10 +48,10 @@ class BlockList
48
48
  }
49
49
 
50
50
  /**
51
- * Vérifie si une adresse IP se trouve dans une plage CIDR donnée.
52
- * @param string $ip L'adresse IP à vérifier.
53
- * @param string $cidr La plage CIDR (ex: '192.168.1.0/24').
54
- * @return bool True si l'IP est dans la plage, false sinon.
51
+ * Checks if an IP address belongs to a given CIDR range.
52
+ * @param string $ip The IP address to verify.
53
+ * @param string $cidr The CIDR range (e.g. '192.168.1.0/24').
54
+ * @return bool True if the IP is within the range, false otherwise.
55
55
  */
56
56
  private function ipInCidr(string $ip, string $cidr): bool
57
57
  {
@@ -5,7 +5,7 @@ declare(strict_types=1);
5
5
  namespace Anonympins\Fingerprint\Utils;
6
6
 
7
7
  /**
8
- * Un simple wrapper de logger pour passer les données à une fonction de rappel.
8
+ * A simple logger wrapper to forward data to a callback function.
9
9
  */
10
10
  class Logger
11
11
  {
@@ -14,11 +14,29 @@ class Logger
14
14
  */
15
15
  private $callback;
16
16
 
17
+ /**
18
+ * Creates a new Logger instance with the given callback.
19
+ * The callback will be invoked with a single log entry array argument
20
+ * each time `log()` is called.
21
+ *
22
+ * @param callable $callback The callback used to process log entries.
23
+ */
17
24
  public function __construct(callable $callback)
18
25
  {
19
26
  $this->callback = $callback;
20
27
  }
21
28
 
29
+ /**
30
+ * Emits a log entry by merging the provided data with a type and a
31
+ * millisecond-precision timestamp, then forwarding it to the callback.
32
+ * Note: the `$level` parameter is currently accepted but not included
33
+ * in the emitted log entry.
34
+ *
35
+ * @param string $level The log level (e.g. "info", "warning", "error").
36
+ * @param string $type The log entry type/category.
37
+ * @param array $data Additional data to include in the log entry.
38
+ * @return void
39
+ */
22
40
  public function log(string $level, string $type, array $data): void
23
41
  {
24
42
  $logEntry = array_merge($data, [
@@ -5,12 +5,12 @@ declare(strict_types=1);
5
5
  namespace Anonympins\Fingerprint\Utils;
6
6
 
7
7
  /**
8
- * Fournit des fonctions pour détecter les patterns d'injection malveillants.
8
+ * Provides utilities to detect malicious injection patterns.
9
9
  */
10
10
  class MaliciousPatterns
11
11
  {
12
12
  /**
13
- * @var array<string, string> Map des patterns malveillants regroupés par type.
13
+ * @var array<string, string> Map of malicious patterns grouped by threat category.
14
14
  */
15
15
  private const INJECTION_PATTERNS = [
16
16
  // SQL/NoSQL injections, including time-based attacks
@@ -44,10 +44,10 @@ class MaliciousPatterns
44
44
  ];
45
45
 
46
46
  /**
47
- * Vérifie si une chaîne de caractères contient des patterns d'injection connus.
48
- * @param string $str La chaîne à vérifier.
49
- * @param array<string> $typesToDetect Les types d'injections à détecter (par défaut, tous).
50
- * @return bool True si un pattern malveillant est détecté, false sinon.
47
+ * Checks whether a string matches known injection patterns.
48
+ * @param string $str The input string to inspect.
49
+ * @param array<string> $typesToDetect Specific injection categories to detect (defaults to all).
50
+ * @return bool True if a malicious pattern is detected, false otherwise.
51
51
  */
52
52
  public static function isMalicious(string $str, array $typesToDetect = []): bool
53
53
  {