@arsedizioni/ars-utils 20.4.8 → 20.4.9
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<"selection" | "none" | "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,32 +409,64 @@ declare class SystemUtils {
|
|
|
409
409
|
*/
|
|
410
410
|
static isColorLight(color: string, minimumLuminance?: number): boolean;
|
|
411
411
|
/**
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
+
*/
|
|
415
416
|
static getMachineId(): string;
|
|
416
417
|
/**
|
|
417
|
-
|
|
418
|
-
|
|
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
|
|
428
|
+
*/
|
|
419
429
|
private static formatAsGuid;
|
|
420
430
|
/**
|
|
421
|
-
*
|
|
431
|
+
* Collects browser fingerprint
|
|
432
|
+
* Focus on hardware characteristics + elements that vary between PCs
|
|
422
433
|
*/
|
|
423
434
|
private static collectFingerprint;
|
|
424
435
|
/**
|
|
425
|
-
*
|
|
436
|
+
* Normalizes platform to be consistent across browsers
|
|
426
437
|
*/
|
|
427
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
|
|
442
|
+
*/
|
|
443
|
+
private static getCanvasHash;
|
|
428
444
|
/**
|
|
429
445
|
* WebGL fingerprinting
|
|
430
446
|
*/
|
|
431
447
|
private static getWebGLFingerprint;
|
|
432
448
|
/**
|
|
433
|
-
*
|
|
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
|
|
459
|
+
*/
|
|
460
|
+
/**
|
|
461
|
+
* Detects available fonts
|
|
434
462
|
*/
|
|
435
463
|
private static detectFonts;
|
|
436
464
|
/**
|
|
437
|
-
*
|
|
465
|
+
* Plugins - REMOVED
|
|
466
|
+
* Plugin list deprecated and different between browsers
|
|
467
|
+
*/
|
|
468
|
+
/**
|
|
469
|
+
* Generates 128-bit hash (32 hex characters) from string
|
|
438
470
|
*/
|
|
439
471
|
private static generateHash;
|
|
440
472
|
}
|
|
@@ -1071,55 +1071,206 @@ class SystemUtils {
|
|
|
1071
1071
|
return luminance > minimumLuminance;
|
|
1072
1072
|
}
|
|
1073
1073
|
/**
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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
|
+
*/
|
|
1077
1078
|
static getMachineId() {
|
|
1078
1079
|
const fingerprint = this.collectFingerprint();
|
|
1079
|
-
const
|
|
1080
|
+
const salt = this.generateSalt();
|
|
1081
|
+
const combined = JSON.stringify(fingerprint) + salt;
|
|
1082
|
+
const hash = this.generateHash(combined);
|
|
1080
1083
|
return this.formatAsGuid(hash);
|
|
1081
1084
|
}
|
|
1082
1085
|
/**
|
|
1083
|
-
|
|
1084
|
-
|
|
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;
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Formats a hexadecimal hash as GUID
|
|
1188
|
+
*/
|
|
1085
1189
|
static formatAsGuid(hash) {
|
|
1190
|
+
// Ensure hash is at least 32 characters long
|
|
1086
1191
|
const paddedHash = hash.padEnd(32, '0');
|
|
1192
|
+
// GUID format: 8-4-4-4-12 characters
|
|
1087
1193
|
return `${paddedHash.substring(0, 8)}-${paddedHash.substring(8, 12)}-${paddedHash.substring(12, 16)}-${paddedHash.substring(16, 20)}-${paddedHash.substring(20, 32)}`;
|
|
1088
1194
|
}
|
|
1089
1195
|
/**
|
|
1090
|
-
*
|
|
1196
|
+
* Collects browser fingerprint
|
|
1197
|
+
* Focus on hardware characteristics + elements that vary between PCs
|
|
1091
1198
|
*/
|
|
1092
1199
|
static collectFingerprint() {
|
|
1093
1200
|
const nav = navigator;
|
|
1094
1201
|
return {
|
|
1095
|
-
//
|
|
1202
|
+
// HARDWARE characteristics
|
|
1096
1203
|
hardwareConcurrency: nav.hardwareConcurrency || 0,
|
|
1097
1204
|
deviceMemory: nav.deviceMemory || 0,
|
|
1098
1205
|
maxTouchPoints: nav.maxTouchPoints || 0,
|
|
1206
|
+
// Screen
|
|
1099
1207
|
screenResolution: `${screen.width}x${screen.height}`,
|
|
1100
1208
|
colorDepth: screen.colorDepth,
|
|
1101
1209
|
pixelDepth: screen.pixelDepth,
|
|
1102
1210
|
availScreen: `${screen.availWidth}x${screen.availHeight}`,
|
|
1211
|
+
// Timezone (can vary between PCs)
|
|
1103
1212
|
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1104
1213
|
timezoneOffset: new Date().getTimezoneOffset(),
|
|
1214
|
+
// WebGL (GPU - identifies specific graphics hardware)
|
|
1105
1215
|
webgl: this.getWebGLFingerprint(),
|
|
1216
|
+
webglParams: this.getWebGLParameters(),
|
|
1217
|
+
// Normalized platform
|
|
1106
1218
|
platform: this.normalizePlatform(nav.platform || ''),
|
|
1107
|
-
|
|
1219
|
+
// Fonts (installed on system - often vary between PCs)
|
|
1220
|
+
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()
|
|
1108
1225
|
};
|
|
1109
1226
|
}
|
|
1110
1227
|
/**
|
|
1111
|
-
*
|
|
1228
|
+
* Normalizes platform to be consistent across browsers
|
|
1112
1229
|
*/
|
|
1113
1230
|
static normalizePlatform(platform) {
|
|
1114
1231
|
platform = platform.toLowerCase();
|
|
1232
|
+
// Normalize Windows variants
|
|
1115
1233
|
if (platform.includes('win'))
|
|
1116
1234
|
return 'windows';
|
|
1235
|
+
// Normalize Mac variants
|
|
1117
1236
|
if (platform.includes('mac'))
|
|
1118
1237
|
return 'macos';
|
|
1238
|
+
// Normalize Linux variants
|
|
1119
1239
|
if (platform.includes('linux'))
|
|
1120
1240
|
return 'linux';
|
|
1121
1241
|
return platform;
|
|
1122
1242
|
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Lightweight canvas hash - uses only numerical hash of rendering
|
|
1245
|
+
* More stable between browsers but varies by GPU/drivers
|
|
1246
|
+
*/
|
|
1247
|
+
static getCanvasHash() {
|
|
1248
|
+
try {
|
|
1249
|
+
const canvas = document.createElement('canvas');
|
|
1250
|
+
canvas.width = 200;
|
|
1251
|
+
canvas.height = 50;
|
|
1252
|
+
const ctx = canvas.getContext('2d');
|
|
1253
|
+
if (!ctx)
|
|
1254
|
+
return '';
|
|
1255
|
+
ctx.textBaseline = 'alphabetic';
|
|
1256
|
+
ctx.fillStyle = '#f60';
|
|
1257
|
+
ctx.fillRect(125, 1, 62, 20);
|
|
1258
|
+
ctx.fillStyle = '#069';
|
|
1259
|
+
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);
|
|
1269
|
+
}
|
|
1270
|
+
catch (e) {
|
|
1271
|
+
return '';
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1123
1274
|
/**
|
|
1124
1275
|
* WebGL fingerprinting
|
|
1125
1276
|
*/
|
|
@@ -1142,7 +1293,58 @@ class SystemUtils {
|
|
|
1142
1293
|
}
|
|
1143
1294
|
}
|
|
1144
1295
|
/**
|
|
1145
|
-
*
|
|
1296
|
+
* Additional WebGL parameters for greater entropy
|
|
1297
|
+
*/
|
|
1298
|
+
static getWebGLParameters() {
|
|
1299
|
+
try {
|
|
1300
|
+
const canvas = document.createElement('canvas');
|
|
1301
|
+
const gl = canvas.getContext('webgl') ||
|
|
1302
|
+
canvas.getContext('experimental-webgl');
|
|
1303
|
+
if (!gl)
|
|
1304
|
+
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('|');
|
|
1315
|
+
}
|
|
1316
|
+
catch (e) {
|
|
1317
|
+
return '';
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
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
|
|
1146
1348
|
*/
|
|
1147
1349
|
static detectFonts() {
|
|
1148
1350
|
const baseFonts = ['monospace', 'sans-serif', 'serif'];
|
|
@@ -1179,9 +1381,14 @@ class SystemUtils {
|
|
|
1179
1381
|
return detectedFonts.join(',');
|
|
1180
1382
|
}
|
|
1181
1383
|
/**
|
|
1182
|
-
*
|
|
1384
|
+
* Plugins - REMOVED
|
|
1385
|
+
* Plugin list deprecated and different between browsers
|
|
1386
|
+
*/
|
|
1387
|
+
/**
|
|
1388
|
+
* Generates 128-bit hash (32 hex characters) from string
|
|
1183
1389
|
*/
|
|
1184
1390
|
static generateHash(str) {
|
|
1391
|
+
// Generate 4 32-bit hashes to get 128-bit total (like a GUID)
|
|
1185
1392
|
let h1 = 0xdeadbeef;
|
|
1186
1393
|
let h2 = 0x41c6ce57;
|
|
1187
1394
|
let h3 = 0x12345678;
|
|
@@ -1197,6 +1404,7 @@ class SystemUtils {
|
|
|
1197
1404
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
1198
1405
|
h3 = Math.imul(h3 ^ (h3 >>> 16), 2246822507) ^ Math.imul(h4 ^ (h4 >>> 13), 3266489909);
|
|
1199
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
|
|
1200
1408
|
return (h1 >>> 0).toString(16).padStart(8, '0') +
|
|
1201
1409
|
(h2 >>> 0).toString(16).padStart(8, '0') +
|
|
1202
1410
|
(h3 >>> 0).toString(16).padStart(8, '0') +
|