From 7bc26dafae09d326a0f66d2b69b379bc19b3b26e Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sun, 3 May 2026 22:56:14 -0400 Subject: feat(server): pty websocket auth tickets (#25660) --- packages/app/src/components/terminal.tsx | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'packages/app/src/components') diff --git a/packages/app/src/components/terminal.tsx b/packages/app/src/components/terminal.tsx index d4212e32e..7bcc02d62 100644 --- a/packages/app/src/components/terminal.tsx +++ b/packages/app/src/components/terminal.tsx @@ -479,6 +479,21 @@ export const Terminal = (props: TerminalProps) => { return false }) + const connectToken = async () => { + const result = await client.pty.connectToken( + { ptyID: id }, + { + throwOnError: false, + headers: { "x-opencode-ticket": "1" }, + }, + ) + if (result.response.status === 200 && result.data?.ticket) return result.data.ticket + if ((result.response.status === 404 || result.response.status === 405) && password) return + if (result.response.status === 403) + throw new Error("PTY connect ticket rejected by origin or CSRF checks. Check the server CORS config.") + throw new Error(`PTY connect ticket failed with ${result.response.status}`) + } + const retry = (err: unknown) => { if (disposed) return if (reconn !== undefined) return @@ -498,16 +513,24 @@ export const Terminal = (props: TerminalProps) => { }, ms) } - const open = () => { + const open = async () => { if (disposed) return drop?.() + const ticket = await connectToken().catch((err) => { + fail(err) + return undefined + }) + if (once.value) return + if (disposed) return + const socket = new WebSocket( terminalWebSocketURL({ url, id, directory, cursor: seek, + ticket, sameOrigin, username, password, -- cgit v1.2.3