Initial release — per-site container isolation with unique device fingerprints

Automatic per-domain containers with hardened fingerprint spoofing:
canvas, WebGL, audio, navigator, screen, timezone, WebRTC, fonts,
ClientRects, plugins, battery, and connection APIs.
This commit is contained in:
sal
2026-02-28 22:59:46 -06:00
commit a058d78c20
11 changed files with 1153 additions and 0 deletions

122
lib/fingerprint-gen.js Normal file
View File

@@ -0,0 +1,122 @@
// Deterministic fingerprint profile generator
// Given the same seed, always produces the same device identity
// Real hardware values — spoofed values must NEVER match these
const REAL_HARDWARE = {
hardwareConcurrency: 4, // 2 cores / 4 threads
screenWidth: 1920,
screenHeight: 1080
};
function generateFingerprintProfile(masterSeed) {
const rng = mulberry32(masterSeed);
function pick(arr) {
return arr[Math.floor(rng() * arr.length)];
}
// Pick from array, but never the excluded value. Rerolls if needed.
function pickExcluding(arr, exclude) {
const filtered = arr.filter(v => {
if (typeof exclude === "object" && exclude !== null) {
return Object.keys(exclude).some(k => v[k] !== exclude[k]);
}
return v !== exclude;
});
return filtered.length > 0 ? pick(filtered) : pick(arr);
}
function subSeed() {
return (rng() * 0xFFFFFFFF) >>> 0;
}
const platforms = ["Win32", "Linux x86_64", "MacIntel"];
const vendors = [
"Google Inc. (NVIDIA)",
"Google Inc. (AMD)",
"Google Inc. (Intel)",
"Google Inc."
];
const renderers = [
"ANGLE (NVIDIA GeForce GTX 1060 Direct3D11 vs_5_0 ps_5_0)",
"ANGLE (AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0)",
"ANGLE (Intel HD Graphics 630 Direct3D11 vs_5_0 ps_5_0)",
"ANGLE (NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0)",
"ANGLE (AMD Radeon RX 6700 XT Direct3D11 vs_5_0 ps_5_0)",
"Mesa Intel(R) UHD Graphics 620",
"Mesa AMD Radeon RX 580",
"ANGLE (Intel, Mesa Intel(R) UHD Graphics 620, OpenGL 4.6)"
];
const resolutions = [
{ width: 2560, height: 1440 },
{ width: 1366, height: 768 },
{ width: 1536, height: 864 },
{ width: 1440, height: 900 },
{ width: 1680, height: 1050 },
{ width: 2560, height: 1080 },
{ width: 3440, height: 1440 },
{ width: 1600, height: 900 }
];
const languageSets = [
["en-US", "en"],
["en-GB", "en"],
["en-US"],
["de-DE", "de", "en-US", "en"],
["fr-FR", "fr", "en-US", "en"]
];
// Exclude real hardwareConcurrency (4)
const hardwareConcurrencies = [2, 6, 8, 12, 16];
const deviceMemories = [4, 8, 16, 32];
const colorDepths = [24, 30, 32];
// Timezones for spoofing — common real-world timezones
const timezones = [
{ name: "America/New_York", offset: 300 },
{ name: "America/Chicago", offset: 360 },
{ name: "America/Denver", offset: 420 },
{ name: "America/Los_Angeles", offset: 480 },
{ name: "Europe/London", offset: 0 },
{ name: "Europe/Berlin", offset: -60 },
{ name: "Europe/Paris", offset: -60 },
{ name: "Asia/Tokyo", offset: -540 },
{ name: "Australia/Sydney", offset: -660 },
{ name: "America/Toronto", offset: 300 },
{ name: "America/Phoenix", offset: 420 }
];
// Resolution: never match real 1920x1080
const res = pickExcluding(resolutions, { width: REAL_HARDWARE.screenWidth, height: REAL_HARDWARE.screenHeight });
return {
seed: masterSeed,
canvasSeed: subSeed(),
audioSeed: subSeed(),
fontSeed: subSeed(),
rectSeed: subSeed(),
nav: {
hardwareConcurrency: pick(hardwareConcurrencies),
platform: pick(platforms),
languages: pick(languageSets),
deviceMemory: pick(deviceMemories),
maxTouchPoints: 0
},
screen: {
width: res.width,
height: res.height,
colorDepth: pick(colorDepths)
},
webgl: {
vendor: pick(vendors),
renderer: pick(renderers)
},
timezone: pick(timezones),
webrtc: {
blockLocal: true
}
};
}

11
lib/prng.js Normal file
View File

@@ -0,0 +1,11 @@
// Mulberry32 — fast, deterministic 32-bit PRNG
// Same seed always produces the same sequence
function mulberry32(seed) {
return function() {
seed |= 0;
seed = seed + 0x6D2B79F5 | 0;
let t = Math.imul(seed ^ (seed >>> 15), 1 | seed);
t = t + Math.imul(t ^ (t >>> 7), 61 | t) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}