@cloudglides/veil 1.0.0 → 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.
- package/README.md +190 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +1000 -0
- package/dist/veil_core.js +370 -0
- package/dist/veil_core_bg.wasm +0 -0
- package/package.json +24 -10
- package/.envrc +0 -1
- package/.github/workflows/build-on-tag.yml +0 -75
- package/example/index.html +0 -226
- package/flake.nix +0 -68
- package/scripts/patch-wasm.js +0 -12
- package/src/cpu.ts +0 -67
- package/src/entropy/adblock.ts +0 -16
- package/src/entropy/approximate.ts +0 -8
- package/src/entropy/audio.ts +0 -17
- package/src/entropy/battery.ts +0 -10
- package/src/entropy/browser.ts +0 -7
- package/src/entropy/canvas.ts +0 -17
- package/src/entropy/complexity.ts +0 -13
- package/src/entropy/connection.ts +0 -14
- package/src/entropy/distribution.ts +0 -8
- package/src/entropy/fonts.ts +0 -4
- package/src/entropy/hardware.ts +0 -10
- package/src/entropy/language.ts +0 -14
- package/src/entropy/os.ts +0 -12
- package/src/entropy/osVersion.ts +0 -6
- package/src/entropy/performance.ts +0 -14
- package/src/entropy/permissions.ts +0 -15
- package/src/entropy/plugins.ts +0 -14
- package/src/entropy/preferences.ts +0 -12
- package/src/entropy/probabilistic.ts +0 -20
- package/src/entropy/screen.ts +0 -12
- package/src/entropy/screenInfo.ts +0 -8
- package/src/entropy/spectral.ts +0 -8
- package/src/entropy/statistical.ts +0 -15
- package/src/entropy/storage.ts +0 -22
- package/src/entropy/timezone.ts +0 -10
- package/src/entropy/userAgent.ts +0 -16
- package/src/entropy/webFeatures.ts +0 -21
- package/src/entropy/webgl.ts +0 -11
- package/src/gpu.ts +0 -132
- package/src/index.test.ts +0 -26
- package/src/index.ts +0 -198
- package/src/normalize/index.ts +0 -31
- package/src/probability.ts +0 -11
- package/src/scoring.ts +0 -106
- package/src/seeded-rng.ts +0 -14
- package/src/types/index.ts +0 -11
- package/src/types.ts +0 -47
- package/src/veil_core.d.ts +0 -4
- package/src/wasm-loader.ts +0 -14
- package/tsconfig.json +0 -12
- package/tsup.config.ts +0 -35
- package/veil-core/Cargo.lock +0 -114
- package/veil-core/Cargo.toml +0 -12
- package/veil-core/src/entropy.rs +0 -132
- package/veil-core/src/lib.rs +0 -90
- package/vitest.config.ts +0 -15
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.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
type AnomalySeverity = "low" | "medium" | "high" | "critical";
|
|
2
|
+
type AnomalyCategory = "entropy_distribution" | "missing_sources" | "value_spoofing" | "cross_source_inconsistency" | "data_quality";
|
|
3
|
+
interface Anomaly {
|
|
4
|
+
id: string;
|
|
5
|
+
category: AnomalyCategory;
|
|
6
|
+
severity: AnomalySeverity;
|
|
7
|
+
message: string;
|
|
8
|
+
explanation: string;
|
|
9
|
+
riskContribution: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface EntropyWarning {
|
|
13
|
+
source: string;
|
|
14
|
+
severity: "info" | "warning" | "error";
|
|
15
|
+
message: string;
|
|
16
|
+
reason: string;
|
|
17
|
+
}
|
|
18
|
+
interface DeviceSignature {
|
|
19
|
+
os: string;
|
|
20
|
+
hardware_cores: number;
|
|
21
|
+
screen_resolution: string;
|
|
22
|
+
user_agent_hash: string;
|
|
23
|
+
}
|
|
24
|
+
interface PreferencesOffset {
|
|
25
|
+
theme: string | null;
|
|
26
|
+
language: string | null;
|
|
27
|
+
timezone: string | null;
|
|
28
|
+
font_size: string | null;
|
|
29
|
+
dark_mode: boolean | null;
|
|
30
|
+
accessibility: string | null;
|
|
31
|
+
}
|
|
32
|
+
interface DeviceIdentity {
|
|
33
|
+
core_hash: string;
|
|
34
|
+
device_signature: DeviceSignature;
|
|
35
|
+
entropy_quality: number;
|
|
36
|
+
preferences_offset: PreferencesOffset;
|
|
37
|
+
preferences_hash: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface FingerprintOptions {
|
|
41
|
+
entropy: {
|
|
42
|
+
userAgent?: boolean;
|
|
43
|
+
canvas?: boolean;
|
|
44
|
+
webgl?: boolean;
|
|
45
|
+
fonts?: boolean;
|
|
46
|
+
storage?: boolean;
|
|
47
|
+
screen?: boolean;
|
|
48
|
+
};
|
|
49
|
+
hash?: "sha256" | "sha512";
|
|
50
|
+
detailed?: boolean;
|
|
51
|
+
}
|
|
52
|
+
interface SourceMetric {
|
|
53
|
+
source: string;
|
|
54
|
+
value: string;
|
|
55
|
+
entropy: number;
|
|
56
|
+
confidence: number;
|
|
57
|
+
stability?: number;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface FingerprintResponse {
|
|
61
|
+
hash: string;
|
|
62
|
+
uniqueness: number;
|
|
63
|
+
confidence: number;
|
|
64
|
+
stability_score?: number;
|
|
65
|
+
usable: boolean;
|
|
66
|
+
warnings?: string[];
|
|
67
|
+
entropy_warnings?: EntropyWarning[];
|
|
68
|
+
tampering_risk: number;
|
|
69
|
+
anomalies: Anomaly[];
|
|
70
|
+
device_identity?: DeviceIdentity;
|
|
71
|
+
sources: SourceMetric[];
|
|
72
|
+
system: {
|
|
73
|
+
os: string;
|
|
74
|
+
language: string;
|
|
75
|
+
timezone: string;
|
|
76
|
+
hardware: {
|
|
77
|
+
cores: number;
|
|
78
|
+
memory: number;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
display: {
|
|
82
|
+
resolution: string;
|
|
83
|
+
colorDepth: number;
|
|
84
|
+
devicePixelRatio: number;
|
|
85
|
+
};
|
|
86
|
+
browser: {
|
|
87
|
+
userAgent: string;
|
|
88
|
+
vendor: string;
|
|
89
|
+
cookieEnabled: boolean;
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
declare function getFingerprint(options?: FingerprintOptions): Promise<string | FingerprintResponse>;
|
|
94
|
+
declare function compareFingerpints(fp1: string | FingerprintResponse, fp2: string | FingerprintResponse): Promise<{
|
|
95
|
+
similarity: number;
|
|
96
|
+
match: boolean;
|
|
97
|
+
}>;
|
|
98
|
+
declare function matchProbability(storedFingerprints: (string | FingerprintResponse)[], currentFingerprint: string | FingerprintResponse): Promise<{
|
|
99
|
+
bestMatch: number;
|
|
100
|
+
confidence: number;
|
|
101
|
+
}>;
|
|
102
|
+
|
|
103
|
+
export { type FingerprintOptions, type FingerprintResponse, compareFingerpints, getFingerprint, matchProbability };
|