@cloudglides/veil 0.1.1 → 1.0.1

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.
Files changed (64) hide show
  1. package/dist/index.d.ts +103 -0
  2. package/dist/index.js +1000 -0
  3. package/dist/veil_core_bg.wasm +0 -0
  4. package/package.json +24 -10
  5. package/.envrc +0 -1
  6. package/.github/workflows/build-on-tag.yml +0 -82
  7. package/.github/workflows/deploy-pages.yml +0 -73
  8. package/example/index.html +0 -220
  9. package/example/veil_core.d.ts +0 -71
  10. package/example/veil_core_bg.wasm +0 -0
  11. package/example/veil_core_bg.wasm.d.ts +0 -20
  12. package/flake.nix +0 -68
  13. package/scripts/patch-wasm.js +0 -12
  14. package/src/cpu.ts +0 -67
  15. package/src/entropy/adblock.ts +0 -16
  16. package/src/entropy/approximate.ts +0 -9
  17. package/src/entropy/audio.ts +0 -17
  18. package/src/entropy/battery.ts +0 -10
  19. package/src/entropy/browser.ts +0 -7
  20. package/src/entropy/canvas.ts +0 -17
  21. package/src/entropy/complexity.ts +0 -14
  22. package/src/entropy/connection.ts +0 -14
  23. package/src/entropy/distribution.ts +0 -9
  24. package/src/entropy/fonts.ts +0 -4
  25. package/src/entropy/hardware.ts +0 -10
  26. package/src/entropy/language.ts +0 -14
  27. package/src/entropy/os.ts +0 -12
  28. package/src/entropy/osVersion.ts +0 -6
  29. package/src/entropy/performance.ts +0 -14
  30. package/src/entropy/permissions.ts +0 -15
  31. package/src/entropy/plugins.ts +0 -14
  32. package/src/entropy/preferences.ts +0 -12
  33. package/src/entropy/probabilistic.ts +0 -20
  34. package/src/entropy/screen.ts +0 -12
  35. package/src/entropy/screenInfo.ts +0 -8
  36. package/src/entropy/spectral.ts +0 -9
  37. package/src/entropy/statistical.ts +0 -15
  38. package/src/entropy/storage.ts +0 -22
  39. package/src/entropy/timezone.ts +0 -10
  40. package/src/entropy/userAgent.ts +0 -16
  41. package/src/entropy/webFeatures.ts +0 -21
  42. package/src/entropy/webgl.ts +0 -11
  43. package/src/gpu.ts +0 -132
  44. package/src/index.test.ts +0 -26
  45. package/src/index.ts +0 -248
  46. package/src/normalize/index.ts +0 -31
  47. package/src/probability.ts +0 -11
  48. package/src/scoring.ts +0 -106
  49. package/src/seeded-rng.ts +0 -14
  50. package/src/stability.ts +0 -405
  51. package/src/tamper.ts +0 -207
  52. package/src/types/index.ts +0 -11
  53. package/src/types.ts +0 -56
  54. package/src/veil_core.d.ts +0 -4
  55. package/src/wasm-loader.ts +0 -44
  56. package/tsconfig.json +0 -12
  57. package/tsup.config.ts +0 -41
  58. package/veil-core/Cargo.lock +0 -114
  59. package/veil-core/Cargo.toml +0 -12
  60. package/veil-core/src/entropy.rs +0 -132
  61. package/veil-core/src/lib.rs +0 -93
  62. package/veil-core/src/similarity.rs +0 -67
  63. package/vitest.config.ts +0 -15
  64. /package/{example → dist}/veil_core.js +0 -0
