@arsedizioni/ars-utils 20.4.5 → 20.4.6
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 +1 -1
- package/core/index.d.ts +33 -0
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs +6 -2
- package/fesm2022/arsedizioni-ars-utils-clipper.common.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-core.mjs +176 -0
- package/fesm2022/arsedizioni-ars-utils-core.mjs.map +1 -1
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs +6 -2
- package/fesm2022/arsedizioni-ars-utils-evolution.common.mjs.map +1 -1
- package/package.json +1 -1
- package/ui.application/index.d.ts +1 -1
|
@@ -1070,6 +1070,182 @@ class SystemUtils {
|
|
|
1070
1070
|
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;
|
|
1071
1071
|
return luminance > minimumLuminance;
|
|
1072
1072
|
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Get a unique machine id
|
|
1075
|
+
* @returns : the machine id
|
|
1076
|
+
*/
|
|
1077
|
+
static getMachineId() {
|
|
1078
|
+
const fingerprint = this.collectFingerprint();
|
|
1079
|
+
const hash = this.generateHash(JSON.stringify(fingerprint));
|
|
1080
|
+
return hash;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Browser fingerprint
|
|
1084
|
+
*/
|
|
1085
|
+
static collectFingerprint() {
|
|
1086
|
+
const nav = navigator;
|
|
1087
|
+
return {
|
|
1088
|
+
userAgent: nav.userAgent || '',
|
|
1089
|
+
language: nav.language || '',
|
|
1090
|
+
languages: nav.languages ? nav.languages.join(',') : '',
|
|
1091
|
+
platform: nav.platform || '',
|
|
1092
|
+
hardwareConcurrency: nav.hardwareConcurrency || 0,
|
|
1093
|
+
deviceMemory: nav.deviceMemory || 0,
|
|
1094
|
+
maxTouchPoints: nav.maxTouchPoints || 0,
|
|
1095
|
+
screenResolution: `${screen.width}x${screen.height}`,
|
|
1096
|
+
colorDepth: screen.colorDepth,
|
|
1097
|
+
pixelDepth: screen.pixelDepth,
|
|
1098
|
+
availScreen: `${screen.availWidth}x${screen.availHeight}`,
|
|
1099
|
+
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
1100
|
+
timezoneOffset: new Date().getTimezoneOffset(),
|
|
1101
|
+
canvas: this.getCanvasFingerprint(),
|
|
1102
|
+
webgl: this.getWebGLFingerprint(),
|
|
1103
|
+
audio: this.getAudioFingerprint(),
|
|
1104
|
+
fonts: this.detectFonts(),
|
|
1105
|
+
plugins: this.getPlugins(),
|
|
1106
|
+
cookieEnabled: nav.cookieEnabled,
|
|
1107
|
+
doNotTrack: nav.doNotTrack || 'unknown'
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
/**
|
|
1111
|
+
* Canvas fingerprinting
|
|
1112
|
+
*/
|
|
1113
|
+
static getCanvasFingerprint() {
|
|
1114
|
+
try {
|
|
1115
|
+
const canvas = document.createElement('canvas');
|
|
1116
|
+
canvas.width = 200;
|
|
1117
|
+
canvas.height = 50;
|
|
1118
|
+
const ctx = canvas.getContext('2d');
|
|
1119
|
+
if (!ctx)
|
|
1120
|
+
return '';
|
|
1121
|
+
ctx.textBaseline = 'alphabetic';
|
|
1122
|
+
ctx.fillStyle = '#f60';
|
|
1123
|
+
ctx.fillRect(125, 1, 62, 20);
|
|
1124
|
+
ctx.fillStyle = '#069';
|
|
1125
|
+
ctx.font = '11pt Arial';
|
|
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();
|
|
1131
|
+
}
|
|
1132
|
+
catch (e) {
|
|
1133
|
+
return '';
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
/**
|
|
1137
|
+
* WebGL fingerprinting
|
|
1138
|
+
*/
|
|
1139
|
+
static getWebGLFingerprint() {
|
|
1140
|
+
try {
|
|
1141
|
+
const canvas = document.createElement('canvas');
|
|
1142
|
+
const gl = canvas.getContext('webgl') ||
|
|
1143
|
+
canvas.getContext('experimental-webgl');
|
|
1144
|
+
if (!gl)
|
|
1145
|
+
return '';
|
|
1146
|
+
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
|
1147
|
+
if (!debugInfo)
|
|
1148
|
+
return '';
|
|
1149
|
+
const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
|
|
1150
|
+
const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
|
|
1151
|
+
return `${vendor}~${renderer}`;
|
|
1152
|
+
}
|
|
1153
|
+
catch (e) {
|
|
1154
|
+
return '';
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* Audio context fingerprinting
|
|
1159
|
+
*/
|
|
1160
|
+
static getAudioFingerprint() {
|
|
1161
|
+
try {
|
|
1162
|
+
const AudioContext = window.AudioContext ||
|
|
1163
|
+
window.webkitAudioContext;
|
|
1164
|
+
if (!AudioContext)
|
|
1165
|
+
return '';
|
|
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;
|
|
1181
|
+
}
|
|
1182
|
+
catch (e) {
|
|
1183
|
+
return '';
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Rileva font disponibili
|
|
1188
|
+
*/
|
|
1189
|
+
static detectFonts() {
|
|
1190
|
+
const baseFonts = ['monospace', 'sans-serif', 'serif'];
|
|
1191
|
+
const testFonts = [
|
|
1192
|
+
'Arial', 'Verdana', 'Times New Roman', 'Courier New',
|
|
1193
|
+
'Georgia', 'Palatino', 'Comic Sans MS', 'Impact'
|
|
1194
|
+
];
|
|
1195
|
+
const canvas = document.createElement('canvas');
|
|
1196
|
+
const ctx = canvas.getContext('2d');
|
|
1197
|
+
if (!ctx)
|
|
1198
|
+
return '';
|
|
1199
|
+
const testString = 'mmmmmmmmmmlli';
|
|
1200
|
+
const testSize = '72px';
|
|
1201
|
+
const baseMeasurements = {};
|
|
1202
|
+
baseFonts.forEach(font => {
|
|
1203
|
+
ctx.font = `${testSize} ${font}`;
|
|
1204
|
+
baseMeasurements[font] = ctx.measureText(testString).width;
|
|
1205
|
+
});
|
|
1206
|
+
const detectedFonts = [];
|
|
1207
|
+
testFonts.forEach(font => {
|
|
1208
|
+
let detected = false;
|
|
1209
|
+
for (const baseFont of baseFonts) {
|
|
1210
|
+
ctx.font = `${testSize} ${font}, ${baseFont}`;
|
|
1211
|
+
const width = ctx.measureText(testString).width;
|
|
1212
|
+
if (width !== baseMeasurements[baseFont]) {
|
|
1213
|
+
detected = true;
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
if (detected) {
|
|
1218
|
+
detectedFonts.push(font);
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
return detectedFonts.join(',');
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Ottiene lista plugins
|
|
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
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Genera hash SHA-256-like da stringa (semplificato)
|
|
1235
|
+
*/
|
|
1236
|
+
static generateHash(str) {
|
|
1237
|
+
let h1 = 0xdeadbeef;
|
|
1238
|
+
let h2 = 0x41c6ce57;
|
|
1239
|
+
for (let i = 0; i < str.length; i++) {
|
|
1240
|
+
const ch = str.charCodeAt(i);
|
|
1241
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
1242
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
1243
|
+
}
|
|
1244
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
1245
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
1246
|
+
const hash = 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
1247
|
+
return hash.toString(16).padStart(16, '0');
|
|
1248
|
+
}
|
|
1073
1249
|
}
|
|
1074
1250
|
|
|
1075
1251
|
class DateIntervalChangeDirective {
|