Skip to content

fix(settings): blur recovery phrase by default#2658

Merged
senamakel merged 5 commits into
tinyhumansai:mainfrom
iamrhn:fix/recovery-phrase-blur
May 26, 2026
Merged

fix(settings): blur recovery phrase by default#2658
senamakel merged 5 commits into
tinyhumansai:mainfrom
iamrhn:fix/recovery-phrase-blur

Conversation

@iamrhn
Copy link
Copy Markdown
Contributor

@iamrhn iamrhn commented May 26, 2026

Fixes #2657

Added a default blur/reveal flow for the recovery phrase screen in RecoveryPhrasePanel.tsx.

  • recovery phrase is now blurred by default
  • pointer events are disabled while hidden
  • added centered eye-slash reveal overlay
  • reveal is one-way and requires explicit user action
  • disabled “Copy to Clipboard” until the phrase is revealed
  • copy button now fades and shows the not-allowed cursor while locked

This prevents the recovery phrase from being visible or copied immediately when opening the panel.

Screenshots

image image

Summary by CodeRabbit

  • New Features

    • Recovery phrase is blurred and non-interactive by default in generate mode; users can reveal it with a new "Reveal recovery phrase" control.
    • Copy-to-clipboard is disabled until the phrase is revealed; disabled styling updated for improved clarity.
  • Chores

    • Added "Reveal recovery phrase" translation entries across multiple language files to enable localization.
  • Tests

    • UI test added to verify reveal behavior and that the copy button becomes enabled after reveal.

Review Change Stack

@iamrhn iamrhn requested a review from a team May 26, 2026 02:49
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a1585d9b-e1c5-4841-b07f-4307d009045c

📥 Commits

Reviewing files that changed from the base of the PR and between f4f63da and e1532cc.

📒 Files selected for processing (1)
  • app/src/components/settings/panels/RecoveryPhrasePanel.test.tsx

📝 Walkthrough

Walkthrough

RecoveryPhrasePanel now requires an explicit reveal before showing a generated recovery phrase: the phrase area is blurred and non-interactive until the user clicks a "Reveal recovery phrase" overlay. The copy button is disabled until the phrase is revealed. Translation keys for the reveal label were added across i18n chunks.

Changes

Privacy-protected recovery phrase reveal

Layer / File(s) Summary
Reveal state, styling, and controls
app/src/components/settings/panels/RecoveryPhrasePanel.tsx, app/src/components/settings/panels/RecoveryPhrasePanel.test.tsx
Adds revealed state to manage visibility. Recovery phrase grid conditionally applies blur and disables pointer/user selection until revealed. Adds a centered overlay "Reveal recovery phrase" button when unrevealed and disables the copy-to-clipboard button (disabled={!revealed}) with updated disabled styling. Includes a test asserting reveal toggles visibility and enables the copy button.
Translation entries
app/src/lib/i18n/en.ts, app/src/lib/i18n/chunks/ar-1.ts, app/src/lib/i18n/chunks/bn-1.ts, app/src/lib/i18n/chunks/de-1.ts, app/src/lib/i18n/chunks/en-1.ts, app/src/lib/i18n/chunks/es-1.ts, app/src/lib/i18n/chunks/fr-1.ts, app/src/lib/i18n/chunks/hi-1.ts, app/src/lib/i18n/chunks/id-1.ts, app/src/lib/i18n/chunks/it-1.ts, app/src/lib/i18n/chunks/ko-1.ts, app/src/lib/i18n/chunks/pt-1.ts, app/src/lib/i18n/chunks/ru-1.ts, app/src/lib/i18n/chunks/zh-CN-1.ts
Adds mnemonic.revealPhrase translation key (value currently provided, often as an English stub) across the main English map and multiple locale chunks.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A hush of letters, hidden tight,
A button waits to lift the night,
Click once and watch the veil unfold,
Then copy softly what you hold,
Quiet kept until the sight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding a blur-by-default feature to the recovery phrase panel for improved privacy.
Linked Issues check ✅ Passed All objectives from issue #2657 are implemented: blur by default, pointer events disabled, one-way reveal with eye-slash overlay, and copy button disabled until revealed.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the recovery phrase blur feature. i18n additions support the new 'Reveal recovery phrase' button, and the test validates the new functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/settings/panels/RecoveryPhrasePanel.tsx`:
- Around line 279-283: In RecoveryPhrasePanel replace the hard-coded aria-label
on the reveal button (the element that calls setRevealed(true)) with a localized
string via the component's useT() hook (e.g.
t('settings.recovery.revealButton')), ensure useT is imported/used in the
component, and add the new key "settings.recovery.revealButton": "Reveal
recovery phrase" to the English translations file en.ts so the aria-label is
produced via t(...) instead of a literal string.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2c936230-a670-4288-be84-511f589e5e7e

