diff --git a/ts/background.preload.ts b/ts/background.preload.ts index 9a81fc280e..d4fa474da3 100644 --- a/ts/background.preload.ts +++ b/ts/background.preload.ts @@ -760,6 +760,8 @@ export async function startApp(): Promise { flushMessageCounter(); + window.SignalClipboard.clearIfNeeded(); + // Hangup active calls calling.hangupAllCalls({ excludeRinging: true, diff --git a/ts/components/PreferencesLocalBackups.dom.tsx b/ts/components/PreferencesLocalBackups.dom.tsx index 71f4416354..d8270677a1 100644 --- a/ts/components/PreferencesLocalBackups.dom.tsx +++ b/ts/components/PreferencesLocalBackups.dom.tsx @@ -35,6 +35,7 @@ import type { } from '../util/os/promptOSAuthMain.main.js'; import { ConfirmationDialog } from './ConfirmationDialog.dom.js'; import { AxoButton } from '../axo/AxoButton.dom.js'; +import { SECOND } from '../util/durations/constants.std.js'; const { noop } = lodash; @@ -275,7 +276,7 @@ function LocalBackupsBackupKeyViewer({ const onCopyBackupKey = useCallback( async function handleCopyBackupKey(e: React.MouseEvent) { e.preventDefault(); - await window.navigator.clipboard.writeText(backupKey); + await window.SignalClipboard.copyTextTemporarily(backupKey, 45 * SECOND); showToast({ toastType: ToastType.CopiedBackupKey }); }, [backupKey, showToast] diff --git a/ts/window.d.ts b/ts/window.d.ts index 925616bb90..bbd2ea4de7 100644 --- a/ts/window.d.ts +++ b/ts/window.d.ts @@ -192,6 +192,12 @@ declare global { // TODO DESKTOP-4801 SignalContext: SignalContextType; + SignalClipboard: { + clear: () => void; + clearIfNeeded: () => void; + copyTextTemporarily: (text: string, clearAfterMs: number) => void; + }; + // Used only in preload to calculate load time preloadCompileStartTime: number; preloadStartTime: number; diff --git a/ts/windows/clipboard.dom.ts b/ts/windows/clipboard.dom.ts new file mode 100644 index 0000000000..c9f2cee3e0 --- /dev/null +++ b/ts/windows/clipboard.dom.ts @@ -0,0 +1,36 @@ +// Copyright 2025 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only + +import { clipboard } from 'electron'; + +let doesClipboardNeedClearing = false; + +function clearClipboard(): void { + clipboard.clear('clipboard'); + + // clipboard.clear is not reliable on Linux, so we actually have to overwrite it + if (window.Signal.OS.isLinux()) { + clipboard.writeText(' '); + } + + doesClipboardNeedClearing = false; +} + +function clearClipboardIfNeeded(): void { + if (doesClipboardNeedClearing) { + clearClipboard(); + } +} + +function copyTextTemporarily(text: string, clearAfterMs: number): void { + clipboard.writeText(text); + doesClipboardNeedClearing = true; + + setTimeout(() => clearClipboard(), clearAfterMs); +} + +window.SignalClipboard = { + clearIfNeeded: clearClipboardIfNeeded, + clear: clearClipboard, + copyTextTemporarily, +}; diff --git a/ts/windows/main/phase2-dependencies.preload.ts b/ts/windows/main/phase2-dependencies.preload.ts index 2e286dc68a..2393f7389e 100644 --- a/ts/windows/main/phase2-dependencies.preload.ts +++ b/ts/windows/main/phase2-dependencies.preload.ts @@ -15,6 +15,7 @@ import { DRAFT_PATH, } from '../../util/basePaths.preload.js'; import { SignalContext } from '../context.preload.js'; +import '../clipboard.dom.js'; initializeLogging();