fix(app): terminal issues

This commit is contained in:
Adam
2026-02-22 06:17:59 -06:00
parent b16f7b426c
commit e70d2b27de
3 changed files with 54 additions and 5 deletions

View File

@@ -39,8 +39,9 @@ export namespace Pty {
return next
}
const token = (ws: Socket) => {
const data = ws.data
const token = (ws: unknown) => {
if (!ws || typeof ws !== "object") return ws
const data = (ws as { data?: unknown }).data
if (data === undefined) return
if (data === null) return
if (typeof data !== "object") return data
@@ -317,7 +318,7 @@ export namespace Pty {
}
}
export function connect(id: string, ws: Socket, cursor?: number) {
export function connect(id: string, ws: Socket, cursor?: number, identity?: unknown) {
const session = state().get(id)
if (!session) {
ws.close()
@@ -337,7 +338,7 @@ export namespace Pty {
}
owners.set(ws, id)
session.subscribers.set(ws, { id: socketId, token: token(ws) })
session.subscribers.set(ws, { id: socketId, token: token(identity ?? ws) })
const cleanup = () => {
session.subscribers.delete(ws)

View File

@@ -182,7 +182,7 @@ export const PtyRoutes = lazy(() =>
ws.close()
return
}
handler = Pty.connect(id, socket, cursor)
handler = Pty.connect(id, socket, cursor, ws)
},
onMessage(event) {
if (typeof event.data !== "string") return

View File

@@ -98,6 +98,54 @@ describe("pty", () => {
})
})
test("does not leak when identity token is only on websocket wrapper", async () => {
await using dir = await tmpdir({ git: true })
await Instance.provide({
directory: dir.path,
fn: async () => {
const a = await Pty.create({ command: "cat", title: "a" })
try {
const outA: string[] = []
const outB: string[] = []
const text = (data: string | Uint8Array | ArrayBuffer) => {
if (typeof data === "string") return data
if (data instanceof ArrayBuffer) return Buffer.from(new Uint8Array(data)).toString("utf8")
return Buffer.from(data).toString("utf8")
}
const raw: Parameters<typeof Pty.connect>[1] = {
readyState: 1,
send: (data) => {
outA.push(text(data))
},
close: () => {
// no-op
},
}
const wrap = { data: { events: { connection: "a" } } }
Pty.connect(a.id, raw, undefined, wrap)
outA.length = 0
// Simulate Bun reusing the raw socket object before the next onOpen,
// while the connection token only exists on the wrapper socket.
raw.send = (data) => {
outB.push(text(data))
}
Pty.write(a.id, "AAA\n")
await Bun.sleep(100)
expect(outB.join("")).not.toContain("AAA")
} finally {
await Pty.remove(a.id)
}
},
})
})
test("does not leak output when socket data mutates in-place", async () => {
await using dir = await tmpdir({ git: true })