rewrite asset paths baked into the page, including JSON-escaped ones
Gitea inlines a script naming its own worker: '\/assets\/js\/eventsource.sharedworker.…js'. That is not an attribute and its slashes are backslash-escaped, so neither the attribute rewrite nor appSubUrl saw it. Unprefixed, the browser resolved it against the PLATFORM's origin, got the SPA's index.html, and reported "Uncaught SyntaxError: Unexpected token '<'" from a file that appeared to load — along with a dead SharedWorker and a heatmap parsing HTML as JSON. appSubUrl covers everything Gitea's code BUILDS at runtime. This covers what is already in the page before that code runs. Narrow on purpose, like dev-proxy's /_bun/ rule: a blanket rewrite of absolute paths inside JavaScript corrupts strings that are not URLs. /assets/ is Gitea's own asset root and specific enough to match safely. The escaping has to match the string it lands in — \/api\/gitea\/_web, not \\/api — or the JS stops parsing. Both forms are tested against a live sample.
This commit is contained in:
+30
-1
@@ -1,5 +1,12 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { rewriteHtml, rewriteLocation, rewriteSetCookie, rewriteAttributes, rewriteAppSubUrl } from './rewrite';
|
||||
import {
|
||||
rewriteHtml,
|
||||
rewriteLocation,
|
||||
rewriteSetCookie,
|
||||
rewriteAttributes,
|
||||
rewriteAppSubUrl,
|
||||
rewriteAssetPaths,
|
||||
} from './rewrite';
|
||||
|
||||
const BASE = '/api/gitea/_web';
|
||||
const ORIGINS = ['http://localhost:3000', 'https://gitea.officer.dev'];
|
||||
@@ -90,6 +97,28 @@ describe('redirects — the most visible failure, because the frame just leaves'
|
||||
});
|
||||
});
|
||||
|
||||
describe('asset paths baked into the page before Gitea\'s own code runs', () => {
|
||||
test('the JSON-escaped form — the SharedWorker URL that broke the dashboard', () => {
|
||||
// Verbatim from a live page. Not an attribute, and its slashes are backslash-escaped, so neither the
|
||||
// attribute rewrite nor appSubUrl touches it. Unprefixed, the browser resolves it against the
|
||||
// PLATFORM's origin, gets the SPA's index.html, and reports `Unexpected token '<'` from a file that
|
||||
// looks like it loaded.
|
||||
const real = String.raw`'\/assets\/js\/eventsource.sharedworker.DV1Z2uJv.js',`;
|
||||
const out = rewriteAssetPaths(real, BASE);
|
||||
expect(out).toContain(String.raw`'\/api\/gitea\/_web\/assets\/js\/eventsource`);
|
||||
// The escaping has to match the string it lands in, or the JS stops parsing.
|
||||
expect(out).not.toContain(String.raw`\\/api`);
|
||||
});
|
||||
|
||||
test('the plain quoted form too', () => {
|
||||
expect(rewriteAssetPaths(`x = "/assets/img/logo.svg"`, BASE)).toContain(`"${BASE}/assets/img/logo.svg"`);
|
||||
});
|
||||
|
||||
test('leaves a path that is not an asset root alone', () => {
|
||||
expect(rewriteAssetPaths(`x = "/user/login"`, BASE)).toBe(`x = "/user/login"`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the origin Gitea declares about itself', () => {
|
||||
test('is discovered from window.config, so ROOT_URL needs no second setting', () => {
|
||||
// The sidecar only knows where it FETCHES from — usually loopback. The public origin lives in the
|
||||
|
||||
Reference in New Issue
Block a user