fix(@desktop/onboarding): cannot run any keycard flow after creating a Keycard replacement

Fixes: #11494
This commit is contained in:
Sale Djenic 2023-07-12 11:18:32 +02:00 committed by saledjenic
parent 1a7532d92c
commit 51edc1b256
8 changed files with 100 additions and 36 deletions

View File

@ -1,4 +1,4 @@
import NimQml, sequtils, chronicles, os, uuids
import NimQml, sequtils, sugar, chronicles, os, uuids
import ../../app_service/service/general/service as general_service
import ../../app_service/service/keychain/service as keychain_service
@ -50,6 +50,7 @@ type
AppController* = ref object of RootObj
storeDefaultKeyPair: bool
syncKeycardBasedOnAppWalletState: bool
applyKeycardReplacement: bool
changedKeycardUids: seq[tuple[oldKcUid: string, newKcUid: string]] # used in case user unlocked keycard during onboarding using seed phrase
statusFoundation: StatusFoundation
notificationsManager*: NotificationsManager
@ -108,7 +109,7 @@ type
proc load(self: AppController)
proc buildAndRegisterLocalAccountSensitiveSettings(self: AppController)
proc buildAndRegisterUserProfile(self: AppController)
proc tryKeycardSyncWithTheAppState(self: AppController)
proc applyNecessaryActionsAfterLoggingIn(self: AppController)
# Startup Module Delegate Interface
proc startupDidLoad*(self: AppController)
@ -117,6 +118,7 @@ proc logout*(self: AppController)
proc finishAppLoading*(self: AppController)
proc storeDefaultKeyPairForNewKeycardUser*(self: AppController)
proc syncKeycardBasedOnAppWalletStateAfterLogin*(self: AppController)
proc applyKeycardReplacementAfterLogin*(self: AppController)
proc addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AppController, oldKeycardUid: string, newKeycardUid: string)
proc removeAllKeycardUidPairsForCheckingForAChangeAfterLogin*(self: AppController)
@ -142,6 +144,7 @@ proc newAppController*(statusFoundation: StatusFoundation): AppController =
result = AppController()
result.storeDefaultKeyPair = false
result.syncKeycardBasedOnAppWalletState = false
result.applyKeycardReplacement = false
result.statusFoundation = statusFoundation
# Preparing settings service to be exposed later as global QObject
@ -386,7 +389,7 @@ proc startupDidLoad*(self: AppController) =
self.startupModule.startUpUIRaised()
proc mainDidLoad*(self: AppController) =
self.tryKeycardSyncWithTheAppState()
self.applyNecessaryActionsAfterLoggingIn()
self.startupModule.moveToAppState()
self.checkForStoringPasswordToKeychain()
@ -509,7 +512,41 @@ proc buildAndRegisterUserProfile(self: AppController) =
singletonInstance.engine.setRootContextProperty("userProfile", self.userProfileVariant)
proc tryKeycardSyncWithTheAppState(self: AppController) =
proc doKeycardReplacement(self: AppController) =
let keyUid = singletonInstance.userProfile.getKeyUid()
let keypair = self.walletAccountService.getKeypairByKeyUid(keyUid)
if keypair.isNil:
error "cannot resolve appropriate keypair for logged in user"
return
let (_, flowEvent) = self.keycardService.getLastReceivedKeycardData()
let instanceUid = flowEvent.instanceUID
let pin = self.startupModule.getPin()
if instanceUid.len == 0 or
keyUid != flowEvent.keyUid or
pin.len != PINLengthForStatusApp:
info "keycard replacement process is not fully completed, try the same again"
return
# we have to delete all keycards with the same key uid to cover the case if user had more then a single keycard for the same keypair
discard self.walletAccountService.deleteAllKeycardsWithKeyUid(singletonInstance.userProfile.getKeyUid())
# store new keycard with accounts, in this context no need to check if accounts match the default Status derivation path,
# cause otherwise we wouldn't be here (cannot have keycard profile with any such path)
let accountsAddresses = keypair.accounts.filter(acc => not acc.isChat).map(acc => acc.address)
let keycard = KeycardDto(
keycardUid: instanceUid,
keycardName: keypair.name,
keyUid: keyUid,
accountsAddresses: accountsAddresses
)
discard self.walletAccountService.addKeycardOrAccounts(keycard, accountsComingFromKeycard = true)
# store metadata to a Keycard
let accountsPathsToStore = keypair.accounts.filter(acc => not acc.isChat).map(acc => acc.path)
self.keycardService.startStoreMetadataFlow(keypair.name, self.startupModule.getPin(), accountsPathsToStore)
info "keycard replacement fully done"
proc applyNecessaryActionsAfterLoggingIn(self: AppController) =
if self.applyKeycardReplacement:
self.doKeycardReplacement()
return
############################################################################## store def kc sync with app kc uid
## Onboarding flows sync keycard state after login keypair | (inc. kp store) | update
## `Im new to Status` -> `Generate new keys` -> na | na | na
@ -551,6 +588,9 @@ proc storeDefaultKeyPairForNewKeycardUser*(self: AppController) =
proc syncKeycardBasedOnAppWalletStateAfterLogin*(self: AppController) =
self.syncKeycardBasedOnAppWalletState = true
proc applyKeycardReplacementAfterLogin*(self: AppController) =
self.applyKeycardReplacement = true
proc addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AppController, oldKeycardUid: string, newKeycardUid: string) =
self.changedKeycardUids.add((oldKcUid: oldKeycardUid, newKcUid: newKeycardUid))

View File

