From bd91afb3dfed9e2d53f206786820c35e41c60877 Mon Sep 17 00:00:00 2001 From: OpeOginni Date: Mon, 4 May 2026 12:20:16 +0200 Subject: [PATCH] fix(httpapi/desktop): strip transfer-encoding in UI proxy and allow public manifest assets --- packages/app/src/components/terminal.tsx | 2 +- packages/opencode/src/server/middleware.ts | 2 ++ .../instance/httpapi/middleware/authorization.ts | 2 ++ packages/opencode/src/server/shared/public-ui.ts | 12 ++++++++++++ packages/opencode/src/server/shared/ui.ts | 1 + 5 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 packages/opencode/src/server/shared/public-ui.ts diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index 7bcc02d62d88..6e3c83774142 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -481,7 +481,7 @@ export const Terminal = (props: TerminalProps) => { const connectToken = async () => { const result = await client.pty.connectToken( - { ptyID: id }, + { ptyID: id, directory }, { throwOnError: false, headers: { "x-opencode-ticket": "1" }, diff --git a/packages/opencode/src/server/middleware.ts b/packages/opencode/src/server/middleware.ts index 898acaf089e5..160d258796b7 100644 --- a/packages/opencode/src/server/middleware.ts +++ b/packages/opencode/src/server/middleware.ts @@ -13,6 +13,7 @@ import { compress } from "hono/compress" import * as ServerBackend from "./backend" import { isAllowedCorsOrigin, type CorsOptions } from "./cors" import { isPtyConnectPath, PTY_CONNECT_TICKET_QUERY } from "./shared/pty-ticket" +import { isPublicUIPath } from "./shared/public-ui" const log = Log.create({ service: "server" }) @@ -45,6 +46,7 @@ export const AuthMiddleware: MiddlewareHandler = (c, next) => { if (c.req.method === "OPTIONS") return next() const password = Flag.OPENCODE_SERVER_PASSWORD if (!password) return next() + if (isPublicUIPath(c.req.method, c.req.path)) return next() if (isPtyConnectPath(c.req.path) && c.req.query(PTY_CONNECT_TICKET_QUERY)) return next() const username = Flag.OPENCODE_SERVER_USERNAME ?? "opencode" diff --git a/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts b/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts index 6c6d0cd1f125..6f5648f30a99 100644 --- a/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts +++ b/packages/opencode/src/server/routes/instance/httpapi/middleware/authorization.ts @@ -3,6 +3,7 @@ import { Effect, Encoding, Layer, Redacted } from "effect" import { HttpRouter, HttpServerRequest, HttpServerResponse } from "effect/unstable/http" import { HttpApiError, HttpApiMiddleware } from "effect/unstable/httpapi" import { hasPtyConnectTicketURL } from "@/server/shared/pty-ticket" +import { isPublicUIPath } from "@/server/shared/public-ui" const AUTH_TOKEN_QUERY = "auth_token" const UNAUTHORIZED = 401 @@ -92,6 +93,7 @@ export const authorizationRouterMiddleware = HttpRouter.middleware()( Effect.gen(function* () { const request = yield* HttpServerRequest.HttpServerRequest const url = new URL(request.url, "http://localhost") + if (isPublicUIPath(request.method, url.pathname)) return yield* effect if (hasPtyConnectTicketURL(url)) return yield* effect return yield* credentialFromURL(url, request).pipe( Effect.flatMap((credential) => validateRawCredential(effect, credential, config)), diff --git a/packages/opencode/src/server/shared/public-ui.ts b/packages/opencode/src/server/shared/public-ui.ts new file mode 100644 index 000000000000..fece09592fa9 --- /dev/null +++ b/packages/opencode/src/server/shared/public-ui.ts @@ -0,0 +1,12 @@ +// Static UI assets the browser fetches without app-managed credentials, e.g. +// the manifest link in . These bypass auth so the page can install/render +// the manifest icons even when a server password is configured. +export const PUBLIC_UI_PATHS = new Set([ + "/site.webmanifest", + "/web-app-manifest-192x192.png", + "/web-app-manifest-512x512.png", +]) + +export function isPublicUIPath(method: string, pathname: string) { + return method === "GET" && PUBLIC_UI_PATHS.has(pathname) +} diff --git a/packages/opencode/src/server/shared/ui.ts b/packages/opencode/src/server/shared/ui.ts index c1558a1a4ea3..40d8aa7afb02 100644 --- a/packages/opencode/src/server/shared/ui.ts +++ b/packages/opencode/src/server/shared/ui.ts @@ -33,6 +33,7 @@ function proxyResponseHeaders(headers: Record) { // transfer metadata makes browsers decode already-decoded assets again. result.delete("content-encoding") result.delete("content-length") + result.delete("transfer-encoding") return result }