fix(desktop): clamp Bot Screen clipboard paste to the bridge's 256 KiB cap

clipboardPasteFrom was called with unbounded clipboard text; the gateway's
RfbClientFilter closes the display WebSocket on any ClientCutText over
_MAX_CUT_TEXT (256 KiB), turning an oversized paste into a full stream
disconnect instead of a dropped paste. Clamp before forwarding and add a
test pinning the ceiling.
This commit is contained in:
chelsealong
2026-09-26 15:05:07 +00:00
committed by brooklyn!
parent 2d6657d72c
commit f9f153ab18
2 changed files with 16 additions and 1 deletions

View File

@@ -144,3 +144,15 @@ it('drops a paste while this viewer only watches (no lease)', async () => {
expect(rfbs[0].clipboardPasteFrom).not.toHaveBeenCalled()
view.unmount()
})
it('drops a paste over the bridge\'s 256 KiB cut-text cap instead of forwarding it', async () => {
const view = render(<BotScreenPane bot={bot} />)
await waitFor(() => expect(rfbs).toHaveLength(1))
await waitFor(() => expect(rfbs[0].viewOnly).toBe(false))
const oversized = 'a'.repeat(256 * 1024 + 1)
fireEvent.paste(rfbs[0].target, { clipboardData: { getData: () => oversized } })
expect(rfbs[0].clipboardPasteFrom).not.toHaveBeenCalled()
view.unmount()
})

View File

@@ -62,6 +62,9 @@ const CLOSE_CONTROL_TAKEN = 4000
/** Evictions arriving this soon after dialing count toward the loop budget; slower ones reset it. */
const EVICTION_LOOP_WINDOW_MS = 10_000
const MAX_RAPID_EVICTIONS = 3
/** Mirrors tools/bot_desktop/rfb_filter.py's _MAX_CUT_TEXT: the bridge closes the display
* socket on any ClientCutText over this, so an oversized paste must never reach the client. */
const MAX_PASTE_CUT_TEXT = 256 * 1024
async function loadRfb(): Promise<
new (target: HTMLElement, socket: WebSocket, options?: Record<string, unknown>) => RfbLike
@@ -293,7 +296,7 @@ export function BotScreenPane({ bot }: { bot: RosterRow }) {
const text = event.clipboardData?.getData('text')
if (text) {
if (text && text.length <= MAX_PASTE_CUT_TEXT) {
event.preventDefault()
client.clipboardPasteFrom(text)
}