mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 04:42:03 -08:00
Added the following parameters to the WebGL testing site: TIMESTAMP_EXT, GPU_DISJOINT_EXT, MAX_VIEWS_OVR
341 lines
10 KiB
HTML
341 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>WebGL Fingerprinting - Camoufox</title>
|
|
<style>
|
|
html,
|
|
body {
|
|
height: 100%;
|
|
margin: 0;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
}
|
|
body {
|
|
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
|
background-color: #1e1e1e;
|
|
color: #d4d4d4;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
.container {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 20px;
|
|
overflow: hidden;
|
|
}
|
|
h1 {
|
|
color: #569cd6;
|
|
margin-top: 0;
|
|
}
|
|
#output {
|
|
flex: 1;
|
|
background-color: #252526;
|
|
border: 1px solid #3e3e42;
|
|
border-radius: 4px;
|
|
padding: 15px;
|
|
white-space: pre-wrap;
|
|
word-wrap: break-word;
|
|
font-family: "Consolas", "Courier New", monospace;
|
|
font-size: 14px;
|
|
overflow-y: auto;
|
|
}
|
|
.button-container {
|
|
display: flex;
|
|
gap: 10px;
|
|
margin-top: 5px;
|
|
}
|
|
.btn {
|
|
background-color: #0e639c;
|
|
color: white;
|
|
border: none;
|
|
padding: 3px 8px;
|
|
cursor: pointer;
|
|
border-radius: 4px;
|
|
font-size: 16px;
|
|
}
|
|
.btn:hover {
|
|
background-color: #1177bb;
|
|
}
|
|
.string {
|
|
color: #ce9178;
|
|
}
|
|
.number {
|
|
color: #b5cea8;
|
|
}
|
|
.boolean {
|
|
color: #569cd6;
|
|
}
|
|
.null {
|
|
color: #569cd6;
|
|
}
|
|
.key {
|
|
color: #9cdcfe;
|
|
}
|
|
#hash {
|
|
margin-bottom: 5px;
|
|
font-family: "Consolas", "Courier New", monospace;
|
|
font-size: 14px;
|
|
color: #569cd6;
|
|
}
|
|
#warning {
|
|
background-color: #ff9800;
|
|
color: #000;
|
|
margin-bottom: 10px;
|
|
border-radius: 4px;
|
|
display: none;
|
|
position: relative;
|
|
transition: opacity 0.3s ease-out, max-height 0.3s ease-out,
|
|
padding 0.3s ease-out;
|
|
opacity: 1;
|
|
max-height: 100px;
|
|
overflow: hidden;
|
|
padding: 10px;
|
|
}
|
|
#warning.hide {
|
|
opacity: 0;
|
|
max-height: 0;
|
|
padding: 0;
|
|
}
|
|
#close-warning {
|
|
position: absolute;
|
|
top: 50%;
|
|
right: 5px;
|
|
transform: translateY(-50%);
|
|
background: none;
|
|
border: none;
|
|
color: #000;
|
|
font-size: 16px;
|
|
cursor: pointer;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>Your WebGL Information (in Camoufox format)</h1>
|
|
<div id="warning">
|
|
Warning: This browser is not Firefox. The fingerprint below will not run
|
|
properly on Camoufox.<button id="close-warning">×</button>
|
|
</div>
|
|
<div id="hash"></div>
|
|
<pre id="output"></pre>
|
|
<div class="button-container">
|
|
<button id="copy-btn" class="btn">Copy data</button>
|
|
<button id="copy-minified-btn" class="btn">Copy data (minified)</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const dumpWebGLCore = async (
|
|
webglContextId,
|
|
experimentalWebglContextId
|
|
) => {
|
|
function getWebGLContext() {
|
|
const canvas = new OffscreenCanvas(256, 256);
|
|
let result = null;
|
|
|
|
try {
|
|
result =
|
|
canvas.getContext(webglContextId, {
|
|
preserveDrawingBuffer: false,
|
|
}) ||
|
|
canvas.getContext(experimentalWebglContextId, {
|
|
preserveDrawingBuffer: false,
|
|
});
|
|
} catch (ex) {}
|
|
|
|
result || (result = null);
|
|
return result;
|
|
}
|
|
|
|
const webglContext = getWebGLContext();
|
|
|
|
if (!webglContext) {
|
|
return {};
|
|
}
|
|
|
|
const glEnums = [
|
|
2849, 2884, 2885, 2886, 2928, 2929, 2930, 2931, 2932, 2960, 2961,
|
|
2962, 2963, 2964, 2965, 2966, 2967, 2968, 2978, 3024, 3042, 3074,
|
|
3088, 3089, 3106, 3107, 3314, 3315, 3316, 3317, 3330, 3331, 3332,
|
|
3333, 3379, 3386, 3408, 3410, 3411, 3412, 3413, 3414, 3415, 7936,
|
|
7937, 7938, 10752, 32773, 32777, 32823, 32824, 32873, 32877, 32878,
|
|
32883, 32926, 32928, 32936, 32937, 32938, 32939, 32968, 32969, 32970,
|
|
32971, 33000, 33001, 33170, 33901, 33902, 34016, 34024, 34045, 34047,
|
|
34068, 34076, 34467, 34816, 34817, 34818, 34819, 34852, 34853, 34854,
|
|
34855, 34856, 34857, 34858, 34859, 34860, 34877, 34921, 34930, 34964,
|
|
34965, 35071, 35076, 35077, 35371, 35373, 35374, 35375, 35376, 35377,
|
|
35379, 35380, 35657, 35658, 35659, 35660, 35661, 35723, 35724, 35725,
|
|
35738, 35739, 35968, 35977, 35978, 35979, 36003, 36004, 36005, 36006,
|
|
36007, 36063, 36183, 36203, 36345, 36347, 36348, 36349, 36387, 36388,
|
|
36392, 36795, 37137, 37154, 37157, 37440, 37441, 37443, 37444, 37445,
|
|
37446, 37447, 38449,
|
|
];
|
|
|
|
let rendererInfo = null;
|
|
const debug_ext = webglContext.getExtension(
|
|
"WEBGL_debug_renderer_info"
|
|
);
|
|
if (debug_ext) {
|
|
rendererInfo = {
|
|
webglVendor: webglContext.getParameter(
|
|
debug_ext.UNMASKED_VENDOR_WEBGL
|
|
),
|
|
webglRenderer: webglContext.getParameter(
|
|
debug_ext.UNMASKED_RENDERER_WEBGL
|
|
),
|
|
};
|
|
}
|
|
|
|
const result = {
|
|
[`${webglContextId}:renderer`]: rendererInfo
|
|
? rendererInfo.webglRenderer
|
|
: "Not available",
|
|
[`${webglContextId}:vendor`]: rendererInfo
|
|
? rendererInfo.webglVendor
|
|
: "Not available",
|
|
[`${webglContextId}:contextAttributes`]:
|
|
webglContext.getContextAttributes(),
|
|
[`${webglContextId}:supportedExtensions`]:
|
|
webglContext.getSupportedExtensions() || [],
|
|
[`${webglContextId}:parameters`]: {},
|
|
[`${webglContextId}:shaderPrecisionFormats`]: {},
|
|
};
|
|
for (const glEnum of glEnums) {
|
|
try {
|
|
const parmValue = webglContext.getParameter(glEnum);
|
|
if (
|
|
Array.isArray(parmValue) ||
|
|
[Float32Array, Int32Array, Uint32Array].some(
|
|
(type) => parmValue instanceof type
|
|
)
|
|
) {
|
|
const arrayValue = Array.from(parmValue);
|
|
result[`${webglContextId}:parameters`][glEnum] =
|
|
arrayValue.length > 0 ? arrayValue : null;
|
|
} else {
|
|
result[`${webglContextId}:parameters`][glEnum] = parmValue;
|
|
}
|
|
} catch (err) {
|
|
console.log(err);
|
|
}
|
|
}
|
|
|
|
const shaderTypes = [
|
|
webglContext.VERTEX_SHADER,
|
|
webglContext.FRAGMENT_SHADER,
|
|
];
|
|
const precisionTypes = [
|
|
webglContext.LOW_FLOAT,
|
|
webglContext.MEDIUM_FLOAT,
|
|
webglContext.HIGH_FLOAT,
|
|
webglContext.LOW_INT,
|
|
webglContext.MEDIUM_INT,
|
|
webglContext.HIGH_INT,
|
|
];
|
|
|
|
for (let shaderType of shaderTypes) {
|
|
for (let precisionType of precisionTypes) {
|
|
const r = webglContext.getShaderPrecisionFormat(
|
|
shaderType,
|
|
precisionType
|
|
);
|
|
const key = `${shaderType},${precisionType}`;
|
|
result[`${webglContextId}:shaderPrecisionFormats`][key] = {
|
|
rangeMin: r.rangeMin,
|
|
rangeMax: r.rangeMax,
|
|
precision: r.precision,
|
|
};
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
function syntaxHighlight(json) {
|
|
json = json
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">");
|
|
return json.replace(
|
|
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
|
|
function (match) {
|
|
var cls = "number";
|
|
if (/^"/.test(match)) {
|
|
if (/:$/.test(match)) {
|
|
cls = "key";
|
|
} else {
|
|
cls = "string";
|
|
}
|
|
} else if (/true|false/.test(match)) {
|
|
cls = "boolean";
|
|
} else if (/null/.test(match)) {
|
|
cls = "null";
|
|
}
|
|
return '<span class="' + cls + '">' + match + "</span>";
|
|
}
|
|
);
|
|
}
|
|
|
|
async function sha256(message) {
|
|
const msgBuffer = new TextEncoder().encode(message);
|
|
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
|
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
const hashHex = hashArray
|
|
.map((b) => b.toString(16).padStart(2, "0"))
|
|
.join("");
|
|
return hashHex;
|
|
}
|
|
|
|
document.addEventListener(
|
|
"DOMContentLoaded",
|
|
async () => {
|
|
// Check if the user agent is Firefox
|
|
const isFirefox =
|
|
navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
|
if (!isFirefox) {
|
|
document.getElementById("warning").style.display = "block";
|
|
}
|
|
|
|
// Add event listener for close button
|
|
document
|
|
.getElementById("close-warning")
|
|
.addEventListener("click", function () {
|
|
document.getElementById("warning").classList.add("hide");
|
|
});
|
|
|
|
const [webglDetail, webgl2Detail] = await Promise.all([
|
|
dumpWebGLCore("webgl", "experimental-webgl"),
|
|
dumpWebGLCore("webgl2", "experimental-webgl2"),
|
|
]);
|
|
|
|
const combinedInfo = { ...webglDetail, ...webgl2Detail };
|
|
const jsonString = JSON.stringify(combinedInfo, null, 2);
|
|
const minifiedJson = JSON.stringify(combinedInfo);
|
|
const hashValue = await sha256(minifiedJson);
|
|
|
|
document.getElementById("hash").textContent = `SHA256: ${hashValue}`;
|
|
document.getElementById("output").innerHTML =
|
|
syntaxHighlight(jsonString);
|
|
|
|
document.getElementById("copy-btn").addEventListener("click", () => {
|
|
navigator.clipboard.writeText(jsonString).then(() => {
|
|
alert("Copied formatted JSON to clipboard!");
|
|
});
|
|
});
|
|
|
|
document
|
|
.getElementById("copy-minified-btn")
|
|
.addEventListener("click", () => {
|
|
navigator.clipboard.writeText(minifiedJson).then(() => {
|
|
alert("Copied minified JSON to clipboard!");
|
|
});
|
|
});
|
|
},
|
|
false
|
|
);
|
|
</script>
|
|
</body>
|
|
</html>
|