@anonympins/fingerprint 0.5.2 → 0.5.5

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 (41) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +1 -1
  3. package/src/js/build-client.js +67 -67
  4. package/src/js/fingerprint.client.js +280 -38
  5. package/src/js/fingerprint.client.obfuscated.js +1 -1
  6. package/src/js/fingerprint.js +474 -163
  7. package/src/js/fingerprint.utils.js +213 -213
  8. package/src/js/library.js +24 -8
  9. package/src/js/mongodb-store.js +165 -79
  10. package/src/js/obfuscation.worker.js +23 -0
  11. package/src/js/pow.solver.inline.js +509 -14
  12. package/src/js/pow.solver.js +350 -32
  13. package/src/js/problem-manager.js +1 -1
  14. package/src/js/redis-store.js +114 -42
  15. package/src/js/tests/cross_parity.test.js +175 -0
  16. package/src/js/tests/dns-circuit-breaker.test.js +55 -0
  17. package/src/js/tests/fingerprint.client.init.test.js +143 -143
  18. package/src/js/tests/fingerprint.client.test.js +128 -128
  19. package/src/js/tests/fingerprint.test.js +57 -2
  20. package/src/js/tests/ip-reputation.test.js +1 -1
  21. package/src/js/tests/obfuscation.test.js +48 -0
  22. package/src/js/tests/pow.solver.test.js +5 -2
  23. package/src/js/tests/usefulWorkSolver.test.js +162 -0
  24. package/src/php/AutoTuner.php +42 -0
  25. package/src/php/Challenge/ChallengeUtils.php +21 -8
  26. package/src/php/FingerprintClient.php +22 -5
  27. package/src/php/FingerprintEngine.php +233 -57
  28. package/src/php/Optimization/Optimization.php +23 -16
  29. package/src/php/Optimization/OptimizationOperators.php +27 -0
  30. package/src/php/ProblemManager.php +1 -1
  31. package/src/php/Store/MongoDbStore.php +184 -104
  32. package/src/php/Store/RedisStore.php +91 -11
  33. package/src/php/Tests/ChallengeUtilsTest.php +285 -285
  34. package/src/php/Tests/DnsCircuitBreakerTest.php +106 -0
  35. package/src/php/Tests/IpReputationTest.php +1 -1
  36. package/src/php/Tests/PowTest.php +1 -1
  37. package/src/php/Tests/RequestUtilsTest.php +29 -0
  38. package/src/php/Tests/TLSClientHelloParserTest.php +177 -117
  39. package/src/php/Utils/BigInt.php +202 -202
  40. package/src/php/Utils/RequestUtils.php +74 -21
  41. package/src/php/Utils/TLSClientHelloParser.php +212 -116
