From fe67de028106885408790a0b80ecb4077c191f7c Mon Sep 17 00:00:00 2001 From: officer Date: Wed, 19 Aug 2026 09:38:08 +0000 Subject: [PATCH] rewrite data-*url attributes, where Gitea hands URLs to its own JavaScript MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dashboard heatmap reads its endpoint from data-heatmap-url: document.querySelector('#user-heatmap').getAttribute('data-heatmap-url'). Unprefixed it fetched from the PLATFORM's origin, got the SPA's index.html and reported "Unexpected token '<'" while parsing JSON — the last error left after everything visible was rendering correctly. data-url carries the language switcher's links and had the same problem. Matched on the `url` suffix rather than by listing attribute names, because the list is Gitea's to change. Found by reading Gitea's own bundle rather than by reasoning about what it probably does — which is what the three previous attempts at this error were. --- sidecar/rewrite.test.ts | 18 ++++++++++++++++++ sidecar/rewrite.ts | 12 ++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/sidecar/rewrite.test.ts b/sidecar/rewrite.test.ts index a70d572..f9cdb65 100644 --- a/sidecar/rewrite.test.ts +++ b/sidecar/rewrite.test.ts @@ -24,6 +24,24 @@ describe('attributes', () => { expect(out).toContain(`action="${BASE}/repo/new"`); }); + // Gitea hands URLs to its own JavaScript through data attributes, which is where the dashboard heatmap + // gets its endpoint — `document.querySelector('#user-heatmap').getAttribute('data-heatmap-url')`. + // Unprefixed it fetched from the PLATFORM's origin, got the SPA's index.html, and reported + // "Unexpected token '<'" while parsing JSON. Found by reading Gitea's bundle, not by guessing. + test('data-*url attributes are rewritten — the heatmap reads its endpoint from one', () => { + const html = '
'; + expect(rewriteAttributes(html, BASE)).toContain(`data-heatmap-url="${BASE}/api/v1/users/x/heatmap"`); + }); + + test('and plain data-url, which the language switcher uses', () => { + expect(rewriteAttributes('', BASE)).toContain(`data-url="${BASE}/?lang=en-US"`); + }); + + test('a data attribute that is not a url is left alone', () => { + const html = '
'; + expect(rewriteAttributes(html, BASE)).toBe(html); + }); + test('a relative href is already correct and must not be touched', () => { expect(rewriteAttributes('', BASE)).toBe(''); }); diff --git a/sidecar/rewrite.ts b/sidecar/rewrite.ts index 9e0b0b7..1c11a72 100644 --- a/sidecar/rewrite.ts +++ b/sidecar/rewrite.ts @@ -58,8 +58,16 @@ const isForeign = (path: string): boolean => path.startsWith('//') || /^[a-z][a- export function rewriteAttributes(html: string, base: string): string { const skip = (path: string) => isForeign(path) || path === base || path.startsWith(`${base}/`); return html - .replace(/(href|src|action)=("|')(\/[^"']*)\2/gi, (match, attr: string, quote: string, path: string) => - skip(path) ? match : `${attr}=${quote}${prefixed(base, path)}${quote}`, + // `data-*url` alongside the obvious three. Gitea hands URLs to its own JavaScript through data + // attributes — `data-heatmap-url` is where the dashboard heatmap gets its endpoint, and `data-url` + // carries the language switcher's links. Missing them meant the heatmap fetched from the PLATFORM's + // origin, got the SPA's index.html, and reported `Unexpected token '<'` while parsing JSON. + // + // Matched on the `url` suffix rather than by listing names, because the list is Gitea's to change. + .replace( + /(href|src|action|data-[a-z-]*url)=("|')(\/[^"']*)\2/gi, + (match, attr: string, quote: string, path: string) => + skip(path) ? match : `${attr}=${quote}${prefixed(base, path)}${quote}`, ) .replace(/url\((\/[^)"']*)\)/g, (match, path: string) => (skip(path) ? match : `url(${prefixed(base, path)})`)); }