📥 Commits

Reviewing files that changed from the base of the PR and between e05cab9 and a5c6d76.

📒 Files selected for processing (1)
  • app/src/components/settings/panels/RecoveryPhrasePanel.tsx

Comment thread app/src/components/settings/panels/RecoveryPhrasePanel.tsx
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/components/settings/panels/RecoveryPhrasePanel.tsx (1)

47-54: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reset revealed state when switching modes to prevent privacy bypass.

The switchMode callback resets several states but does not reset revealed. This creates a privacy loophole:

  1. User reveals the recovery phrase in "generate" mode (revealed = true)
  2. User switches to "import" mode (phrase not shown in import mode, but revealed stays true)
  3. User switches back to "generate" mode
  4. Recovery phrase is immediately visible without requiring a new explicit reveal action

This defeats the one-way reveal protection introduced in this PR.

🔐 Proposed fix to reset revealed state
 const switchMode = useCallback((nextMode: 'generate' | 'import') => {
   setMode(nextMode);
   setConfirmed(false);
   setError(null);
   setImportValid(null);
   setSelectedWordCount(IMPORT_SLOTS_INITIAL);
   setImportWords(Array(IMPORT_SLOTS_INITIAL).fill(''));
+  setRevealed(false);
 }, []);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/RecoveryPhrasePanel.tsx` around lines 47 -
54, The switchMode callback (function switchMode) resets several states but
fails to reset the revealed flag, allowing a previously revealed recovery phrase
to reappear when toggling modes; update switchMode to also set revealed to false
(i.e., call setRevealed(false)) whenever switching modes so the phrase remains
hidden until the user explicitly re-reveals it.
🧹 Nitpick comments (1)
app/src/components/settings/panels/RecoveryPhrasePanel.tsx (1)

78-93: ⚡ Quick win

Consider adding a revealed guard in handleCopy for defense in depth.

While the copy button is correctly disabled when !revealed (line 303), the handleCopy function itself does not check the reveal state. This means programmatic calls (e.g., via developer tools or future code changes) could bypass the privacy protection.

🛡️ Proposed defense-in-depth guard
 const handleCopy = useCallback(async () => {
+  if (!revealed) return;
   try {
     await navigator.clipboard.writeText(mnemonic);
     setCopied(true);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/settings/panels/RecoveryPhrasePanel.tsx` around lines 78 -
93, Add a defense-in-depth guard in the handleCopy function to ensure it only
copies when the recovery phrase is revealed: at the start of handleCopy check
the revealed boolean (the same prop/state used to disable the button) and return
early if not true; keep existing logic that uses mnemonic and setCopied
unchanged so programmatic calls cannot bypass the UI guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@app/src/components/settings/panels/RecoveryPhrasePanel.tsx`:
- Around line 47-54: The switchMode callback (function switchMode) resets
several states but fails to reset the revealed flag, allowing a previously
revealed recovery phrase to reappear when toggling modes; update switchMode to
also set revealed to false (i.e., call setRevealed(false)) whenever switching
modes so the phrase remains hidden until the user explicitly re-reveals it.

---

Nitpick comments:
In `@app/src/components/settings/panels/RecoveryPhrasePanel.tsx`:
- Around line 78-93: Add a defense-in-depth guard in the handleCopy function to
ensure it only copies when the recovery phrase is revealed: at the start of
handleCopy check the revealed boolean (the same prop/state used to disable the
button) and return early if not true; keep existing logic that uses mnemonic and
setCopied unchanged so programmatic calls cannot bypass the UI guard.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 135597d5-7f78-4011-bec0-4afdc1691ab9

📥 Commits

Reviewing files that changed from the base of the PR and between a5c6d76 and c8d2ae5.

📒 Files selected for processing (2)
  • app/src/components/settings/panels/RecoveryPhrasePanel.tsx
  • app/src/lib/i18n/en.ts
✅ Files skipped from review due to trivial changes (1)
  • app/src/lib/i18n/en.ts

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 26, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 26, 2026
@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 26, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 26, 2026
@senamakel
Copy link
Copy Markdown
Member

so fly!!

@senamakel senamakel merged commit b6d3158 into tinyhumansai:main May 26, 2026
30 of 31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recovery phrase should require manual reveal

2 participants