Skip to content

fix(auth): never sign as a conflicting source when the pin is missing- #3094 - #1069

Open
aristidesstaffieri wants to merge 14 commits into
feat/account-mgmt-v2from
fix/signer-fallback-link-status
Open

aristidesstaffieri wants to merge 14 commits into
feat/account-mgmt-v2from
fix/signer-fallback-link-status

Conversation

@aristidesstaffieri

Copy link
Copy Markdown
Contributor

What

When the pinned source isn't held, getSigningIdentity now picks the fallback signer by link status: a held source the server listed as linked, then one it hasn't answered for yet, with phrases first in each tier. It never signs with a source the server reported as a conflict, and if only those are held it returns null so requests go out anonymously. It still never writes the pin. New tests cover each tier, the all-conflict case, and a held pin that has no status.

Why

The fallback signed with the first held source. If the server had marked that source as another user's, every request would resolve to that user and the analytics reconcile from stellar/freighter-private#69 would cache their canonical id. The link status map from stellar/freighter-private#68 already records which sources are in this wallet's cluster, so the fallback can rank by it without another request. This covers the conflict half of the re-pin that stellar/freighter-private#66 asked for. Today the pinned source goes missing only when it fails to derive at unlock, since recovery wipes the wallet and nothing removes accounts.

Screenshots / video

N/A, background only.

Checklist

  • I have read CONTRIBUTING.md and this PR meets its requirements.
  • This PR has narrow scope and does not mix refactoring with feature changes.
  • This PR adds tests for the new functionality or fixes.
  • These changes have been tested in both Chrome and Firefox.
  • This PR includes relevant before and after screenshots for UI changes.
  • I took the time to review my own PR.

  Ports stellar/freighter#3057. Settings gets an Accounts & recovery card
  that lists accounts grouped by the recovery phrase or secret key behind
  them. Edit account renames an account, opens it on stellar.expert, and
  reveals its secret key or recovery phrase after a password or biometric
  check.

  revealAccountSecretKey and revealRecoveryPhrase in ducks/auth check the
  session is still authenticated before and after decrypting, and a phrase
  is only returned for the source the account belongs to.
  Accounts & recovery waits for the secret sources before listing accounts,
  so rows no longer appear ungrouped and then regroup. Rename on Edit
  account opens the floating bottom sheet; Home keeps the centered modal.
  Ports stellar/freighter#3059. The switcher groups wallets under the
  recovery phrase or secret key behind them, with collapsible headers that
  stay collapsed until the app restarts. A wallet with one source stays a
  flat list. The header keeps only the address and a copy button, since
  rename and the explorer link are on Edit account and QR is on the scan
  screen. Rows drop the "Imported" tag, and the unused rename modal is
  removed.
  Port of stellar/freighter#3082. Add wallet now opens an "Add account"
  chooser with Create new wallet and Import Secret Key. Create new wallet
  lists the wallet's recovery phrases, so an account can be added under
  an existing phrase or under a newly generated one. Each new account is
  named in a sheet prefilled with the next free "Account N".

  A new phrase is held in auth module state, never in store state or
  navigation params, until the user backs it up and confirms with their
  password. Each generation gets an id that the screens pass along, and
  saving refuses a phrase that a later generation replaced. The held
  phrase is cleared once saved, when the backup screen closes, and on
  lock, logout or wipe.

  Import Recovery Phrase and Connect Hardware Wallet are left out. Mobile
  has no hardware support, and importing a phrase still replaces the
  whole wallet.
  Port of stellar/freighter#3086. Sign-up, import, sign-in, add, rename,
  switch and the wipe's storage clear now run one at a time behind a
  promise-chain lock. A lazily loaded private key is written to a fresh
  read of the temporary store under the lock. A switch drops its account
  if a soft-lock lands mid-switch. Funded-account lookups during a
  recovery-phrase import time out after 5s.
