mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-10 00:16:59 +00:00
fix: secondary external-signer login lands on onboarding when switching
LocalPreferences.setDefaultAccount called setCurrentAccount before saveToEncryptedStorage. setCurrentAccount emits the new list onto the savedAccounts MutableStateFlow, which AlwaysOnNotificationServiceManager collects and reacts to by calling loadAccountConfigFromEncryptedStorage for every saved account — including the just-added one. That call hit encryptedPreferences(newNpub) before NOSTR_PUBKEY had been written, got null, and cached the null in cachedAccounts. cachedAccounts is a process-lifetime map, so the poisoned entry survived the eventual disk write. Every subsequent switchUser to that account took the cached null path, fell through to requestLoginUI(), and AccountScreen rendered LoggedOffSetup — the onboarding screen with TOS unchecked, asking the user to re-do the Amber handshake. Write the per-npub file first, then seed the cache with the in-memory AccountSettings, then publish onto the savedAccounts flow. Also stop caching null returns in loadAccountConfigFromEncryptedStorage so any future racy reader can't poison the cache either.
This commit is contained in:
@@ -323,8 +323,16 @@ object LocalPreferences {
|
||||
}
|
||||
|
||||
suspend fun setDefaultAccount(accountSettings: AccountSettings) {
|
||||
setCurrentAccount(accountSettings)
|
||||
// Save the per-npub file before emitting onto the savedAccounts flow.
|
||||
// Otherwise a collector (e.g. AlwaysOnNotificationServiceManager) can race in
|
||||
// and call loadAccountConfigFromEncryptedStorage(npub) before NOSTR_PUBKEY is
|
||||
// written, get null back, and poison `cachedAccounts[npub] = null` for the
|
||||
// rest of the session — making every later switch to this account land on
|
||||
// LoggedOff instead of LoggedIn.
|
||||
saveToEncryptedStorage(accountSettings)
|
||||
val npub = accountSettings.keyPair.pubKey.toNpub()
|
||||
mutex.withLock { cachedAccounts.put(npub, accountSettings) }
|
||||
setCurrentAccount(accountSettings)
|
||||
}
|
||||
|
||||
suspend fun allSavedAccounts(): List<AccountInfo> = savedAccounts()
|
||||
@@ -489,19 +497,20 @@ object LocalPreferences {
|
||||
|
||||
suspend fun loadAccountConfigFromEncryptedStorage(npub: String): AccountSettings? {
|
||||
// if already loaded, return right away
|
||||
if (cachedAccounts.containsKey(npub)) {
|
||||
return cachedAccounts[npub]
|
||||
}
|
||||
cachedAccounts[npub]?.let { return it }
|
||||
|
||||
return withContext(Dispatchers.IO) {
|
||||
mutex.withLock {
|
||||
if (cachedAccounts.containsKey(npub)) {
|
||||
return@withContext cachedAccounts.get(npub)
|
||||
}
|
||||
cachedAccounts[npub]?.let { return@withContext it }
|
||||
|
||||
val accountSettings = innerLoadCurrentAccountFromEncryptedStorage(npub)
|
||||
|
||||
cachedAccounts.put(npub, accountSettings)
|
||||
// Only cache successful loads. Caching null would leave the account
|
||||
// permanently unreachable for the rest of the session if a reader
|
||||
// raced in before the per-npub file finished being written.
|
||||
if (accountSettings != null) {
|
||||
cachedAccounts.put(npub, accountSettings)
|
||||
}
|
||||
|
||||
return@withContext accountSettings
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user