

























@@ -0,0 +1,60 @@
1+import { readFileSync } from "node:fs";
2+import { describe, expect, it } from "vitest";
3+4+const VIEWER_CLIENT_SRC = readFileSync(
5+new URL("./viewer-client.ts", import.meta.url),
6+"utf8",
7+);
8+9+const XSS_PATTERNS = ["onerror", "<script", "onclick", "javascript:", "onload"];
10+11+describe("createToolbarButton icon safety", () => {
12+it("toolbarIconSvg map exists and has exactly 8 icon names", () => {
13+const requiredNames = [
14+"split",
15+"unified",
16+"wrap-on",
17+"wrap-off",
18+"background-on",
19+"background-off",
20+"theme-dark",
21+"theme-light",
22+] as const;
23+for (const name of requiredNames) {
24+expect(
25+VIEWER_CLIENT_SRC.includes(name + ":") || VIEWER_CLIENT_SRC.includes(`"${name}"`),
26+`icon "${name}" should exist in toolbarIconSvg`,
27+).toBe(true);
28+}
29+});
30+31+it("no iconMarkup: string parameter exists", () => {
32+expect(VIEWER_CLIENT_SRC.includes("iconMarkup: string")).toBe(false);
33+});
34+35+it("innerHTML reads only from toolbarIconSvg lookup", () => {
36+expect(VIEWER_CLIENT_SRC.includes("button.innerHTML = toolbarIconSvg[params.icon]")).toBe(true);
37+});
38+39+it("SVG strings in toolbarIconSvg contain no XSS patterns", () => {
40+for (const pattern of XSS_PATTERNS) {
41+expect(
42+VIEWER_CLIENT_SRC.includes(pattern),
43+`source must not contain "${pattern}"`,
44+).toBe(false);
45+}
46+});
47+48+it("old icon functions are removed", () => {
49+const removedFunctions = [
50+"function splitIcon(",
51+"function unifiedIcon(",
52+"function wrapIcon(",
53+"function backgroundIcon(",
54+"function themeIcon(",
55+];
56+for (const fn of removedFunctions) {
57+expect(VIEWER_CLIENT_SRC.includes(fn), `"${fn}" should be removed`).toBe(false);
58+}
59+});
60+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。