diff --git a/desktop/build-deb.sh b/desktop/build-deb.sh index e49c396..1c98af0 100755 --- a/desktop/build-deb.sh +++ b/desktop/build-deb.sh @@ -148,6 +148,9 @@ fi if command -v gtk-update-icon-cache >/dev/null 2>&1; then gtk-update-icon-cache -q -t -f /usr/share/icons/hicolor || true fi +# Stop any stale background server from a previous package build so the next +# launch or systemd restart serves the updated /opt/pubscript bundle cleanly. +pkill -f "/opt/pubscript/server/dist/server.mjs" >/dev/null 2>&1 || true exit 0 EOF chmod 0755 "$STAGE_DIR/DEBIAN/postinst" diff --git a/server/src/index.ts b/server/src/index.ts index 06384f8..8ac8a93 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -605,8 +605,9 @@ export async function buildApp() { const webRoot = process.env.PUBSCRIPT_WEB_DIST || resolve(here, "../../apps/web/dist"); if (existsSync(webRoot) && existsSync(resolve(webRoot, "index.html"))) { + const resolvedWebRoot = resolve(webRoot); await app.register(fastifyStatic, { - root: webRoot, + root: resolvedWebRoot, prefix: "/", wildcard: false, }); @@ -616,6 +617,20 @@ export async function buildApp() { !req.url.startsWith("/api/") && !req.url.startsWith("/ws") ) { + const cleanPath = decodeURIComponent((req.url.split("?")[0] ?? "/").replace(/^\/+/, "")); + if (cleanPath && !cleanPath.includes("..")) { + const candidate = resolve(resolvedWebRoot, cleanPath); + if ( + candidate.startsWith(resolvedWebRoot) && + existsSync(candidate) && + statSync(candidate).isFile() + ) { + return reply.sendFile(cleanPath); + } + } + if (cleanPath.startsWith("assets/")) { + return reply.code(404).send({ error: "asset_not_found" }); + } return reply.sendFile("index.html"); } return reply.code(404).send({ error: "not_found" });