@anonympins/fingerprint 0.7.2 → 0.7.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 +36 -9
- package/README.md +1 -1
- package/package.json +109 -107
- package/public/fingerprint-anti-bot.zip +0 -0
- package/src/js/fingerprint.client.js +252 -45
- package/src/js/fingerprint.client.obfuscated.js +1 -1
- package/src/js/fingerprint.js +265 -185
- package/src/js/fingerprint.utils.js +32 -5
- package/src/js/fingerprint.worker.js +81 -0
- package/src/js/library.js +6 -2
- package/src/js/pow.solver.js +2 -3
- package/src/js/problem-manager.js +113 -113
- package/src/js/tests/fingerprint.client.init.test.js +30 -0
- package/src/js/tests/fingerprint.test.js +136 -4
- package/src/js/tests/threatIntel.test.js +76 -0
- package/src/php/AutoTuner.php +36 -18
- package/src/php/Challenge/ChallengeUtils.php +121 -240
- package/src/php/DirectFingerprint.php +16 -4
- package/src/php/FingerprintClient.php +17 -19
- package/src/php/FingerprintEngine.php +77 -39
- package/src/php/Ja3AnomalyDetector.php +20 -12
- package/src/php/Optimization/Optimization.php +5 -1
- package/src/php/Optimization/OptimizationOperators.php +5 -1
- package/src/php/Optimization/ProblemInitializers.php +16 -4
- package/src/php/ProblemManager.php +20 -14
- package/src/php/Tests/ChallengeUtilsTest.php +469 -453
- package/src/php/Tests/FingerprintEngineTest.php +6 -1
- package/src/php/Tests/RequestUtilsTest.php +1 -1
- package/src/php/Tests/ThreatIntelTest.php +64 -0
- package/src/php/Utils/Env.php +51 -49
- package/src/php/Utils/MaliciousPatterns.php +74 -74
- package/src/php/Utils/RequestUtils.php +231 -132
- package/src/php/WordPress/WpDbStore.php +4 -0
- package/src/php/WordPress/{fingerprint-wordpress.php → fingerprint-anti-bot.php} +131 -126
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-de_DE.po +1 -1
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.mo +0 -0
- package/src/php/WordPress/languages/fingerprint-wordpress-fr_FR.po +1 -1
- package/src/php/WordPress/package.php +6 -3
- package/src/php/WordPress/readme.txt +36 -0
- package/public/fingerprint-wordpress.zip +0 -0
|
@@ -159,9 +159,14 @@ const ClientLibrary = {
|
|
|
159
159
|
* @param {object} [detail={}] - The data to include in the event's detail property.
|
|
160
160
|
*/
|
|
161
161
|
_dispatchEvent(eventName, detail = {}) {
|
|
162
|
-
if (typeof window === 'undefined'
|
|
163
|
-
const
|
|
164
|
-
|
|
162
|
+
if (typeof window === 'undefined') return;
|
|
163
|
+
const CustomEventCtor = window.CustomEvent || (typeof CustomEvent !== 'undefined' ? CustomEvent : null);
|
|
164
|
+
if (!CustomEventCtor) return;
|
|
165
|
+
try {
|
|
166
|
+
const event = new CustomEventCtor(`fingerprint:${eventName}`, { detail });
|
|
167
|
+
window.dispatchEvent(event);
|
|
168
|
+
} catch (e) {
|
|
169
|
+
}
|
|
165
170
|
},
|
|
166
171
|
|
|
167
172
|
/**
|
|
@@ -190,10 +195,20 @@ const ClientLibrary = {
|
|
|
190
195
|
const canvas2d = typeof CanvasRenderingContext2D !== 'undefined' ? CanvasRenderingContext2D : win.CanvasRenderingContext2D;
|
|
191
196
|
const webgl = typeof WebGLRenderingContext !== 'undefined' ? WebGLRenderingContext : win.WebGLRenderingContext;
|
|
192
197
|
|
|
198
|
+
const isFetchTampered = () => {
|
|
199
|
+
if (ClientLibrary._isFetchPatched) {
|
|
200
|
+
if (ClientLibrary._originalFetch) {
|
|
201
|
+
return !Function.prototype.toString.call(ClientLibrary._originalFetch).includes('[native code]');
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return checkNative(win, 'fetch');
|
|
206
|
+
};
|
|
207
|
+
|
|
193
208
|
return checkNative(htmlCanvas?.prototype, 'toDataURL') ||
|
|
194
209
|
checkNative(canvas2d?.prototype, 'getImageData') ||
|
|
195
210
|
checkNative(webgl?.prototype, 'getParameter') ||
|
|
196
|
-
|
|
211
|
+
isFetchTampered();
|
|
197
212
|
},
|
|
198
213
|
|
|
199
214
|
/**
|
|
@@ -949,38 +964,118 @@ const ClientLibrary = {
|
|
|
949
964
|
},
|
|
950
965
|
|
|
951
966
|
/**
|
|
952
|
-
*
|
|
953
|
-
*
|
|
954
|
-
* @returns {
|
|
967
|
+
* Évalue le comportement côté client en local sans transmettre de données brutes.
|
|
968
|
+
* Retourne 1 si le comportement est humain/légitime, 0 en cas de suspicion/bot.
|
|
969
|
+
* @returns {number} 1 ou 0
|
|
955
970
|
*/
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
metrics.
|
|
971
|
+
evaluateBehavior() {
|
|
972
|
+
let score = 0;
|
|
973
|
+
if (metrics.honeypotInteraction) return 100;
|
|
974
|
+
if (ClientLibrary.detectTamperedPrototypes()) score += 80;
|
|
975
|
+
|
|
976
|
+
// Vérification du rendu graphique
|
|
977
|
+
if (metrics.rendering) {
|
|
978
|
+
if (metrics.rendering.offscreenAnom) return 0;
|
|
979
|
+
const fps = parseFloat(metrics.rendering.fps || 0);
|
|
980
|
+
const jitter = parseFloat(metrics.rendering.jitter || 0);
|
|
981
|
+
if (fps > 250 || (fps > 0 && fps < 15)) score += 50;
|
|
982
|
+
if (jitter > 6.0) score += Math.min(80, (jitter - 6.0) * 10);
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
// Mouvements de souris robotiques
|
|
986
|
+
if (mouseMovementsHistory.length >= 3) {
|
|
987
|
+
let totalDist = 0;
|
|
988
|
+
let pauses = 0;
|
|
989
|
+
const segments = [];
|
|
990
|
+
for (let i = 1; i < mouseMovementsHistory.length; i++) {
|
|
991
|
+
const p1 = mouseMovementsHistory[i - 1];
|
|
992
|
+
const p2 = mouseMovementsHistory[i];
|
|
993
|
+
const dx = p2.x - p1.x;
|
|
994
|
+
const dy = p2.y - p1.y;
|
|
995
|
+
const dt = p2.t - p1.t;
|
|
996
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
997
|
+
if (dt > 0) segments.push(dist / dt);
|
|
998
|
+
totalDist += dist;
|
|
999
|
+
if (dt > 100 && dist < 5) pauses++;
|
|
1000
|
+
}
|
|
1001
|
+
if (segments.length >= 2) {
|
|
1002
|
+
const totalTime = mouseMovementsHistory[mouseMovementsHistory.length - 1].t - mouseMovementsHistory[0].t;
|
|
1003
|
+
const avgSpeed = totalTime > 0 ? totalDist / totalTime : 0;
|
|
1004
|
+
const pStart = mouseMovementsHistory[0];
|
|
1005
|
+
const pEnd = mouseMovementsHistory[mouseMovementsHistory.length - 1];
|
|
1006
|
+
const straightDist = Math.sqrt(Math.pow(pEnd.x - pStart.x, 2) + Math.pow(pEnd.y - pStart.y, 2));
|
|
1007
|
+
const straightness = totalDist > 0 ? straightDist / totalDist : 1;
|
|
1008
|
+
if (avgSpeed > 3.0) score += 25;
|
|
1009
|
+
if (straightness > 0.95) score += 30;
|
|
1010
|
+
if (pauses === 0 && segments.length > 20) score += 15;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Analyse des événements tactiles
|
|
1015
|
+
if (touchMovementsHistory.length >= 3) {
|
|
1016
|
+
let totalDist = 0;
|
|
1017
|
+
let totalPressure = 0;
|
|
1018
|
+
let totalRadius = 0;
|
|
1019
|
+
for (const pt of touchMovementsHistory) {
|
|
1020
|
+
totalPressure += pt.p || 0;
|
|
1021
|
+
totalRadius += pt.r || 0;
|
|
1022
|
+
}
|
|
1023
|
+
const avgPressure = totalPressure / touchMovementsHistory.length;
|
|
1024
|
+
const avgRadius = totalRadius / touchMovementsHistory.length;
|
|
1025
|
+
let sqDiffPressure = 0;
|
|
1026
|
+
let sqDiffRadius = 0;
|
|
1027
|
+
for (const pt of touchMovementsHistory) {
|
|
1028
|
+
sqDiffPressure += Math.pow((pt.p || 0) - avgPressure, 2);
|
|
1029
|
+
sqDiffRadius += Math.pow((pt.r || 0) - avgRadius, 2);
|
|
1030
|
+
}
|
|
1031
|
+
if (avgPressure > 0 && (sqDiffPressure / touchMovementsHistory.length) === 0) {
|
|
1032
|
+
score += 30;
|
|
1033
|
+
}
|
|
1034
|
+
if (avgRadius > 0 && (sqDiffRadius / touchMovementsHistory.length) === 0) {
|
|
1035
|
+
score += 30;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
959
1038
|
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
1039
|
+
// Détection de rack / ferme de téléphones mobiles immobiles
|
|
1040
|
+
if (typeof window !== 'undefined' && (window.navigator?.userAgent || '').includes('Mobile')) {
|
|
1041
|
+
if (metrics.motionVariance === 0) return 0;
|
|
1042
|
+
}
|
|
963
1043
|
|
|
964
|
-
|
|
965
|
-
if (
|
|
966
|
-
|
|
1044
|
+
// Variance des clics ultra-précise (bot de clic)
|
|
1045
|
+
if (clicksHistory.length >= 3) {
|
|
1046
|
+
const targets = {};
|
|
1047
|
+
for (const c of clicksHistory) {
|
|
1048
|
+
if (!c.targetId) continue;
|
|
1049
|
+
if (!targets[c.targetId]) targets[c.targetId] = [];
|
|
1050
|
+
targets[c.targetId].push(c);
|
|
1051
|
+
}
|
|
1052
|
+
for (const id in targets) {
|
|
1053
|
+
const clks = targets[id];
|
|
1054
|
+
if (clks.length >= 3) {
|
|
1055
|
+
const mx = clks.reduce((s, c) => s + c.x, 0) / clks.length;
|
|
1056
|
+
const my = clks.reduce((s, c) => s + c.y, 0) / clks.length;
|
|
1057
|
+
const v = clks.reduce((s, c) => s + Math.pow(c.x - mx, 2) + Math.pow(c.y - my, 2), 0) / clks.length;
|
|
1058
|
+
if (v < 1.0) return 0;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
967
1061
|
}
|
|
968
|
-
|
|
969
|
-
//
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
metrics.keystrokeFlightTimes = keystrokeFlightTimes;
|
|
975
|
-
|
|
976
|
-
// Calculate mean keystroke latency
|
|
977
|
-
if (keystrokeLatencies.length > 0) {
|
|
978
|
-
const sum = keystrokeLatencies.reduce((a, b) => a + b, 0);
|
|
979
|
-
metrics.keystrokeLatency = sum / keystrokeLatencies.length;
|
|
980
|
-
} else {
|
|
981
|
-
metrics.keystrokeLatency = 0;
|
|
1062
|
+
|
|
1063
|
+
// Dynamique des touches de clavier robotique
|
|
1064
|
+
if (keystrokeDwellTimes.length >= 5) {
|
|
1065
|
+
const mean = keystrokeDwellTimes.reduce((a, b) => a + b, 0) / keystrokeDwellTimes.length;
|
|
1066
|
+
const variance = keystrokeDwellTimes.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / keystrokeDwellTimes.length;
|
|
1067
|
+
if (Math.sqrt(variance) < 2.0 || mean < 15.0) return 0;
|
|
982
1068
|
}
|
|
983
|
-
|
|
1069
|
+
|
|
1070
|
+
return 1;
|
|
1071
|
+
},
|
|
1072
|
+
|
|
1073
|
+
/**
|
|
1074
|
+
* Récupère le résultat comportemental sous forme binaire (1 = valide/humain, 0 = suspect).
|
|
1075
|
+
* @returns {number} 1 ou 0
|
|
1076
|
+
*/
|
|
1077
|
+
getClientBehaviorMetrics() {
|
|
1078
|
+
return this.evaluateBehavior();
|
|
984
1079
|
},
|
|
985
1080
|
|
|
986
1081
|
/**
|
|
@@ -991,14 +1086,13 @@ const ClientLibrary = {
|
|
|
991
1086
|
*/
|
|
992
1087
|
async protectedFetch(resource, options = {}) {
|
|
993
1088
|
const fp = this.getDeviceFingerprint();
|
|
994
|
-
const rawBehavior = this.getClientBehaviorMetrics();
|
|
995
1089
|
const zkpProof = await this.generateZkpProof(fp); // Generate ZKP proof
|
|
996
|
-
const behavior =
|
|
1090
|
+
const behavior = this.getClientBehaviorMetrics();
|
|
997
1091
|
|
|
998
1092
|
const headers = new Headers(options.headers || {});
|
|
999
1093
|
headers.set('X-ZKP-Proof', zkpProof); // Add ZKP proof to headers
|
|
1000
1094
|
headers.set('X-Device-Fingerprint', fp);
|
|
1001
|
-
headers.set('X-Behavior-Metrics',
|
|
1095
|
+
headers.set('X-Behavior-Metrics', String(behavior));
|
|
1002
1096
|
|
|
1003
1097
|
options.headers = headers;
|
|
1004
1098
|
return fetch(resource, options);
|
|
@@ -1008,6 +1102,8 @@ const ClientLibrary = {
|
|
|
1008
1102
|
_isFetchPatched: false,
|
|
1009
1103
|
_interceptorChain: [],
|
|
1010
1104
|
// Store original fetch bound to window to prevent illegal invocation errors
|
|
1105
|
+
_targetDomains: [],
|
|
1106
|
+
_swRegistration: null,
|
|
1011
1107
|
_originalFetch: (typeof window !== 'undefined') ? window.fetch.bind(window) : null,
|
|
1012
1108
|
|
|
1013
1109
|
/**
|
|
@@ -1045,10 +1141,78 @@ const ClientLibrary = {
|
|
|
1045
1141
|
*/
|
|
1046
1142
|
onHoneypotTrigger() {
|
|
1047
1143
|
metrics.honeypotInteraction = true;
|
|
1144
|
+
if (this.workerPath) {
|
|
1145
|
+
this.syncServiceWorkerCredentials();
|
|
1146
|
+
}
|
|
1048
1147
|
// Dispatch event allowing host applications to react
|
|
1049
1148
|
this._dispatchEvent('honeypotTriggered');
|
|
1050
1149
|
},
|
|
1051
1150
|
|
|
1151
|
+
/**
|
|
1152
|
+
* Registers and manages the Service Worker for transparent HTTPS request decoration.
|
|
1153
|
+
* @param {string} workerPath - Path to the worker script.
|
|
1154
|
+
* @param {string[]} [targetDomains=[]] - Domains to intercept.
|
|
1155
|
+
* @param {string} [scope] - Service Worker registration scope.
|
|
1156
|
+
* @returns {Promise<ServiceWorkerRegistration|null>}
|
|
1157
|
+
*/
|
|
1158
|
+
async initServiceWorker(workerPath, targetDomains = [], scope = undefined) {
|
|
1159
|
+
if (typeof navigator === 'undefined' || !('serviceWorker' in navigator)) {
|
|
1160
|
+
console.warn('[Fingerprint] Service Worker is not supported in this browser.');
|
|
1161
|
+
return null;
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
try {
|
|
1165
|
+
const registerOptions = scope ? { scope } : {};
|
|
1166
|
+
const registration = await navigator.serviceWorker.register(workerPath, registerOptions);
|
|
1167
|
+
this._swRegistration = registration;
|
|
1168
|
+
|
|
1169
|
+
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
|
1170
|
+
this.syncServiceWorkerCredentials(targetDomains);
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
await navigator.serviceWorker.ready;
|
|
1174
|
+
this.syncServiceWorkerCredentials(targetDomains);
|
|
1175
|
+
|
|
1176
|
+
if (typeof window !== 'undefined') {
|
|
1177
|
+
window.addEventListener('focus', () => this.syncServiceWorkerCredentials(targetDomains), { passive: true });
|
|
1178
|
+
document.addEventListener('visibilitychange', () => {
|
|
1179
|
+
if (document.visibilityState === 'visible') {
|
|
1180
|
+
this.syncServiceWorkerCredentials(targetDomains);
|
|
1181
|
+
}
|
|
1182
|
+
}, { passive: true });
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
console.log('[Fingerprint] Network Service Worker active and synchronized.');
|
|
1186
|
+
return registration;
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
console.warn('[Fingerprint] Failed to register Service Worker:', error);
|
|
1189
|
+
return null;
|
|
1190
|
+
}
|
|
1191
|
+
},
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Synchronizes device fingerprint and behavior metrics with the active Service Worker.
|
|
1195
|
+
* @param {string[]} [targetDomains=[]]
|
|
1196
|
+
*/
|
|
1197
|
+
syncServiceWorkerCredentials(targetDomains = []) {
|
|
1198
|
+
if (typeof navigator === 'undefined' || !navigator.serviceWorker) return;
|
|
1199
|
+
const domains = (Array.isArray(targetDomains) && targetDomains.length > 0)
|
|
1200
|
+
? targetDomains
|
|
1201
|
+
: (this._targetDomains || []);
|
|
1202
|
+
const payload = {
|
|
1203
|
+
type: 'UPDATE_CREDENTIALS',
|
|
1204
|
+
fp: this.getDeviceFingerprint(),
|
|
1205
|
+
behavior: this.getClientBehaviorMetrics(),
|
|
1206
|
+
targetDomains: domains
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
if (navigator.serviceWorker.controller) {
|
|
1210
|
+
navigator.serviceWorker.controller.postMessage(payload);
|
|
1211
|
+
} else if (this._swRegistration && this._swRegistration.active) {
|
|
1212
|
+
this._swRegistration.active.postMessage(payload);
|
|
1213
|
+
}
|
|
1214
|
+
},
|
|
1215
|
+
|
|
1052
1216
|
/**
|
|
1053
1217
|
* Initializes the fingerprinting fetch interceptor.
|
|
1054
1218
|
* Appends to interceptor chain without clobbering existing handlers.
|
|
@@ -1071,11 +1235,10 @@ const ClientLibrary = {
|
|
|
1071
1235
|
|
|
1072
1236
|
if (shouldProtect) {
|
|
1073
1237
|
const fp = this.getDeviceFingerprint();
|
|
1074
|
-
const
|
|
1075
|
-
const behavior = await signMetrics(rawBehavior);
|
|
1238
|
+
const behavior = this.getClientBehaviorMetrics();
|
|
1076
1239
|
const headers = new Headers(options.headers || {});
|
|
1077
1240
|
headers.set('X-Device-Fingerprint', fp);
|
|
1078
|
-
headers.set('X-Behavior-Metrics',
|
|
1241
|
+
headers.set('X-Behavior-Metrics', String(behavior));
|
|
1079
1242
|
options.headers = headers;
|
|
1080
1243
|
}
|
|
1081
1244
|
|
|
@@ -1193,10 +1356,20 @@ const ClientLibrary = {
|
|
|
1193
1356
|
* @param {Response} response - Initial response (status 404/challenge).
|
|
1194
1357
|
* @param {RequestInfo} resource - Original request resource.
|
|
1195
1358
|
* @param {RequestInit} options - Original request options.
|
|
1359
|
+
* @param {number} [maxRetries=3] - Maximum allowed challenge retry attempts.
|
|
1196
1360
|
* @returns {Promise<Response>} - Retried response.
|
|
1197
1361
|
* @private
|
|
1198
1362
|
*/
|
|
1199
|
-
async solveChallengeAndRetry(response, resource, options) {
|
|
1363
|
+
async solveChallengeAndRetry(response, resource, options = {}, maxRetries = 3) {
|
|
1364
|
+
const effectiveMaxRetries = (options && typeof options._powMaxRetries === 'number')
|
|
1365
|
+
? options._powMaxRetries
|
|
1366
|
+
: (typeof maxRetries === 'number' ? maxRetries : 3);
|
|
1367
|
+
const currentRetries = (options && options._powRetryCount) || (resource && resource._powRetryCount) || 0;
|
|
1368
|
+
if (currentRetries >= effectiveMaxRetries) {
|
|
1369
|
+
console.warn(`[Fingerprint] Challenge retry limit reached (${effectiveMaxRetries}). Aborting challenge retry loop.`);
|
|
1370
|
+
return response;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1200
1373
|
if (!response || response.status !== 404 || !response.headers?.get?.('content-type')?.includes('application/json') || response.bodyUsed) {
|
|
1201
1374
|
return response;
|
|
1202
1375
|
}
|
|
@@ -1223,8 +1396,16 @@ const ClientLibrary = {
|
|
|
1223
1396
|
// Attach solver fingerprint to retry request
|
|
1224
1397
|
url.searchParams.set('pow_fp', solverFp);
|
|
1225
1398
|
|
|
1226
|
-
// Use fetch to retry with
|
|
1227
|
-
|
|
1399
|
+
// Use fetch to retry with incremented retry count to prevent infinite challenge loops
|
|
1400
|
+
const retryOptions = {
|
|
1401
|
+
...options,
|
|
1402
|
+
_powRetryCount: currentRetries + 1,
|
|
1403
|
+
_powMaxRetries: effectiveMaxRetries
|
|
1404
|
+
};
|
|
1405
|
+
const fetchFn = (typeof window !== 'undefined' && typeof window.fetch === 'function')
|
|
1406
|
+
? window.fetch
|
|
1407
|
+
: fetch;
|
|
1408
|
+
return fetchFn(url.toString(), retryOptions);
|
|
1228
1409
|
} catch (e) {
|
|
1229
1410
|
console.error('[Fingerprint] Failed to solve or retry challenge:', e);
|
|
1230
1411
|
return response; // Retourne la réponse 429 originale en cas d'échec
|
|
@@ -1249,6 +1430,7 @@ const ClientLibrary = {
|
|
|
1249
1430
|
honeypots = [],
|
|
1250
1431
|
trapUrls = [], // Trap URLs
|
|
1251
1432
|
wasmPath,
|
|
1433
|
+
worker = false,
|
|
1252
1434
|
workerPath, // NOUVEAU
|
|
1253
1435
|
fetch: fetchConfig = {}
|
|
1254
1436
|
} = config;
|
|
@@ -1262,8 +1444,30 @@ const ClientLibrary = {
|
|
|
1262
1444
|
if (mouse) {
|
|
1263
1445
|
this.startMouseEntropyTracker();
|
|
1264
1446
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1447
|
+
|
|
1448
|
+
// Instantiation du Service Worker via initializeClient
|
|
1449
|
+
let resolvedWorkerPath = null;
|
|
1450
|
+
let workerScope = undefined;
|
|
1451
|
+
let workerTargetDomains = fetchConfig.targetDomains || [];
|
|
1452
|
+
|
|
1453
|
+
if (typeof worker === 'string') {
|
|
1454
|
+
resolvedWorkerPath = worker;
|
|
1455
|
+
} else if (typeof worker === 'object' && worker !== null) {
|
|
1456
|
+
resolvedWorkerPath = worker.path || '/fingerprint.worker.js';
|
|
1457
|
+
workerScope = worker.scope;
|
|
1458
|
+
if (Array.isArray(worker.targetDomains)) {
|
|
1459
|
+
workerTargetDomains = worker.targetDomains;
|
|
1460
|
+
}
|
|
1461
|
+
} else if (worker === true) {
|
|
1462
|
+
resolvedWorkerPath = '/fingerprint.worker.js';
|
|
1463
|
+
} else if (workerPath) {
|
|
1464
|
+
resolvedWorkerPath = workerPath;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
if (resolvedWorkerPath) {
|
|
1468
|
+
this.workerPath = resolvedWorkerPath;
|
|
1469
|
+
this._targetDomains = workerTargetDomains;
|
|
1470
|
+
this.initServiceWorker(resolvedWorkerPath, workerTargetDomains, workerScope);
|
|
1267
1471
|
}
|
|
1268
1472
|
if (keystrokes) {
|
|
1269
1473
|
this.startKeystrokeDynamicsTracker();
|
|
@@ -1294,16 +1498,17 @@ const ClientLibrary = {
|
|
|
1294
1498
|
if (trapUrls.length > 0) {
|
|
1295
1499
|
this.injectTrapLinks(trapUrls);
|
|
1296
1500
|
}
|
|
1297
|
-
// Enable fetch
|
|
1298
|
-
if (config.fetch) {
|
|
1501
|
+
// Enable fetch monkey-patching only if explicitly configured and no Service Worker is used
|
|
1502
|
+
if (config.fetch && !resolvedWorkerPath) {
|
|
1299
1503
|
this.initializeFetch(fetchConfig.targetDomains);
|
|
1300
1504
|
|
|
1301
1505
|
// Add challenge resolution interceptor
|
|
1302
1506
|
if (fetchConfig.handleChallenges !== false) {
|
|
1507
|
+
const maxRetries = typeof fetchConfig.maxRetries === 'number' ? fetchConfig.maxRetries : 3;
|
|
1303
1508
|
this.addFetchInterceptor(async (resource, options, next) => {
|
|
1304
1509
|
const originalResponse = await next(resource, options);
|
|
1305
1510
|
// Clone response to prevent draining the body stream for original caller
|
|
1306
|
-
return this.solveChallengeAndRetry(originalResponse.clone(), resource, options);
|
|
1511
|
+
return this.solveChallengeAndRetry(originalResponse.clone(), resource, options, maxRetries);
|
|
1307
1512
|
});
|
|
1308
1513
|
}
|
|
1309
1514
|
}
|
|
@@ -1521,6 +1726,8 @@ export const generateZkpProof = ClientLibrary.generateZkpProof.bind(ClientLibrar
|
|
|
1521
1726
|
export const initializeSpace = ClientLibrary.initializeSpace.bind(ClientLibrary);
|
|
1522
1727
|
export const readSpaceBlock = ClientLibrary.readSpaceBlock.bind(ClientLibrary);
|
|
1523
1728
|
export const solveSpaceChallenge = ClientLibrary.solveSpaceChallenge.bind(ClientLibrary);
|
|
1729
|
+
export const initServiceWorker = ClientLibrary.initServiceWorker.bind(ClientLibrary);
|
|
1730
|
+
export const syncServiceWorkerCredentials = ClientLibrary.syncServiceWorkerCredentials.bind(ClientLibrary);
|
|
1524
1731
|
|
|
1525
1732
|
// Export the internal object for testing purposes
|
|
1526
1733
|
export default ClientLibrary;
|