@ -463,9 +463,9 @@ proc loginLocalPairingAccount*(self: Controller) =
kcEvent.encryptionKey.publicKey = self.localPairingStatus.password
discard self.accountsService.loginAccountKeycard(self.localPairingStatus.account, kcEvent)
proc loginAccountKeycard*(self: Controller, storeToKeychainValue: string, syncWalletAfterLogin = false) =
if syncWalletAfterLogin:
self.syncKeycardBasedOnAppWalletStateAfterLogin()
proc loginAccountKeycard*(self: Controller, storeToKeychainValue: string, keycardReplacement = false) =
if keycardReplacement:
self.delegate.applyKeycardReplacementAfterLogin()
singletonInstance.localAccountSettings.setStoreToKeychainValue(storeToKeychainValue)
self.delegate.moveToLoadingAppState()
let selAcc = self.getSelectedLoginAccount()

View File

@ -63,4 +63,4 @@ method resolveKeycardNextState*(self: BiometricsState, keycardFlowType: string,
var storeToKeychainValue = LS_VALUE_NEVER
if self.storeToKeychain:
storeToKeychainValue = LS_VALUE_NOT_NOW
controller.loginAccountKeycard(storeToKeychainValue, syncWalletAfterLogin = true)
controller.loginAccountKeycard(storeToKeychainValue, keycardReplacement = true)

View File

@ -57,10 +57,10 @@ method resolveKeycardNextState*(self: KeycardPinSetState, keycardFlowType: strin
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0:
controller.setKeycardEvent(keycardEvent)
controller.loginAccountKeycard(storeToKeychainValue = LS_VALUE_NOT_NOW, syncWalletAfterLogin = true)
controller.loginAccountKeycard(storeToKeychainValue = LS_VALUE_NOT_NOW, keycardReplacement = true)
if self.flowType == FlowType.AppLogin:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0:
# we are here in case of recover account from the login flow using seed phrase
controller.setKeycardEvent(keycardEvent)
controller.loginAccountKeycard(storeToKeychainValue = LS_VALUE_NEVER, syncWalletAfterLogin = false)
controller.loginAccountKeycard(storeToKeychainValue = LS_VALUE_NEVER, keycardReplacement = false)

View File

@ -151,6 +151,9 @@ method storeDefaultKeyPairForNewKeycardUser*(self: AccessInterface) {.base.} =
method syncKeycardBasedOnAppWalletStateAfterLogin*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method applyKeycardReplacementAfterLogin*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AccessInterface, oldKeycardUid: string,
newKeycardUid: string) {.base.} =
raise newException(ValueError, "No implementation available")
@ -197,5 +200,6 @@ type
c.finishAppLoading()
c.storeDefaultKeyPairForNewKeycardUser()
c.syncKeycardBasedOnAppWalletStateAfterLogin()
c.applyKeycardReplacementAfterLogin()
c.addToKeycardUidPairsToCheckForAChangeAfterLogin(string, string)
c.removeAllKeycardUidPairsForCheckingForAChangeAfterLogin()

View File

@ -511,6 +511,9 @@ method storeDefaultKeyPairForNewKeycardUser*[T](self: Module[T]) =
method syncKeycardBasedOnAppWalletStateAfterLogin*[T](self: Module[T]) =
self.delegate.syncKeycardBasedOnAppWalletStateAfterLogin()
method applyKeycardReplacementAfterLogin*[T](self: Module[T]) =
self.delegate.applyKeycardReplacementAfterLogin()
method addToKeycardUidPairsToCheckForAChangeAfterLogin*[T](self: Module[T], oldKeycardUid: string, newKeycardUid: string) =
self.delegate.addToKeycardUidPairsToCheckForAChangeAfterLogin(oldKeycardUid, newKeycardUid)

View File

@ -41,6 +41,7 @@ const SIGNAL_KEYPAIR_SYNCED* = "keypairSynced"
const SIGNAL_KEYPAIR_NAME_CHANGED* = "keypairNameChanged"
const SIGNAL_NEW_KEYCARD_SET* = "newKeycardSet"
const SIGNAL_KEYCARD_DELETED* = "keycardDeleted"
const SIGNAL_ALL_KEYCARDS_DELETED* = "allKeycardsDeleted"
const SIGNAL_KEYCARD_ACCOUNTS_REMOVED* = "keycardAccountsRemoved"
const SIGNAL_KEYCARD_LOCKED* = "keycardLocked"
const SIGNAL_KEYCARD_UNLOCKED* = "keycardUnlocked"
@ -918,6 +919,19 @@ QtObject:
self.events.emit(SIGNAL_KEYCARD_DELETED, data)
return data.success
proc deleteAllKeycardsWithKeyUid*(self: Service, keyUid: string): bool =
var data = KeycardArgs(
success: false,
keycard: KeycardDto(keyUid: keyUid)
)
try:
let response = backend.deleteAllKeycardsWithKeyUID(keyUid)
data.success = responseHasNoErrors("deleteAllKeycardsWithKeyUid", response)
except Exception as e:
error "error: ", procName="deleteAllKeycardsWithKeyUid", errName = e.name, errDesription = e.msg
self.events.emit(SIGNAL_ALL_KEYCARDS_DELETED, data)
return data.success
proc handleWalletAccount(self: Service, account: WalletAccountDto, notify: bool = true) =
if account.removed:
self.removeAccountFromLocalStoreAndNotify(account.address, notify)

View File

@ -255,6 +255,9 @@ rpc(updateKeycardUID, "accounts"):
rpc(deleteKeycard, "accounts"):
keycardUid: string
rpc(deleteAllKeycardsWithKeyUID, "accounts"):
keyUid: string
rpc(updateAccountPosition, "accounts"):
address: string
position: int