chore(share): fix escape in reference link and handling of attachment links
Some checks are pending
Checks / main (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
Deploy Documentation / Build and Deploy Documentation (push) Waiting to run
Dev / Test development (push) Waiting to run
Dev / Build Docker image (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile) (push) Blocked by required conditions
Dev / Check Docker build (Dockerfile.alpine) (push) Blocked by required conditions
/ Check Docker build (Dockerfile) (push) Waiting to run
/ Check Docker build (Dockerfile.alpine) (push) Waiting to run
/ Build Docker images (Dockerfile, ubuntu-24.04-arm, linux/arm64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.alpine, ubuntu-latest, linux/amd64) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v7) (push) Blocked by required conditions
/ Build Docker images (Dockerfile.legacy, ubuntu-24.04-arm, linux/arm/v8) (push) Blocked by required conditions
/ Merge manifest lists (push) Blocked by required conditions
playwright / E2E tests on linux-arm64 (push) Waiting to run
playwright / E2E tests on linux-x64 (push) Waiting to run

This commit is contained in:
Elian Doran 2025-11-19 09:19:02 +02:00
parent ae184ab894
commit 2e5d91a5bc
No known key found for this signature in database
2 changed files with 97 additions and 26 deletions

View File

@ -35,30 +35,6 @@ describe("content_renderer", () => {
expect(result.content).toStrictEqual(content); expect(result.content).toStrictEqual(content);
}); });
it("handles attachment link", () => {
const content = trimIndentation`\
<h1>Test</h1>
<p>
<a class="reference-link" href="#root/iwTmeWnqBG5Q?viewMode=attachments&amp;attachmentId=q14s2Id7V6pp">
5863845791835102555.mp4
</a>
&nbsp;
</p>
`;
const note = buildShareNote({
content,
attachments: [ { id: "q14s2Id7V6pp", title: "5863845791835102555.mp4" } ]
});
const result = getContent(note);
expect(result.content).toStrictEqual(trimIndentation`\
<h1>Test</h1>
<p>
<a class="reference-link attachment-link role-file" href="api/attachments/q14s2Id7V6pp/download">5863845791835102555.mp4</a>
&nbsp;
</p>
`);
});
it("renders included notes", () => { it("renders included notes", () => {
buildShareNotes([ buildShareNotes([
{ id: "subnote1", content: `<p>Foo</p><div>Bar</div>` }, { id: "subnote1", content: `<p>Foo</p><div>Bar</div>` },
@ -110,6 +86,98 @@ describe("content_renderer", () => {
</pre> </pre>
`) `)
}); });
describe("Reference links", () => {
it("handles attachment link", () => {
const content = trimIndentation`\
<h1>Test</h1>
<p>
<a class="reference-link" href="#root/iwTmeWnqBG5Q?viewMode=attachments&amp;attachmentId=q14s2Id7V6pp">
5863845791835102555.mp4
</a>
&nbsp;
</p>
`;
const note = buildShareNote({
content,
attachments: [ { id: "q14s2Id7V6pp", title: "5863845791835102555.mp4" } ]
});
const result = getContent(note);
expect(result.content).toStrictEqual(trimIndentation`\
<h1>Test</h1>
<p>
<a class="reference-link attachment-link role-file" href="api/attachments/q14s2Id7V6pp/download">5863845791835102555.mp4</a>
&nbsp;
</p>
`);
});
it("handles protected notes", () => {
buildShareNote({
id: "MSkxxCFbBsYP",
title: "Foo",
isProtected: true
});
const note = buildShareNote({
id: "note",
content: trimIndentation`\
<p>
<a class="reference-link" href="#root/zaIItd4TM5Ly/MSkxxCFbBsYP">
Foo
</a>
</p>
`
});
const result = getContent(note);
expect(result.content).toStrictEqual(trimIndentation`\
<p>
<a class="reference-link type-text" href="./MSkxxCFbBsYP">[protected]</a>
</p>
`);
});
it("handles missing notes", () => {
const note = buildShareNote({
id: "note",
content: trimIndentation`\
<p>
<a class="reference-link" href="#root/zaIItd4TM5Ly/AsKxyCFbBsYp">
Foo
</a>
</p>
`
});
const result = getContent(note);
expect(result.content).toStrictEqual(trimIndentation`\
<p>
<a class="reference-link">[missing note]</a>
</p>
`);
});
it("properly escapes note title", () => {
buildShareNote({
id: "MSkxxCFbBsYP",
title: "The quick <strong>brown</strong> fox"
});
const note = buildShareNote({
id: "note",
content: trimIndentation`\
<p>
<a class="reference-link" href="#root/zaIItd4TM5Ly/MSkxxCFbBsYP">
Hi
</a>
</p>
`
});
const result = getContent(note);
expect(result.content).toStrictEqual(trimIndentation`\
<p>
<a class="reference-link type-text" href="./MSkxxCFbBsYP"><span><span class="bx bx-note"></span>The quick &lt;strong&gt;brown&lt;/strong&gt; fox</span></a>
</p>
`);
});
});
}); });
describe("renderCode", () => { describe("renderCode", () => {

View File

@ -394,14 +394,17 @@ function handleAttachmentLink(linkEl: HTMLElement, href: string, getNote: (id: s
*/ */
function cleanUpReferenceLinks(linkEl: HTMLElement) { function cleanUpReferenceLinks(linkEl: HTMLElement) {
// Note: this method is basically a reimplementation of getReferenceLinkTitleSync from the link service of the client. // Note: this method is basically a reimplementation of getReferenceLinkTitleSync from the link service of the client.
const noteId = linkEl.getAttribute("href")?.split("/").at(-1); const href = linkEl.getAttribute("href") ?? "";
if (linkEl.classList.contains("attachment-link")) return;
const noteId = href.split("/").at(-1);
const note = noteId ? shaca.getNote(noteId) : undefined; const note = noteId ? shaca.getNote(noteId) : undefined;
if (!note) { if (!note) {
linkEl.innerHTML = "[missing note]"; linkEl.innerHTML = "[missing note]";
} else if (note.isProtected) { } else if (note.isProtected) {
linkEl.innerHTML = "[protected]"; linkEl.innerHTML = "[protected]";
} else { } else {
linkEl.innerHTML = `<span><span class="${note.getIcon()}"></span>${note.title}</span>`; linkEl.innerHTML = `<span><span class="${note.getIcon()}"></span>${utils.escapeHtml(note.title)}</span>`;
} }
} }