@arsedizioni/ars-utils 20.4.9 → 20.4.10

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/core/index.d.ts CHANGED
@@ -409,64 +409,36 @@ declare class SystemUtils {
409
409
  */
410
410
  static isColorLight(color: string, minimumLuminance?: number): boolean;
411
411
  /**
412
- * Generates a unique Machine ID based on browser fingerprinting
413
- * Purely deterministic - same device = same ID
414
- * GUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
415
- */
416
- static getMachineId(): string;
417
- /**
418
- * Generates a salt based on additional system characteristics
419
- * to differentiate identical PCs
420
- */
421
- private static generateSalt;
422
- /**
423
- * Gets or creates a persistent salt in cookies
424
- */
425
- private static getCookieSalt;
426
- /**
427
- * Formats a hexadecimal hash as GUID
412
+ * Get a unique machine id
413
+ * @returns : the machine id
428
414
  */
429
- private static formatAsGuid;
415
+ static getMachineId(): string;
430
416
  /**
431
- * Collects browser fingerprint
432
- * Focus on hardware characteristics + elements that vary between PCs
417
+ * Browser fingerprint
433
418
  */
434
419
  private static collectFingerprint;
435
420
  /**
436
- * Normalizes platform to be consistent across browsers
437
- */
438
- private static normalizePlatform;
439
- /**
440
- * Lightweight canvas hash - uses only numerical hash of rendering
441
- * More stable between browsers but varies by GPU/drivers
421
+ * Canvas fingerprinting
442
422
  */
443
- private static getCanvasHash;
423
+ private static getCanvasFingerprint;
444
424
  /**
445
425
  * WebGL fingerprinting
446
426
  */
447
427
  private static getWebGLFingerprint;
448
428
  /**
449
- * Additional WebGL parameters for greater entropy
450
- */
451
- private static getWebGLParameters;
452
- /**
453
- * Entropy from performance timing (varies by system load)
454
- */
455
- private static getPerformanceEntropy;
456
- /**
457
- * Audio context fingerprinting - REMOVED
458
- * Audio can give different results between browsers
429
+ * Audio context fingerprinting
459
430
  */
431
+ private static getAudioFingerprint;
460
432
  /**
461
- * Detects available fonts
433
+ * Rileva font disponibili
462
434
  */
463
435
  private static detectFonts;
464
436
  /**
465
- * Plugins - REMOVED
466
- * Plugin list deprecated and different between browsers
437
+ * Ottiene lista plugins
467
438
  */
439
+ private static getPlugins;
468
440
  /**
469
- * Generates 128-bit hash (32 hex characters) from string
441
+ * Genera hash SHA-256-like da stringa (semplificato)
470
442
  */
471
443
  private static generateHash;
472
444
  }
@@ -1071,180 +1071,46 @@ class SystemUtils {
1071
1071
  return luminance > minimumLuminance;
1072
1072
  }