package/src/index.ts DELETED
@@ -1,248 +0,0 @@
1
- import type { FingerprintOptions, FingerprintResponse, SourceMetric } from "./types";
2
- import { getUserAgentEntropy } from "./entropy/userAgent";
3
- import { getCanvasEntropy } from "./entropy/canvas";
4
- import { getWebGLEntropy } from "./entropy/webgl";
5
- import { getFontsEntropy } from "./entropy/fonts";
6
- import { getStorageEntropy } from "./entropy/storage";
7
- import { getScreenEntropy } from "./entropy/screen";
8
- import { getDistributionEntropy } from "./entropy/distribution";
9
- import { getComplexityEntropy } from "./entropy/complexity";
10
- import { getSpectralEntropy } from "./entropy/spectral";
11
- import { getApproximateEntropy } from "./entropy/approximate";
12
- import { getOSEntropy } from "./entropy/os";
13
- import { getLanguageEntropy } from "./entropy/language";
14
- import { getTimezoneEntropy } from "./entropy/timezone";
15
- import { getHardwareEntropy } from "./entropy/hardware";
16
- import { getPluginsEntropy } from "./entropy/plugins";
17
- import { getBrowserEntropy } from "./entropy/browser";
18
- import { getOSVersionEntropy } from "./entropy/osVersion";
19
- import { getScreenInfoEntropy } from "./entropy/screenInfo";
20
- import { getAdblockEntropy } from "./entropy/adblock";
21
- import { getWebFeaturesEntropy } from "./entropy/webFeatures";
22
- import { getPreferencesEntropy } from "./entropy/preferences";
23
- import { getPermissionsEntropy } from "./entropy/permissions";
24
- import { getStatisticalEntropy } from "./entropy/statistical";
25
- import { getProbabilisticEntropy } from "./entropy/probabilistic";
26
- function levenshteinDistance(s1: string, s2: string): number {
27
- const len1 = s1.length;
28
- const len2 = s2.length;
29
- const matrix: number[][] = Array(len1 + 1).fill(null).map(() => Array(len2 + 1).fill(0));
30
-
31
- for (let i = 0; i <= len1; i++) matrix[i][0] = i;
32
- for (let j = 0; j <= len2; j++) matrix[0][j] = j;
33
-
34
- for (let i = 1; i <= len1; i++) {
35
- for (let j = 1; j <= len2; j++) {
36
- const cost = s1[i - 1] === s2[j - 1] ? 0 : 1;
37
- matrix[i][j] = Math.min(
38
- matrix[i - 1][j] + 1,
39
- matrix[i][j - 1] + 1,
40
- matrix[i - 1][j - 1] + cost,
41
- );
42
- }
43
- }
44
- return matrix[len1][len2];
45
- }
46
-
47
- function similarityScore(s1: string, s2: string): number {
48
- const distance = levenshteinDistance(s1, s2);
49
- const maxLen = Math.max(s1.length, s2.length);
50
- return maxLen === 0 ? 1 : 1 - distance / maxLen;
51
- }
52
-
53
- import * as normalize from "./normalize";
54
- import { initializeWasm } from "./wasm-loader";
55
- import { scoreFingerprint, calculateEntropy, type EntropySource } from "./scoring";
56
- import { analyzeTamper } from "./tamper";
57
- import { getSourceStability, assessFingerprint, generateDeviceIdentity } from "./stability";
58
-
59
- export async function getFingerprint(
60
- options?: FingerprintOptions,
61
- ): Promise<string | FingerprintResponse> {
62
- await initializeWasm();
63
-
64
- const opts = {
65
- entropy: {},
66
- hash: "sha256",
67
- ...options,
68
- };
69
-
70
- const sources: EntropySource[] = [];
71
-
72
- if (opts.entropy.userAgent !== false) {
73
- const value = await getUserAgentEntropy();
74
- sources.push({ name: "userAgent", value, entropy: calculateEntropy(value) });
75
- }
76
-
77
- if (opts.entropy.canvas !== false) {
78
- const value = await getCanvasEntropy();
79
- sources.push({ name: "canvas", value, entropy: calculateEntropy(value) });
80
- }
81
-
82
- if (opts.entropy.webgl !== false) {
83
- const value = await getWebGLEntropy();
84
- sources.push({ name: "webgl", value, entropy: calculateEntropy(value) });
85
- }
86
-
87
- if (opts.entropy.fonts !== false) {
88
- const value = await getFontsEntropy();
89
- sources.push({ name: "fonts", value, entropy: calculateEntropy(value) });
90
- }
91
-
92
- if (opts.entropy.storage !== false) {
93
- const value = await getStorageEntropy();
94
- sources.push({ name: "storage", value, entropy: calculateEntropy(value) });
95
- }
96
-
97
- if (opts.entropy.screen !== false) {
98
- const value = await getScreenEntropy();
99
- sources.push({ name: "screen", value, entropy: calculateEntropy(value) });
100
- }
101
-
102
- const baseSeed = sources.map(s => s.value).join("|");
103
-
104
- sources.push({ name: "distribution", value: await getDistributionEntropy(baseSeed), entropy: 0 });
105
- sources.push({ name: "complexity", value: await getComplexityEntropy(), entropy: 0 });
106
- sources.push({ name: "spectral", value: await getSpectralEntropy(baseSeed), entropy: 0 });
107
- sources.push({ name: "approximate", value: await getApproximateEntropy(baseSeed), entropy: 0 });
108
- sources.push({ name: "os", value: await getOSEntropy(), entropy: 0 });
109
- sources.push({ name: "language", value: await getLanguageEntropy(), entropy: 0 });
110
- sources.push({ name: "timezone", value: await getTimezoneEntropy(), entropy: 0 });
111
- sources.push({ name: "hardware", value: await getHardwareEntropy(), entropy: 0 });
112
- sources.push({ name: "plugins", value: await getPluginsEntropy(), entropy: 0 });
113
- sources.push({ name: "browser", value: await getBrowserEntropy(), entropy: 0 });
114
- sources.push({ name: "osVersion", value: await getOSVersionEntropy(), entropy: 0 });
115
- sources.push({ name: "screenInfo", value: await getScreenInfoEntropy(), entropy: 0 });
116
- sources.push({ name: "adblock", value: await getAdblockEntropy(), entropy: 0 });
117
- sources.push({ name: "webFeatures", value: await getWebFeaturesEntropy(), entropy: 0 });
118
- sources.push({ name: "preferences", value: await getPreferencesEntropy(), entropy: 0 });
119
- sources.push({ name: "permissions", value: await getPermissionsEntropy(), entropy: 0 });
120
- sources.push({ name: "statistical", value: await getStatisticalEntropy(), entropy: 0 });
121
- sources.push({ name: "probabilistic", value: await getProbabilisticEntropy(), entropy: 0 });
122
-
123
- for (const source of sources) {
124
- if (source.entropy === 0) {
125
- source.entropy = calculateEntropy(source.value);
126
- }
127
- }
128
-
129
- const score = scoreFingerprint(sources);
130
- const tamper = analyzeTamper(sources);
131
- const stability = getSourceStability(sources);
132
- const assessment = assessFingerprint(sources);
133
-
134
- const deviceIdentity = generateDeviceIdentity(sources);
135
-
136
- const data = sources.map(s => s.value);
137
- const combined = data.join("|");
138
-
139
- const coreWeight = "core:" + deviceIdentity.core_hash;
140
- const prefsWeight = "prefs:" + deviceIdentity.preferences_hash;
141
- const weightedInput = `${coreWeight}|${prefsWeight}|${combined}`;
142
-
143
- const algorithm = opts.hash === "sha512" ? "SHA-512" : "SHA-256";
144
- const hash = await crypto.subtle.digest(
145
- algorithm,
146
- new TextEncoder().encode(weightedInput),
147
- );
148
-
149
- let fingerprint = Array.from(new Uint8Array(hash))
150
- .map((b) => b.toString(16).padStart(2, "0"))
151
- .join("");
152
-
153
- if (opts.detailed) {
154
- const os = await getOSVersionEntropy();
155
- const lang = await getLanguageEntropy();
156
- const tz = await getTimezoneEntropy();
157
- const hw = await getHardwareEntropy();
158
- const sr = await getScreenInfoEntropy();
159
- const ua = await getUserAgentEntropy();
160
- const browser = await getBrowserEntropy();
161
-
162
- const sourceMetrics: SourceMetric[] = sources.map(s => {
163
- const stab = stability.find(st => st.source === s.name);
164
- return {
165
- source: s.name,
166
- value: s.value,
167
- entropy: s.entropy,
168
- confidence: score.likelihood > 0 ? Math.min(s.entropy / score.likelihood, 1) : 0,
169
- stability: stab?.stability,
170
- };
171
- });
172
-
173
- const avgStability = stability.length > 0
174
- ? stability.reduce((a, b) => a + b.stability, 0) / stability.length
175
- : 0;
176
-
177
- const response: FingerprintResponse = {
178
- hash: fingerprint,
179
- uniqueness: score.uniqueness,
180
- confidence: score.confidence,
181
- stability_score: avgStability,
182
- usable: assessment.usable,
183
- warnings: assessment.warnings.length > 0 ? assessment.warnings : undefined,
184
- entropy_warnings: assessment.entropy_warnings.length > 0 ? assessment.entropy_warnings : undefined,
185
- tampering_risk: tamper.tampering_risk,
186
- anomalies: tamper.anomalies,
187
- device_identity: deviceIdentity,
188
- sources: sourceMetrics,
189
- system: {
190
- os,
191
- language: lang.split("|")[0],
192
- timezone: tz.split("|")[0],
193
- hardware: {
194
- cores: navigator.hardwareConcurrency || 0,
195
- memory: (navigator as any).deviceMemory || 0,
196
- },
197
- },
198
- display: {
199
- resolution: `${screen.width}x${screen.height}`,
200
- colorDepth: screen.colorDepth,
201
- devicePixelRatio: window.devicePixelRatio,
202
- },
203
- browser: {
204
- userAgent: navigator.userAgent,
205
- vendor: navigator.vendor,
206
- cookieEnabled: navigator.cookieEnabled,
207
- },
208
- };
209
-
210
- return response;
211
- }
212
-
213
- return fingerprint;
214
- }
215
-
216
- export async function compareFingerpints(
217
- fp1: string | FingerprintResponse,
218
- fp2: string | FingerprintResponse,
219
- ): Promise<{ similarity: number; match: boolean }> {
220
- const hash1 = typeof fp1 === "string" ? fp1 : fp1.hash;
221
- const hash2 = typeof fp2 === "string" ? fp2 : fp2.hash;
222
-
223
- const sim = similarityScore(hash1, hash2);
224
- const match = sim > 0.95;
225
-
226
- return { similarity: sim, match };
227
- }
228
-
229
- export async function matchProbability(
230
- storedFingerprints: (string | FingerprintResponse)[],
231
- currentFingerprint: string | FingerprintResponse,
232
- ): Promise<{ bestMatch: number; confidence: number }> {
233
- const currentHash = typeof currentFingerprint === "string" ? currentFingerprint : currentFingerprint.hash;
234
-
235
- let bestMatch = 0;
236
- for (const stored of storedFingerprints) {
237
- const storedHash = typeof stored === "string" ? stored : stored.hash;
238
- const sim = similarityScore(currentHash, storedHash);
239
- if (sim > bestMatch) {
240
- bestMatch = sim;
241
- }
242
- }
243
-
244
- const confidence = Math.min(bestMatch * 1.2, 1.0);
245
- return { bestMatch, confidence };
246
- }
247
-
248
- export type { FingerprintOptions, FingerprintResponse } from "./types";
@@ -1,31 +0,0 @@
1
- export function normalizeScreen(width: number, height: number): string {
2
- const bucketSize = 100;
3
- const bw = Math.floor(width / bucketSize) * bucketSize;
4
- const bh = Math.floor(height / bucketSize) * bucketSize;
5
- return `${bw}x${bh}`;
6
- }
7
-
8
- export function normalizeTimezone(tz: string): string {
9
- return tz.split("/")[0];
10
- }
11
-
12
- export function normalizeUserAgent(ua: string): string {
13
- const parts = ua.split(" ");
14
- return parts.slice(0, 3).join(" ");
15
- }
16
-
17
- export function normalizeFloat(num: number, decimals: number = 10): string {
18
- return num.toFixed(decimals);
19
- }
20
-
21
- export function normalizeCanvas(dataUrl: string): string {
22
- return dataUrl.substring(0, 100);
23
- }
24
-
25
- export function normalizeStorage(storageStr: string): string {
26
- const [localStorage, indexedDB] = storageStr.split("|");
27
- const ls = localStorage.includes("true") ? "1" : "0";
28
- const idb = indexedDB.includes("true") ? "1" : "0";
29
-
30
- return `${ls}${idb}`;
31
- }
@@ -1,11 +0,0 @@
1
- export function calculateMean(values: number[]): number {
2
- if (values.length === 0) return 0;
3
- return values.reduce((a, b) => a + b, 0) / values.length;
4
- }
5
-
6
- export function hellingerDistance(p: number[], q: number[]): number {
7
- if (p.length !== q.length) return 0;
8
-
9
- const sum = p.reduce((s, pi, i) => s + Math.pow(Math.sqrt(pi) - Math.sqrt(q[i]), 2), 0);
10
- return Math.sqrt(sum / 2);
11
- }
package/src/scoring.ts DELETED
@@ -1,106 +0,0 @@
1
- import { calculateMean, hellingerDistance } from "./probability";
2
-
3
- export interface EntropySource {
4
- name: string;
5
- value: string;
6
- entropy: number;
7
- }
8
-
9
- export interface FingerprintScore {
10
- likelihood: number;
11
- confidence: number;
12
- uniqueness: number;
13
- divergence: number;
14
- sources: EntropySource[];
15
- }
16
-
17
- export function calculateEntropy(data: string): number {
18
- const freq: Record<string, number> = {};
19
- for (const char of data) {
20
- freq[char] = (freq[char] || 0) + 1;
21
- }
22
-
23
- let entropy = 0;
24
- for (const count of Object.values(freq)) {
25
- const p = count / data.length;
26
- if (p > 0) {
27
- entropy -= p * Math.log2(p);
28
- }
29
- }
30
- return entropy;
31
- }
32
-
33
- export function calculateLikelihood(sources: EntropySource[]): number {
34
- const entropies = sources.map(s => s.entropy).filter(e => !isNaN(e) && e > 0);
35
-
36
- if (entropies.length === 0) return 0;
37
-
38
- const mean = entropies.reduce((a, b) => a + b) / entropies.length;
39
- const variance = entropies.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / entropies.length;
40
- const stdDev = Math.sqrt(variance);
41
-
42
- return mean * (1 + stdDev / mean);
43
- }
44
-
45
- export function calculateConfidence(sources: EntropySource[], likelihood: number): number {
46
- const maxPossibleEntropy = Math.log2(256);
47
- const sourceCount = sources.length;
48
-
49
- const normalizedLikelihood = Math.min(likelihood / maxPossibleEntropy, 1);
50
- const sourceWeighting = Math.log2(sourceCount + 1) / Math.log2(32);
51
-
52
- return normalizedLikelihood * sourceWeighting;
53
- }
54
-
55
- export function calculateUniqueness(sources: EntropySource[], likelihood: number, confidence: number): number {
56
- const distinctSources = new Set(sources.map(s => s.value)).size;
57
- const totalSources = sources.length;
58
- const diversity = distinctSources / totalSources;
59
-
60
- const informationContent = likelihood * Math.log2(totalSources);
61
- const uniquenessScore = informationContent * confidence * diversity;
62
-
63
- return Math.min(uniquenessScore / 100, 0.999);
64
- }
65
-
66
- export function scoreFingerprint(sources: EntropySource[]): FingerprintScore {
67
- const likelihood = calculateLikelihood(sources);
68
- const confidence = calculateConfidence(sources, likelihood);
69
- const uniqueness = calculateUniqueness(sources, likelihood, confidence);
70
-
71
- const entropies = sources.map(s => s.entropy).filter(e => !isNaN(e) && e > 0);
72
- const uniformDist = new Array(entropies.length).fill(1 / entropies.length);
73
- const normalizedEntropies = entropies.length > 0
74
- ? entropies.map(e => e / calculateMean(entropies))
75
- : [];
76
-
77
- const divergence = normalizedEntropies.length > 0
78
- ? hellingerDistance(normalizedEntropies, uniformDist.slice(0, normalizedEntropies.length))
79
- : 0;
80
-
81
- return {
82
- likelihood,
83
- confidence,
84
- uniqueness,
85
- divergence,
86
- sources,
87
- };
88
- }
89
-
90
- export function bayesianCombine(sources: EntropySource[]): Record<string, number> {
91
- const score = scoreFingerprint(sources);
92
-
93
- const weights: Record<string, number> = {};
94
- const totalEntropy = sources.reduce((sum, s) => sum + (s.entropy || 0), 0);
95
-
96
- for (const source of sources) {
97
- const sourceEntropy = source.entropy || 0;
98
- const prior = 1 / sources.length;
99
- const likelihood = sourceEntropy / (totalEntropy || 1);
100
- const posterior = (likelihood * prior) / score.likelihood;
101
-
102
- weights[source.name] = posterior;
103
- }
104
-
105
- return weights;
106
- }
package/src/seeded-rng.ts DELETED
@@ -1,14 +0,0 @@
1
- export function seededRng(seed: string, count: number): number[] {
2
- let hash = 5381;
3
- for (let i = 0; i < seed.length; i++) {
4
- hash = ((hash << 5) + hash) ^ seed.charCodeAt(i);
5
- }
6
-
7
- const samples: number[] = [];
8
- for (let i = 0; i < count; i++) {
9
- hash = (hash * 1103515245 + 12345) & 0x7fffffff;
10
- samples.push(hash / 0x7fffffff);
11
- }
12
-
13
- return samples;
14
- }