@cloudglides/veil 1.0.0 → 1.0.2

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 (58) hide show
  1. package/README.md +190 -0
  2. package/dist/index.d.ts +103 -0
  3. package/dist/index.js +999 -0
  4. package/dist/veil_core.js +370 -0
  5. package/dist/veil_core_bg.wasm +0 -0
  6. package/package.json +24 -10
  7. package/.envrc +0 -1
  8. package/.github/workflows/build-on-tag.yml +0 -75
  9. package/example/index.html +0 -226
  10. package/flake.nix +0 -68
  11. package/scripts/patch-wasm.js +0 -12
  12. package/src/cpu.ts +0 -67
  13. package/src/entropy/adblock.ts +0 -16
  14. package/src/entropy/approximate.ts +0 -8
  15. package/src/entropy/audio.ts +0 -17
  16. package/src/entropy/battery.ts +0 -10
  17. package/src/entropy/browser.ts +0 -7
  18. package/src/entropy/canvas.ts +0 -17
  19. package/src/entropy/complexity.ts +0 -13
  20. package/src/entropy/connection.ts +0 -14
  21. package/src/entropy/distribution.ts +0 -8
  22. package/src/entropy/fonts.ts +0 -4
  23. package/src/entropy/hardware.ts +0 -10
  24. package/src/entropy/language.ts +0 -14
  25. package/src/entropy/os.ts +0 -12
  26. package/src/entropy/osVersion.ts +0 -6
  27. package/src/entropy/performance.ts +0 -14
  28. package/src/entropy/permissions.ts +0 -15
  29. package/src/entropy/plugins.ts +0 -14
  30. package/src/entropy/preferences.ts +0 -12
  31. package/src/entropy/probabilistic.ts +0 -20
  32. package/src/entropy/screen.ts +0 -12
  33. package/src/entropy/screenInfo.ts +0 -8
  34. package/src/entropy/spectral.ts +0 -8
  35. package/src/entropy/statistical.ts +0 -15
  36. package/src/entropy/storage.ts +0 -22
  37. package/src/entropy/timezone.ts +0 -10
  38. package/src/entropy/userAgent.ts +0 -16
  39. package/src/entropy/webFeatures.ts +0 -21
  40. package/src/entropy/webgl.ts +0 -11
  41. package/src/gpu.ts +0 -132
  42. package/src/index.test.ts +0 -26
  43. package/src/index.ts +0 -198
  44. package/src/normalize/index.ts +0 -31
  45. package/src/probability.ts +0 -11
  46. package/src/scoring.ts +0 -106
  47. package/src/seeded-rng.ts +0 -14
  48. package/src/types/index.ts +0 -11
  49. package/src/types.ts +0 -47
  50. package/src/veil_core.d.ts +0 -4
  51. package/src/wasm-loader.ts +0 -14
  52. package/tsconfig.json +0 -12
  53. package/tsup.config.ts +0 -35
  54. package/veil-core/Cargo.lock +0 -114
  55. package/veil-core/Cargo.toml +0 -12
  56. package/veil-core/src/entropy.rs +0 -132
  57. package/veil-core/src/lib.rs +0 -90
  58. package/vitest.config.ts +0 -15