1073
1073
  /**
1074
- * Generates a unique Machine ID based on browser fingerprinting
1075
- * Purely deterministic - same device = same ID
1076
- * GUID format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
1077
- */
1074
+ * Get a unique machine id
1075
+ * @returns : the machine id
1076
+ */
1078
1077
  static getMachineId() {
1079
1078
  const fingerprint = this.collectFingerprint();
1080
- const salt = this.generateSalt();
1081
- const combined = JSON.stringify(fingerprint) + salt;
1082
- const hash = this.generateHash(combined);
1083
- return this.formatAsGuid(hash);
1084
- }
1085
- /**
1086
- * Generates a salt based on additional system characteristics
1087
- * to differentiate identical PCs
1088
- */
1089
- static generateSalt() {
1090
- const saltComponents = [];
1091
- // 1. Battery API (if available - varies by battery state)
1092
- try {
1093
- const nav = navigator;
1094
- if (nav.getBattery) {
1095
- // Note: it's async but we only use API presence
1096
- saltComponents.push('battery-available');
1097
- }
1098
- }
1099
- catch (e) { }
1100
- // 2. Connection API (connection type, varies by network)
1101
- try {
1102
- const conn = navigator.connection ||
1103
- navigator.mozConnection ||
1104
- navigator.webkitConnection;
1105
- if (conn) {
1106
- saltComponents.push(conn.effectiveType || '');
1107
- saltComponents.push(conn.downlink?.toString() || '');
1108
- saltComponents.push(conn.rtt?.toString() || '');
1109
- }
1110
- }
1111
- catch (e) { }
1112
- // 3. Media Devices (number and type of I/O devices)
1113
- try {
1114
- if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
1115
- // Placeholder - will be populated async, but keep synchronicity
1116
- saltComponents.push('media-devices-available');
1117
- }
1118
- }
1119
- catch (e) { }
1120
- // 4. Permissions (permissions state varies by user/installation)
1121
- try {
1122
- if (navigator.permissions) {
1123
- saltComponents.push('permissions-available');
1124
- }
1125
- }
1126
- catch (e) { }
1127
- // 5. First access timestamp (stored in cookie/sessionStorage compatible)
1128
- try {
1129
- // Use a cookie to persist salt across sessions
1130
- const cookieSalt = this.getCookieSalt();
1131
- if (cookieSalt) {
1132
- saltComponents.push(cookieSalt);
1133
- }
1134
- }
1135
- catch (e) { }
1136
- // 6. Entropy from Math.random() seeded with performance.now()
1137
- try {
1138
- const seed = performance.now() % 1000;
1139
- const randomFactor = Math.sin(seed) * 10000;
1140
- saltComponents.push(Math.floor(randomFactor).toString(36));
1141
- }
1142
- catch (e) { }
1143
- // 7. Specific DOM characteristics
1144
- try {
1145
- const docElement = document.documentElement;
1146
- saltComponents.push(docElement.clientHeight.toString());
1147
- saltComponents.push(docElement.clientWidth.toString());
1148
- saltComponents.push(window.innerHeight.toString());
1149
- saltComponents.push(window.innerWidth.toString());
1150
- saltComponents.push(window.outerHeight.toString());
1151
- saltComponents.push(window.outerWidth.toString());
1152
- }
1153
- catch (e) { }
1154
- // 8. Additional navigator properties
1155
- try {
1156
- const nav = navigator;
1157
- saltComponents.push(nav.vendor || '');
1158
- saltComponents.push(nav.productSub || '');
1159
- saltComponents.push(nav.oscpu || '');
1160
- }
1161
- catch (e) { }
1162
- return saltComponents.filter(s => s).join('|');
1163
- }
1164
- /**
1165
- * Gets or creates a persistent salt in cookies
1166
- */
1167
- static getCookieSalt() {
1168
- const cookieName = '_machine_salt';
1169
- // Read existing cookie
1170
- const cookies = document.cookie.split(';');
1171
- for (const cookie of cookies) {
1172
- const [name, value] = cookie.trim().split('=');
1173
- if (name === cookieName) {
1174
- return value;
1175
- }
1176
- }
1177
- // Create new persistent salt
1178
- const newSalt = Math.random().toString(36).substring(2, 15) +
1179
- Date.now().toString(36);
1180
- // Save cookie with 10 year expiration
1181
- const expires = new Date();
1182
- expires.setFullYear(expires.getFullYear() + 10);
1183
- document.cookie = `${cookieName}=${newSalt}; expires=${expires.toUTCString()}; path=/; SameSite=Strict`;
1184
- return newSalt;
1079
+ const hash = this.generateHash(JSON.stringify(fingerprint));
1080
+ return hash;
1185
1081
  }
1186
1082
  /**
1187
- * Formats a hexadecimal hash as GUID
1188
- */
1189
- static formatAsGuid(hash) {
1190
- // Ensure hash is at least 32 characters long
1191
- const paddedHash = hash.padEnd(32, '0');
1192
- // GUID format: 8-4-4-4-12 characters
1193
- return `${paddedHash.substring(0, 8)}-${paddedHash.substring(8, 12)}-${paddedHash.substring(12, 16)}-${paddedHash.substring(16, 20)}-${paddedHash.substring(20, 32)}`;
1194
- }
1195
- /**
1196
- * Collects browser fingerprint
1197
- * Focus on hardware characteristics + elements that vary between PCs
1083
+ * Browser fingerprint
1198
1084
  */
1199
1085
  static collectFingerprint() {
1200
1086
  const nav = navigator;
1201
1087
  return {
1202
- // HARDWARE characteristics
1088
+ userAgent: nav.userAgent || '',
1089
+ language: nav.language || '',
1090
+ languages: nav.languages ? nav.languages.join(',') : '',
1091
+ platform: nav.platform || '',
1203
1092
  hardwareConcurrency: nav.hardwareConcurrency || 0,
1204
1093
  deviceMemory: nav.deviceMemory || 0,
1205
1094
  maxTouchPoints: nav.maxTouchPoints || 0,
1206
- // Screen
1207
1095
  screenResolution: `${screen.width}x${screen.height}`,
1208
1096
  colorDepth: screen.colorDepth,
1209
1097
  pixelDepth: screen.pixelDepth,
1210
1098
  availScreen: `${screen.availWidth}x${screen.availHeight}`,
1211
- // Timezone (can vary between PCs)
1212
1099
  timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
1213
1100
  timezoneOffset: new Date().getTimezoneOffset(),
1214
- // WebGL (GPU - identifies specific graphics hardware)
1101
+ canvas: this.getCanvasFingerprint(),
1215
1102
  webgl: this.getWebGLFingerprint(),
1216
- webglParams: this.getWebGLParameters(),
1217
- // Normalized platform
1218
- platform: this.normalizePlatform(nav.platform || ''),
1219
- // Fonts (installed on system - often vary between PCs)
1103
+ audio: this.getAudioFingerprint(),
1220
1104
  fonts: this.detectFonts(),
1221
- // Lightweight canvas fingerprint (varies by GPU/specific drivers)
1222
- canvasHash: this.getCanvasHash(),
1223
- // Additional entropy from performance
1224
- performanceEntropy: this.getPerformanceEntropy()
1105
+ plugins: this.getPlugins(),
1106
+ cookieEnabled: nav.cookieEnabled,
1107
+ doNotTrack: nav.doNotTrack || 'unknown'
1225
1108
  };
1226
1109
  }
1227
1110
  /**
1228
- * Normalizes platform to be consistent across browsers
1229
- */
1230
- static normalizePlatform(platform) {
1231
- platform = platform.toLowerCase();
1232
- // Normalize Windows variants
1233
- if (platform.includes('win'))
1234
- return 'windows';
1235
- // Normalize Mac variants
1236
- if (platform.includes('mac'))
1237
- return 'macos';
1238
- // Normalize Linux variants
1239
- if (platform.includes('linux'))
1240
- return 'linux';
1241
- return platform;
1242
- }
1243
- /**
1244
- * Lightweight canvas hash - uses only numerical hash of rendering
1245
- * More stable between browsers but varies by GPU/drivers
1111
+ * Canvas fingerprinting
1246
1112
  */
