@arsedizioni/ars-utils 20.4.9 → 20.4.11
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/clipper.ui/index.d.ts
CHANGED
|
@@ -1033,7 +1033,7 @@ declare class ClipperDocumentMenuComponent implements OnInit, OnDestroy {
|
|
|
1033
1033
|
private changeDetector;
|
|
1034
1034
|
private clipperService;
|
|
1035
1035
|
readonly useSelections: _angular_core.InputSignal<boolean>;
|
|
1036
|
-
readonly selectionSource: _angular_core.InputSignal<"
|
|
1036
|
+
readonly selectionSource: _angular_core.InputSignal<"none" | "selection" | "bag">;
|
|
1037
1037
|
protected selection: () => ClipperDocumentInfo[];
|
|
1038
1038
|
readonly parent: _angular_core.InputSignal<ClipperSearchResultManager>;
|
|
1039
1039
|
readonly item: _angular_core.InputSignal<ClipperDocumentInfo>;
|
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
|
-
|
|
413
|
-
|
|
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
|
-
|
|
415
|
+
static getMachineId(): string;
|
|
430
416
|
/**
|
|
431
|
-
*
|
|
432
|
-
* Focus on hardware characteristics + elements that vary between PCs
|
|
417
|
+
* Browser fingerprint
|
|
433
418
|
*/
|
|
434
419
|
private static collectFingerprint;
|
|
435
420
|
/**
|
|
436
|
-
*
|
|
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
|
|
423
|
+
private static getCanvasFingerprint;
|
|
444
424
|
/**
|
|
445
425
|
* WebGL fingerprinting
|
|
446
426
|
*/
|
|
447
427
|
private static getWebGLFingerprint;
|
|
448
428
|
/**
|
|
449
|
-
*
|
|
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
|
-
*
|
|
433
|
+
* Rileva font disponibili
|
|
462
434
|
*/
|
|
463
435
|
private static detectFonts;
|
|
464
436
|
/**
|
|
465
|
-
*
|
|
466
|
-
* Plugin list deprecated and different between browsers
|
|
437
|
+
* Ottiene lista plugins
|
|
467
438
|
*/
|
|
439
|
+
private static getPlugins;
|
|
468
440
|
/**
|
|
469
|
-
*
|
|
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
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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
|
|
1081
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
1101
|
+
canvas: this.getCanvasFingerprint(),
|
|
1215
1102
|
webgl: this.getWebGLFingerprint(),
|
|
1216
|
-
|
|
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
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
performanceEntropy: this.getPerformanceEntropy()
|
|
1105
|
+
plugins: this.getPlugins(),
|
|
1106
|
+
cookieEnabled: nav.cookieEnabled,
|
|
1107
|
+
doNotTrack: nav.doNotTrack || 'unknown'
|
|
1225
1108
|
};
|
|
1226
1109
|
}
|
|
1227
1110
|
/**
|
|
1228
|
-
*
|
|
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
|
|
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('
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
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
|
-
*
|
|
1158
|
+
* Audio context fingerprinting
|
|
1297
1159
|
*/
|
|
1298
|
-
static
|
|
1160
|
+
static getAudioFingerprint() {
|
|
1299
1161
|
try {
|
|
1300
|
-
const
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
if (!gl)
|
|
1162
|
+
const AudioContext = window.AudioContext ||
|
|
1163
|
+
window.webkitAudioContext;
|
|
1164
|
+
if (!AudioContext)
|
|
1304
1165
|
return '';
|
|
1305
|
-
const
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
|
|
1406
|
-
|
|
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
|
|