From 2f772e96abecf519f9a911f4ced5a3e9b70606a2 Mon Sep 17 00:00:00 2001 From: trevor-signal <131492920+trevor-signal@users.noreply.github.com> Date: Fri, 5 Jun 2026 13:38:53 -0400 Subject: [PATCH] Add warning dialog when copying recovery key --- _locales/en/messages.json | 20 ++++ images/warning-circle.svg | 7 ++ ts/components/PreferencesLocalBackups.dom.tsx | 91 +++++++++++++++---- ts/components/ToastManager.dom.tsx | 6 +- 4 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 images/warning-circle.svg diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 113322786a..e8c51935eb 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -8540,10 +8540,30 @@ "messageformat": "Record your recovery key", "description": "Title for viewing the recovery (backup) key for local message backups." }, + "icu:Preferences--local-backups-recovery-key--title": { + "messageformat": "Your recovery key", + "description": "Title for viewing the recovery (backup) key for local message backups." + }, "icu:Preferences--local-backups-record-backup-key-description": { "messageformat": "This key is required to recover your account and data. Store this key somewhere safe. If you lose it, you won’t be able to recover your account. Learn more.", "description": "Description for viewing the recovery (backup) key for local message backups." }, + "icu:Preferences--local-backups-recovery-key--description": { + "messageformat": "This key is required to recover your account and data. Store it somewhere safe and never share it with anyone. Signal will never message you for your recovery key. Learn more.", + "description": "Description for viewing the recovery (backup) key for local message backups." + }, + "icu:Preferences__recovery-key__do-not-share-title": { + "messageformat": "Do not share recovery key", + "description": "Title of the dialog warning the user not to share their recovery key, shown after copying the recovery key." + }, + "icu:Preferences__recovery-key__do-not-share-description": { + "messageformat": "Signal will never message you for your recovery key. Never respond to a chat pretending to be Signal. Store your recovery key somewhere safe and never share it with anyone. Learn more.", + "description": "Body of the dialog warning the user not to share their recovery key, shown after copying the recovery key." + }, + "icu:Preferences__recovery-key__do-not-share-confirm": { + "messageformat": "Got it", + "description": "Button to dismiss the dialog warning the user not to share their recovery key." + }, "icu:Preferences--local-backups-confirm-recovery-key": { "messageformat": "Confirm your recovery key", "description": "Title for confirming the recovery (backup) key for local message backups by re-entering it into a text box." diff --git a/images/warning-circle.svg b/images/warning-circle.svg new file mode 100644 index 0000000000..2080ea470e --- /dev/null +++ b/images/warning-circle.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/ts/components/PreferencesLocalBackups.dom.tsx b/ts/components/PreferencesLocalBackups.dom.tsx index bc1422c562..978fd44a35 100644 --- a/ts/components/PreferencesLocalBackups.dom.tsx +++ b/ts/components/PreferencesLocalBackups.dom.tsx @@ -1,7 +1,7 @@ // Copyright 2025 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import type { ChangeEvent, JSX, MouseEvent } from 'react'; +import type { ChangeEvent, JSX } from 'react'; import { useCallback, useMemo, useState, useRef } from 'react'; import lodash from 'lodash'; import classNames from 'classnames'; @@ -37,6 +37,9 @@ import { AxoSymbol } from '../axo/AxoSymbol.dom.tsx'; const { noop } = lodash; const log = createLogger('PreferencesLocalBackups'); +const SIGNAL_USER_SAFETY_LINK = + 'https://support.signal.org/hc/articles/9932566320410-Staying-Safe-from-Phishing-Scams-and-Impersonation'; + export function PreferencesLocalBackups({ backupKey, backupKeyHash, @@ -553,6 +556,10 @@ function LocalBackupsSetupFolderPicker({ type BackupKeyStep = 'view' | 'confirm' | 'caution' | 'reference'; +function Strong(parts: Array) { + return {parts}; +} + function LocalBackupsBackupKeyViewer({ backupKey, i18n, @@ -568,6 +575,8 @@ function LocalBackupsBackupKeyViewer({ }): JSX.Element { const [isBackupKeyConfirmed, setIsBackupKeyConfirmed] = useState(false); + const [isShowingDoNotShareModal, setIsShowingDoNotShareModal] = + useState(false); const [step, setStep] = useState( isReferencing ? 'reference' : 'view' ); @@ -577,20 +586,21 @@ function LocalBackupsBackupKeyViewer({ () => formatBackupKeyForDisplay(backupKey, { convertAmbiguousChars: true }), [backupKey] ); - const onCopyBackupKey = useCallback( - async function handleCopyBackupKey(e: MouseEvent) { - e.preventDefault(); - window.SignalClipboard.copyTextTemporarily( - backupKeyForDisplay, - 45 * SECOND - ); - showToast({ toastType: ToastType.CopiedBackupKey }); - }, - [backupKeyForDisplay, showToast] - ); + const onCopyBackupKey = useCallback(() => { + window.SignalClipboard.copyTextTemporarily( + backupKeyForDisplay, + 45 * SECOND + ); + showToast({ toastType: ToastType.CopiedBackupKey }); + }, [backupKeyForDisplay, showToast]); - const learnMoreLink = (parts: Array) => ( - + const learnMorePhishingLink = (parts: Array) => ( + {parts} ); @@ -600,13 +610,13 @@ function LocalBackupsBackupKeyViewer({ let footerLeft: JSX.Element | undefined; let footerRight: JSX.Element; if (isStepViewOrReference) { - title = i18n('icu:Preferences--local-backups-record-recovery-key'); + title = i18n('icu:Preferences--local-backups-recovery-key--title'); description = ( ); @@ -655,6 +665,51 @@ function LocalBackupsBackupKeyViewer({ return (
+ {isShowingDoNotShareModal ? ( + setIsShowingDoNotShareModal(false)} + > + + +
+ + + {i18n('icu:Preferences__recovery-key__do-not-share-title')} + +
+ +
+ +
+
+
+ + { + onCopyBackupKey(); + setIsShowingDoNotShareModal(false); + }} + > + {i18n('icu:Preferences__recovery-key__do-not-share-confirm')} + + +
+
+ ) : null} {step === 'caution' && ( setIsShowingDoNotShareModal(true)} > {i18n('icu:Preferences__local-backups-copy-key')} diff --git a/ts/components/ToastManager.dom.tsx b/ts/components/ToastManager.dom.tsx index 2d3419a53f..37ba2fc716 100644 --- a/ts/components/ToastManager.dom.tsx +++ b/ts/components/ToastManager.dom.tsx @@ -321,7 +321,11 @@ function renderToast({ if (toastType === ToastType.CopiedBackupKey) { return ( - {i18n('icu:Preferences__local-backups-copied-recovery-key')} +
+ +    + {i18n('icu:Preferences__local-backups-copied-recovery-key')} +
); }