…he wallet

  Port of stellar/freighter#3084. Add wallet now offers Import Recovery
  Phrase, which adds a typed 12- or 24-word phrase as a new source with
  index 0 and any funded indices up to 49 on mainnet. Index 0 becomes
  active and nothing already in the wallet changes. A held phrase, an
  address already in the wallet or a wrong password is refused before
  anything is written. The funded-account lookups run before the
  account-mutation lock is taken, and the checks and writes run under it.
  If no account gets stored, the source and its indices are removed again.
  Port of stellar/freighter#3091. Import Wallet takes one input and works
  out whether it holds a 12 or 24-word recovery phrase or a Stellar secret
  key. The field keeps a secret key's case. A secret key goes through the
  new importWalletFromSecretKey store action, which stores one imported
  account with a secret-key source and no phrase. It checks the key before
  wiping anything and runs behind the account-mutation lock. If storing
  fails after the wipe, it wipes again so the user can retry.

  Set Password names the secret key in its acknowledgement, and both the
  Set Password and Biometrics steps can finish a secret-key import.
  Security hides "Show recovery phrase" for a wallet that holds only
  secret keys. The import is tracked as account_recovery.completed or
  account_recovery.failed with recovery_method "secret_key".
  Port of the minimum importing time from stellar/freighter#3091
  (835b23a8). runWithWalletSetupOverlay waits at least SETTING_UP_MIN_MS
  (500ms) before turning ready or fading out, so a secret-key import
  doesn't flash "Importing your wallet...". The Biometrics screen tests
  run on fake timers so the wait stays inside each test.
  storeKeys removes a key it just wrote if adding it to the index fails,
  then rethrows the index error. clearAllData also removes every
  stellarwallet_* keychain entry after the index-based removal, so an
  entry the index doesn't list can't survive a wipe.
  importWalletFromSecretKey and importSecretKey send a fixed reason_code
  to analytics instead of the scrubbed error text, which can carry the
  key in a form scrubStrKeys misses (key_S…). Adds the missing
  trackAccountScreenImportAccountFail to the analytics mock in
  jest.setup.js.
…lback

  storeAccount waits for every write it started before it throws, using
  a new settleAll helper, so nothing lands after a rollback. Failed
  sign-up, phrase import and key import share rollBackWalletSetup, which
  also removes BIOMETRIC_PASSWORD. The Biometrics screen saves the
  password again before each Enable attempt so a retry still works.
  signUp, importWallet and importWalletFromSecretKey reset auto-lock
  themselves, just before the pre-store wipe, instead of in their store
  actions before validation. An invalid secret key now leaves the timer,
  the background timestamp and the LOCKED marker as they were. The reset
  still runs under the account-mutation lock and before the new hash key.
  useHasRecoveryPhrase falls back to true when reading the secret
  sources fails, as its doc says, so a stale false from an earlier
  key-only read can't hide "Show recovery phrase" after a phrase is
  added.
@aristidesstaffieri aristidesstaffieri changed the title Fix/signer fallback link status fix(auth): never sign as a conflicting source when the pin is missing- #3094 Nov 13, 2026
@aristidesstaffieri aristidesstaffieri self-assigned this Nov 13, 2026
@aristidesstaffieri
aristidesstaffieri marked this pull request as ready for review November 13, 2026 23:06
@github-actions

Copy link
Copy Markdown
Contributor

iOS Simulator preview build is ready: https://github.com/stellar/freighter-mobile/releases/tag/untagged-4d0daa5cc32d59c1b1e4
Backend: sandbox (aristidesstaffieri). SDF collaborators only — install instructions in the release description.

@github-actions

Copy link
Copy Markdown
Contributor

Android Emulator preview APK is ready: https://github.com/stellar/freighter-mobile/releases/tag/untagged-9f1154ad0f7fa1593584
Backend: sandbox (aristidesstaffieri). SDF collaborators only — install instructions in the release description.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants