@cloudglides/veil 0.1.0 → 0.1.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.
@@ -78,3 +78,5 @@ jobs:
78
78
  dist/veil_core_bg.wasm
79
79
  env:
80
80
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
81
+
82
+
@@ -0,0 +1,73 @@
1
+ name: Deploy to GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+
8
+ concurrency:
9
+ group: "pages"
10
+ cancel-in-progress: false
11
+
12
+ permissions:
13
+ contents: read
14
+ pages: write
15
+ id-token: write
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: pnpm/action-setup@v2
24
+ with:
25
+ version: 8
26
+
27
+ - uses: actions/setup-node@v4
28
+ with:
29
+ node-version: '20'
30
+ cache: 'pnpm'
31
+
32
+ - uses: dtolnay/rust-toolchain@stable
33
+
34
+ - name: Install wasm-pack
35
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
36
+
37
+ - name: Install dependencies
38
+ run: pnpm install
39
+
40
+ - name: Build WASM
41
+ run: pnpm run build:wasm
42
+
43
+ - name: Build
44
+ run: pnpm run build
45
+ env:
46
+ # Add this if you need base path configuration
47
+ VITE_BASE_PATH: /veil/
48
+
49
+ - name: Copy dist to example
50
+ run: |
51
+ cp -r dist/* example/
52
+ touch example/.nojekyll
53
+
54
+ - name: Setup Pages
55
+ uses: actions/configure-pages@v3
56
+
57
+ - name: Upload artifact
58
+ uses: actions/upload-pages-artifact@v4
59
+ with:
60
+ path: 'example'
61
+
62
+ deploy:
63
+ environment:
64
+ name: github-pages
65
+ url: ${{ steps.deployment.outputs.page_url }}
66
+ runs-on: ubuntu-latest
67
+ needs: build
68
+ steps:
69
+ - name: Deploy to GitHub Pages
70
+ id: deployment
71
+ uses: actions/deploy-pages@v4
72
+
73
+
package/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Veil
2
+
3
+ A deterministic browser fingerprinting library with mathematical rigor and tamper detection.
4
+
5
+ ## Features
6
+
7
+ - **Deterministic Hashing** - Consistent fingerprints across browser refreshes
8
+ - **Mathematical Rigor** - Information-theoretic entropy sources with Bayesian scoring
9
+ - **Tamper Detection** - Identifies suspicious patterns and anomalies in entropy data
10
+ - **Browser Compatible** - Works in modern browsers via WASM
11
+ - **Minimal Overhead** - Lightweight library with no external dependencies
12
+ - **Detailed Metrics** - Uniqueness, confidence, and per-source entropy analysis
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @cloudglides/veil
18
+ # or
19
+ pnpm add @cloudglides/veil
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```javascript
25
+ import { getFingerprint } from "@cloudglides/veil";
26
+
27
+ // Simple hash
28
+ const hash = await getFingerprint();
29
+ console.log(hash); // e.g., "a3f5d8c..."
30
+
31
+ // Detailed analysis
32
+ const fingerprint = await getFingerprint({ detailed: true });
33
+ console.log(fingerprint.hash); // fingerprint hash
34
+ console.log(fingerprint.uniqueness); // 0-1 uniqueness score
35
+ console.log(fingerprint.confidence); // 0-1 confidence score
36
+ console.log(fingerprint.tampering_risk); // 0-1 tampering risk
37
+ console.log(fingerprint.anomalies); // array of detected anomalies
38
+ console.log(fingerprint.sources); // entropy sources and their contributions
39
+ ```
40
+
41
+ ## API Reference
42
+
43
+ ### `getFingerprint(options?): Promise<string | FingerprintResponse>`
44
+
45
+ Generates a browser fingerprint.
46
+
47
+ **Options:**
48
+
49
+ ```typescript
50
+ interface FingerprintOptions {
51
+ entropy?: {
52
+ userAgent?: boolean; // default: true
53
+ canvas?: boolean; // default: true
54
+ webgl?: boolean; // default: true
55
+ fonts?: boolean; // default: true
56
+ storage?: boolean; // default: true
57
+ screen?: boolean; // default: true
58
+ };
59
+ hash?: "sha256" | "sha512"; // default: "sha256"
60
+ detailed?: boolean; // return full response (default: false)
61
+ }
62
+ ```
63
+
64
+ **Returns:**
65
+
66
+ - `string` - 64 or 128 character hash (if `detailed: false`)
67
+ - `FingerprintResponse` - Full analysis object (if `detailed: true`)
68
+
69
+ ### `compareFingerpints(fp1, fp2): Promise<{ similarity: number; match: boolean }>`
70
+
71
+ Compares two fingerprints using Levenshtein distance.
72
+
73
+ ```javascript
74
+ const fp1 = await getFingerprint();
75
+ const fp2 = await getFingerprint();
76
+ const { similarity, match } = await compareFingerpints(fp1, fp2);
77
+
78
+ console.log(similarity); // 0-1, higher = more similar
79
+ console.log(match); // true if similarity > 0.95
80
+ ```
81
+
82
+ ### `matchProbability(stored, current): Promise<{ bestMatch: number; confidence: number }>`
83
+
84
+ Finds best match from a stored fingerprint set.
85
+
86
+ ```javascript
87
+ const currentFp = await getFingerprint();
88
+ const storedFps = [fp1, fp2, fp3];
89
+
90
+ const { bestMatch, confidence } = await matchProbability(storedFps, currentFp);
91
+ console.log(bestMatch); // 0-1 highest similarity
92
+ console.log(confidence); // probability estimate
93
+ ```
94
+
95
+ ## Entropy Sources
96
+
97
+ Veil collects entropy from multiple sources:
98
+
99
+ - **userAgent** - Browser user agent string
100
+ - **canvas** - HTML5 canvas fingerprinting
101
+ - **webgl** - WebGL capabilities and renderer
102
+ - **fonts** - Installed system fonts
103
+ - **storage** - LocalStorage and SessionStorage
104
+ - **screen** - Display resolution and color depth
105
+ - **distribution** - KS-test on seeded random samples
106
+ - **complexity** - Lempel-Ziv complexity
107
+ - **spectral** - Spectral entropy analysis
108
+ - **approximate** - Approximate entropy
109
+ - **os** - Operating system detection
110
+ - **language** - Browser language preferences
111
+ - **timezone** - System timezone
112
+ - **hardware** - CPU cores and device memory
113
+ - **plugins** - Browser plugins/extensions
114
+ - **browser** - Browser vendor and version
115
+ - **adblock** - Adblock detection
116
+ - **webFeatures** - Supported web APIs
117
+
118
+ ## Tamper Detection
119
+
120
+ Each fingerprint includes a `tampering_risk` score (0-1) and list of detected `anomalies`:
121
+
122
+ ```javascript
123
+ const fp = await getFingerprint({ detailed: true });
124
+
125
+ if (fp.tampering_risk > 0.5) {
126
+ console.warn("High tampering risk detected:", fp.anomalies);
127
+ }
128
+ ```
129
+
130
+ **Detected Anomalies:**
131
+
132
+ - Suspiciously uniform entropy across sources
133
+ - Duplicate values in multiple sources
134
+ - Missing critical entropy sources
135
+ - Cross-source inconsistencies (e.g., canvas/webgl mismatch)
136
+ - Suspicious placeholder values (null, fake, mock)
137
+
138
+ ## Example
139
+
140
+ See `/example/index.html` for a working demo with UI controls.
141
+
142
+ ```bash
143
+ # Start local server
144
+ python3 -m http.server 8000
145
+
146
+ # Visit http://localhost:8000/example/
147
+ ```
148
+
149
+ ## How It Works
150
+
151
+ 1. **Entropy Collection** - Gathers browser characteristics from 25+ sources
152
+ 2. **Hashing** - Combines entropy sources and applies SHA-256/512
153
+ 3. **Scoring** - Calculates uniqueness via Bayesian methods
154
+ 4. **Anomaly Detection** - Analyzes entropy distribution for tampering signs
155
+ 5. **Output** - Returns fingerprint hash with optional detailed metrics
156
+
157
+ The library uses WASM (via Rust) for computationally intensive operations:
158
+
159
+ - Kolmogorov-Smirnov test (distribution analysis)
160
+ - Lempel-Ziv complexity
161
+ - Spectral entropy
162
+ - Approximate entropy
163
+
164
+ ## Performance
165
+
166
+ - Generation: ~50-100ms (first call includes WASM init)
167
+ - Subsequent calls: ~20-30ms
168
+ - Bundle size: ~23KB (gzipped)
169
+
170
+ ## Browser Support
171
+
172
+ - Chrome/Edge 90+
173
+ - Firefox 88+
174
+ - Safari 14+
175
+ - Any browser supporting:
176
+ - WebAssembly
177
+ - Web Crypto API
178
+ - Canvas API
179
+
180
+ ## License
181
+
182
+ MIT - See LICENSE file
183
+
184
+ ## Contributing
185
+
186
+ Contributions welcome. Please open an issue or PR on GitHub.
187
+
188
+ ---
189
+
190
+ **Disclaimer:** Browser fingerprinting has privacy implications. Use responsibly and ensure compliance with local regulations and user privacy expectations.
@@ -2,6 +2,7 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
+ <!-- base href removed to fix module import paths -->
5
6
  <title>Veil Fingerprinting Demo</title>
6
7
  <style>
7
8
  body {
@@ -96,14 +97,6 @@
96
97
  <input type="checkbox" id="detailedCheckbox" checked />
97
98
  Detailed output (JSON)
98
99
  </label>
99
- <label>
100
- <input type="checkbox" id="cpuCheckbox" />
101
- CPU benchmark
102
- </label>
103
- <label>
104
- <input type="checkbox" id="gpuCheckbox" />
105
- GPU benchmark
106
- </label>
107
100
  </div>
108
101
 
109
102
  <div class="controls">
@@ -115,33 +108,26 @@
115
108
  <div id="result">Click "Generate" to start...</div>
116
109
 
117
110
  <script type="module">
118
- import { getFingerprint } from "../dist/index.js";
111
+ let distPath = '../dist/index.js';
112
+ if (window.location.pathname.includes('/veil/')) {
113
+ distPath = '/veil/dist/index.js';
114
+ }
115
+ const { getFingerprint } = await import(distPath);
119
116
 
120
117
  window.generateFingerprint = async () => {
121
118
  const result = document.getElementById("result");
122
119
  const detailed = document.getElementById("detailedCheckbox").checked;
123
- const cpuBenchmark = document.getElementById("cpuCheckbox").checked;
124
- const gpuBenchmark = document.getElementById("gpuCheckbox").checked;
125
120
 
126
121
  result.innerHTML = '<div class="loading">Generating fingerprint...</div>';
127
122
  console.log("Starting fingerprint generation");
128
- console.log("Options:", { detailed, cpuBenchmark, gpuBenchmark });
123
+ console.log("Options:", { detailed });
129
124
 
130
125
  try {
131
126
  const startTime = performance.now();
132
127
 
133
- if (cpuBenchmark) {
134
- console.log("Running CPU benchmark...");
135
- }
136
- if (gpuBenchmark) {
137
- console.log("Running GPU benchmark...");
138
- }
139
-
140
128
  const fp = await getFingerprint({
141
129
  hash: "sha256",
142
130
  detailed,
143
- cpuBenchmark,
144
- gpuBenchmark,
145
131
  });
146
132
 
147
133
  const endTime = performance.now();
@@ -169,7 +155,15 @@
169
155
 
170
156
  <strong>Metrics:</strong><br/>
171
157
  <pre>Uniqueness: ${(fp.uniqueness * 100).toFixed(2)}%
172
- Confidence: ${(fp.confidence * 100).toFixed(2)}%</pre>
158
+ Confidence: ${(fp.confidence * 100).toFixed(2)}%
159
+ Tampering Risk: ${(fp.tampering_risk * 100).toFixed(2)}%</pre>
160
+
161
+ ${fp.anomalies.length > 0 ? `
162
+ <strong>Anomalies Detected (${fp.anomalies.length}):</strong><br/>
163
+ <pre>${fp.anomalies.map(a =>
164
+ `[${a.severity.toUpperCase()}] ${a.id} (${a.category})\n${a.message}\nRisk: ${(a.riskContribution * 100).toFixed(0)}%\n`
165
+ ).join("\n")}</pre>
166
+ ` : ""}
173
167
 
174
168
  <strong>System:</strong><br/>
175
169
  <pre>OS: ${fp.system.os}
@@ -0,0 +1,71 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ export function approx_entropy(samples: Float64Array, m: number): number;
5
+
6
+ export function cosine_similarity(v1: Float64Array, v2: Float64Array): number;
7
+
8
+ export function fnv_hash(s: string): string;
9
+
10
+ export function kolmogorov_complexity(s: string): number;
11
+
12
+ export function ks_test(values: Float64Array): number;
13
+
14
+ export function levenshtein_distance(s1: string, s2: string): number;
15
+
16
+ export function lz_complexity(data: Uint8Array): number;
17
+
18
+ export function murmur_hash(s: string): string;
19
+
20
+ export function sample_ent(samples: Float64Array, m: number, r: number): number;
21
+
22
+ export function shannon_entropy(s: string): number;
23
+
24
+ export function similarity_score(s1: string, s2: string): number;
25
+
26
+ export function spectral(samples: Float64Array): number;
27
+
28
+ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
29
+
30
+ export interface InitOutput {
31
+ readonly memory: WebAssembly.Memory;
32
+ readonly cosine_similarity: (a: number, b: number, c: number, d: number) => number;
33
+ readonly levenshtein_distance: (a: number, b: number, c: number, d: number) => number;
34
+ readonly similarity_score: (a: number, b: number, c: number, d: number) => number;
35
+ readonly approx_entropy: (a: number, b: number, c: number) => number;
36
+ readonly fnv_hash: (a: number, b: number) => [number, number];
37
+ readonly kolmogorov_complexity: (a: number, b: number) => number;
38
+ readonly ks_test: (a: number, b: number) => number;
39
+ readonly lz_complexity: (a: number, b: number) => number;
40
+ readonly sample_ent: (a: number, b: number, c: number, d: number) => number;
41
+ readonly shannon_entropy: (a: number, b: number) => number;
42
+ readonly spectral: (a: number, b: number) => number;
43
+ readonly murmur_hash: (a: number, b: number) => [number, number];
44
+ readonly __wbindgen_externrefs: WebAssembly.Table;
45
+ readonly __wbindgen_malloc: (a: number, b: number) => number;
46
+ readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
47
+ readonly __wbindgen_free: (a: number, b: number, c: number) => void;
48
+ readonly __wbindgen_start: () => void;
49
+ }
50
+
51
+ export type SyncInitInput = BufferSource | WebAssembly.Module;
52
+
53
+ /**
54
+ * Instantiates the given `module`, which can either be bytes or
55
+ * a precompiled `WebAssembly.Module`.
56
+ *
57
+ * @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated.
58
+ *
59
+ * @returns {InitOutput}
60
+ */
61
+ export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput;
62
+
63
+ /**
64
+ * If `module_or_path` is {RequestInfo} or {URL}, makes a request and
65
+ * for everything else, calls `WebAssembly.instantiate` directly.
66
+ *
67
+ * @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
68
+ *
69
+ * @returns {Promise<InitOutput>}
70
+ */
71
+ export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;