1247
- static getCanvasHash() {
1113
+ static getCanvasFingerprint() {
1248
1114
  try {
1249
1115
  const canvas = document.createElement('canvas');
1250
1116
  canvas.width = 200;
@@ -1257,15 +1123,11 @@ class SystemUtils {
1257
1123
  ctx.fillRect(125, 1, 62, 20);
1258
1124
  ctx.fillStyle = '#069';
1259
1125
  ctx.font = '11pt Arial';
1260
- ctx.fillText('FP', 2, 15);
1261
- // Get only a numerical hash instead of complete dataURL
1262
- const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
1263
- let hash = 0;
1264
- for (let i = 0; i < imageData.data.length; i += 4) {
1265
- hash = ((hash << 5) - hash) + imageData.data[i];
1266
- hash = hash & hash;
1267
- }
1268
- return hash.toString(16);
1126
+ ctx.fillText('MachineID 🔒', 2, 15);
1127
+ ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
1128
+ ctx.font = 'bold 18pt Times';
1129
+ ctx.fillText('Fingerprint', 4, 45);
1130
+ return canvas.toDataURL();
1269
1131
  }
1270
1132
  catch (e) {
1271
1133
  return '';
@@ -1293,58 +1155,36 @@ class SystemUtils {
1293
1155
  }
1294
1156
  }
1295
1157
  /**
1296
- * Additional WebGL parameters for greater entropy
1158
+ * Audio context fingerprinting
1297
1159
  */
1298
- static getWebGLParameters() {
1160
+ static getAudioFingerprint() {
1299
1161
  try {
1300
- const canvas = document.createElement('canvas');
1301
- const gl = canvas.getContext('webgl') ||
1302
- canvas.getContext('experimental-webgl');
1303
- if (!gl)
1162
+ const AudioContext = window.AudioContext ||
1163
+ window.webkitAudioContext;
1164
+ if (!AudioContext)
1304
1165
  return '';
1305
- const params = [
1306
- gl.getParameter(gl.MAX_TEXTURE_SIZE),
1307
- gl.getParameter(gl.MAX_VIEWPORT_DIMS),
1308
- gl.getParameter(gl.MAX_VERTEX_ATTRIBS),
1309
- gl.getParameter(gl.MAX_VARYING_VECTORS),
1310
- gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS),
1311
- gl.getParameter(gl.SHADING_LANGUAGE_VERSION),
1312
- gl.getSupportedExtensions()?.length || 0
1313
- ];
1314
- return params.join('|');
1166
+ const context = new AudioContext();
1167
+ const oscillator = context.createOscillator();
1168
+ const analyser = context.createAnalyser();
1169
+ const gainNode = context.createGain();
1170
+ const scriptProcessor = context.createScriptProcessor(4096, 1, 1);
1171
+ gainNode.gain.value = 0;
1172
+ oscillator.connect(analyser);
1173
+ analyser.connect(scriptProcessor);
1174
+ scriptProcessor.connect(gainNode);
1175
+ gainNode.connect(context.destination);
1176
+ oscillator.start(0);
1177
+ const fingerprint = `${context.sampleRate}-${analyser.fftSize}`;
1178
+ oscillator.stop();
1179
+ context.close();
1180
+ return fingerprint;
1315
1181
  }
1316
1182
  catch (e) {
1317
1183
  return '';
1318
1184
  }
1319
1185
  }
1320
1186
  /**
1321
- * Entropy from performance timing (varies by system load)
1322
- */
1323
- static getPerformanceEntropy() {
1324
- try {
1325
- // Use performance.now() variation as entropy
1326
- const now = performance.now();
1327
- const seed = Math.floor(now * 1000) % 10000;
1328
- // Get navigation timing if available
1329
- let timingEntropy = '';
1330
- if (performance.timing) {
1331
- const timing = performance.timing;
1332
- const loadTime = timing.loadEventEnd - timing.navigationStart;
1333
- const domReady = timing.domContentLoadedEventEnd - timing.navigationStart;
1334
- timingEntropy = `${Math.floor(loadTime / 100)}-${Math.floor(domReady / 100)}`;
1335
- }
1336
- return `${seed}-${timingEntropy}`;
1337
- }
1338
- catch (e) {
1339
- return '';
1340
- }
1341
- }
1342
- /**
1343
- * Audio context fingerprinting - REMOVED
1344
- * Audio can give different results between browsers
1345
- */
1346
- /**
1347
- * Detects available fonts
1187
+ * Rileva font disponibili
1348
1188
  */
1349
1189
  static detectFonts() {
1350
1190
  const baseFonts = ['monospace', 'sans-serif', 'serif'];
@@ -1381,34 +1221,30 @@ class SystemUtils {
1381
1221
  return detectedFonts.join(',');
1382
1222
  }
1383
1223
  /**
1384
- * Plugins - REMOVED
1385
- * Plugin list deprecated and different between browsers
1224
+ * Ottiene lista plugins
1386
1225
  */
1226
+ static getPlugins() {
1227
+ const plugins = [];
1228
+ for (let i = 0; i < navigator.plugins.length; i++) {
1229
+ plugins.push(navigator.plugins[i].name);
1230
+ }
1231
+ return plugins.join(',');
1232
+ }
1387
1233
  /**
1388
- * Generates 128-bit hash (32 hex characters) from string
1234
+ * Genera hash SHA-256-like da stringa (semplificato)
1389
1235
  */
1390
1236
  static generateHash(str) {
1391
- // Generate 4 32-bit hashes to get 128-bit total (like a GUID)
1392
1237
  let h1 = 0xdeadbeef;
1393
1238
  let h2 = 0x41c6ce57;
1394
- let h3 = 0x12345678;
1395
- let h4 = 0x9abcdef0;
1396
1239
  for (let i = 0; i < str.length; i++) {
1397
1240
  const ch = str.charCodeAt(i);
1398
1241
  h1 = Math.imul(h1 ^ ch, 2654435761);
1399
1242
  h2 = Math.imul(h2 ^ ch, 1597334677);
1400
- h3 = Math.imul(h3 ^ ch, 2246822507);
1401
- h4 = Math.imul(h4 ^ ch, 3266489909);
1402
1243
  }
1403
1244
  h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
1404
1245
  h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
1405
- h3 = Math.imul(h3 ^ (h3 >>> 16), 2246822507) ^ Math.imul(h4 ^ (h4 >>> 13), 3266489909);
1406
- h4 = Math.imul(h4 ^ (h4 >>> 16), 2246822507) ^ Math.imul(h3 ^ (h3 >>> 13), 3266489909);
1407
- // Combine the 4 hashes into a single 128-bit hash
1408
- return (h1 >>> 0).toString(16).padStart(8, '0') +
1409
- (h2 >>> 0).toString(16).padStart(8, '0') +
1410
- (h3 >>> 0).toString(16).padStart(8, '0') +
1411
- (h4 >>> 0).toString(16).padStart(8, '0');
1246
+ const hash = 4294967296 * (2097151 & h2) + (h1 >>> 0);
1247
+ return hash.toString(16).padStart(16, '0');
1412
1248
  }
1413
1249
  }
1414
1250