fix(files): decode markdown refs, scope links to the preview session, drop name= from the sanitizer

Review follow-up on #503. marked percent-encodes link and image destinations, and the rebase pass encoded them a second time, so a space or a CJK character in a file name made file-raw look for a file literally named my%20image.png; refs are now decoded once (a malformed escape is kept as written) and stripped of ?query along with #fragment. Root-relative refs resolve from the workspace root as on GitHub instead of falling through as Codeman URLs. Rebased links carry the preview's own session id and the response-viewer delegate prefers it, so a document opened from another session's attachment card opens its links in that workspace rather than the active tab's.

The sanitizer no longer allows name=: marked never emits it, and <img name="app"> made document.app that image, which every inline onclick="app.…()" handler resolves before the global, so one rendered README broke every viewer button until a reload. Adds the zh-CN strings for the three toolbar titles.
This commit is contained in:
JD
2026-09-28 15:22:37 -04:00
parent 5e27043bf7
commit 612c69d57a
10 changed files with 88 additions and 22 deletions
+10
View File
@@ -165,6 +165,16 @@ describe('COD-56 markdown sanitizer (DOMPurify allowlist)', () => {
expect(sanitize(html).toLowerCase()).not.toContain(tag);
});
}
// DOM clobbering: <img name="app"> makes document.app that image, and inline
// onclick="app.…()" handlers resolve `app` on the document before the global,
// so a rendered README could break every button until a reload.
it('drops name= (marked never emits it; it clobbers document.<name>)', () => {
const out = sanitize('<img name="app" src="https://example.com/x.png" alt="x"><a name="app" href="#a">a</a>');
expect(out).not.toMatch(/\sname\s*=/i);
expect(out).toContain('src="https://example.com/x.png"');
expect(out).toContain('href="#a"');
});
});
describe('legitimate markdown-rendered HTML survives', () => {