From e50f0936853f9d666eabcdd14924f8c0d84e27a9 Mon Sep 17 00:00:00 2001 From: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com> Date: Wed, 6 May 2026 20:34:34 +0200 Subject: [PATCH] web/rac: Ignore empty remote clipboard payloads (#22067) web/rac: ignore empty remote clipboard payloads Some remote sessions (notably SSH) push empty or whitespace-only clipboard updates that overwrite the user's local clipboard, leaving subsequent paste attempts with nothing to deliver. Filter those payloads in the StringReader.onend callback so the local clipboard is preserved. Closes #21439 Co-authored-by: Agent (authentik-i21439-featured-elevated-kobicha) <279763771+playpen-agent@users.noreply.github.com> --- web/src/rac/index.entrypoint.ts | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/web/src/rac/index.entrypoint.ts b/web/src/rac/index.entrypoint.ts index 6b3077c0fc..23641ebdc5 100644 --- a/web/src/rac/index.entrypoint.ts +++ b/web/src/rac/index.entrypoint.ts @@ -2,6 +2,8 @@ import "#elements/LoadingOverlay"; import Styles from "./index.entrypoint.css"; +import { writeToClipboard } from "#common/clipboard"; + import { Interface } from "#elements/Interface"; import { WithBrandConfig } from "#elements/mixins/branding"; @@ -155,22 +157,35 @@ export class RacInterface extends WithBrandConfig(Interface) { if (/^text\//.exec(mimetype)) { const reader = new Guacamole.StringReader(stream); let data = ""; + reader.ontext = (text) => { data += text; }; + reader.onend = () => { - this._previousClipboardValue = data; - navigator.clipboard.writeText(data); + const trimmed = data.trim(); + // Some remote sessions (notably SSH) push empty clipboard + // payloads that would otherwise clobber the user's local + // clipboard, breaking subsequent paste attempts. Ignore + // them so the local clipboard remains intact. + if (!trimmed) { + console.debug("authentik/rac: ignored empty remote clipboard payload"); + return; + } + this._previousClipboardValue = trimmed; + writeToClipboard(trimmed); }; } else { const reader = new Guacamole.BlobReader(stream, mimetype); + reader.onend = () => { const blob = reader.getBlob(); - navigator.clipboard.write([ - new ClipboardItem({ - [blob.type]: blob, - }), - ]); + + const item = new ClipboardItem({ + [blob.type]: blob, + }); + + writeToClipboard(item); }; } console.debug("authentik/rac: updated clipboard from remote");