@@ -1,15 +0,0 @@
1
- export async function getStatisticalEntropy(): Promise<string> {
2
- const ua = navigator.userAgent;
3
- const freq: Record<string, number> = {};
4
-
5
- for (const char of ua) {
6
- freq[char] = (freq[char] || 0) + 1;
7
- }
8
-
9
- const values = Object.values(freq);
10
- const mean = values.reduce((a, b) => a + b) / values.length;
11
- const variance = values.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / values.length;
12
- const stdDev = Math.sqrt(variance);
13
-
14
- return `mean:${mean.toFixed(4)}|var:${variance.toFixed(4)}|std:${stdDev.toFixed(4)}`;
15
- }
@@ -1,22 +0,0 @@
1
- export async function getStorageEntropy(): Promise<string> {
2
- let ls = false;
3
- let idb = false;
4
-
5
- try {
6
- const test = "__storage_test__";
7
- window.localStorage.setItem(test, test);
8
- window.localStorage.removeItem(test);
9
- ls = true;
10
- } catch {
11
- ls = false;
12
- }
13
-
14
- try {
15
- const request = window.indexedDB.open("__idb_test__");
16
- idb = true;
17
- } catch {
18
- idb = false;
19
- }
20
-
21
- return `localStorage:${ls}|indexedDB:${idb}`;
22
- }
@@ -1,10 +0,0 @@
1
- export async function getTimezoneEntropy(): Promise<string> {
2
- const tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
3
- const offset = new Date().getTimezoneOffset();
4
-
5
- const tzEntropy = Math.log2(Math.abs(offset) + 1);
6
- const offsetBits = offset.toString().length * 8;
7
- const tzUniqueness = Math.log2(24 * 60 / Math.max(Math.abs(offset), 1));
8
-
9
- return `TZ:${tz}|offset:${offset}|H(TZ)=${tzEntropy.toFixed(3)}|U=${tzUniqueness.toFixed(3)}`;
10
- }
@@ -1,16 +0,0 @@
1
- export async function getUserAgentEntropy(): Promise<string> {
2
- const ua = navigator.userAgent;
3
-
4
- let entropy = 0;
5
- const freq: Record<string, number> = {};
6
- for (const char of ua) {
7
- freq[char] = (freq[char] || 0) + 1;
8
- }
9
-
10
- for (const count of Object.values(freq)) {
11
- const p = count / ua.length;
12
- entropy -= p * Math.log2(p);
13
- }
14
-
15
- return `${ua}|H(UA)=${entropy.toFixed(4)}`;
16
- }
@@ -1,21 +0,0 @@
1
- export async function getWebFeaturesEntropy(): Promise<string> {
2
- const features = {
3
- localStorage: !!window.localStorage,
4
- sessionStorage: !!window.sessionStorage,
5
- indexedDB: !!window.indexedDB,
6
- openDatabase: !!(window as any).openDatabase,
7
- serviceWorker: !!navigator.serviceWorker,
8
- webWorker: typeof Worker !== "undefined",
9
- geolocation: !!navigator.geolocation,
10
- notifications: !!window.Notification,
11
- };
12
-
13
- const enabled = Object.values(features).filter(Boolean).length;
14
- const total = Object.keys(features).length;
15
- const supportRatio = enabled / total;
16
- const supportEntropy = Math.log2(total) * (1 - Math.abs(supportRatio - 0.5) * 2);
17
-
18
- return `enabled:${enabled}/${total}|σ=${supportRatio.toFixed(3)}|H(features)=${supportEntropy.toFixed(3)}|${Object.entries(features)
19
- .map(([k, v]) => `${k}:${v}`)
20
- .join("|")}`;
21
- }
@@ -1,11 +0,0 @@
1
- export async function getWebGLEntropy(): Promise<string> {
2
- const canvas = document.createElement("canvas");
3
- const gl = canvas.getContext("webgl") || canvas.getContext("webgl2");
4
- if (!gl) return "webgl:unavailable";
5
-
6
- const vendor = gl.getParameter(gl.VENDOR) || "unknown";
7
- const renderer = gl.getParameter(gl.RENDERER) || "unknown";
8
- const version = gl.getParameter(gl.VERSION) || "unknown";
9
-
10
- return `vendor:${vendor}|renderer:${renderer}|version:${version}`;
11
- }
package/src/gpu.ts DELETED
@@ -1,132 +0,0 @@
1
- export async function runGPUBenchmark(): Promise<{
2
- renderTime: number;
3
- textureOps: number;
4
- shaderPerformance: number;
5
- }> {
6
- const canvas = document.createElement("canvas");
7
- canvas.width = 512;
8
- canvas.height = 512;
9
-
10
- const gl = canvas.getContext("webgl2") || canvas.getContext("webgl");
11
- if (!gl) {
12
- return { renderTime: 0, textureOps: 0, shaderPerformance: 0 };
13
- }
14
-
15
- const start = performance.now();
16
-
17
- const vertexShader = gl.createShader(gl.VERTEX_SHADER);
18
- if (!vertexShader) return { renderTime: 0, textureOps: 0, shaderPerformance: 0 };
19
-
20
- gl.shaderSource(
21
- vertexShader,
22
- `
23
- attribute vec2 position;
24
- void main() {
25
- gl_Position = vec4(position, 0.0, 1.0);
26
- }
27
- `,
28
- );
29
- gl.compileShader(vertexShader);
30
-
31
- const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
32
- if (!fragmentShader) return { renderTime: 0, textureOps: 0, shaderPerformance: 0 };
33
-
34
- gl.shaderSource(
35
- fragmentShader,
36
- `
37
- precision highp float;
38
- uniform sampler2D tex;
39
- void main() {
40
- gl_FragColor = texture2D(tex, vec2(0.5, 0.5));
41
- }
42
- `,
43
- );
44
- gl.compileShader(fragmentShader);
45
-
46
- const program = gl.createProgram();
47
- if (!program) return { renderTime: 0, textureOps: 0, shaderPerformance: 0 };
48
-
49
- gl.attachShader(program, vertexShader);
50
- gl.attachShader(program, fragmentShader);
51
- gl.linkProgram(program);
52
- gl.useProgram(program);
53
-
54
- const positionBuffer = gl.createBuffer();
55
- gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
56
- gl.bufferData(
57
- gl.ARRAY_BUFFER,
58
- new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]),
59
- gl.STATIC_DRAW,
60
- );
61
-
62
- const texture = gl.createTexture();
63
- gl.bindTexture(gl.TEXTURE_2D, texture);
64
- gl.texImage2D(
65
- gl.TEXTURE_2D,
66
- 0,
67
- gl.RGBA,
68
- 256,
69
- 256,
70
- 0,
71
- gl.RGBA,
72
- gl.UNSIGNED_BYTE,
73
- new Uint8Array(256 * 256 * 4).fill(128),
74
- );
75
-
76
- for (let i = 0; i < 100; i++) {
77
- gl.clear(gl.COLOR_BUFFER_BIT);
78
- gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
79
- }
80
-
81
- gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(4));
82
-
83
- const renderTime = performance.now() - start;
84
-
85
- const textureOps = 100;
86
- const shaderPerformance = 512 * 512 * 100 / (renderTime || 1);
87
-
88
- gl.deleteShader(vertexShader);
89
- gl.deleteShader(fragmentShader);
90
- gl.deleteProgram(program);
91
- gl.deleteBuffer(positionBuffer);
92
- gl.deleteTexture(texture);
93
-
94
- canvas.remove();
95
-
96
- return {
97
- renderTime,
98
- textureOps,
99
- shaderPerformance,
100
- };
101
- }
102
-
103
- export async function getGPUHash(): Promise<string> {
104
- const benchmark = await runGPUBenchmark();
105
- const canvas = document.createElement("canvas");
106
- canvas.width = 256;
107
- canvas.height = 256;
108
-
109
- const ctx = canvas.getContext("2d");
110
- if (!ctx) return "";
111
-
112
- for (let i = 0; i < 256; i++) {
113
- for (let j = 0; j < 256; j++) {
114
- const hue = (benchmark.renderTime * (i + j)) % 360;
115
- const sat = (benchmark.shaderPerformance * i) % 100;
116
- const lum = (benchmark.textureOps * j) % 100;
117
-
118
- ctx.fillStyle = `hsl(${hue}, ${sat}%, ${lum}%)`;
119
- ctx.fillRect(i, j, 1, 1);
120
- }
121
- }
122
-
123
- const imageData = ctx.getImageData(0, 0, 256, 256);
124
- const data = imageData.data;
125
-
126
- let hash = 0;
127
- for (let i = 0; i < data.length; i += 4) {
128
- hash ^= ((data[i] + data[i + 1] + data[i + 2]) * (i * 1)) >> 0;
129
- }
130
-
131
- return hash.toString(16);
132
- }
package/src/index.test.ts DELETED
@@ -1,26 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { getFingerprint } from "./index";
3
-
4
- describe("veil fingerprinting", () => {
5
- it("should generate consistent fingerprint", async () => {
6
- const fp1 = await getFingerprint();
7
- const fp2 = await getFingerprint();
8
- expect(fp1).toBe(fp2);
9
- });
10
-
11
- it("should generate different fingerprints with different options", async () => {
12
- const fp1 = await getFingerprint({ entropy: { canvas: true } });
13
- const fp2 = await getFingerprint({ entropy: { canvas: false } });
14
- expect(fp1).not.toBe(fp2);
15
- });
16
-
17
- it("should support SHA-512", async () => {
18
- const fp = await getFingerprint({ hash: "sha512" });
19
- expect(fp.length).toBeGreaterThan(64);
20
- });
21
-
22
- it("should return hex string", async () => {
23
- const fp = await getFingerprint();
24
- expect(/^[a-f0-9]+$/.test(fp)).toBe(true);
25
- });
26
- });
package/src/index.ts DELETED
@@ -1,198 +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
- import {
27
- murmur_hash,
28
- fnv_hash,
29
- shannon_entropy,
30
- kolmogorov_complexity,
31
- } from "./veil_core.js";
32
- import * as normalize from "./normalize";
33
- import { initializeWasm } from "./wasm-loader";
34
- import { scoreFingerprint, calculateEntropy, type EntropySource } from "./scoring";
35
- import { getGPUHash, runGPUBenchmark } from "./gpu";
36
- import { getCPUHash, runCPUBenchmark } from "./cpu";
37
- import { seededRng } from "./seeded-rng";
38
-
39
- export async function getFingerprint(
40
- options?: FingerprintOptions,
41
- ): Promise<string | FingerprintResponse> {
42
- await initializeWasm();
43
-
44
- const opts = {
45
- entropy: {},
46
- hash: "sha256",
47
- ...options,
48
- };
49
-
50
- const sources: EntropySource[] = [];
51
-
52
- if (opts.entropy.userAgent !== false) {
53
- const value = await getUserAgentEntropy();
54
- sources.push({ name: "userAgent", value, entropy: calculateEntropy(value) });
55
- }
56
-
57
- if (opts.entropy.canvas !== false) {
58
- const value = await getCanvasEntropy();
59
- sources.push({ name: "canvas", value, entropy: calculateEntropy(value) });
60
- }
61
-
62
- if (opts.entropy.webgl !== false) {
63
- const value = await getWebGLEntropy();
64
- sources.push({ name: "webgl", value, entropy: calculateEntropy(value) });
65
- }
66
-
67
- if (opts.entropy.fonts !== false) {
68
- const value = await getFontsEntropy();
69
- sources.push({ name: "fonts", value, entropy: calculateEntropy(value) });
70
- }
71
-
72
- if (opts.entropy.storage !== false) {
73
- const value = await getStorageEntropy();
74
- sources.push({ name: "storage", value, entropy: calculateEntropy(value) });
75
- }
76
-
77
- if (opts.entropy.screen !== false) {
78
- const value = await getScreenEntropy();
79
- sources.push({ name: "screen", value, entropy: calculateEntropy(value) });
80
- }
81
-
82
- const baseSeed = sources.map(s => s.value).join("|");
83
-
84
- sources.push({ name: "distribution", value: await getDistributionEntropy(baseSeed), entropy: 0 });
85
- sources.push({ name: "complexity", value: await getComplexityEntropy(), entropy: 0 });
86
- sources.push({ name: "spectral", value: await getSpectralEntropy(baseSeed), entropy: 0 });
87
- sources.push({ name: "approximate", value: await getApproximateEntropy(baseSeed), entropy: 0 });
88
- sources.push({ name: "os", value: await getOSEntropy(), entropy: 0 });
89
- sources.push({ name: "language", value: await getLanguageEntropy(), entropy: 0 });
90
- sources.push({ name: "timezone", value: await getTimezoneEntropy(), entropy: 0 });
91
- sources.push({ name: "hardware", value: await getHardwareEntropy(), entropy: 0 });
92
- sources.push({ name: "plugins", value: await getPluginsEntropy(), entropy: 0 });
93
- sources.push({ name: "browser", value: await getBrowserEntropy(), entropy: 0 });
94
- sources.push({ name: "osVersion", value: await getOSVersionEntropy(), entropy: 0 });
95
- sources.push({ name: "screenInfo", value: await getScreenInfoEntropy(), entropy: 0 });
96
- sources.push({ name: "adblock", value: await getAdblockEntropy(), entropy: 0 });
97
- sources.push({ name: "webFeatures", value: await getWebFeaturesEntropy(), entropy: 0 });
98
- sources.push({ name: "preferences", value: await getPreferencesEntropy(), entropy: 0 });
99
- sources.push({ name: "permissions", value: await getPermissionsEntropy(), entropy: 0 });
100
- sources.push({ name: "statistical", value: await getStatisticalEntropy(), entropy: 0 });
101
- sources.push({ name: "probabilistic", value: await getProbabilisticEntropy(), entropy: 0 });
102
-
103
- for (const source of sources) {
104
- if (source.entropy === 0) {
105
- source.entropy = calculateEntropy(source.value);
106
- }
107
- }
108
-
109
- const score = scoreFingerprint(sources);
110
-
111
- const data = sources.map(s => s.value);
112
-
113
- const dataStr = data.join("|");
114
- const shannon = shannon_entropy(dataStr);
115
- const kolmogorov = kolmogorov_complexity(dataStr);
116
- const murmur = murmur_hash(dataStr);
117
- const fnv = fnv_hash(dataStr);
118
-
119
- const mathMetrics = `${shannon}|${kolmogorov}|${murmur}|${fnv}`;
120
- const combined = dataStr + "|" + mathMetrics;
121
-
122
- const algorithm = opts.hash === "sha512" ? "SHA-512" : "SHA-256";
123
- const hash = await crypto.subtle.digest(
124
- algorithm,
125
- new TextEncoder().encode(combined),
126
- );
127
-
128
- let fingerprint = Array.from(new Uint8Array(hash))
129
- .map((b) => b.toString(16).padStart(2, "0"))
130
- .join("");
131
-
132
- if (opts.gpuBenchmark) {
133
- const gpuHash = await getGPUHash();
134
- fingerprint = Array.from(new Uint8Array(
135
- await crypto.subtle.digest("SHA-256", new TextEncoder().encode(fingerprint + gpuHash))
136
- ))
137
- .map((b) => b.toString(16).padStart(2, "0"))
138
- .join("");
139
- }
140
-
141
- if (opts.cpuBenchmark) {
142
- const cpuHash = await getCPUHash();
143
- fingerprint = Array.from(new Uint8Array(
144
- await crypto.subtle.digest("SHA-256", new TextEncoder().encode(fingerprint + cpuHash))
145
- ))
146
- .map((b) => b.toString(16).padStart(2, "0"))
147
- .join("");
148
- }
149
-
150
- if (opts.detailed) {
151
- const os = await getOSVersionEntropy();
152
- const lang = await getLanguageEntropy();
153
- const tz = await getTimezoneEntropy();
154
- const hw = await getHardwareEntropy();
155
- const sr = await getScreenInfoEntropy();
156
- const ua = await getUserAgentEntropy();
157
- const browser = await getBrowserEntropy();
158
-
159
- const sourceMetrics: SourceMetric[] = sources.map(s => ({
160
- source: s.name,
161
- value: s.value,
162
- entropy: s.entropy,
163
- confidence: score.likelihood > 0 ? Math.min(s.entropy / score.likelihood, 1) : 0,
164
- }));
165
-
166
- const response: FingerprintResponse = {
167
- hash: fingerprint,
168
- uniqueness: score.uniqueness,
169
- confidence: score.confidence,
170
- sources: sourceMetrics,
171
- system: {
172
- os,
173
- language: lang.split("|")[0],
174
- timezone: tz.split("|")[0],
175
- hardware: {
176
- cores: navigator.hardwareConcurrency || 0,
177
- memory: (navigator as any).deviceMemory || 0,
178
- },
179
- },
180
- display: {
181
- resolution: `${screen.width}x${screen.height}`,
182
- colorDepth: screen.colorDepth,
183
- devicePixelRatio: window.devicePixelRatio,
184
- },
185
- browser: {
186
- userAgent: navigator.userAgent,
187
- vendor: navigator.vendor,
188
- cookieEnabled: navigator.cookieEnabled,
189
- },
190
- };
191
-
192
- return response;
193
- }
194
-
195
- return fingerprint;
196
- }
197
-
198
- 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
- }
@@ -1,11 +0,0 @@
1
- export interface FingerprintOptions {
2
- entropy: {
3
- userAgent?: boolean;
4
- canvas?: boolean;
5
- webgl?: boolean;
6
- fonts?: boolean;
7
- storage?: boolean;
8
- screen?: boolean;
9
- };
10
- hash?: "sha256" | "sha512";
11
- }
package/src/types.ts DELETED
@@ -1,47 +0,0 @@
1
- export interface FingerprintOptions {
2
- entropy: {
3
- userAgent?: boolean;
4
- canvas?: boolean;
5
- webgl?: boolean;
6
- fonts?: boolean;
7
- storage?: boolean;
8
- screen?: boolean;
9
- };
10
- hash?: "sha256" | "sha512";
11
- detailed?: boolean;
12
- gpuBenchmark?: boolean;
13
- cpuBenchmark?: boolean;
14
- }
15
-
16
- export interface SourceMetric {
17
- source: string;
18
- value: string;
19
- entropy: number;
20
- confidence: number;
21
- }
22
-
23
- export interface FingerprintResponse {
24
- hash: string;
25
- uniqueness: number;
26
- confidence: number;
27
- sources: SourceMetric[];
28
- system: {
29
- os: string;
30
- language: string;
31
- timezone: string;
32
- hardware: {
33
- cores: number;
34
- memory: number;
35
- };
36
- };
37
- display: {
38
- resolution: string;
39
- colorDepth: number;
40
- devicePixelRatio: number;
41
- };
42
- browser: {
43
- userAgent: string;
44
- vendor: string;
45
- cookieEnabled: boolean;
46
- };
47
- }
@@ -1,4 +0,0 @@
1
- export function fnv_hash(s: string): string;
2
- export function kolmogorov_complexity(s: string): number;
3
- export function murmur_hash(s: string): string;
4
- export function shannon_entropy(s: string): number;