mirror of
https://github.com/CloakHQ/CloakBrowser.git
synced 2026-10-18 23:07:13 -05:00
feat: info/doctor reports Windows + Office font completeness
Windows font check now covers the full 8-font set (adds the two monospace fonts) and reports a strict N/8 count; the launch-time warning fires on any incomplete set, not just when none are present. Adds a separate Office-font group (10 fonts) reported as an informational N/10 with no install nudge. Ported across all three wrappers (Python, JS, .NET) to keep them in sync.
This commit is contained in:
10 files changed
+254
-71
No files matched your search
@@ -205,11 +205,19 @@ def _collect_diagnostics(quick: bool) -> dict:
|
||||
# Windows-font probe — only meaningful on a Linux host spoofing Windows.
|
||||
# Omitted entirely off Linux, where it carries no signal.
|
||||
if platform.system() == "Linux":
|
||||
from .browser import _windows_fonts_present
|
||||
from .browser import (
|
||||
_OFFICE_FONT_TELLS,
|
||||
_WINDOWS_FONT_TELLS,
|
||||
_count_fonts_present,
|
||||
)
|
||||
|
||||
present = _windows_fonts_present()
|
||||
# Strict count, not "any one present" — real font installs are atomic
|
||||
# (you have the whole pack or none), so report how complete the set is.
|
||||
win_n = _count_fonts_present(_WINDOWS_FONT_TELLS)
|
||||
office_n = _count_fonts_present(_OFFICE_FONT_TELLS)
|
||||
diag["fonts"] = {
|
||||
"windows_fonts": {True: "ok", False: "missing", None: "unknown"}[present]
|
||||
"windows": None if win_n is None else [win_n, len(_WINDOWS_FONT_TELLS)],
|
||||
"office": None if office_n is None else [office_n, len(_OFFICE_FONT_TELLS)],
|
||||
}
|
||||
|
||||
diag["license"] = license_info
|
||||
@@ -270,10 +278,22 @@ def _print_diagnostics(diag: dict) -> None:
|
||||
print(" → install the missing system libraries (e.g. apt-get install)")
|
||||
|
||||
if "fonts" in diag:
|
||||
fonts = diag["fonts"]["windows_fonts"]
|
||||
print(f"Win fonts: {fonts}")
|
||||
if fonts == "missing":
|
||||
print(" → spoofing Windows on Linux without Windows fonts; install msttcorefonts")
|
||||
win = diag["fonts"]["windows"]
|
||||
if win is None:
|
||||
print("Win fonts: unknown (fc-list unavailable)")
|
||||
else:
|
||||
n, total = win
|
||||
verdict = "ok" if n == total else "missing" if n == 0 else "partial"
|
||||
print(f"Win fonts: {verdict} ({n}/{total})")
|
||||
if n < total:
|
||||
print(" → incomplete Windows font set; copy real Windows fonts (Segoe UI, Calibri, Consolas)")
|
||||
office = diag["fonts"].get("office")
|
||||
if office is not None:
|
||||
n, total = office
|
||||
# Office is informational only — no Office pack is a normal Windows
|
||||
# persona (~53% of real machines have none), so no install nudge.
|
||||
verdict = "ok" if n == total else "absent" if n == 0 else "partial"
|
||||
print(f"Office fonts: {verdict} ({n}/{total})")
|
||||
|
||||
lic = diag["license"]
|
||||
tier = lic["tier"]
|
||||
|
||||
+44
-11
@@ -1171,6 +1171,10 @@ def build_args(
|
||||
# Microsoft-proprietary fonts that signal a real Windows install (absent from
|
||||
# ttf-mscorefonts-installer). Keep in sync with issue #395 and
|
||||
# docs/chrome40-fpjs-font-minimum-set-investigation.md.
|
||||
# Windows OS fonts — ship with Windows itself, so their absence on a
|
||||
# Windows-spoofing Linux host degrades results. The two monospace fonts
|
||||
# (Consolas + Courier New) are part of the recommended set so the generic
|
||||
# `monospace` family resolves to a Windows font. See issue #395.
|
||||
_WINDOWS_FONT_TELLS = (
|
||||
"Segoe UI",
|
||||
"Segoe UI Light",
|
||||
@@ -1178,17 +1182,36 @@ _WINDOWS_FONT_TELLS = (
|
||||
"Marlett",
|
||||
"MS UI Gothic",
|
||||
"Franklin Gothic",
|
||||
"Consolas",
|
||||
"Courier New",
|
||||
)
|
||||
|
||||
# MS Office supplemental fonts, installed as one atomic block by every Office
|
||||
# install. Roughly half of real Windows machines have this pack and half do
|
||||
# not, so its absence is a perfectly normal Windows setup, NOT a problem —
|
||||
# reported as an informational signal only, never a warning.
|
||||
_OFFICE_FONT_TELLS = (
|
||||
"MT Extra",
|
||||
"Century",
|
||||
"Century Gothic",
|
||||
"MS Reference Specialty",
|
||||
"Wingdings 2",
|
||||
"Wingdings 3",
|
||||
"Book Antiqua",
|
||||
"Bookshelf Symbol 7",
|
||||
"Monotype Corsiva",
|
||||
"Bookman Old Style",
|
||||
)
|
||||
|
||||
_font_warning_checked = False
|
||||
|
||||
|
||||
def _windows_fonts_present() -> bool | None:
|
||||
"""Probe for Windows fonts via fc-list.
|
||||
def _count_fonts_present(tells: tuple[str, ...]) -> int | None:
|
||||
"""Count how many tell-tale fonts are installed, via fc-list.
|
||||
|
||||
Tri-state: True if any tell-tale font is installed, False if none found,
|
||||
None if it can't be determined (fc-list missing or errored). Callers must
|
||||
NOT warn on None — only an explicit False means "no Windows fonts".
|
||||
Returns the number present (0..len(tells)), or None if it can't be
|
||||
determined (fc-list missing or errored). Callers must NOT treat None as
|
||||
zero — None means "unknown", 0 means "genuinely none installed".
|
||||
"""
|
||||
import subprocess
|
||||
try:
|
||||
@@ -1200,11 +1223,21 @@ def _windows_fonts_present() -> bool | None:
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
listing = result.stdout.lower()
|
||||
return any(font.lower() in listing for font in _WINDOWS_FONT_TELLS)
|
||||
return sum(1 for font in tells if font.lower() in listing)
|
||||
|
||||
|
||||
def _windows_fonts_present() -> bool | None:
|
||||
"""True if ALL Windows OS fonts are installed, False if any are missing,
|
||||
None if unknown. Strict: a partial set is treated as incomplete, since the
|
||||
font install is atomic and a missing font degrades the Windows persona.
|
||||
"""
|
||||
n = _count_fonts_present(_WINDOWS_FONT_TELLS)
|
||||
return None if n is None else n == len(_WINDOWS_FONT_TELLS)
|
||||
|
||||
|
||||
def _maybe_warn_windows_fonts(chrome_args: list[str]) -> None:
|
||||
"""Warn once when spoofing Windows on a Linux host with no Windows fonts.
|
||||
"""Warn once when spoofing Windows on a Linux host without the full Windows
|
||||
font set.
|
||||
|
||||
Best-effort and silent on error — never raises. Gated by an in-process flag
|
||||
plus a cache-dir marker so it fires at most once per environment. Suppress
|
||||
@@ -1234,13 +1267,13 @@ def _maybe_warn_windows_fonts(chrome_args: list[str]) -> None:
|
||||
return
|
||||
present = _windows_fonts_present()
|
||||
if present is None or present is True:
|
||||
return # fonts present, or can't determine — don't warn
|
||||
return # full set present, or can't determine — don't warn
|
||||
# Write straight to stderr (like the welcome banner and the JS/.NET
|
||||
# wrappers) so an app's logging config can't silence it.
|
||||
sys.stderr.write(
|
||||
"[cloakbrowser] No Windows fonts found — installing them is strongly "
|
||||
"advised for best results when spoofing Windows on Linux. "
|
||||
"https://github.com/CloakHQ/cloakbrowser#font-setup-on-linux "
|
||||
"[cloakbrowser] Incomplete Windows font set — installing the full "
|
||||
"set is strongly advised for best results when spoofing Windows on "
|
||||
"Linux. https://github.com/CloakHQ/cloakbrowser#font-setup-on-linux "
|
||||
"(silence: CLOAKBROWSER_SUPPRESS_FONT_WARNING=1)\n"
|
||||
)
|
||||
try:
|
||||
|
||||
@@ -132,10 +132,26 @@ static void PrintDiagnostics(Dictionary<string, object?> diag)
|
||||
|
||||
if (diag.TryGetValue("fonts", out var fontsObj) && fontsObj is Dictionary<string, object?> fonts)
|
||||
{
|
||||
string winFonts = (string)fonts["windows_fonts"]!;
|
||||
Console.WriteLine($"Win fonts: {winFonts}");
|
||||
if (winFonts == "missing")
|
||||
Console.WriteLine(" → spoofing Windows on Linux without Windows fonts; install msttcorefonts");
|
||||
if (fonts["windows"] is int[] win)
|
||||
{
|
||||
int n = win[0], total = win[1];
|
||||
string verdict = n == total ? "ok" : n == 0 ? "missing" : "partial";
|
||||
Console.WriteLine($"Win fonts: {verdict} ({n}/{total})");
|
||||
if (n < total)
|
||||
Console.WriteLine(" → incomplete Windows font set; copy real Windows fonts (Segoe UI, Calibri, Consolas)");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Win fonts: unknown (fc-list unavailable)");
|
||||
}
|
||||
// Office is informational only — no Office pack is a normal Windows
|
||||
// persona (~53% of real machines have none), so no install nudge.
|
||||
if (fonts.TryGetValue("office", out var officeObj) && officeObj is int[] office)
|
||||
{
|
||||
int n = office[0], total = office[1];
|
||||
string verdict = n == total ? "ok" : n == 0 ? "absent" : "partial";
|
||||
Console.WriteLine($"Office fonts: {verdict} ({n}/{total})");
|
||||
}
|
||||
}
|
||||
|
||||
var lic = (Dictionary<string, object?>)diag["license"]!;
|
||||
|
||||
@@ -358,23 +358,36 @@ public static class CloakLauncher
|
||||
// environment. See docs/chrome40-fpjs-font-minimum-set-investigation.md.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
// Microsoft-proprietary fonts that signal a real Windows install (absent from
|
||||
// ttf-mscorefonts-installer). Keep in sync with issue #395 and
|
||||
// docs/chrome40-fpjs-font-minimum-set-investigation.md.
|
||||
private static readonly string[] WindowsFontTells =
|
||||
// Windows OS fonts — ship with Windows itself, so their absence on a
|
||||
// Windows-spoofing Linux host degrades results. The two monospace fonts
|
||||
// (Consolas + Courier New) are part of the recommended set so the generic
|
||||
// `monospace` family resolves to a Windows font. See issue #395.
|
||||
internal static readonly string[] WindowsFontTells =
|
||||
{
|
||||
"Segoe UI", "Segoe UI Light", "Calibri", "Marlett", "MS UI Gothic", "Franklin Gothic",
|
||||
"Segoe UI", "Segoe UI Light", "Calibri", "Marlett", "MS UI Gothic",
|
||||
"Franklin Gothic", "Consolas", "Courier New",
|
||||
};
|
||||
|
||||
// MS Office supplemental fonts, installed as one atomic block by every Office
|
||||
// install. Roughly half of real Windows machines have this pack and half do
|
||||
// not, so its absence is a perfectly normal Windows setup, NOT a problem —
|
||||
// reported as an informational signal only, never a warning.
|
||||
internal static readonly string[] OfficeFontTells =
|
||||
{
|
||||
"MT Extra", "Century", "Century Gothic", "MS Reference Specialty",
|
||||
"Wingdings 2", "Wingdings 3", "Book Antiqua", "Bookshelf Symbol 7",
|
||||
"Monotype Corsiva", "Bookman Old Style",
|
||||
};
|
||||
|
||||
internal static bool _fontWarningChecked;
|
||||
|
||||
/// <summary>
|
||||
/// Probe for Windows fonts via fc-list. Tri-state: true if any tell-tale font
|
||||
/// is installed, false if none found, null if it can't be determined (fc-list
|
||||
/// missing or errored). Callers must NOT warn on null — only an explicit false
|
||||
/// means "no Windows fonts".
|
||||
/// Count how many tell-tale fonts are installed, via fc-list. Returns the
|
||||
/// number present (0..tells.Length), or null if it can't be determined
|
||||
/// (fc-list missing or errored). Callers must NOT treat null as zero — null
|
||||
/// means "unknown", 0 means "genuinely none installed".
|
||||
/// </summary>
|
||||
internal static bool? WindowsFontsPresent()
|
||||
internal static int? CountFontsPresent(string[] tells)
|
||||
{
|
||||
string output;
|
||||
try
|
||||
@@ -411,14 +424,25 @@ public static class CloakLauncher
|
||||
return null;
|
||||
}
|
||||
var listing = output.ToLowerInvariant();
|
||||
return WindowsFontTells.Any(f => listing.Contains(f.ToLowerInvariant()));
|
||||
return tells.Count(f => listing.Contains(f.ToLowerInvariant()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warn once when spoofing Windows on a Linux host with no Windows fonts.
|
||||
/// Best-effort and silent on error — never throws. Gated by an in-process flag
|
||||
/// plus a cache-dir marker so it fires at most once per environment. Suppress
|
||||
/// entirely with CLOAKBROWSER_SUPPRESS_FONT_WARNING.
|
||||
/// True if ALL Windows OS fonts are installed, false if any are missing, null
|
||||
/// if unknown. Strict: a partial set is treated as incomplete, since the font
|
||||
/// install is atomic and a missing font degrades the Windows persona.
|
||||
/// </summary>
|
||||
internal static bool? WindowsFontsPresent()
|
||||
{
|
||||
var n = CountFontsPresent(WindowsFontTells);
|
||||
return n is null ? null : n == WindowsFontTells.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Warn once when spoofing Windows on a Linux host without the full Windows
|
||||
/// font set. Best-effort and silent on error — never throws. Gated by an
|
||||
/// in-process flag plus a cache-dir marker so it fires at most once per
|
||||
/// environment. Suppress entirely with CLOAKBROWSER_SUPPRESS_FONT_WARNING.
|
||||
/// </summary>
|
||||
internal static void MaybeWarnWindowsFonts(IReadOnlyList<string> chromeArgs)
|
||||
{
|
||||
@@ -441,11 +465,11 @@ public static class CloakLauncher
|
||||
var marker = Path.Combine(Config.GetCacheDir(), ".font_warning_shown");
|
||||
if (File.Exists(marker)) return;
|
||||
var present = WindowsFontsPresent();
|
||||
if (present != false) return; // true (present) or null (undeterminable)
|
||||
if (present != false) return; // true (full set) or null (undeterminable)
|
||||
CloakLog.Warning(
|
||||
"[cloakbrowser] No Windows fonts found — installing them is strongly " +
|
||||
"advised for best results when spoofing Windows on Linux. " +
|
||||
"https://github.com/CloakHQ/cloakbrowser#font-setup-on-linux " +
|
||||
"[cloakbrowser] Incomplete Windows font set — installing the full " +
|
||||
"set is strongly advised for best results when spoofing Windows on " +
|
||||
"Linux. https://github.com/CloakHQ/cloakbrowser#font-setup-on-linux " +
|
||||
"(silence: CLOAKBROWSER_SUPPRESS_FONT_WARNING=1)");
|
||||
try
|
||||
{
|
||||
|
||||
@@ -63,10 +63,14 @@ internal static class Diagnostics
|
||||
// Omitted entirely off Linux, where it carries no signal.
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
bool? present = CloakLauncher.WindowsFontsPresent();
|
||||
// Strict count, not "any one present" — real font installs are atomic
|
||||
// (you have the whole pack or none), so report how complete the set is.
|
||||
int? winN = CloakLauncher.CountFontsPresent(CloakLauncher.WindowsFontTells);
|
||||
int? officeN = CloakLauncher.CountFontsPresent(CloakLauncher.OfficeFontTells);
|
||||
diag["fonts"] = new Dictionary<string, object?>
|
||||
{
|
||||
["windows_fonts"] = present == true ? "ok" : present == false ? "missing" : "unknown",
|
||||
["windows"] = winN is null ? null : new[] { winN.Value, CloakLauncher.WindowsFontTells.Length },
|
||||
["office"] = officeN is null ? null : new[] { officeN.Value, CloakLauncher.OfficeFontTells.Length },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+25
-7
@@ -21,7 +21,7 @@ import {
|
||||
normalizeRequestedVersion,
|
||||
CHROMIUM_VERSION,
|
||||
} from "./config.js";
|
||||
import { windowsFontsPresent } from "./fonts.js";
|
||||
import { countFontsPresent, WINDOWS_FONT_TELLS, OFFICE_FONT_TELLS } from "./fonts.js";
|
||||
import { resolveLicenseKey, validateLicense, getProLatestVersion, type LicenseInfo } from "./license.js";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { createRequire } from "node:module";
|
||||
@@ -192,9 +192,13 @@ export async function collectDiagnostics(quick: boolean): Promise<Record<string,
|
||||
// Windows-font probe — only meaningful on a Linux host spoofing Windows.
|
||||
// Omitted entirely off Linux, where it carries no signal.
|
||||
if (os.platform() === "linux") {
|
||||
const present = windowsFontsPresent();
|
||||
// Strict count, not "any one present" — real font installs are atomic
|
||||
// (you have the whole pack or none), so report how complete the set is.
|
||||
const winN = countFontsPresent(WINDOWS_FONT_TELLS);
|
||||
const officeN = countFontsPresent(OFFICE_FONT_TELLS);
|
||||
diag.fonts = {
|
||||
windows_fonts: present === true ? "ok" : present === false ? "missing" : "unknown",
|
||||
windows: winN === null ? null : [winN, WINDOWS_FONT_TELLS.length],
|
||||
office: officeN === null ? null : [officeN, OFFICE_FONT_TELLS.length],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -254,10 +258,24 @@ function printDiagnostics(diag: Record<string, any>): void {
|
||||
}
|
||||
|
||||
if (diag.fonts) {
|
||||
const fonts = diag.fonts.windows_fonts;
|
||||
console.log(`Win fonts: ${fonts}`);
|
||||
if (fonts === "missing") {
|
||||
console.log(" → spoofing Windows on Linux without Windows fonts; install msttcorefonts");
|
||||
const win = diag.fonts.windows;
|
||||
if (win === null) {
|
||||
console.log("Win fonts: unknown (fc-list unavailable)");
|
||||
} else {
|
||||
const [n, total] = win;
|
||||
const verdict = n === total ? "ok" : n === 0 ? "missing" : "partial";
|
||||
console.log(`Win fonts: ${verdict} (${n}/${total})`);
|
||||
if (n < total) {
|
||||
console.log(" → incomplete Windows font set; copy real Windows fonts (Segoe UI, Calibri, Consolas)");
|
||||
}
|
||||
}
|
||||
const office = diag.fonts.office;
|
||||
if (office != null) {
|
||||
const [n, total] = office;
|
||||
// Office is informational only — no Office pack is a normal Windows
|
||||
// persona (~53% of real machines have none), so no install nudge.
|
||||
const verdict = n === total ? "ok" : n === 0 ? "absent" : "partial";
|
||||
console.log(`Office fonts: ${verdict} (${n}/${total})`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+45
-14
@@ -13,28 +13,48 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { getCacheDir } from "./config.js";
|
||||
|
||||
// Microsoft-proprietary fonts that signal a real Windows install (absent from
|
||||
// ttf-mscorefonts-installer). Keep in sync with issue #395 and
|
||||
// docs/chrome40-fpjs-font-minimum-set-investigation.md.
|
||||
const WINDOWS_FONT_TELLS = [
|
||||
// Windows OS fonts — ship with Windows itself, so their absence on a
|
||||
// Windows-spoofing Linux host degrades results. The two monospace fonts
|
||||
// (Consolas + Courier New) are part of the recommended set so the generic
|
||||
// `monospace` family resolves to a Windows font. See issue #395.
|
||||
export const WINDOWS_FONT_TELLS = [
|
||||
"Segoe UI",
|
||||
"Segoe UI Light",
|
||||
"Calibri",
|
||||
"Marlett",
|
||||
"MS UI Gothic",
|
||||
"Franklin Gothic",
|
||||
"Consolas",
|
||||
"Courier New",
|
||||
];
|
||||
|
||||
// MS Office supplemental fonts, installed as one atomic block by every Office
|
||||
// install. Roughly half of real Windows machines have this pack and half do
|
||||
// not, so its absence is a perfectly normal Windows setup, NOT a problem —
|
||||
// reported as an informational signal only, never a warning.
|
||||
export const OFFICE_FONT_TELLS = [
|
||||
"MT Extra",
|
||||
"Century",
|
||||
"Century Gothic",
|
||||
"MS Reference Specialty",
|
||||
"Wingdings 2",
|
||||
"Wingdings 3",
|
||||
"Book Antiqua",
|
||||
"Bookshelf Symbol 7",
|
||||
"Monotype Corsiva",
|
||||
"Bookman Old Style",
|
||||
];
|
||||
|
||||
let fontWarningChecked = false;
|
||||
|
||||
/**
|
||||
* Probe for Windows fonts via fc-list.
|
||||
* Count how many tell-tale fonts are installed, via fc-list.
|
||||
*
|
||||
* Tri-state: true if any tell-tale font is installed, false if none found,
|
||||
* null if it can't be determined (fc-list missing or errored). Callers must
|
||||
* NOT warn on null — only an explicit false means "no Windows fonts".
|
||||
* Returns the number present (0..tells.length), or null if it can't be
|
||||
* determined (fc-list missing or errored). Callers must NOT treat null as
|
||||
* zero — null means "unknown", 0 means "genuinely none installed".
|
||||
*/
|
||||
export function windowsFontsPresent(): boolean | null {
|
||||
export function countFontsPresent(tells: string[]): number | null {
|
||||
let listing: string;
|
||||
try {
|
||||
// maxBuffer 16 MB: a host with a large font set can produce an fc-list
|
||||
@@ -44,11 +64,22 @@ export function windowsFontsPresent(): boolean | null {
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
return WINDOWS_FONT_TELLS.some((f) => listing.includes(f.toLowerCase()));
|
||||
return tells.filter((f) => listing.includes(f.toLowerCase())).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn once when spoofing Windows on a Linux host with no Windows fonts.
|
||||
* True if ALL Windows OS fonts are installed, false if any are missing, null
|
||||
* if unknown. Strict: a partial set is treated as incomplete, since the font
|
||||
* install is atomic and a missing font degrades the Windows persona.
|
||||
*/
|
||||
export function windowsFontsPresent(): boolean | null {
|
||||
const n = countFontsPresent(WINDOWS_FONT_TELLS);
|
||||
return n === null ? null : n === WINDOWS_FONT_TELLS.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn once when spoofing Windows on a Linux host without the full Windows
|
||||
* font set.
|
||||
*
|
||||
* Best-effort and silent on error — never throws. Gated by an in-process flag
|
||||
* plus a cache-dir marker so it fires at most once per environment. Suppress
|
||||
@@ -73,10 +104,10 @@ export function maybeWarnWindowsFonts(chromeArgs: string[]): void {
|
||||
const marker = path.join(getCacheDir(), ".font_warning_shown");
|
||||
if (fs.existsSync(marker)) return;
|
||||
const present = windowsFontsPresent();
|
||||
if (present === null || present === true) return; // present or undeterminable
|
||||
if (present === null || present === true) return; // full set present or undeterminable
|
||||
console.warn(
|
||||
"[cloakbrowser] No Windows fonts found — installing them is strongly " +
|
||||
"advised for best results when spoofing Windows on Linux. " +
|
||||
"[cloakbrowser] Incomplete Windows font set — installing the full set " +
|
||||
"is strongly advised for best results when spoofing Windows on Linux. " +
|
||||
"https://github.com/CloakHQ/cloakbrowser#font-setup-on-linux " +
|
||||
"(silence: CLOAKBROWSER_SUPPRESS_FONT_WARNING=1)",
|
||||
);
|
||||
|
||||
@@ -41,7 +41,7 @@ describe("collectDiagnostics", () => {
|
||||
|
||||
expect(diag.binary).toBeDefined();
|
||||
// fonts section only present on Linux
|
||||
if (os.platform() === "linux") expect(diag.fonts.windows_fonts).toBeTruthy();
|
||||
if (os.platform() === "linux") expect(diag.fonts.windows).toBeDefined();
|
||||
else expect(diag.fonts).toBeUndefined();
|
||||
expect(typeof diag.geoip.db_present).toBe("boolean");
|
||||
expect(Object.keys(diag.modules).length).toBeGreaterThan(0);
|
||||
|
||||
+21
-3
@@ -12,7 +12,14 @@ import path from "node:path";
|
||||
vi.mock("node:child_process", () => ({ execFileSync: vi.fn() }));
|
||||
|
||||
const WIN_ARGS = ["--fingerprint-platform=windows", "--no-sandbox"];
|
||||
const MSG = "No Windows fonts found";
|
||||
const MSG = "Incomplete Windows font set";
|
||||
|
||||
// fc-list output containing all 8 Windows tell fonts (the complete set).
|
||||
const ALL_WIN_FONTS =
|
||||
"Segoe UI:style=Regular\nSegoe UI Light:style=Light\nCalibri:style=Regular\n" +
|
||||
"Marlett:style=Regular\nMS UI Gothic:style=Regular\n" +
|
||||
"Franklin Gothic Medium:style=Regular\nConsolas:style=Regular\n" +
|
||||
"Courier New:style=Regular";
|
||||
|
||||
let cacheDir: string;
|
||||
|
||||
@@ -111,12 +118,23 @@ describe("maybeWarnWindowsFonts", () => {
|
||||
expect(fs.existsSync(marker())).toBe(false);
|
||||
});
|
||||
|
||||
it("does not warn when Windows fonts are present", async () => {
|
||||
it("does not warn when the full Windows set is present", async () => {
|
||||
vi.spyOn(os, "platform").mockReturnValue("linux");
|
||||
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const { maybeWarn, execFileSync } = await load();
|
||||
execFileSync.mockReturnValue("/x/segoeui.ttf: Segoe UI:style=Regular" as any);
|
||||
execFileSync.mockReturnValue(ALL_WIN_FONTS as any);
|
||||
maybeWarn(WIN_ARGS);
|
||||
expect(warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("warns on a partial Windows set (strict — all 8 required)", async () => {
|
||||
vi.spyOn(os, "platform").mockReturnValue("linux");
|
||||
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
||||
const { maybeWarn, execFileSync } = await load();
|
||||
// Only 1 of the 8 tells present.
|
||||
execFileSync.mockReturnValue("/x/segoeui.ttf: Segoe UI:style=Regular" as any);
|
||||
maybeWarn(WIN_ARGS);
|
||||
expect(warn).toHaveBeenCalledTimes(1);
|
||||
expect(String(warn.mock.calls[0][0])).toContain(MSG);
|
||||
});
|
||||
});
|
||||
@@ -14,7 +14,15 @@ import pytest
|
||||
import cloakbrowser.browser as browser
|
||||
|
||||
WIN_ARGS = ["--fingerprint-platform=windows", "--no-sandbox"]
|
||||
MSG = "No Windows fonts found"
|
||||
MSG = "Incomplete Windows font set"
|
||||
|
||||
# fc-list output containing all 8 Windows tell fonts (the complete set).
|
||||
ALL_WIN_FONTS = (
|
||||
"Segoe UI:style=Regular\nSegoe UI Light:style=Light\nCalibri:style=Regular\n"
|
||||
"Marlett:style=Regular\nMS UI Gothic:style=Regular\n"
|
||||
"Franklin Gothic Medium:style=Regular\nConsolas:style=Regular\n"
|
||||
"Courier New:style=Regular"
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
@@ -110,7 +118,18 @@ def test_no_warn_no_crash_when_fc_list_absent(tmp_path, capsys):
|
||||
assert not (tmp_path / ".font_warning_shown").exists()
|
||||
|
||||
|
||||
def test_no_warn_when_fonts_present(tmp_path, capsys):
|
||||
def test_no_warn_when_full_set_present(tmp_path, capsys):
|
||||
with (
|
||||
patch("platform.system", return_value="Linux"),
|
||||
patch("subprocess.run", side_effect=_fc_list(0, ALL_WIN_FONTS)),
|
||||
patch("cloakbrowser.config.get_cache_dir", return_value=tmp_path),
|
||||
):
|
||||
browser._maybe_warn_windows_fonts(WIN_ARGS)
|
||||
assert MSG not in capsys.readouterr().err
|
||||
|
||||
|
||||
def test_warns_on_partial_set(tmp_path, capsys):
|
||||
# Only 1 of the 8 tells present — strict check treats this as incomplete.
|
||||
listing = "/usr/share/fonts/segoeui.ttf: Segoe UI:style=Regular"
|
||||
with (
|
||||
patch("platform.system", return_value="Linux"),
|
||||
@@ -118,4 +137,4 @@ def test_no_warn_when_fonts_present(tmp_path, capsys):
|
||||
patch("cloakbrowser.config.get_cache_dir", return_value=tmp_path),
|
||||
):
|
||||
browser._maybe_warn_windows_fonts(WIN_ARGS)
|
||||
assert MSG not in capsys.readouterr().err
|
||||
assert MSG in capsys.readouterr().err
|
||||
Reference in new issue
Block a user