@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.
@@ -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
- _originalFetch: (typeof window !== 'undefined') ? window.fetch : () => Promise.reject(new Error('fetch is not available')),
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
- if (fetchConfig !== undefined) {
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;