@@ -1,80 +1,166 @@
1
- /**
2
- * @file Creates a store adapter for MongoDB.
3
- * This adapter uses a collection as a key-value store and leverages MongoDB's TTL indexes
4
- * for automatic expiration of documents.
5
- */
6
-
7
- /**
8
- * Creates a store adapter for a MongoDB collection.
9
- * It's recommended to pass the `db` object and let the adapter handle the collection.
10
- *
11
- * **Note:** For TTL to work, you must create a TTL index on the `expiresAt` field in your collection.
12
- * In the mongo shell, run:
13
- * `db.yourCollectionName.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 })`
14
- *
15
- * @param {import('mongodb').Db} db - An instance of a MongoDB Db object.
16
- * @param {string} [collectionName='fingerprint_store'] - The name of the collection to use.
17
- * @returns {import('./fingerprint.js').IStore} An object that complies with the IStore interface.
18
- */
19
- export function createMongoDbStore(db, collectionName = 'fingerprint_store') {
20
- const collection = db.collection(collectionName);
21
-
22
- // Custom replacer/reviver to handle Set serialization (identical to Redis/SQL stores)
23
- const replacer = (k, v) => (v instanceof Set ? Array.from(v) : v);
24
- const reviver = (k, v) => (k === 'ips' && Array.isArray(v) ? new Set(v) : v);
25
-
26
- return {
27
- async get(key) {
28
- const doc = await collection.findOne({ _id: key });
29
- if (!doc) return null;
30
-
31
- // Active expiration check to bypass eventual consistency of MongoDB's 60s TTL cleanup daemon
32
- if (doc.expiresAt && new Date(doc.expiresAt) < new Date()) {
33
- await this.delete(key);
34
- return null;
35
- }
36
-
37
- try {
38
- return JSON.parse(doc.value, reviver);
39
- } catch (e) {
40
- // Fallback for legacy un-serialized raw values
41
- return doc.value;
42
- }
43
- },
44
- async set(key, value, ttl) {
45
- const stringValue = JSON.stringify(value, replacer);
46
- const doc = {
47
- _id: key,
48
- value: stringValue,
49
- };
50
-
51
- if (ttl && ttl > 0) {
52
- // Set the expiration date for the TTL index.
53
- doc.expiresAt = new Date(Date.now() + ttl * 1000);
54
- }
55
-
56
- await collection.updateOne(
57
- { _id: key },
58
- { $set: doc },
59
- { upsert: true }
60
- );
61
- },
62
- async has(key) {
63
- const doc = await collection.findOne({ _id: key }, { projection: { expiresAt: 1 } });
64
- if (!doc) return false;
65
-
66
- if (doc.expiresAt && new Date(doc.expiresAt) < new Date()) {
67
- await this.delete(key);
68
- return false;
69
- }
70
- return true;
71
- },
72
- async delete(key) {
73
- await collection.deleteOne({ _id: key });
74
- },
75
- async init() {
76
- // Automates index configuration
77
- await collection.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 });
78
- }
79
- };
1
+ /**
2
+ * @file Creates a store adapter for MongoDB.
3
+ * This adapter uses a collection as a key-value store and leverages MongoDB's TTL indexes
4
+ * for automatic expiration of documents.
5
+ */
6
+
7
+ /**
8
+ * Creates a store adapter for a MongoDB collection.
9
+ * It's recommended to pass the `db` object and let the adapter handle the collection.
10
+ *
11
+ * **Note:** For TTL to work, you must create a TTL index on the `expiresAt` field in your collection.
12
+ * In the mongo shell, run:
13
+ * `db.yourCollectionName.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 })`
14
+ *
15
+ * @param {import('mongodb').Db} db - An instance of a MongoDB Db object.
16
+ * @param {string} [collectionName='fingerprint_store'] - The name of the collection to use.
17
+ * @returns {import('./fingerprint.js').IStore} An object that complies with the IStore interface.
18
+ */
19
+ export function createMongoDbStore(db, collectionName = 'fingerprint_store') {
20
+ const collection = db.collection(collectionName);
21
+
22
+ // Custom replacer/reviver to handle Set serialization (identical to Redis/SQL stores)
23
+ const replacer = (k, v) => (v instanceof Set ? Array.from(v) : v);
24
+ const reviver = (k, v) => (k === 'ips' && Array.isArray(v) ? new Set(v) : v);
25
+
26
+ const localStore = new Map();
27
+ const localTimeouts = new Map();
28
+ let isDown = false;
29
+ let reconnecting = false;
30
+
31
+ const triggerFallback = () => {
32
+ if (!isDown) {
33
+ isDown = true;
34
+ attemptReconnection();
35
+ }
36
+ };
37
+
38
+ const attemptReconnection = () => {
39
+ if (reconnecting) return;
40
+ reconnecting = true;
41
+ const interval = setInterval(async () => {
42
+ try {
43
+ if (db.admin) {
44
+ await db.admin().ping();
45
+ } else {
46
+ await collection.findOne({}, { projection: { _id: 1 } });
47
+ }
48
+ isDown = false;
49
+ reconnecting = false;
50
+ clearInterval(interval);
51
+ } catch (err) {
52
+ // Toujours déconnecté
53
+ }
54
+ }, 5000);
55
+ if (interval.unref) interval.unref();
56
+ };
57
+
58
+ const setLocal = (key, value, ttl) => {
59
+ localStore.set(key, value);
60
+ if (localTimeouts.has(key)) {
61
+ clearTimeout(localTimeouts.get(key));
62
+ }
63
+ if (ttl && ttl > 0) {
64
+ const timeout = setTimeout(() => {
65
+ localStore.delete(key);
66
+ localTimeouts.delete(key);
67
+ }, ttl * 1000);
68
+ if (timeout.unref) timeout.unref();
69
+ localTimeouts.set(key, timeout);
70
+ }
71
+ };
72
+
73
+ return {
74
+ async get(key) {
75
+ if (isDown) {
76
+ return localStore.get(key) || null;
77
+ }
78
+ try {
79
+ const doc = await collection.findOne({ _id: key });
80
+ if (!doc) return null;
81
+
82
+ // Active expiration check to bypass eventual consistency of MongoDB's 60s TTL cleanup daemon
83
+ if (doc.expiresAt && new Date(doc.expiresAt) < new Date()) {
84
+ await this.delete(key);
85
+ return null;
86
+ }
87
+
88
+ try {
89
+ return JSON.parse(doc.value, reviver);
90
+ } catch (e) {
91
+ // Fallback for legacy un-serialized raw values
92
+ return doc.value;
93
+ }
94
+ } catch (e) {
95
+ triggerFallback();
96
+ return localStore.get(key) || null;
97
+ }
98
+ },
99
+ async set(key, value, ttl) {
100
+ if (isDown) {
101
+ setLocal(key, value, ttl);
102
+ return;
103
+ }
104
+ try {
105
+ const stringValue = JSON.stringify(value, replacer);
106
+ const doc = {
107
+ _id: key,
108
+ value: stringValue,
109
+ };
110
+
111
+ if (ttl && ttl > 0) {
112
+ // Set the expiration date for the TTL index.
113
+ doc.expiresAt = new Date(Date.now() + ttl * 1000);
114
+ }
115
+
116
+ await collection.updateOne(
117
+ { _id: key },
118
+ { $set: doc },
119
+ { upsert: true }
120
+ );
121
+ } catch (e) {
122
+ triggerFallback();
123
+ setLocal(key, value, ttl);
124
+ }
125
+ },
126
+ async has(key) {
127
+ if (isDown) {
128
+ return localStore.has(key);
129
+ }
130
+ try {
131
+ const doc = await collection.findOne({ _id: key }, { projection: { expiresAt: 1 } });
132
+ if (!doc) return false;
133
+
134
+ if (doc.expiresAt && new Date(doc.expiresAt) < new Date()) {
135
+ await this.delete(key);
136
+ return false;
137
+ }
138
+ return true;
139
+ } catch (e) {
140
+ triggerFallback();
141
+ return localStore.has(key);
142
+ }
143
+ },
144
+ async delete(key) {
145
+ if (localTimeouts.has(key)) {
146
+ clearTimeout(localTimeouts.get(key));
147
+ localTimeouts.delete(key);
148
+ }
149
+ localStore.delete(key);
150
+ if (isDown) return;
151
+ try {
152
+ await collection.deleteOne({ _id: key });
153
+ } catch (e) {
154
+ triggerFallback();
155
+ }
156
+ },
157
+ async init() {
158
+ try {
159
+ // Automates index configuration
160
+ await collection.createIndex({ "expiresAt": 1 }, { expireAfterSeconds: 0 });
161
+ } catch (e) {
162
+ triggerFallback();
163
+ }
164
+ }
165
+ };
80
166
  }
@@ -0,0 +1,23 @@
1
+ import { parentPort } from 'node:worker_threads';
2
+ import JavaScriptObfuscator from 'javascript-obfuscator';
3
+
4
+ if (parentPort) {
5
+ parentPort.on('message', (workerData) => {
6
+ const { jsCode, seed } = workerData;
7
+ try {
8
+ const obfuscationResult = JavaScriptObfuscator.obfuscate(jsCode, {
9
+ compact: true,
10
+ controlFlowFlattening: true,
11
+ deadCodeInjection: true,
12
+ stringArray: true,
13
+ stringArrayRotate: true,
14
+ stringArrayShuffle: true,
15
+ seed: Math.abs(seed),
16
+ selfDefending: true,
17
+ });
18
+ parentPort.postMessage({ obfuscatedCode: obfuscationResult.getObfuscatedCode() });
19
+ } catch (error) {
20
+ parentPort.postMessage({ error: error.message, stack: error.stack });
21
+ }
22
+ });
23
+ }