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:
+24
-1
@@ -103,6 +103,29 @@ export function rewriteAbsolute(html: string, base: string, origins: string[]):
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asset paths embedded in JavaScript, including JSON-escaped ones.
|
||||
*
|
||||
* Gitea inlines a script that names its own worker: `'\\/assets\\/js\\/eventsource.sharedworker.…js'`.
|
||||
* That is not an attribute and its slashes are backslash-escaped, so neither of the rewrites above sees
|
||||
* it. Unprefixed, the browser resolves it against the PLATFORM's origin, gets the SPA's index.html, and
|
||||
* reports `Uncaught SyntaxError: Unexpected token '<'` from a file that looks like it loaded.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* `appSubUrl` covers everything Gitea's code BUILDS at runtime. This covers what is already baked into
|
||||
* the page before that code runs.
|
||||
*/
|
||||
export function rewriteAssetPaths(html: string, base: string): string {
|
||||
// `/api/gitea/_web` becomes `\/api\/gitea\/_web`, matching the escaping of the string it is going into.
|
||||
const escapedBase = base.split('/').join('\\/');
|
||||
return html
|
||||
.replace(/\\\/assets\\\//g, `${escapedBase}\\/assets\\/`)
|
||||
.replace(/(["'`])\/assets\//g, (_m, q: string) => `${q}${base}/assets/`);
|
||||
}
|
||||
|
||||
/**
|
||||
* The public URL Gitea believes it has, read out of its own page.
|
||||
*
|
||||
@@ -128,7 +151,7 @@ export function rewriteHtml(html: string, base: string, origins: string[]): stri
|
||||
// attribute pass then skips as already-prefixed.
|
||||
const declared = appUrlOrigin(html);
|
||||
const all = declared ? [...origins, declared] : origins;
|
||||
return rewriteAttributes(rewriteAppSubUrl(rewriteAbsolute(html, base, all), base), base);
|
||||
return rewriteAssetPaths(rewriteAttributes(rewriteAppSubUrl(rewriteAbsolute(html, base, all), base), base), base);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user