fix(runtime): download pinned MiSans fonts individually for 7.5

This commit is contained in:
2026-10-16 16:32:58 +08:00
parent 39cd470f92
commit 65d118a145
4 changed files with 36 additions and 31 deletions
+6 -1
View File
@@ -1,6 +1,11 @@
This runtime uses MiSans fonts by Xiaomi.
Official source: https://hyperos.mi.com/font/zh/download/
Archive: https://hyperos.mi.com/font-download/MiSans.zip
Download mirror (third-party, not an official Xiaomi repository):
https://github.com/boyan01/mi_sans_font/tree/68f3ec3fee5830ce8a1d955d462fa0df401a5341/lib/fonts
Files: MiSans-Regular.ttf and MiSans-Bold.ttf
These mirrored files differ from the current official ZIP; they are not claimed
to be the latest release. The mirror repository's license does not replace the
Xiaomi font license.
MiSans is subject to the MiSans Fonts Intellectual Property License Agreement
published on the official download page. It is not an open-source font license.
+22 -26
View File
@@ -1,33 +1,29 @@
import { createHash } from 'node:crypto';
import { mkdtempSync, writeFileSync, rmSync, mkdirSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { writeFileSync, mkdirSync } from 'node:fs';
import { join } from 'node:path';
import { execFileSync } from 'node:child_process';
const url = 'https://hyperos.mi.com/font-download/MiSans.zip';
const sha256 = 'b6aa1fc827035922612df8edf36e5609bca1c5441e25cd57572204569b7b81d9';
const weights = ['Thin', 'ExtraLight', 'Light', 'Normal', 'Regular', 'Medium', 'Demibold', 'Semibold', 'Bold', 'Heavy'];
// Third-party mirror, pinned to a reviewed commit; Xiaomi's font license applies.
const base = 'https://raw.githubusercontent.com/boyan01/mi_sans_font/68f3ec3fee5830ce8a1d955d462fa0df401a5341/lib/fonts/';
const fonts = [
['MiSans-Regular.ttf', '7172aa1b5c703780ee12df3fe4c50481dde01f3b125a045a398000a88d032ae5', 'Regular'],
['MiSans-Bold.ttf', '250fb5c8d4657f103e332b0b948a995e45f2c159beb8d0528424e2d32ae421be', 'Bold'],
];
const destination = '/usr/local/share/fonts/misans';
const temporary = mkdtempSync(join(tmpdir(), 'misans-'));
try {
const response = await fetch(url, { signal: AbortSignal.timeout(300000) });
if (!response.ok) throw new Error(`MiSans download failed: ${response.status}`);
const archive = Buffer.from(await response.arrayBuffer());
if (createHash('sha256').update(archive).digest('hex') !== sha256) {
throw new Error('MiSans archive checksum mismatch; review upstream changes before updating');
mkdirSync(destination, { recursive: true });
for (const [name, sha256] of fonts) {
console.log('Downloading ' + name);
const response = await fetch(base + name, { signal: AbortSignal.timeout(120000) });
if (!response.ok) throw new Error('MiSans download failed: ' + name + ' HTTP ' + response.status);
const font = Buffer.from(await response.arrayBuffer());
if (createHash('sha256').update(font).digest('hex') !== sha256) {
throw new Error('MiSans checksum mismatch: ' + name);
}
const archivePath = join(temporary, 'MiSans.zip');
writeFileSync(archivePath, archive);
mkdirSync(destination, { recursive: true });
for (const weight of weights) {
const name = `MiSans-${weight}.ttf`;
// Extract only fixed, reviewed filenames; never unpack arbitrary archive paths.
const font = execFileSync('python3', ['-c', 'import sys, zipfile; sys.stdout.buffer.write(zipfile.ZipFile(sys.argv[1]).read(sys.argv[2]))', archivePath, `MiSans/ttf/${name}`], { maxBuffer: 16000000 });
writeFileSync(join(destination, name), font, { mode: 0o644 });
}
execFileSync('fc-cache', ['-f', destination], { stdio: 'inherit' });
const family = execFileSync('fc-match', ['-f', '%{family}', 'MiSans'], { encoding: 'utf8' });
if (!family.split(',').includes('MiSans')) throw new Error(`MiSans font lookup failed: ${family}`);
} finally {
rmSync(temporary, { recursive: true, force: true });
writeFileSync(join(destination, name), font, { mode: 0o644 });
}
execFileSync('fc-cache', ['-f', destination], { stdio: 'inherit' });
for (const [name, , style] of fonts) {
const file = execFileSync('fc-match', ['-f', '%{file}', 'MiSans:style=' + style], { encoding: 'utf8' });
if (file !== join(destination, name)) throw new Error('MiSans font lookup failed: ' + style + ': ' + file);
}
console.log('Installed MiSans Regular and Bold (SHA-256 verified)');