Skip to content

Commit f85db23

Browse files
authored
fix(windows): enforce theme schemaVersion at runtime (#288)
* fix(windows): enforce theme schemaVersion at runtime * fix(windows): write schema version for generated themes
1 parent 3ad3571 commit f85db23

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

windows/scripts/injector.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,9 @@ export async function loadTheme(themeDir) {
525525
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
526526
throw new Error("Theme root must be an object");
527527
}
528+
if (raw.schemaVersion !== 1) {
529+
throw new Error("Theme must use schemaVersion 1");
530+
}
528531
const image = normalizedText(raw.image, "image", null, 240);
529532
if (!image || path.isAbsolute(image)) throw new Error("Theme image must be a relative path");
530533
const imagePath = path.resolve(realThemeDir, image);
@@ -561,6 +564,7 @@ export async function loadTheme(themeDir) {
561564
line: normalizeThemeColor(rawColors?.line, "rgba(124, 255, 70, .28)"),
562565
};
563566
const theme = {
567+
schemaVersion: 1,
564568
id: normalizeThemeText(raw.id, "custom", 80, "id", themePath),
565569
name: normalizeThemeText(raw.name, "Codex Dream Skin", 80, "name", themePath),
566570
brandSubtitle: normalizeThemeText(raw.brandSubtitle, "CODEX DREAM SKIN", 120, "brandSubtitle", themePath),

windows/scripts/theme-windows.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@ function Set-DreamSkinActiveTheme {
594594
try { $oldImage = (Read-DreamSkinTheme -ThemeDirectory $paths.Active).ImagePath } catch {}
595595
if ($null -eq $Theme) {
596596
$Theme = [pscustomobject]@{
597+
schemaVersion = 1
597598
id = 'custom'
598599
name = '自定义主题'
599600
appearance = 'auto'
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import assert from "node:assert/strict";
2+
import fs from "node:fs/promises";
3+
import os from "node:os";
4+
import path from "node:path";
5+
import test from "node:test";
6+
import { fileURLToPath } from "node:url";
7+
import { loadTheme } from "../scripts/injector.mjs";
8+
9+
const here = path.dirname(fileURLToPath(import.meta.url));
10+
const windowsRoot = path.resolve(here, "..");
11+
const sourceImage = path.join(windowsRoot, "assets", "dream-reference.jpg");
12+
13+
async function makeTheme(root, schemaVersion, includeSchema = true) {
14+
await fs.copyFile(sourceImage, path.join(root, "background.jpg"));
15+
const theme = {
16+
id: "schema-contract-fixture",
17+
name: "Schema contract fixture",
18+
image: "background.jpg",
19+
};
20+
if (includeSchema) theme.schemaVersion = schemaVersion;
21+
await fs.writeFile(path.join(root, "theme.json"), `${JSON.stringify(theme, null, 2)}\n`);
22+
}
23+
24+
async function withTheme(schemaVersion, includeSchema, callback) {
25+
const root = await fs.mkdtemp(path.join(os.tmpdir(), "dreamskin-schema-contract."));
26+
try {
27+
await makeTheme(root, schemaVersion, includeSchema);
28+
await callback(root);
29+
} finally {
30+
await fs.rm(root, { recursive: true, force: true });
31+
}
32+
}
33+
34+
test("Windows runtime accepts and preserves theme schemaVersion 1", async () => {
35+
await withTheme(1, true, async (root) => {
36+
const loaded = await loadTheme(root);
37+
assert.equal(loaded.theme.schemaVersion, 1);
38+
});
39+
});
40+
41+
test("Windows runtime rejects missing and future theme schema versions", async () => {
42+
await withTheme(undefined, false, async (root) => {
43+
await assert.rejects(loadTheme(root), /must use schemaVersion 1/);
44+
});
45+
await withTheme(2, true, async (root) => {
46+
await assert.rejects(loadTheme(root), /must use schemaVersion 1/);
47+
});
48+
await withTheme("1", true, async (root) => {
49+
await assert.rejects(loadTheme(root), /must use schemaVersion 1/);
50+
});
51+
});

0 commit comments

Comments
 (0)