File size: 2,559 Bytes
755a930
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d15d7f7
755a930
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7843436
755a930
 
 
 
7843436
755a930
 
 
 
 
7843436
755a930
 
 
 
7843436
755a930
 
 
 
 
7843436
755a930
 
 
 
7843436
755a930
 
 
 
 
7843436
755a930
 
 
 
 
 
 
 
 
 
7843436
755a930
 
 
 
 
7843436
755a930
 
 
 
7843436
755a930
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
/**
 * Security Tests (Section 4 of TESTS.md)
 *
 * Tests XSS escaping in published HTML output.
 */
import { describe, it, expect } from "vitest";
import { renderArticleHTML, type PublishMeta } from "../src/publisher/html-renderer.js";

const EMPTY_CSS = {
  variables: ":root { --text-color: #000; }",
  reset: "",
  base: "",
  layout: "",
  print: "",
  editorTokens: "",
  article: "",
  components: "",
  publisher: "",
};

const BASE_META: PublishMeta = {
  title: "Test",
  description: "Test description",
  authors: [],
  affiliations: [],
  date: "2025-01-01",
};

const MINIMAL_JSON = {
  type: "doc",
  content: [{ type: "paragraph", content: [{ type: "text", text: "Hello" }] }],
};

describe("4.4 XSS prevention", () => {
  it("4.4.1 licence field is escaped in published HTML", async () => {
    const meta: PublishMeta = {
      ...BASE_META,
      licence: '<script>alert("xss")</script>',
    };
    const html = await renderArticleHTML(MINIMAL_JSON, meta, EMPTY_CSS);

    expect(html).not.toContain('<script>alert("xss")</script>');
    expect(html).toContain("&lt;script&gt;");
  });

  it("4.4.2 title is escaped in published HTML", async () => {
    const meta: PublishMeta = {
      ...BASE_META,
      title: '<img src=x onerror="alert(1)">',
    };
    const html = await renderArticleHTML(MINIMAL_JSON, meta, EMPTY_CSS);

    expect(html).not.toContain('<img src=x onerror="alert(1)">');
    expect(html).toContain("&lt;img");
  });

  it("4.4.3 description is escaped in meta tags", async () => {
    const meta: PublishMeta = {
      ...BASE_META,
      description: '"><script>alert(1)</script>',
    };
    const html = await renderArticleHTML(MINIMAL_JSON, meta, EMPTY_CSS);

    expect(html).not.toContain('"><script>');
    expect(html).toContain("&quot;&gt;&lt;script&gt;");
  });

  it("4.4.4 author names are escaped", async () => {
    const meta: PublishMeta = {
      ...BASE_META,
      authors: [
        {
          name: '<script>alert(1)</script>',
          affiliationIndices: [],
          affiliationNames: [],
        },
      ],
    };
    const html = await renderArticleHTML(MINIMAL_JSON, meta, EMPTY_CSS);

    expect(html).not.toContain('<script>alert(1)</script>');
    expect(html).toContain("&lt;script&gt;");
  });

  it("4.4.5 DOI is escaped in links", async () => {
    const meta: PublishMeta = {
      ...BASE_META,
      doi: '"><script>alert(1)</script>',
    };
    const html = await renderArticleHTML(MINIMAL_JSON, meta, EMPTY_CSS);

    expect(html).not.toContain('"><script>');
  });
});