Remove DOM dimension noise and fix document.fonts to prevent site crashes

DOM element dimension noise (offsetWidth/Height etc.) broke complex web apps
like Discord by returning fractional values where integers are expected.
Removed entirely — measureText noise is sufficient for font enumeration.

Changed document.fonts.check() to return true (uniform response) instead of
false, which caused font loading logic to hang in apps waiting for fonts.
This commit is contained in:
sal
2026-03-04 21:34:12 -06:00
parent 23759e34a4
commit 5df1a6cfa5
3 changed files with 10 additions and 35 deletions

View File

@@ -27,8 +27,8 @@ Every website you visit is automatically placed in its own isolated container wi
| Screen | Resolution, color depth, window dimensions |
| Timezone | getTimezoneOffset, Date.toString, Intl.DateTimeFormat |
| WebRTC | Forced relay-only ICE policy (blocks local IP leak) |
| Fonts | Noise on measureText + DOM element dimensions (offsetWidth/Height etc.) |
| Font API | document.fonts.check() blocked, size reports 0 |
| Fonts | Noise on measureText (prevents font enumeration) |
| Font API | document.fonts.check() returns uniform response |
| ClientRects | Sub-pixel noise on getBoundingClientRect |
| Plugins | Reports empty |
| Battery | Always reports full/charging |

View File

@@ -470,39 +470,13 @@
return metrics;
}, pageWindow.CanvasRenderingContext2D.prototype, { defineAs: "measureText" });
// --- DOM Element Dimension Noise ---
// Font enumeration measures offsetWidth/Height of test spans to detect installed fonts.
// Adding seeded noise prevents consistent dimension-based font fingerprinting.
const fontDimProps = ["offsetWidth", "offsetHeight", "scrollWidth", "scrollHeight", "clientWidth", "clientHeight"];
for (const prop of fontDimProps) {
const origDesc = Object.getOwnPropertyDescriptor(window.HTMLElement.prototype, prop);
if (origDesc && origDesc.get) {
const origGet = origDesc.get;
Object.defineProperty(pageWindow.HTMLElement.prototype, prop, {
get: exportFunction(function() {
const val = origGet.call(this);
return val + (fontRng() - 0.5) * 0.3;
}, pageWindow),
configurable: true,
enumerable: true
});
}
}
// --- document.fonts (FontFaceSet) API Protection ---
// document.fonts.check() directly reveals installed fonts; size/iterators expose count.
// document.fonts.check() always returns true so font loading logic works,
// but prevents enumeration of specific fonts by giving a uniform response.
if (pageWindow.document.fonts) {
try {
Object.defineProperty(pageWindow.document.fonts, "check", {
value: exportFunction(function() { return false; }, pageWindow),
configurable: true, enumerable: true
});
Object.defineProperty(pageWindow.document.fonts, "size", {
get: exportFunction(function() { return 0; }, pageWindow),
configurable: true, enumerable: true
});
Object.defineProperty(pageWindow.document.fonts, "forEach", {
value: exportFunction(function() {}, pageWindow),
value: exportFunction(function() { return true; }, pageWindow),
configurable: true, enumerable: true
});
} catch(e) {}

View File

@@ -924,12 +924,13 @@ function testDocFonts() {
report.docfonts = vals;
let html = "";
html += row("document.fonts.size", size, size === 0 ? "spoofed" : "real");
html += row("check('16px Arial')", checkArial, !checkArial ? "spoofed" : "real");
html += row("check('16px monospace')", checkMono, !checkMono ? "spoofed" : "real");
html += row("document.fonts.size", size);
html += row("check('16px Arial')", checkArial, checkArial ? "spoofed" : "real");
html += row("check('16px monospace')", checkMono, checkMono ? "spoofed" : "real");
el.innerHTML = html;
const spoofed = size === 0 && !checkArial && !checkMono;
// check() returning true for everything = spoofed (uniform response)
const spoofed = checkArial && checkMono;
sectionStatus.docfonts = spoofed ? "pass" : "warn";
setDot("dot-docfonts", sectionStatus.docfonts);
}