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)})`)); }