From b44fc7a8421046733f28ff82feb21ca8e5ffafe9 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Mon, 23 Jan 2023 12:41:59 +0100 Subject: [PATCH] fix(@desktop/keycard): keycard may be factory reseted during unlock flow in some scenarios (onboarding part) - Unexpected wiping out the data during the unlock flow handled (onboarding part) - Back button actions fixed part 2/2 (onboarding part) Fixes: #9183 --- src/app/boot/app_controller.nim | 68 +++++++--- src/app/modules/startup/controller.nim | 45 ++++++- .../startup/internal/biometrics_state.nim | 16 +-- .../internal/keycard_enter_pin_state.nim | 5 +- .../internal/keycard_enter_puk_state.nim | 9 +- .../internal/keycard_pin_set_state.nim | 18 ++- .../internal/keycard_recover_state.nim | 18 ++- .../internal/keycard_repeat_pin_state.nim | 125 ++++++++++++++---- .../internal/keycard_wrong_keycard_state.nim | 8 +- .../internal/keycard_wrong_pin_state.nim | 7 +- .../internal/keycard_wrong_puk_state.nim | 5 +- ..._keycard_max_puk_retries_reached_state.nim | 2 +- .../startup/internal/state_factory.nim | 2 +- ...tate_factory_onboarding_implementation.nim | 8 -- .../internal/user_profile_chat_key_state.nim | 6 +- .../user_profile_confirm_password_state.nim | 2 +- .../user_profile_enter_seed_phrase_state.nim | 59 +++++---- .../internal/welcome_state_new_user.nim | 6 +- .../internal/welcome_state_old_user.nim | 4 +- src/app/modules/startup/io_interface.nim | 16 ++- src/app/modules/startup/module.nim | 16 ++- src/app_service/service/accounts/service.nim | 9 +- src/app_service/service/keycard/service.nim | 8 +- .../Onboarding/views/KeycardStateView.qml | 2 +- .../Onboarding/views/SeedPhraseInputView.qml | 4 + .../Wallet/panels/DerivationPathsPanel.qml | 2 +- .../popups/keycard/states/KeycardPin.qml | 5 +- 27 files changed, 323 insertions(+), 152 deletions(-) diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index d833a8fde81..3b073630b44 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -46,8 +46,9 @@ logScope: type AppController* = ref object of RootObj - storeKeyPair: bool - syncWalletForReplacedKeycard: bool + storeDefaultKeyPair: bool + syncKeycardBasedOnAppWalletState: bool + changedKeycardUids: seq[tuple[oldKcUid: string, newKcUid: string]] # used in case user unlocked keycard during onboarding using seed phrase statusFoundation: StatusFoundation notificationsManager*: NotificationsManager @@ -108,8 +109,10 @@ proc startupDidLoad*(self: AppController) proc userLoggedIn*(self: AppController): string proc logout*(self: AppController) proc finishAppLoading*(self: AppController) -proc storeKeyPairForNewKeycardUser*(self: AppController) -proc syncWalletAccountsOnLoginForReplacedKeycard*(self: AppController) +proc storeDefaultKeyPairForNewKeycardUser*(self: AppController) +proc syncKeycardBasedOnAppWalletStateAfterLogin*(self: AppController) +proc addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AppController, oldKeycardUid: string, newKeycardUid: string) +proc removeAllKeycardUidPairsForCheckingForAChangeAfterLogin*(self: AppController) # Main Module Delegate Interface proc mainDidLoad*(self: AppController) @@ -131,8 +134,8 @@ proc connect(self: AppController) = proc newAppController*(statusFoundation: StatusFoundation): AppController = result = AppController() - result.storeKeyPair = false - result.syncWalletForReplacedKeycard = false + result.storeDefaultKeyPair = false + result.syncKeycardBasedOnAppWalletState = false result.statusFoundation = statusFoundation # Preparing settings service to be exposed later as global QObject @@ -440,8 +443,29 @@ proc buildAndRegisterUserProfile(self: AppController) = singletonInstance.engine.setRootContextProperty("userProfile", self.userProfileVariant) + ############################################################################## store def kc sync with app kc uid + ## Onboarding flows sync keycard state after login keypair | (inc. kp store) | update + ## `I’m new to Status` -> `Generate new keys` -> na | na | na + ## `I’m new to Status` -> `Generate keys for a new Keycard` -> yes | no | no + ## `I’m new to Status` -> `Import a seed phrase` -> `Import a seed phrase` -> na | na | na + ## `I’m new to Status` -> `Import a seed phrase` -> `Import a seed phrase into a new Keycard` -> yes | no | no + ## + ## `I already use Status` -> `Scan sync code` -> flow not developed yet + ## `I already use Status` -> `I don’t have other device` -> `Login with Keycard` (fetched) -> no | yes | no + ## `I already use Status` -> `I don’t have other device` -> `Login with Keycard` (unlock via puk, fetched) -> no | yes | no + ## `I already use Status` -> `I don’t have other device` -> `Login with Keycard` (unlock via seed phrase, fetched) -> no | yes | yes (kc details should be fetched and set to db while recovering, that's the reason why) + ## `I already use Status` -> `I don’t have other device` -> `Login with Keycard` (not fetched) -> no | yes | no + ## `I already use Status` -> `I don’t have other device` -> `Login with Keycard` (unlock via puk, not fetched) -> no | yes | no + ## `I already use Status` -> `I don’t have other device` -> `Login with Keycard` (unlock via seed phrase, not fetched) -> no | yes | no + ## `I already use Status` -> `I don’t have other device` -> `Enter a seed phrase` -> na | na | na + ## + ## `Login` -> na | na | na + ## `Login` -> if card was unlocked via puk -> na | na | na + ## `Login` -> if card was unlocked via seed phrase -> no | no | yes + ## `Login` -> `Create replacement Keycard with seed phrase` -> no | yes | no (we don't know which kc is replaced if user has more kc for the same kp) + ############################################################################## if singletonInstance.userProfile.getIsKeycardUser(): - if self.storeKeyPair: + if self.storeDefaultKeyPair: let allAccounts = self.walletAccountService.fetchAccounts() let defaultWalletAccounts = allAccounts.filter(a => a.walletType == WalletTypeDefaultStatusAccount and @@ -460,10 +484,10 @@ proc buildAndRegisterUserProfile(self: AppController) = keyUid: loggedInAccount.keyUid) let keystoreDir = self.accountsService.getKeyStoreDir() discard self.walletAccountService.addMigratedKeyPair(keyPair, keystoreDir) - if self.syncWalletForReplacedKeycard: + if self.syncKeycardBasedOnAppWalletState: let allAccounts = self.walletAccountService.fetchAccounts() let accountsForLoggedInUser = allAccounts.filter(a => a.keyUid == loggedInAccount.keyUid) - var kpDto = KeyPairDto(keycardUid: "", + var keyPair = KeyPairDto(keycardUid: "", keycardName: displayName, keycardLocked: false, accountsAddresses: @[], @@ -471,7 +495,7 @@ proc buildAndRegisterUserProfile(self: AppController) = var activeValidPathsToStoreToAKeycard: seq[string] for acc in accountsForLoggedInUser: activeValidPathsToStoreToAKeycard.add(acc.path) - kpDto.accountsAddresses.add(acc.address) + keyPair.accountsAddresses.add(acc.address) self.keycardService.startStoreMetadataFlow(displayName, self.startupModule.getPin(), activeValidPathsToStoreToAKeycard) ## sleep for 3 seconds, since that is more than enough to store metadata to a keycard, if the reader is still plugged in ## and the card is still inserted, otherwise we just skip that. @@ -480,14 +504,26 @@ proc buildAndRegisterUserProfile(self: AppController) = ## instance uid for GetMetadata flow we will be able to use SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC signal for syncing ## otherwise we need to handle that way separatelly in `handleKeycardSyncing` of shared module sleep(3000) + self.keycardService.cancelCurrentFlow() let (_, kcEvent) = self.keycardService.getLastReceivedKeycardData() if kcEvent.instanceUID.len > 0: - kpDto.keycardUid = kcEvent.instanceUID + keyPair.keycardUid = kcEvent.instanceUID let keystoreDir = self.accountsService.getKeyStoreDir() - discard self.walletAccountService.addMigratedKeyPair(kpDto, keystoreDir) + discard self.walletAccountService.addMigratedKeyPair(keyPair, keystoreDir) -proc storeKeyPairForNewKeycardUser*(self: AppController) = - self.storeKeyPair = true + if self.changedKeycardUids.len > 0: + let oldUid = self.changedKeycardUids[0].oldKcUid + let newUid = self.changedKeycardUids[^1].newKcUid + discard self.walletAccountService.updateKeycardUid(oldUid, newUid) -proc syncWalletAccountsOnLoginForReplacedKeycard*(self: AppController) = - self.syncWalletForReplacedKeycard = true \ No newline at end of file +proc storeDefaultKeyPairForNewKeycardUser*(self: AppController) = + self.storeDefaultKeyPair = true + +proc syncKeycardBasedOnAppWalletStateAfterLogin*(self: AppController) = + self.syncKeycardBasedOnAppWalletState = true + +proc addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AppController, oldKeycardUid: string, newKeycardUid: string) = + self.changedKeycardUids.add((oldKcUid: oldKeycardUid, newKcUid: newKeycardUid)) + +proc removeAllKeycardUidPairsForCheckingForAChangeAfterLogin*(self: AppController) = + self.changedKeycardUids = @[] \ No newline at end of file diff --git a/src/app/modules/startup/controller.nim b/src/app/modules/startup/controller.nim index 708f157552b..cfaf4d19aec 100644 --- a/src/app/modules/startup/controller.nim +++ b/src/app/modules/startup/controller.nim @@ -50,6 +50,7 @@ type tmpSeedPhraseLength: int tmpKeyUid: string tmpKeycardEvent: KeycardEvent + tmpCardMetadata: CardMetadata tmpKeychainErrorOccurred: bool tmpRecoverUsingSeedPhraseWhileLogin: bool @@ -162,6 +163,7 @@ proc shouldStartWithOnboardingScreen*(self: Controller): bool = return self.accountsService.openedAccounts().len == 0 proc storeProfileDataAndProceedWithAppLoading*(self: Controller) = + self.delegate.removeAllKeycardUidPairsForCheckingForAChangeAfterLogin() # reason for this is in the table in AppController.nim file self.profileService.setDisplayName(self.tmpDisplayName) let images = self.storeIdentityImage() self.accountsService.updateLoggedInAccount(self.tmpDisplayName, images) @@ -266,6 +268,18 @@ proc setRemainingAttempts*(self: Controller, value: int) = proc setKeycardEvent*(self: Controller, value: KeycardEvent) = self.tmpKeycardEvent = value +proc setMetadataFromKeycard*(self: Controller, cardMetadata: CardMetadata) = + self.tmpCardMetadata = cardMetadata + +proc getMetadataFromKeycard*(self: Controller): CardMetadata = + return self.tmpCardMetadata + +proc addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: Controller, oldKeycardUid: string, newKeycardUid: string) = + self.delegate.addToKeycardUidPairsToCheckForAChangeAfterLogin(oldKeycardUid, newKeycardUid) + +proc syncKeycardBasedOnAppWalletStateAfterLogin(self: Controller) = + self.delegate.syncKeycardBasedOnAppWalletStateAfterLogin() + proc keychainErrorOccurred*(self: Controller): bool = return self.tmpKeychainErrorOccurred @@ -354,23 +368,33 @@ proc storeImportedAccountAndLogin*(self: Controller, storeToKeychain: bool) = let accountId = self.getImportedAccount().id self.setupAccount(accountId, storeToKeychain) -proc storeKeycardAccountAndLogin*(self: Controller, storeToKeychain: bool) = +proc storeKeycardAccountAndLogin*(self: Controller, storeToKeychain: bool, newKeycard: bool) = if self.importMnemonic(): self.delegate.moveToLoadingAppState() - self.delegate.storeKeyPairForNewKeycardUser() - self.storeMetadataForNewKeycardUser() + if newKeycard: + self.delegate.storeDefaultKeyPairForNewKeycardUser() + self.storeMetadataForNewKeycardUser() + else: + self.syncKeycardBasedOnAppWalletStateAfterLogin() self.accountsService.setupAccountKeycard(KeycardEvent(), self.tmpDisplayName, useImportedAcc = true) self.setupKeychain(storeToKeychain) else: error "an error ocurred while importing mnemonic" -proc setupKeycardAccount*(self: Controller, storeToKeychain: bool) = +proc setupKeycardAccount*(self: Controller, storeToKeychain: bool, newKeycard: bool) = if self.tmpSeedPhrase.len > 0: # if `tmpSeedPhrase` is not empty means user has recovered keycard via seed phrase - self.storeKeycardAccountAndLogin(storeToKeychain) + self.storeKeycardAccountAndLogin(storeToKeychain, newKeycard) else: + if self.tmpKeycardEvent.keyUid.len == 0 or + self.accountsService.openedAccountsContainsKeyUid(self.tmpKeycardEvent.keyUid): + self.delegate.importAccountError(ACCOUNT_ALREADY_EXISTS_ERROR) + return self.delegate.moveToLoadingAppState() - self.delegate.storeKeyPairForNewKeycardUser() + if newKeycard: + self.delegate.storeDefaultKeyPairForNewKeycardUser() + else: + self.syncKeycardBasedOnAppWalletStateAfterLogin() self.accountsService.setupAccountKeycard(self.tmpKeycardEvent, self.tmpDisplayName, useImportedAcc = false) self.setupKeychain(storeToKeychain) @@ -419,7 +443,7 @@ proc login*(self: Controller) = proc loginAccountKeycard*(self: Controller, storeToKeychain = false, syncWalletAfterLogin = false) = if syncWalletAfterLogin: - self.delegate.syncWalletAccountsOnLoginForReplacedKeycard() + self.syncKeycardBasedOnAppWalletStateAfterLogin() if storeToKeychain: ## storing not now, user will be asked to store the pin once he is logged in singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW) @@ -434,6 +458,9 @@ proc getKeyUidForSeedPhrase*(self: Controller, seedPhrase: string): string = let acc = self.accountsService.createAccountFromMnemonic(seedPhrase) return acc.keyUid +proc getCurrentKeycardServiceFlow*(self: Controller): keycard_service.KCSFlowType = + return self.keycardService.getCurrentFlow() + proc getLastReceivedKeycardData*(self: Controller): tuple[flowType: string, flowEvent: KeycardEvent] = return self.keycardService.getLastReceivedKeycardData() @@ -463,6 +490,10 @@ proc runStoreMetadataFlow*(self: Controller, cardName: string, pin: string, wall self.cancelCurrentFlow() self.keycardService.startStoreMetadataFlow(cardName, pin, walletPaths) +proc runGetMetadataFlow*(self: Controller, resolveAddress = false, exportMasterAddr = false, pin = "") = + self.cancelCurrentFlow() + self.keycardService.startGetMetadataFlow(resolveAddress, exportMasterAddr, pin) + proc resumeCurrentFlow*(self: Controller) = self.keycardService.resumeCurrentFlow() diff --git a/src/app/modules/startup/internal/biometrics_state.nim b/src/app/modules/startup/internal/biometrics_state.nim index 956a01ba3d3..cb7a345eb7c 100644 --- a/src/app/modules/startup/internal/biometrics_state.nim +++ b/src/app/modules/startup/internal/biometrics_state.nim @@ -10,10 +10,6 @@ proc newBiometricsState*(flowType: FlowType, backState: State): BiometricsState proc delete*(self: BiometricsState) = self.State.delete -method executeBackCommand*(self: BiometricsState, controller: Controller) = - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - controller.runRecoverAccountFlow() - method executePrimaryCommand*(self: BiometricsState, controller: Controller) = let storeToKeychain = true # true, cause we have support for keychain for mac os if self.flowType == FlowType.FirstRunNewUserNewKeys: @@ -25,11 +21,11 @@ method executePrimaryCommand*(self: BiometricsState, controller: Controller) = ## but since current implementation is like that and this is not a bug fixing issue, left as it is. controller.storeImportedAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunOldUserKeycardImport: - controller.setupKeycardAccount(storeToKeychain) + controller.setupKeycardAccount(storeToKeychain, newKeycard = false) elif self.flowType == FlowType.LostKeycardReplacement: self.storeToKeychain = storeToKeychain controller.startLoginFlowAutomatically(controller.getPin()) @@ -45,11 +41,11 @@ method executeSecondaryCommand*(self: BiometricsState, controller: Controller) = ## but since current implementation is like that and this is not a bug fixing issue, left as it is. controller.storeImportedAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunOldUserKeycardImport: - controller.setupKeycardAccount(storeToKeychain) + controller.setupKeycardAccount(storeToKeychain, newKeycard = false) elif self.flowType == FlowType.LostKeycardReplacement: self.storeToKeychain = storeToKeychain controller.startLoginFlowAutomatically(controller.getPin()) diff --git a/src/app/modules/startup/internal/keycard_enter_pin_state.nim b/src/app/modules/startup/internal/keycard_enter_pin_state.nim index 32c19ecef4b..af1c13639c9 100644 --- a/src/app/modules/startup/internal/keycard_enter_pin_state.nim +++ b/src/app/modules/startup/internal/keycard_enter_pin_state.nim @@ -56,6 +56,7 @@ method resolveKeycardNextState*(self: KeycardEnterPinState, keycardFlowType: str if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setKeycardEvent(keycardEvent) if not main_constants.IS_MACOS: - controller.setupKeycardAccount(false) + controller.setupKeycardAccount(storeToKeychain = false, newKeycard = false) return nil - return createState(StateType.Biometrics, self.flowType, self) \ No newline at end of file + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.Biometrics, self.flowType, backState) \ No newline at end of file diff --git a/src/app/modules/startup/internal/keycard_enter_puk_state.nim b/src/app/modules/startup/internal/keycard_enter_puk_state.nim index 46b7f8901bf..9b2d36af807 100644 --- a/src/app/modules/startup/internal/keycard_enter_puk_state.nim +++ b/src/app/modules/startup/internal/keycard_enter_puk_state.nim @@ -37,7 +37,7 @@ method resolveKeycardNextState*(self: KeycardEnterPukState, keycardFlowType: str controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) if not main_constants.IS_MACOS: - controller.setupKeycardAccount(false) + controller.setupKeycardAccount(storeToKeychain = false, newKeycard = false) return nil let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) return createState(StateType.Biometrics, self.flowType, backState) @@ -52,4 +52,9 @@ method resolveKeycardNextState*(self: KeycardEnterPukState, keycardFlowType: str controller.setRemainingAttempts(keycardEvent.pukRetries) if keycardEvent.pukRetries > 0: return createState(StateType.KeycardWrongPuk, self.flowType, self.getBackState) - return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) \ No newline at end of file + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + controller.setKeycardEvent(keycardEvent) + controller.setPukValid(true) + controller.loginAccountKeycard() + return nil \ No newline at end of file diff --git a/src/app/modules/startup/internal/keycard_pin_set_state.nim b/src/app/modules/startup/internal/keycard_pin_set_state.nim index 156c185876d..3bdd6b445c0 100644 --- a/src/app/modules/startup/internal/keycard_pin_set_state.nim +++ b/src/app/modules/startup/internal/keycard_pin_set_state.nim @@ -25,11 +25,9 @@ method getNextPrimaryState*(self: KeycardPinSetState, controller: Controller): S return createState(StateType.KeycardWrongPuk, self.flowType, self.getBackState) if self.flowType == FlowType.AppLogin: if controller.getRecoverUsingSeedPhraseWhileLogin(): - return createState(StateType.LoginKeycardReadingKeycard, self.flowType, nil) - if controller.getValidPuk(): - controller.loginAccountKeycard() return nil - return createState(StateType.KeycardWrongPuk, self.flowType, self.getBackState) + if not controller.getValidPuk(): + return createState(StateType.KeycardWrongPuk, self.flowType, self.getBackState) if self.flowType == FlowType.LostKeycardReplacement: if not main_constants.IS_MACOS: return nil @@ -40,13 +38,13 @@ method executePrimaryCommand*(self: KeycardPinSetState, controller: Controller) if main_constants.IS_MACOS: return if controller.getValidPuk(): - controller.setupKeycardAccount(false) + controller.setupKeycardAccount(storeToKeychain = false, newKeycard = false) if self.flowType == FlowType.AppLogin: if controller.getRecoverUsingSeedPhraseWhileLogin(): controller.startLoginFlowAutomatically(controller.getPin()) return if controller.getValidPuk(): - controller.setupKeycardAccount(false) + controller.loginAccountKeycard() if self.flowType == FlowType.LostKeycardReplacement: if main_constants.IS_MACOS: return @@ -58,4 +56,10 @@ method resolveKeycardNextState*(self: KeycardPinSetState, keycardFlowType: strin if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len == 0: controller.setKeycardEvent(keycardEvent) - controller.loginAccountKeycard() \ No newline at end of file + controller.loginAccountKeycard(storeToKeychain = true, syncWalletAfterLogin = 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(storeToKeychain = false, syncWalletAfterLogin = false) \ No newline at end of file diff --git a/src/app/modules/startup/internal/keycard_recover_state.nim b/src/app/modules/startup/internal/keycard_recover_state.nim index db0bf8c5615..e076d9d7dd7 100644 --- a/src/app/modules/startup/internal/keycard_recover_state.nim +++ b/src/app/modules/startup/internal/keycard_recover_state.nim @@ -9,15 +9,13 @@ proc delete*(self: KeycardRecoverState) = self.State.delete method getNextPrimaryState*(self: KeycardRecoverState, controller: Controller): State = - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, self) - if self.flowType == FlowType.AppLogin: - controller.setRecoverUsingSeedPhraseWhileLogin(true) - return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, self) + if self.flowType == FlowType.FirstRunOldUserKeycardImport or + self.flowType == FlowType.AppLogin: + controller.setRecoverUsingSeedPhraseWhileLogin(true) + return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, self) method getNextSecondaryState*(self: KeycardRecoverState, controller: Controller): State = - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - return createState(StateType.KeycardEnterPuk, self.flowType, self) - if self.flowType == FlowType.AppLogin: - controller.setRecoverUsingSeedPhraseWhileLogin(false) - return createState(StateType.KeycardEnterPuk, self.flowType, self) + if self.flowType == FlowType.FirstRunOldUserKeycardImport or + self.flowType == FlowType.AppLogin: + controller.setRecoverUsingSeedPhraseWhileLogin(false) + return createState(StateType.KeycardEnterPuk, self.flowType, self) diff --git a/src/app/modules/startup/internal/keycard_repeat_pin_state.nim b/src/app/modules/startup/internal/keycard_repeat_pin_state.nim index a29066ccac6..5491c1c1fc6 100644 --- a/src/app/modules/startup/internal/keycard_repeat_pin_state.nim +++ b/src/app/modules/startup/internal/keycard_repeat_pin_state.nim @@ -1,9 +1,11 @@ type KeycardRepeatPinState* = ref object of State + oldKeycardUid: string proc newKeycardRepeatPinState*(flowType: FlowType, backState: State): KeycardRepeatPinState = result = KeycardRepeatPinState() result.setup(flowType, StateType.KeycardRepeatPin, backState) + result.oldKeycardUid = "" proc delete*(self: KeycardRepeatPinState) = self.State.delete @@ -20,10 +22,15 @@ method executePrimaryCommand*(self: KeycardRepeatPinState, controller: Controlle controller.storePinToKeycard(controller.getPin(), controller.generateRandomPUK()) return if self.flowType == FlowType.FirstRunOldUserKeycardImport or - self.flowType == FlowType.AppLogin or - self.flowType == FlowType.LostKeycardReplacement: + self.flowType == FlowType.AppLogin: + if controller.getRecoverUsingSeedPhraseWhileLogin(): + controller.runGetMetadataFlow() + return controller.storePinToKeycard(controller.getPin(), puk = "") return + if self.flowType == FlowType.LostKeycardReplacement: + controller.storePinToKeycard(controller.getPin(), puk = "") + return method resolveKeycardNextState*(self: KeycardRepeatPinState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = @@ -43,34 +50,96 @@ method resolveKeycardNextState*(self: KeycardRepeatPinState, keycardFlowType: st let backState = findBackStateWithTargetedStateType(self, StateType.UserProfileImportSeedPhrase) return createState(StateType.KeycardPinSet, self.flowType, backState) if self.flowType == FlowType.FirstRunOldUserKeycardImport: - if keycardFlowType == ResponseTypeValueEnterPUK: - if keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPUK: - controller.setRemainingAttempts(keycardEvent.pukRetries) - controller.setPukValid(false) - if keycardEvent.pukRetries > 0: - return createState(StateType.KeycardPinSet, self.flowType, self.getBackState) - return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueKeycardFlowResult: - controller.setKeycardEvent(keycardEvent) - controller.setPukValid(true) - return createState(StateType.KeycardPinSet, self.flowType, self.getBackState) + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata: + controller.setMetadataFromKeycard(keycardEvent.cardMetadata) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + if keycardEvent.error.len == 0: + self.oldKeycardUid = keycardEvent.instanceUID + controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), controller.getPin(), puk = "", + factoryReset = true) + return + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.RecoverAccount or + controller.getCurrentKeycardServiceFlow() == KCSFlowType.LoadAccount: + if keycardFlowType == ResponseTypeValueEnterPUK: + if keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPUK: + controller.setRemainingAttempts(keycardEvent.pukRetries) + controller.setPukValid(false) + if keycardEvent.pukRetries > 0: + return createState(StateType.KeycardPinSet, self.flowType, self.getBackState) + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPUKRetries: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true)) + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamFreeSlots: + return createState(StateType.KeycardMaxPairingSlotsReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + controller.setKeycardEvent(keycardEvent) + controller.setPukValid(true) + if controller.getRecoverUsingSeedPhraseWhileLogin(): + controller.addToKeycardUidPairsToCheckForAChangeAfterLogin(self.oldKeycardUid, keycardEvent.instanceUID) + let md = controller.getMetadataFromKeycard() + let paths = md.walletAccounts.map(a => a.path) + controller.runStoreMetadataFlow(cardName = md.name, pin = controller.getPin(), walletPaths = paths) + return + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.KeycardPinSet, self.flowType, backState) + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.StoreMetadata: + if keycardFlowType == ResponseTypeValueKeycardFlowResult and + keycardEvent.instanceUID.len > 0: + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.KeycardPinSet, self.flowType, backState) if self.flowType == FlowType.AppLogin: - if keycardFlowType == ResponseTypeValueEnterPUK and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPUK: - controller.setRemainingAttempts(keycardEvent.pukRetries) - controller.setPukValid(false) - if keycardEvent.pukRetries > 0: - return createState(StateType.KeycardPinSet, self.flowType, self.getBackState) - return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) - if keycardFlowType == ResponseTypeValueKeycardFlowResult: - controller.setKeycardEvent(keycardEvent) - controller.setPukValid(true) - return createState(StateType.KeycardPinSet, self.flowType, self.getBackState) + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata: + controller.setMetadataFromKeycard(keycardEvent.cardMetadata) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + if keycardEvent.error.len == 0: + self.oldKeycardUid = keycardEvent.instanceUID + controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), controller.getPin(), puk = "", + factoryReset = true) + return + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.Login or + controller.getCurrentKeycardServiceFlow() == KCSFlowType.LoadAccount: + if keycardFlowType == ResponseTypeValueEnterPUK: + if keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPUK: + controller.setRemainingAttempts(keycardEvent.pukRetries) + controller.setPukValid(false) + if keycardEvent.pukRetries > 0: + return createState(StateType.KeycardPinSet, self.flowType, self.getBackState) + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamPUKRetries: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.MaxPUKReached, add = true)) + return createState(StateType.KeycardMaxPukRetriesReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0 and + keycardEvent.error == RequestParamFreeSlots: + return createState(StateType.KeycardMaxPairingSlotsReached, self.flowType, self.getBackState) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + controller.setKeycardEvent(keycardEvent) + controller.setPukValid(true) + if controller.getRecoverUsingSeedPhraseWhileLogin(): + controller.addToKeycardUidPairsToCheckForAChangeAfterLogin(self.oldKeycardUid, keycardEvent.instanceUID) + let md = controller.getMetadataFromKeycard() + let paths = md.walletAccounts.map(a => a.path) + controller.runStoreMetadataFlow(cardName = md.name, pin = controller.getPin(), walletPaths = paths) + return + return createState(StateType.KeycardPinSet, self.flowType, nil) + if controller.getCurrentKeycardServiceFlow() == KCSFlowType.StoreMetadata: + if keycardFlowType == ResponseTypeValueKeycardFlowResult and + keycardEvent.instanceUID.len > 0: + return createState(StateType.KeycardPinSet, self.flowType, nil) if self.flowType == FlowType.LostKeycardReplacement: if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) - let backState = findBackStateWithTargetedStateType(self, StateType.LostKeycardOptions) - return createState(StateType.KeycardPinSet, self.flowType, backState) \ No newline at end of file + if main_constants.IS_MACOS: + let backState = findBackStateWithTargetedStateType(self, StateType.LostKeycardOptions) + return createState(StateType.KeycardPinSet, self.flowType, backState) + return createState(StateType.KeycardPinSet, self.flowType, nil) \ No newline at end of file diff --git a/src/app/modules/startup/internal/keycard_wrong_keycard_state.nim b/src/app/modules/startup/internal/keycard_wrong_keycard_state.nim index b14d96e6792..f6b275c5d9a 100644 --- a/src/app/modules/startup/internal/keycard_wrong_keycard_state.nim +++ b/src/app/modules/startup/internal/keycard_wrong_keycard_state.nim @@ -6,4 +6,10 @@ proc newKeycardWrongKeycardState*(flowType: FlowType, backState: State): Keycard result.setup(flowType, StateType.KeycardWrongKeycard, backState) proc delete*(self: KeycardWrongKeycardState) = - self.State.delete \ No newline at end of file + self.State.delete + +method executeBackCommand*(self: KeycardWrongKeycardState, controller: Controller) = + if self.flowType == FlowType.FirstRunOldUserKeycardImport or + self.flowType == FlowType.AppLogin or + self.flowType == FlowType.LostKeycardReplacement: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false)) \ No newline at end of file diff --git a/src/app/modules/startup/internal/keycard_wrong_pin_state.nim b/src/app/modules/startup/internal/keycard_wrong_pin_state.nim index 3e251e7a2a3..9e80eab1171 100644 --- a/src/app/modules/startup/internal/keycard_wrong_pin_state.nim +++ b/src/app/modules/startup/internal/keycard_wrong_pin_state.nim @@ -48,6 +48,7 @@ method resolveKeycardNextState*(self: KeycardWrongPinState, keycardFlowType: str if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setKeycardEvent(keycardEvent) if not main_constants.IS_MACOS: - controller.setupKeycardAccount(false) - return nil - return createState(StateType.Biometrics, self.flowType, self) \ No newline at end of file + controller.setupKeycardAccount(storeToKeychain = false, newKeycard = false) + return nil + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.Biometrics, self.flowType, backState) \ No newline at end of file diff --git a/src/app/modules/startup/internal/keycard_wrong_puk_state.nim b/src/app/modules/startup/internal/keycard_wrong_puk_state.nim index f7977b33332..8c2165f5559 100644 --- a/src/app/modules/startup/internal/keycard_wrong_puk_state.nim +++ b/src/app/modules/startup/internal/keycard_wrong_puk_state.nim @@ -39,9 +39,10 @@ method resolveKeycardNextState*(self: KeycardWrongPukState, keycardFlowType: str controller.setKeycardEvent(keycardEvent) controller.setPukValid(true) if not main_constants.IS_MACOS: - controller.setupKeycardAccount(false) + controller.setupKeycardAccount(storeToKeychain = false, newKeycard = false) return nil - return createState(StateType.Biometrics, self.flowType, self.getBackState) + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.Biometrics, self.flowType, backState) if self.flowType == FlowType.AppLogin: if keycardFlowType == ResponseTypeValueEnterPUK and keycardEvent.error.len > 0 and diff --git a/src/app/modules/startup/internal/login_keycard_max_puk_retries_reached_state.nim b/src/app/modules/startup/internal/login_keycard_max_puk_retries_reached_state.nim index a524203f64f..97d1239b8c9 100644 --- a/src/app/modules/startup/internal/login_keycard_max_puk_retries_reached_state.nim +++ b/src/app/modules/startup/internal/login_keycard_max_puk_retries_reached_state.nim @@ -15,7 +15,7 @@ method executeBackCommand*(self: LoginKeycardMaxPukRetriesReachedState, controll method getNextPrimaryState*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller): State = if self.flowType == FlowType.AppLogin: controller.setRecoverUsingSeedPhraseWhileLogin(true) - return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, nil) + return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, self) method getNextTertiaryState*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller): State = if self.flowType == FlowType.AppLogin: diff --git a/src/app/modules/startup/internal/state_factory.nim b/src/app/modules/startup/internal/state_factory.nim index 7921ca6b6f7..6800f5816a9 100644 --- a/src/app/modules/startup/internal/state_factory.nim +++ b/src/app/modules/startup/internal/state_factory.nim @@ -1,4 +1,4 @@ -import chronicles +import sequtils, sugar, chronicles import ../../../../constants as main_constants import ../../../../app_service/service/keycard/constants import ../controller diff --git a/src/app/modules/startup/internal/state_factory_onboarding_implementation.nim b/src/app/modules/startup/internal/state_factory_onboarding_implementation.nim index a7414e6600e..0236456b823 100644 --- a/src/app/modules/startup/internal/state_factory_onboarding_implementation.nim +++ b/src/app/modules/startup/internal/state_factory_onboarding_implementation.nim @@ -121,20 +121,12 @@ proc ensureReaderAndCardPresenceAndResolveNextOnboardingState*(state: State, key keycardEvent.error.len > 0 and keycardEvent.error == RequestParamFreeSlots: return createState(StateType.KeycardMaxPairingSlotsReached, state.flowType, backState) - if keycardFlowType == ResponseTypeValueEnterNewPIN and - keycardEvent.error.len > 0 and - keycardEvent.error == ErrorRequireInit: - return createState(StateType.KeycardCreatePin, state.flowType, backState) if state.flowType == FlowType.AppLogin: if keycardFlowType == ResponseTypeValueSwapCard and keycardEvent.error.len > 0 and keycardEvent.error == RequestParamPUKRetries: return createState(StateType.KeycardMaxPukRetriesReached, state.flowType, state.getBackState) - if keycardFlowType == ResponseTypeValueEnterNewPIN and - keycardEvent.error.len > 0 and - keycardEvent.error == ErrorRequireInit: - return createState(StateType.KeycardCreatePin, state.flowType, state.getBackState) if state.flowType == FlowType.LostKeycardReplacement: var backState = state.getBackState diff --git a/src/app/modules/startup/internal/user_profile_chat_key_state.nim b/src/app/modules/startup/internal/user_profile_chat_key_state.nim index 51ecdb896f6..a2358397fc8 100644 --- a/src/app/modules/startup/internal/user_profile_chat_key_state.nim +++ b/src/app/modules/startup/internal/user_profile_chat_key_state.nim @@ -13,11 +13,11 @@ method executePrimaryCommand*(self: UserProfileChatKeyState, controller: Control return let storeToKeychain = false # false, cause we don't have keychain support for other than mac os if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunOldUserKeycardImport: - controller.setupKeycardAccount(storeToKeychain) + controller.setupKeycardAccount(storeToKeychain, newKeycard = false) method getNextPrimaryState*(self: UserProfileChatKeyState, controller: Controller): State = if self.flowType == FlowType.FirstRunNewUserNewKeys or diff --git a/src/app/modules/startup/internal/user_profile_confirm_password_state.nim b/src/app/modules/startup/internal/user_profile_confirm_password_state.nim index 7aa12babb67..c37b75b2e2f 100644 --- a/src/app/modules/startup/internal/user_profile_confirm_password_state.nim +++ b/src/app/modules/startup/internal/user_profile_confirm_password_state.nim @@ -22,7 +22,7 @@ method executePrimaryCommand*(self: UserProfileConfirmPasswordState, controller: elif self.flowType == FlowType.FirstRunNewUserImportSeedPhrase: controller.storeImportedAccountAndLogin(storeToKeychain) elif self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.storeKeycardAccountAndLogin(storeToKeychain) + controller.storeKeycardAccountAndLogin(storeToKeychain, newKeycard = true) elif self.flowType == FlowType.FirstRunOldUserImportSeedPhrase: controller.storeImportedAccountAndLogin(storeToKeychain = false) diff --git a/src/app/modules/startup/internal/user_profile_enter_seed_phrase_state.nim b/src/app/modules/startup/internal/user_profile_enter_seed_phrase_state.nim index b2ed4a7366b..a85da394c18 100644 --- a/src/app/modules/startup/internal/user_profile_enter_seed_phrase_state.nim +++ b/src/app/modules/startup/internal/user_profile_enter_seed_phrase_state.nim @@ -22,40 +22,43 @@ method getNextPrimaryState*(self: UserProfileEnterSeedPhraseState, controller: C if self.flowType == FlowType.FirstRunNewUserImportSeedPhrase: return createState(StateType.UserProfileCreate, self.flowType, self) if self.flowType == FlowType.FirstRunOldUserKeycardImport: - if not self.enteredMnemonicMatchTargetedKeyUid: - return createState(StateType.KeycardWrongKeycard, self.flowType, self) + if self.enteredMnemonicMatchTargetedKeyUid: + return createState(StateType.KeycardCreatePin, self.flowType, self) + let backState = findBackStateWithTargetedStateType(self, StateType.RecoverOldUser) + return createState(StateType.KeycardWrongKeycard, self.flowType, backState) if self.flowType == FlowType.FirstRunOldUserImportSeedPhrase: return createState(StateType.UserProfileCreatePassword, self.flowType, self) + if self.flowType == FlowType.AppLogin: + if self.enteredMnemonicMatchTargetedKeyUid: + return createState(StateType.KeycardCreatePin, self.flowType, self) + return createState(StateType.KeycardWrongKeycard, self.flowType, self) method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller: Controller) = - if self.flowType == FlowType.AppLogin: - self.successfulImport = controller.validMnemonic(controller.getSeedPhrase()) and - controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getSelectedLoginAccount().keyUid - if self.successfulImport: - controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), pin = "", puk = "", - factoryReset = true) + if self.flowType == FlowType.FirstRunNewUserImportSeedPhrase or + self.flowType == FlowType.FirstRunOldUserImportSeedPhrase: + self.successfulImport = controller.importMnemonic() else: - if self.flowType == FlowType.FirstRunNewUserImportSeedPhrase or - self.flowType == FlowType.FirstRunOldUserImportSeedPhrase: - self.successfulImport = controller.importMnemonic() - else: - self.successfulImport = controller.validMnemonic(controller.getSeedPhrase()) - if self.successfulImport: - if self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: + self.successfulImport = controller.validMnemonic(controller.getSeedPhrase()) + if self.successfulImport: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false)) + let keyUid = controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) + + if self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: + controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase()) + if self.flowType == FlowType.FirstRunOldUserKeycardImport: + self.enteredMnemonicMatchTargetedKeyUid = keyUid == controller.getKeyUid() + if not self.enteredMnemonicMatchTargetedKeyUid: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true)) + if self.flowType == FlowType.AppLogin: + self.enteredMnemonicMatchTargetedKeyUid = controller.keyUidMatchSelectedLoginAccount(keyUid) + if not self.enteredMnemonicMatchTargetedKeyUid: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true)) + if self.flowType == FlowType.LostKeycardReplacement: + self.enteredMnemonicMatchTargetedKeyUid = controller.keyUidMatchSelectedLoginAccount(keyUid) + if self.enteredMnemonicMatchTargetedKeyUid: controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase()) - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - self.enteredMnemonicMatchTargetedKeyUid = controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getKeyUid() - if self.enteredMnemonicMatchTargetedKeyUid: - controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), pin = "", puk = "", - factoryReset = true) - if self.flowType == FlowType.LostKeycardReplacement: - controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false)) - let keyUid = controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) - self.enteredMnemonicMatchTargetedKeyUid = controller.keyUidMatchSelectedLoginAccount(keyUid) - if self.enteredMnemonicMatchTargetedKeyUid: - controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase()) - else: - controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true)) + else: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true)) method resolveKeycardNextState*(self: UserProfileEnterSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/internal/welcome_state_new_user.nim b/src/app/modules/startup/internal/welcome_state_new_user.nim index ee8d9a77ebb..edcc0da141a 100644 --- a/src/app/modules/startup/internal/welcome_state_new_user.nim +++ b/src/app/modules/startup/internal/welcome_state_new_user.nim @@ -9,9 +9,9 @@ proc delete*(self: WelcomeStateNewUser) = self.State.delete method executeBackCommand*(self: WelcomeStateNewUser, controller: Controller) = - if self.flowType == FlowType.FirstRunNewUserNewKeycardKeys: - controller.cancelCurrentFlow() - elif self.flowType == FlowType.AppLogin and controller.isSelectedAccountAKeycardAccount(): + controller.cancelCurrentFlow() + if self.stateType != StateType.Welcome and controller.isSelectedAccountAKeycardAccount(): + # means we're getting back to login flow controller.runLoginFlow() method executeSecondaryCommand*(self: WelcomeStateNewUser, controller: Controller) = diff --git a/src/app/modules/startup/internal/welcome_state_old_user.nim b/src/app/modules/startup/internal/welcome_state_old_user.nim index 1e2bf8fdcda..3a9ef1235ef 100644 --- a/src/app/modules/startup/internal/welcome_state_old_user.nim +++ b/src/app/modules/startup/internal/welcome_state_old_user.nim @@ -9,7 +9,9 @@ proc delete*(self: WelcomeStateOldUser) = self.State.delete method executeBackCommand*(self: WelcomeStateOldUser, controller: Controller) = - if self.flowType == FlowType.AppLogin and controller.isSelectedAccountAKeycardAccount(): + controller.cancelCurrentFlow() + if self.stateType != StateType.Welcome and controller.isSelectedAccountAKeycardAccount(): + # means we're getting back to login flow controller.runLoginFlow() method getNextPrimaryState*(self: WelcomeStateOldUser, controller: Controller): State = diff --git a/src/app/modules/startup/io_interface.nim b/src/app/modules/startup/io_interface.nim index 590f9ab63c0..a89d548a821 100644 --- a/src/app/modules/startup/io_interface.nim +++ b/src/app/modules/startup/io_interface.nim @@ -140,10 +140,16 @@ method setRemainingAttempts*(self: AccessInterface, value: int) {.base.} = method runFactoryResetPopup*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method storeKeyPairForNewKeycardUser*(self: AccessInterface) {.base.} = +method storeDefaultKeyPairForNewKeycardUser*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") -method syncWalletAccountsOnLoginForReplacedKeycard*(self: AccessInterface) {.base.} = +method syncKeycardBasedOnAppWalletStateAfterLogin*(self: AccessInterface) {.base.} = + raise newException(ValueError, "No implementation available") + +method addToKeycardUidPairsToCheckForAChangeAfterLogin*(self: AccessInterface, oldKeycardUid: string, newKeycardUid: string) {.base.} = + raise newException(ValueError, "No implementation available") + +method removeAllKeycardUidPairsForCheckingForAChangeAfterLogin*(self: AccessInterface) {.base.} = raise newException(ValueError, "No implementation available") method checkForStoringPasswordToKeychain*(self: AccessInterface) {.base.} = @@ -167,5 +173,7 @@ type c.startupDidLoad() c.userLoggedIn() c.finishAppLoading() - c.storeKeyPairForNewKeycardUser() - c.syncWalletAccountsOnLoginForReplacedKeycard() + c.storeDefaultKeyPairForNewKeycardUser() + c.syncKeycardBasedOnAppWalletStateAfterLogin() + c.addToKeycardUidPairsToCheckForAChangeAfterLogin(string, string) + c.removeAllKeycardUidPairsForCheckingForAChangeAfterLogin() \ No newline at end of file diff --git a/src/app/modules/startup/module.nim b/src/app/modules/startup/module.nim index ee394dffcba..dd0311a582f 100644 --- a/src/app/modules/startup/module.nim +++ b/src/app/modules/startup/module.nim @@ -347,7 +347,7 @@ proc delayStartingApp[T](self: Module[T]) = ## - FlowType.FirstRunOldUserImportSeedPhrase ## - FlowType.FirstRunOldUserKeycardImport ## we want to delay app start just to be sure that messages from waku will be received - self.controller.connectToTimeoutEventAndStratTimer(timeoutInMilliseconds = 30000) # delay for 30 seconds + self.controller.connectToTimeoutEventAndStratTimer(timeoutInMilliseconds = 10000) # delay for 30 seconds method startAppAfterDelay*[T](self: Module[T]) = if not self.view.fetchingDataModel().allMessagesLoaded(): @@ -469,11 +469,17 @@ method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurr self.view.setCurrentStartupState(newState) debug "new state for onboarding/login flow continuation after shared flow is terminated", setCurrFlow=newState.flowType(), newCurrState=newState.stateType() -method storeKeyPairForNewKeycardUser*[T](self: Module[T]) = - self.delegate.storeKeyPairForNewKeycardUser() +method storeDefaultKeyPairForNewKeycardUser*[T](self: Module[T]) = + self.delegate.storeDefaultKeyPairForNewKeycardUser() -method syncWalletAccountsOnLoginForReplacedKeycard*[T](self: Module[T]) = - self.delegate.syncWalletAccountsOnLoginForReplacedKeycard() +method syncKeycardBasedOnAppWalletStateAfterLogin*[T](self: Module[T]) = + self.delegate.syncKeycardBasedOnAppWalletStateAfterLogin() + +method addToKeycardUidPairsToCheckForAChangeAfterLogin*[T](self: Module[T], oldKeycardUid: string, newKeycardUid: string) = + self.delegate.addToKeycardUidPairsToCheckForAChangeAfterLogin(oldKeycardUid, newKeycardUid) + +method removeAllKeycardUidPairsForCheckingForAChangeAfterLogin*[T](self: Module[T]) = + self.delegate.removeAllKeycardUidPairsForCheckingForAChangeAfterLogin() method checkForStoringPasswordToKeychain*[T](self: Module[T]) = self.controller.checkForStoringPasswordToKeychain() \ No newline at end of file diff --git a/src/app_service/service/accounts/service.nim b/src/app_service/service/accounts/service.nim index a64d5f2e248..937865a5fc8 100644 --- a/src/app_service/service/accounts/service.nim +++ b/src/app_service/service/accounts/service.nim @@ -25,7 +25,7 @@ logScope: topics = "accounts-service" const PATHS = @[PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET, PATH_ENCRYPTION] -const ACCOUNT_ALREADY_EXISTS_ERROR = "account already exists" +const ACCOUNT_ALREADY_EXISTS_ERROR* = "account already exists" const output_csv {.booldefine.} = false const KDF_ITERATIONS* {.intdefine.} = 256_000 @@ -147,6 +147,13 @@ QtObject: except Exception as e: error "error: ", procName="openedAccounts", errName = e.name, errDesription = e.msg + proc openedAccountsContainsKeyUid*(self: Service, keyUid: string): bool = + let openedAccounts = self.openedAccounts() + for acc in openedAccounts: + if acc.keyUid == keyUid: + return true + return false + proc storeDerivedAccounts(self: Service, accountId, hashedPassword: string, paths: seq[string]): DerivedAccounts = let response = status_account.storeDerivedAccounts(accountId, hashedPassword, paths) diff --git a/src/app_service/service/keycard/service.nim b/src/app_service/service/keycard/service.nim index 5321c3fcdec..b0f19fa765e 100644 --- a/src/app_service/service/keycard/service.nim +++ b/src/app_service/service/keycard/service.nim @@ -131,19 +131,19 @@ QtObject: self.updateLocalPayloadForCurrentFlow(payload, cleanBefore = true) let response = keycard_go.keycardStartFlow(self.currentFlow.int, $payload) if self.doLogging: - debug "keycardStartFlow", currentFlow=self.currentFlow.int, payload=payload, response=response + debug "keycardStartFlow", kcServiceCurrFlow=($self.currentFlow), payload=payload, response=response proc resumeFlow(self: Service, payload: JsonNode) = self.updateLocalPayloadForCurrentFlow(payload) let response = keycard_go.keycardResumeFlow($payload) if self.doLogging: - debug "keycardResumeFlow", currentFlow=self.currentFlow.int, payload=payload, response=response + debug "keycardResumeFlow", kcServiceCurrFlow=($self.currentFlow), payload=payload, response=response proc cancelCurrentFlow*(self: Service) = let response = keycard_go.keycardCancelFlow() self.currentFlow = KCSFlowType.NoFlow if self.doLogging: - debug "keycardCancelFlow", currentFlow=self.currentFlow.int, response=response + debug "keycardCancelFlow", kcServiceCurrFlow=($self.currentFlow), response=response proc generateRandomPUK*(self: Service): string = randomize() @@ -154,7 +154,7 @@ QtObject: if(self.closingApp or self.currentFlow == KCSFlowType.NoFlow): return if self.doLogging: - debug "onTimeout, about to start flow: ", currentFlow=self.currentFlow + debug "onTimeout, about to start flow: ", kcServiceCurrFlow=($self.currentFlow) self.startFlow(self.setPayloadForCurrentFlow) proc runTimer(self: Service) = diff --git a/ui/app/AppLayouts/Onboarding/views/KeycardStateView.qml b/ui/app/AppLayouts/Onboarding/views/KeycardStateView.qml index 25badf33d9d..1aa361958e0 100644 --- a/ui/app/AppLayouts/Onboarding/views/KeycardStateView.qml +++ b/ui/app/AppLayouts/Onboarding/views/KeycardStateView.qml @@ -361,7 +361,7 @@ Item { } PropertyChanges { target: message - text: qsTr("Remove Keycard and try again") + text: qsTr("Go back, remove Keycard and try again") color: Theme.palette.baseColor1 font.pixelSize: Constants.keycard.general.fontSize3 } diff --git a/ui/app/AppLayouts/Onboarding/views/SeedPhraseInputView.qml b/ui/app/AppLayouts/Onboarding/views/SeedPhraseInputView.qml index bc8e3d915e7..80b43a25c94 100644 --- a/ui/app/AppLayouts/Onboarding/views/SeedPhraseInputView.qml +++ b/ui/app/AppLayouts/Onboarding/views/SeedPhraseInputView.qml @@ -37,6 +37,10 @@ Item { onWrongSeedPhraseChanged: { if (wrongSeedPhrase) { + if (root.startupStore.startupModuleInst.flowType === Constants.startupFlow.firstRunOldUserImportSeedPhrase) { + invalidSeedTxt.text = qsTr("Profile keypair for the inserted seed phrase is already set up") + return + } invalidSeedTxt.text = qsTr("Seed phrase doesn’t match the profile of an existing Keycard user on this device") } else { diff --git a/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml b/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml index 304428144e8..126d51d3003 100644 --- a/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/DerivationPathsPanel.qml @@ -30,7 +30,7 @@ ColumnLayout { } property bool pathError: Utils.isInvalidPath(RootStore.derivedAddressesError) property bool derivationAddressLoading: RootStore.derivedAddressesLoading - property string defaultDerivationPath: "m/44'/60'/0'/0/0" + property string defaultDerivationPath: "m/44'/60'/0'/0" } spacing: 7 diff --git a/ui/imports/shared/popups/keycard/states/KeycardPin.qml b/ui/imports/shared/popups/keycard/states/KeycardPin.qml index 7f95b9c880c..932cdfe128d 100644 --- a/ui/imports/shared/popups/keycard/states/KeycardPin.qml +++ b/ui/imports/shared/popups/keycard/states/KeycardPin.qml @@ -39,14 +39,15 @@ Item { } Component.onCompleted: { - if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication) { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication || + root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) { timer.start() } } Timer { id: timer - interval: 1000 + interval: 500 onTriggered: { pinInputField.statesInitialization() pinInputField.forceFocus()