@anonympins/fingerprint 0.0.9 → 0.1.1
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/README.md +494 -477
- package/fingerprint.client.js +63 -3
- package/fingerprint.js +2267 -1882
- package/library.js +136 -5
- package/package.json +3 -2
- package/pow.solver.js +214 -0
package/fingerprint.client.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { cyrb53, FingerprintBuilder } from './fingerprint.builder.js';
|
|
2
|
+
import { solveChallenge } from './pow.solver.js';
|
|
2
3
|
|
|
3
4
|
const ClientLibrary = {
|
|
4
5
|
// Cache pour éviter de recalculer les constantes (Hardware, etc.)
|
|
@@ -237,7 +238,9 @@ const ClientLibrary = {
|
|
|
237
238
|
|
|
238
239
|
_isFetchPatched: false,
|
|
239
240
|
_interceptorChain: [],
|
|
240
|
-
|
|
241
|
+
// On "lie" (bind) la fonction fetch à son contexte d'origine (window) pour éviter les erreurs "Illegal invocation".
|
|
242
|
+
// C'est la correction clé pour le problème que vous rencontrez.
|
|
243
|
+
_originalFetch: (typeof window !== 'undefined') ? window.fetch.bind(window) : () => Promise.reject(new Error('fetch is not available')),
|
|
241
244
|
|
|
242
245
|
/**
|
|
243
246
|
* Adds an interceptor function to the `fetch` chain.
|
|
@@ -320,6 +323,53 @@ const ClientLibrary = {
|
|
|
320
323
|
this.addFetchInterceptor(fingerprintInterceptor);
|
|
321
324
|
},
|
|
322
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Intercepte une réponse de challenge JSON, le résout, et réessaie la requête.
|
|
328
|
+
* @param {Response} response - La réponse initiale (potentiellement 429).
|
|
329
|
+
* @param {RequestInfo} resource - La ressource de la requête originale.
|
|
330
|
+
* @param {RequestInit} options - Les options de la requête originale.
|
|
331
|
+
* @returns {Promise<Response>} - La réponse de la requête réessayée.
|
|
332
|
+
* @private
|
|
333
|
+
*/
|
|
334
|
+
async solveChallengeAndRetry(response, resource, options) {
|
|
335
|
+
if (response.status !== 404 || !response.headers.get('content-type')?.includes('application/json')) {
|
|
336
|
+
return response;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
const challengeData = await response.json();
|
|
341
|
+
if (!challengeData.challenge || !challengeData.challenge.type) {
|
|
342
|
+
return response; // Pas un challenge JSON valide
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
console.log(`[Fingerprint] Received a '${challengeData.challenge.type}' challenge. Solving...`);
|
|
346
|
+
const solution = await solveChallenge(challengeData.challenge);
|
|
347
|
+
console.log('[Fingerprint] Challenge solved. Retrying original request.');
|
|
348
|
+
|
|
349
|
+
// Ajouter la solution aux paramètres de la requête pour le nouvel essai
|
|
350
|
+
const url = new URL((resource instanceof Request) ? resource.url : String(resource), window.location.origin);
|
|
351
|
+
// Le type de challenge est maintenant `cpu_mem` pour les API
|
|
352
|
+
url.searchParams.set('pow_type', 'cpu_mem');
|
|
353
|
+
url.searchParams.set('pow_nonce', challengeData.challenge.nonce);
|
|
354
|
+
|
|
355
|
+
// La solution peut être un objet (pour les challenges combinés) ou une valeur simple
|
|
356
|
+
Object.entries(solution).forEach(([key, value]) => {
|
|
357
|
+
// Le serveur attend pow_solution_cpu et pow_solution_mem
|
|
358
|
+
// On s'assure que la clé est bien 'cpu' ou 'mem' avant de l'ajouter
|
|
359
|
+
if (key === 'cpu' || key === 'mem') {
|
|
360
|
+
url.searchParams.set(`pow_solution_${key}`, String(value));
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// On utilise la chaîne d'intercepteurs pour la requête réessayée,
|
|
365
|
+
// ce qui garantit que le fetch original est appelé avec le bon contexte.
|
|
366
|
+
// Cela évite de réintroduire l'erreur "Illegal invocation".
|
|
367
|
+
return window.fetch(url.toString(), options);
|
|
368
|
+
} catch (e) {
|
|
369
|
+
console.error('[Fingerprint] Failed to solve or retry challenge:', e);
|
|
370
|
+
return response; // Retourne la réponse 429 originale en cas d'échec
|
|
371
|
+
}
|
|
372
|
+
},
|
|
323
373
|
/**
|
|
324
374
|
* @typedef {object} ClientConfig
|
|
325
375
|
* @property {boolean} [mouse=true] - Activer le suivi de l'entropie de la souris.
|
|
@@ -339,7 +389,7 @@ const ClientLibrary = {
|
|
|
339
389
|
mouse = true,
|
|
340
390
|
keystrokes = true,
|
|
341
391
|
honeypots = [],
|
|
342
|
-
fetch: fetchConfig,
|
|
392
|
+
fetch: fetchConfig = {},
|
|
343
393
|
} = config;
|
|
344
394
|
|
|
345
395
|
if (mouse) {
|
|
@@ -351,8 +401,17 @@ const ClientLibrary = {
|
|
|
351
401
|
if (honeypots.length > 0) {
|
|
352
402
|
this.initializeHoneypots(honeypots);
|
|
353
403
|
}
|
|
354
|
-
|
|
404
|
+
// On active l'interception si `fetch` est configuré, même avec un objet vide.
|
|
405
|
+
if (config.fetch) {
|
|
355
406
|
this.initializeFetch(fetchConfig.targetDomains);
|
|
407
|
+
|
|
408
|
+
// Ajoute l'intercepteur pour la résolution de challenge
|
|
409
|
+
if (fetchConfig.handleChallenges !== false) {
|
|
410
|
+
this.addFetchInterceptor(async (resource, options, next) => {
|
|
411
|
+
const response = await next(resource, options);
|
|
412
|
+
return this.solveChallengeAndRetry(response, resource, options);
|
|
413
|
+
});
|
|
414
|
+
}
|
|
356
415
|
}
|
|
357
416
|
}
|
|
358
417
|
};
|
|
@@ -394,6 +453,7 @@ export const addFetchInterceptor = ClientLibrary.addFetchInterceptor.bind(Client
|
|
|
394
453
|
export const patchGlobalFetch = ClientLibrary.patchGlobalFetch.bind(ClientLibrary);
|
|
395
454
|
export const initializeFetch = ClientLibrary.initializeFetch.bind(ClientLibrary);
|
|
396
455
|
export const initializeClient = ClientLibrary.initializeClient.bind(ClientLibrary);
|
|
456
|
+
export const solveChallengeAndRetry = ClientLibrary.solveChallengeAndRetry.bind(ClientLibrary);
|
|
397
457
|
|
|
398
458
|
// Export the internal object for testing purposes
|
|
399
459
|
export default ClientLibrary;
|