diff --git a/src/app/modules/startup/controller.nim b/src/app/modules/startup/controller.nim index 0b2e6fac56..1be514d108 100644 --- a/src/app/modules/startup/controller.nim +++ b/src/app/modules/startup/controller.nim @@ -36,6 +36,7 @@ type profileService: profile_service.Service keycardService: keycard_service.Service connectionIds: seq[UUID] + keychainConnectionIds: seq[UUID] tmpProfileImageDetails: ProfileImageDetails tmpDisplayName: string tmpPassword: string @@ -70,14 +71,32 @@ proc newController*(delegate: io_interface.AccessInterface, result.keycardService = keycardService result.tmpPinMatch = false result.tmpSeedPhraseLength = 0 - result.tmpKeychainErrorOccurred = true + result.tmpKeychainErrorOccurred = false result.tmpRecoverUsingSeedPhraseWhileLogin = false result.tmpSelectedLoginAccountIsKeycardAccount = false # Forward declaration proc cleanTmpData*(self: Controller) +proc disconnectKeychain*(self: Controller) = + for id in self.keychainConnectionIds: + self.events.disconnect(id) + self.keychainConnectionIds = @[] + +proc connectKeychain*(self: Controller) = + var handlerId = self.events.onWithUUID(SIGNAL_KEYCHAIN_SERVICE_SUCCESS) do(e:Args): + let args = KeyChainServiceArg(e) + self.delegate.emitObtainingPasswordSuccess(args.data) + self.keychainConnectionIds.add(handlerId) + + handlerId = self.events.onWithUUID(SIGNAL_KEYCHAIN_SERVICE_ERROR) do(e:Args): + let args = KeyChainServiceArg(e) + self.tmpKeychainErrorOccurred = true + self.delegate.emitObtainingPasswordError(args.errDescription, args.errType) + self.keychainConnectionIds.add(handlerId) + proc disconnect*(self: Controller) = + self.disconnectKeychain() for id in self.connectionIds: self.events.disconnect(id) @@ -85,6 +104,8 @@ proc delete*(self: Controller) = self.disconnect() proc init*(self: Controller) = + self.connectKeychain() + var handlerId = self.events.onWithUUID(SignalType.NodeLogin.event) do(e:Args): let signal = NodeSignal(e) self.delegate.onNodeLogin(signal.event.error) @@ -101,17 +122,6 @@ proc init*(self: Controller) = self.events.emit("nodeReady", Args()) self.connectionIds.add(handlerId) - handlerId = self.events.onWithUUID(SIGNAL_KEYCHAIN_SERVICE_SUCCESS) do(e:Args): - let args = KeyChainServiceArg(e) - self.delegate.emitObtainingPasswordSuccess(args.data) - self.connectionIds.add(handlerId) - - handlerId = self.events.onWithUUID(SIGNAL_KEYCHAIN_SERVICE_ERROR) do(e:Args): - let args = KeyChainServiceArg(e) - self.tmpKeychainErrorOccurred = true - self.delegate.emitObtainingPasswordError(args.errDescription, args.errType) - self.connectionIds.add(handlerId) - handlerId = self.events.onWithUUID(SIGNAL_KEYCARD_RESPONSE) do(e: Args): let args = KeycardArgs(e) self.delegate.onKeycardResponse(args.flowType, args.flowEvent) @@ -234,7 +244,7 @@ proc cleanTmpData*(self: Controller) = self.tmpSelectedLoginAccountKeyUid = "" self.tmpSelectedLoginAccountIsKeycardAccount = false self.tmpProfileImageDetails = ProfileImageDetails() - self.tmpKeychainErrorOccurred = true + self.tmpKeychainErrorOccurred = false self.setDisplayName("") self.setPassword("") self.setDefaultWalletEmoji("") @@ -273,7 +283,7 @@ proc validMnemonic*(self: Controller, mnemonic: string): bool = return true return false -proc importMnemonic(self: Controller): bool = +proc importMnemonic*(self: Controller): bool = let error = self.accountsService.importMnemonic(self.tmpSeedPhrase) if(error.len == 0): self.delegate.importAccountSuccess() diff --git a/src/app/modules/startup/internal/login_keycard_empty_state.nim b/src/app/modules/startup/internal/login_keycard_empty_state.nim index 883a1af1c2..b8391f195d 100644 --- a/src/app/modules/startup/internal/login_keycard_empty_state.nim +++ b/src/app/modules/startup/internal/login_keycard_empty_state.nim @@ -8,17 +8,22 @@ proc newLoginKeycardEmptyState*(flowType: FlowType, backState: State): LoginKeyc proc delete*(self: LoginKeycardEmptyState) = self.State.delete -method executePrimaryCommand*(self: LoginKeycardEmptyState, controller: Controller) = - if self.flowType == FlowType.AppLogin: - controller.runLoadAccountFlow(seedPhraseLength = 0, seedPhrase = "", puk = "", factoryReset = true) - method getNextSecondaryState*(self: LoginKeycardEmptyState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + let newState = createState(StateType.WelcomeNewStatusUser, self.flowType, self) + newState.executeSecondaryCommand(controller) + return newState method getNextTertiaryState*(self: LoginKeycardEmptyState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardEmptyState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginKeycardEmptyState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/internal/login_keycard_enter_password_state.nim b/src/app/modules/startup/internal/login_keycard_enter_password_state.nim new file mode 100644 index 0000000000..221aba7755 --- /dev/null +++ b/src/app/modules/startup/internal/login_keycard_enter_password_state.nim @@ -0,0 +1,24 @@ +type + LoginKeycardEnterPasswordState* = ref object of State + +proc newLoginKeycardEnterPasswordState*(flowType: FlowType, backState: State): LoginKeycardEnterPasswordState = + result = LoginKeycardEnterPasswordState() + result.setup(flowType, StateType.LoginKeycardEnterPassword, backState) + +proc delete*(self: LoginKeycardEnterPasswordState) = + self.State.delete + +method executePrimaryCommand*(self: LoginKeycardEnterPasswordState, controller: Controller) = + if self.flowType == FlowType.AppLogin: + if not controller.isSelectedLoginAccountKeycardAccount(): + controller.login() + +method getNextTertiaryState*(self: LoginKeycardEnterPasswordState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardEnterPasswordState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_keycard_enter_pin_state.nim b/src/app/modules/startup/internal/login_keycard_enter_pin_state.nim index 45b9974b7e..6040103d27 100644 --- a/src/app/modules/startup/internal/login_keycard_enter_pin_state.nim +++ b/src/app/modules/startup/internal/login_keycard_enter_pin_state.nim @@ -10,18 +10,19 @@ proc delete*(self: LoginKeycardEnterPinState) = method executePrimaryCommand*(self: LoginKeycardEnterPinState, controller: Controller) = if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - elif controller.getPin().len == PINLengthForStatusApp: - controller.enterKeycardPin(controller.getPin()) - -method getNextSecondaryState*(self: LoginKeycardEnterPinState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + if controller.isSelectedLoginAccountKeycardAccount() and + controller.getPin().len == PINLengthForStatusApp: + controller.enterKeycardPin(controller.getPin()) method getNextTertiaryState*(self: LoginKeycardEnterPinState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardEnterPinState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginKeycardEnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = @@ -32,8 +33,7 @@ method resolveKeycardNextState*(self: LoginKeycardEnterPinState, keycardFlowType if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len == 0: controller.setKeycardEvent(keycardEvent) - controller.loginAccountKeycard() - return nil + return createState(StateType.LoginKeycardPinVerified, self.flowType, nil) if keycardFlowType == ResponseTypeValueEnterPIN and keycardEvent.error.len > 0 and keycardEvent.error == RequestParamPIN: diff --git a/src/app/modules/startup/internal/login_keycard_insert_keycard_state.nim b/src/app/modules/startup/internal/login_keycard_insert_keycard_state.nim index 344b59ec42..708fe95145 100644 --- a/src/app/modules/startup/internal/login_keycard_insert_keycard_state.nim +++ b/src/app/modules/startup/internal/login_keycard_insert_keycard_state.nim @@ -8,24 +8,15 @@ proc newLoginKeycardInsertKeycardState*(flowType: FlowType, backState: State): L proc delete*(self: LoginKeycardInsertKeycardState) = self.State.delete -method executePrimaryCommand*(self: LoginKeycardInsertKeycardState, controller: Controller) = - if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: - controller.enterKeycardPin(controller.getPin()) - -method getNextPrimaryState*(self: LoginKeycardInsertKeycardState, controller: Controller): State = - if controller.keychainErrorOccurred() or controller.getPin().len != PINLengthForStatusApp: - return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) - -method getNextSecondaryState*(self: LoginKeycardInsertKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) - method getNextTertiaryState*(self: LoginKeycardInsertKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardInsertKeycardState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginKeycardInsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = @@ -39,5 +30,5 @@ method resolveKeycardNextState*(self: LoginKeycardInsertKeycardState, keycardFlo return nil if keycardFlowType == ResponseTypeValueCardInserted: controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false)) - return createState(StateType.LoginKeycardReadingKeycard, self.flowType, nil) + return createState(StateType.LoginKeycardInsertedKeycard, self.flowType, nil) return nil \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_keycard_inserted_keycard_state.nim b/src/app/modules/startup/internal/login_keycard_inserted_keycard_state.nim new file mode 100644 index 0000000000..cbde83f336 --- /dev/null +++ b/src/app/modules/startup/internal/login_keycard_inserted_keycard_state.nim @@ -0,0 +1,13 @@ +type + LoginKeycardInsertedKeycardState* = ref object of State + +proc newLoginKeycardInsertedKeycardState*(flowType: FlowType, backState: State): LoginKeycardInsertedKeycardState = + result = LoginKeycardInsertedKeycardState() + result.setup(flowType, StateType.LoginKeycardInsertedKeycard, backState) + +proc delete*(self: LoginKeycardInsertedKeycardState) = + self.State.delete + +method getNextPrimaryState*(self: LoginKeycardInsertedKeycardState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + return createState(StateType.LoginKeycardReadingKeycard, self.flowType, nil) diff --git a/src/app/modules/startup/internal/login_keycard_max_pairing_slots_reached_state.nim b/src/app/modules/startup/internal/login_keycard_max_pairing_slots_reached_state.nim new file mode 100644 index 0000000000..f7d5d88fe7 --- /dev/null +++ b/src/app/modules/startup/internal/login_keycard_max_pairing_slots_reached_state.nim @@ -0,0 +1,32 @@ +type + LoginKeycardMaxPairingSlotsReachedState* = ref object of State + +proc newLoginKeycardMaxPairingSlotsReachedState*(flowType: FlowType, backState: State): LoginKeycardMaxPairingSlotsReachedState = + result = LoginKeycardMaxPairingSlotsReachedState() + result.setup(flowType, StateType.LoginKeycardMaxPairingSlotsReached, backState) + +proc delete*(self: LoginKeycardMaxPairingSlotsReachedState) = + self.State.delete + +method executeBackCommand*(self: LoginKeycardMaxPairingSlotsReachedState, controller: Controller) = + if self.flowType == FlowType.AppLogin and controller.isKeycardCreatedAccountSelectedOne(): + controller.runLoginFlow() + +method getNextPrimaryState*(self: LoginKeycardMaxPairingSlotsReachedState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.setRecoverUsingSeedPhraseWhileLogin(true) + return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, nil) + +method getNextTertiaryState*(self: LoginKeycardMaxPairingSlotsReachedState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardMaxPairingSlotsReachedState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + +method resolveKeycardNextState*(self: LoginKeycardMaxPairingSlotsReachedState, keycardFlowType: string, keycardEvent: KeycardEvent, + controller: Controller): State = + return ensureReaderAndCardPresenceAndResolveNextLoginState(self, keycardFlowType, keycardEvent, controller) \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_keycard_max_pin_retries_reached_state.nim b/src/app/modules/startup/internal/login_keycard_max_pin_retries_reached_state.nim index d8778d83ba..3c6cbfc3ca 100644 --- a/src/app/modules/startup/internal/login_keycard_max_pin_retries_reached_state.nim +++ b/src/app/modules/startup/internal/login_keycard_max_pin_retries_reached_state.nim @@ -13,15 +13,18 @@ method executeBackCommand*(self: LoginKeycardMaxPinRetriesReachedState, controll controller.runLoginFlow() method getNextPrimaryState*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller): State = - return createState(StateType.KeycardRecover, self.flowType, self) - -method getNextSecondaryState*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + return createState(StateType.KeycardRecover, self.flowType, self) method getNextTertiaryState*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginKeycardMaxPinRetriesReachedState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = 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 e1e81d589e..dbbaf8a864 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 @@ -8,11 +8,25 @@ proc newLoginKeycardMaxPukRetriesReachedState*(flowType: FlowType, backState: St proc delete*(self: LoginKeycardMaxPukRetriesReachedState) = self.State.delete +method executeBackCommand*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller) = + if self.flowType == FlowType.AppLogin and controller.isKeycardCreatedAccountSelectedOne(): + controller.runLoginFlow() + method getNextPrimaryState*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller): State = if self.flowType == FlowType.AppLogin: controller.setRecoverUsingSeedPhraseWhileLogin(true) return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, nil) +method getNextTertiaryState*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + method resolveKeycardNextState*(self: LoginKeycardMaxPukRetriesReachedState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = return ensureReaderAndCardPresenceAndResolveNextLoginState(self, keycardFlowType, keycardEvent, controller) \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim b/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim new file mode 100644 index 0000000000..235f38a59e --- /dev/null +++ b/src/app/modules/startup/internal/login_keycard_pin_verified_state.nim @@ -0,0 +1,13 @@ +type + LoginKeycardPinVerifiedState* = ref object of State + +proc newLoginKeycardPinVerifiedState*(flowType: FlowType, backState: State): LoginKeycardPinVerifiedState = + result = LoginKeycardPinVerifiedState() + result.setup(flowType, StateType.LoginKeycardPinVerified, backState) + +proc delete*(self: LoginKeycardPinVerifiedState) = + self.State.delete + +method executePrimaryCommand*(self: LoginKeycardPinVerifiedState, controller: Controller) = + if self.flowType == FlowType.AppLogin: + controller.loginAccountKeycard() \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_keycard_reading_keycard_state.nim b/src/app/modules/startup/internal/login_keycard_reading_keycard_state.nim index 815dc00f21..6d76991fcd 100644 --- a/src/app/modules/startup/internal/login_keycard_reading_keycard_state.nim +++ b/src/app/modules/startup/internal/login_keycard_reading_keycard_state.nim @@ -10,25 +10,12 @@ proc newLoginKeycardReadingKeycardState*(flowType: FlowType, backState: State): proc delete*(self: LoginKeycardReadingKeycardState) = self.State.delete -method executePrimaryCommand*(self: LoginKeycardReadingKeycardState, controller: Controller) = - if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: - controller.enterKeycardPin(controller.getPin()) - method getNextPrimaryState*(self: LoginKeycardReadingKeycardState, controller: Controller): State = - if controller.keychainErrorOccurred() or controller.getPin().len != PINLengthForStatusApp: - return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) - -method getNextSecondaryState*(self: LoginKeycardReadingKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) - -method getNextTertiaryState*(self: LoginKeycardReadingKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + let (flowType, flowEvent) = controller.getLastReceivedKeycardData() + # this is used in case a keycard is not inserted in the moment when flow is run (we're animating an insertion) + return ensureReaderAndCardPresenceAndResolveNextLoginState(self, flowType, flowEvent, controller) method resolveKeycardNextState*(self: LoginKeycardReadingKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = + # this is used in case a keycard is inserted and we jump to the first meaningful screen return ensureReaderAndCardPresenceAndResolveNextLoginState(self, keycardFlowType, keycardEvent, controller) \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_keycard_recognized_keycard_state.nim b/src/app/modules/startup/internal/login_keycard_recognized_keycard_state.nim new file mode 100644 index 0000000000..96214a461e --- /dev/null +++ b/src/app/modules/startup/internal/login_keycard_recognized_keycard_state.nim @@ -0,0 +1,17 @@ +type + LoginKeycardRecognizedKeycardState* = ref object of State + +proc newLoginKeycardRecognizedKeycardState*(flowType: FlowType, backState: State): LoginKeycardRecognizedKeycardState = + result = LoginKeycardRecognizedKeycardState() + result.setup(flowType, StateType.LoginKeycardRecognizedKeycard, backState) + +proc delete*(self: LoginKeycardRecognizedKeycardState) = + self.State.delete + +method getNextPrimaryState*(self: LoginKeycardRecognizedKeycardState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + let value = singletonInstance.localAccountSettings.getStoreToKeychainValue() + if value == LS_VALUE_STORE: + controller.tryToObtainDataFromKeychain() + return createState(StateType.Login, self.flowType, nil) + return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) diff --git a/src/app/modules/startup/internal/login_keycard_wrong_keycard.nim b/src/app/modules/startup/internal/login_keycard_wrong_keycard.nim index 55985b9eb2..b5ecf04343 100644 --- a/src/app/modules/startup/internal/login_keycard_wrong_keycard.nim +++ b/src/app/modules/startup/internal/login_keycard_wrong_keycard.nim @@ -10,22 +10,19 @@ proc delete*(self: LoginKeycardWrongKeycardState) = method executePrimaryCommand*(self: LoginKeycardWrongKeycardState, controller: Controller) = if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: - controller.enterKeycardPin(controller.getPin()) - -method getNextPrimaryState*(self: LoginKeycardWrongKeycardState, controller: Controller): State = - if controller.keychainErrorOccurred() or controller.getPin().len != PINLengthForStatusApp: - return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) - -method getNextSecondaryState*(self: LoginKeycardWrongKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + if controller.isSelectedLoginAccountKeycardAccount() and + controller.getPin().len == PINLengthForStatusApp: + controller.enterKeycardPin(controller.getPin()) method getNextTertiaryState*(self: LoginKeycardWrongKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardWrongKeycardState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginKeycardWrongKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/internal/login_keycard_wrong_pin_state.nim b/src/app/modules/startup/internal/login_keycard_wrong_pin_state.nim index 8c53520f14..47b631db9a 100644 --- a/src/app/modules/startup/internal/login_keycard_wrong_pin_state.nim +++ b/src/app/modules/startup/internal/login_keycard_wrong_pin_state.nim @@ -12,22 +12,19 @@ proc delete*(self: LoginKeycardWrongPinState) = method executePrimaryCommand*(self: LoginKeycardWrongPinState, controller: Controller) = if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: - controller.enterKeycardPin(controller.getPin()) - -method getNextPrimaryState*(self: LoginKeycardWrongPinState, controller: Controller): State = - if controller.keychainErrorOccurred() or controller.getPin().len != PINLengthForStatusApp: - return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) - -method getNextSecondaryState*(self: LoginKeycardWrongPinState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + if controller.isSelectedLoginAccountKeycardAccount() and + controller.getPin().len == PINLengthForStatusApp: + controller.enterKeycardPin(controller.getPin()) method getNextTertiaryState*(self: LoginKeycardWrongPinState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginKeycardWrongPinState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginKeycardWrongPinState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = @@ -50,5 +47,4 @@ method resolveKeycardNextState*(self: LoginKeycardWrongPinState, keycardFlowType if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len == 0: controller.setKeycardEvent(keycardEvent) - controller.loginAccountKeycard() - return nil \ No newline at end of file + return createState(StateType.LoginKeycardPinVerified, self.flowType, nil) \ No newline at end of file diff --git a/src/app/modules/startup/internal/login_not_keycard_state.nim b/src/app/modules/startup/internal/login_not_keycard_state.nim index 4eb319c454..dea4470b72 100644 --- a/src/app/modules/startup/internal/login_not_keycard_state.nim +++ b/src/app/modules/startup/internal/login_not_keycard_state.nim @@ -12,13 +12,15 @@ method executePrimaryCommand*(self: LoginNotKeycardState, controller: Controller if self.flowType == FlowType.AppLogin: controller.runLoadAccountFlow(seedPhraseLength = 0, seedPhrase = "", puk = "", factoryReset = true) -method getNextSecondaryState*(self: LoginNotKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) - method getNextTertiaryState*(self: LoginNotKeycardState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginNotKeycardState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginNotKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/internal/login_plugin_state.nim b/src/app/modules/startup/internal/login_plugin_state.nim index ac7d91360c..899b031199 100644 --- a/src/app/modules/startup/internal/login_plugin_state.nim +++ b/src/app/modules/startup/internal/login_plugin_state.nim @@ -8,24 +8,15 @@ proc newLoginPluginState*(flowType: FlowType, backState: State): LoginPluginStat proc delete*(self: LoginPluginState) = self.State.delete -method executePrimaryCommand*(self: LoginPluginState, controller: Controller) = - if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: - controller.enterKeycardPin(controller.getPin()) - -method getNextPrimaryState*(self: LoginPluginState, controller: Controller): State = - if controller.keychainErrorOccurred() or controller.getPin().len != PINLengthForStatusApp: - return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) - -method getNextSecondaryState*(self: LoginPluginState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) - method getNextTertiaryState*(self: LoginPluginState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginPluginState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginPluginState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/internal/login_state.nim b/src/app/modules/startup/internal/login_state.nim index 248c354984..0bbd067ff7 100644 --- a/src/app/modules/startup/internal/login_state.nim +++ b/src/app/modules/startup/internal/login_state.nim @@ -10,22 +10,29 @@ proc delete*(self: LoginState) = method executePrimaryCommand*(self: LoginState, controller: Controller) = if self.flowType == FlowType.AppLogin: + if controller.keychainErrorOccurred(): + return if not controller.isSelectedLoginAccountKeycardAccount(): controller.login() - elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: + elif controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) -method getNextPrimaryState*(self: LoginState, controller: Controller): State = - if controller.keychainErrorOccurred() or controller.getPin().len != PINLengthForStatusApp: - return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) - method getNextSecondaryState*(self: LoginState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + if not controller.isSelectedLoginAccountKeycardAccount(): + return createState(StateType.LoginKeycardEnterPassword, self.flowType, nil) + else: + return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) method getNextTertiaryState*(self: LoginState, controller: Controller): State = - controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeNewStatusUser, self.flowType, self) + +method getNextQuaternaryState*(self: LoginState, controller: Controller): State = + if self.flowType == FlowType.AppLogin: + controller.cancelCurrentFlow() + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) method resolveKeycardNextState*(self: LoginState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/internal/state.nim b/src/app/modules/startup/internal/state.nim index 22347a45b8..39697fec52 100644 --- a/src/app/modules/startup/internal/state.nim +++ b/src/app/modules/startup/internal/state.nim @@ -53,12 +53,17 @@ type StateType* {.pure.} = enum Login = "Login" LoginPlugin = "LoginPlugin" LoginKeycardInsertKeycard = "LoginKeycardInsertKeycard" + LoginKeycardInsertedKeycard = "LoginKeycardInsertedKeycard" LoginKeycardReadingKeycard = "LoginKeycardReadingKeycard" + LoginKeycardRecognizedKeycard = "LoginKeycardRecognizedKeycard" LoginKeycardEnterPin = "LoginKeycardEnterPin" + LoginKeycardEnterPassword = "LoginKeycardEnterPassword" + LoginKeycardPinVerified = "LoginKeycardPinVerified" LoginKeycardWrongKeycard = "LoginKeycardWrongKeycard" LoginKeycardWrongPin = "LoginKeycardWrongPin" LoginKeycardMaxPinRetriesReached = "LoginKeycardMaxPinRetriesReached" LoginKeycardMaxPukRetriesReached = "LoginKeycardMaxPukRetriesReached" + LoginKeycardMaxPairingSlotsReached = "LoginKeycardMaxPairingSlotsReached" LoginKeycardEmpty = "LoginKeycardEmpty" LoginNotKeycard = "LoginNotKeycard" diff --git a/src/app/modules/startup/internal/state_factory.nim b/src/app/modules/startup/internal/state_factory.nim index 54d528a113..a828cea821 100644 --- a/src/app/modules/startup/internal/state_factory.nim +++ b/src/app/modules/startup/internal/state_factory.nim @@ -56,12 +56,17 @@ include welcome_state include login_state include login_plugin_state include login_keycard_insert_keycard_state +include login_keycard_inserted_keycard_state include login_keycard_reading_keycard_state +include login_keycard_recognized_keycard_state include login_keycard_enter_pin_state +include login_keycard_enter_password_state +include login_keycard_pin_verified_state include login_keycard_wrong_keycard include login_keycard_wrong_pin_state include login_keycard_max_pin_retries_reached_state include login_keycard_max_puk_retries_reached_state +include login_keycard_max_pairing_slots_reached_state include login_keycard_empty_state include login_not_keycard_state @@ -140,10 +145,18 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newLoginPluginState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardInsertKeycard: return newLoginKeycardInsertKeycardState(flowType, backState) + if stateToBeCreated == StateType.LoginKeycardInsertedKeycard: + return newLoginKeycardInsertedKeycardState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardReadingKeycard: return newLoginKeycardReadingKeycardState(flowType, backState) + if stateToBeCreated == StateType.LoginKeycardRecognizedKeycard: + return newLoginKeycardRecognizedKeycardState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardEnterPin: return newLoginKeycardEnterPinState(flowType, backState) + if stateToBeCreated == StateType.LoginKeycardEnterPassword: + return newLoginKeycardEnterPasswordState(flowType, backState) + if stateToBeCreated == StateType.LoginKeycardPinVerified: + return newLoginKeycardPinVerifiedState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardWrongKeycard: return newLoginKeycardWrongKeycardState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardWrongPin: @@ -152,6 +165,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newLoginKeycardMaxPinRetriesReachedState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardMaxPukRetriesReached: return newLoginKeycardMaxPukRetriesReachedState(flowType, backState) + if stateToBeCreated == StateType.LoginKeycardMaxPairingSlotsReached: + return newLoginKeycardMaxPairingSlotsReachedState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardEmpty: return newLoginKeycardEmptyState(flowType, backState) if stateToBeCreated == StateType.LoginNotKeycard: @@ -193,7 +208,7 @@ proc ensureReaderAndCardPresenceLogin*(state: State, keycardFlowType: string, ke return createState(StateType.LoginKeycardInsertKeycard, state.flowType, state.getBackState) if keycardFlowType == ResponseTypeValueCardInserted: controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = false)) - return createState(StateType.LoginKeycardReadingKeycard, state.flowType, state.getBackState) + return createState(StateType.LoginKeycardInsertedKeycard, state.flowType, state.getBackState) proc ensureReaderAndCardPresenceAndResolveNextOnboardingState*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = let ensureState = ensureReaderAndCardPresenceOnboarding(state, keycardFlowType, keycardEvent, controller) @@ -303,17 +318,12 @@ proc ensureReaderAndCardPresenceAndResolveNextLoginState*(state: State, keycardF if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len == 0: controller.setKeycardEvent(keycardEvent) - controller.loginAccountKeycard() - return nil + return createState(StateType.LoginKeycardPinVerified, state.flowType, nil) if keycardFlowType == ResponseTypeValueEnterPIN: if keycardEvent.error.len == 0: if not controller.keyUidMatch(keycardEvent.keyUid): return createState(StateType.LoginKeycardWrongKeycard, state.flowType, nil) - let value = singletonInstance.localAccountSettings.getStoreToKeychainValue() - if value == LS_VALUE_STORE: - controller.tryToObtainDataFromKeychain() - return nil - return createState(StateType.LoginKeycardEnterPin, state.flowType, nil) + return createState(StateType.LoginKeycardRecognizedKeycard, state.flowType, nil) if keycardEvent.error.len > 0: if keycardEvent.error == RequestParamPIN: controller.setKeycardData($keycardEvent.pinRetries) @@ -331,4 +341,6 @@ proc ensureReaderAndCardPresenceAndResolveNextLoginState*(state: State, keycardF if keycardEvent.error == ErrorNotAKeycard: return createState(StateType.LoginNotKeycard, state.flowType, nil) if keycardEvent.error == RequestParamPUKRetries: - return createState(StateType.LoginKeycardMaxPukRetriesReached, state.flowType, nil) \ No newline at end of file + return createState(StateType.LoginKeycardMaxPukRetriesReached, state.flowType, nil) + if keycardEvent.error == RequestParamFreeSlots: + return createState(StateType.LoginKeycardMaxPairingSlotsReached, state.flowType, nil) \ No newline at end of file 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 6de7228602..239d1fe06c 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 @@ -33,14 +33,18 @@ method executePrimaryCommand*(self: UserProfileEnterSeedPhraseState, controller: if self.successfulImport: controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), puk = "", factoryReset = true) else: - self.successfulImport = controller.validMnemonic(controller.getSeedPhrase()) - if self.successfulImport: - if self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: - controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase()) - if self.flowType == FlowType.FirstRunOldUserKeycardImport: - self.correctKeycard = controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getKeyUid() - if self.correctKeycard: - controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), puk = "", factoryReset = true) + if self.flowType == FlowType.FirstRunOldUserImportSeedPhrase or + self.flowType == FlowType.FirstRunNewUserImportSeedPhrase: + self.successfulImport = controller.importMnemonic() + else: + self.successfulImport = controller.validMnemonic(controller.getSeedPhrase()) + if self.successfulImport: + if self.flowType == FlowType.FirstRunNewUserImportSeedPhraseIntoKeycard: + controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase()) + if self.flowType == FlowType.FirstRunOldUserKeycardImport: + self.correctKeycard = controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getKeyUid() + if self.correctKeycard: + controller.runLoadAccountFlow(controller.getSeedPhraseLength(), controller.getSeedPhrase(), puk = "", factoryReset = true) method resolveKeycardNextState*(self: UserProfileEnterSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = diff --git a/src/app/modules/startup/module.nim b/src/app/modules/startup/module.nim index b5969b2c30..cfc178550c 100644 --- a/src/app/modules/startup/module.nim +++ b/src/app/modules/startup/module.nim @@ -251,14 +251,21 @@ method importAccountSuccess*[T](self: Module[T]) = self.view.importAccountSuccess() method setSelectedLoginAccount*[T](self: Module[T], item: login_acc_item.Item) = + self.controller.disconnectKeychain() self.controller.cancelCurrentFlow() self.controller.setSelectedLoginAccount(item.getKeyUid(), item.getKeycardCreatedAccount()) - self.view.setCurrentStartupState(newLoginState(FlowType.AppLogin, nil)) if item.getKeycardCreatedAccount(): + self.view.setCurrentStartupState(newLoginState(FlowType.AppLogin, nil)) self.controller.runLoginFlow() - else: - self.controller.tryToObtainDataFromKeychain() + else: + let value = singletonInstance.localAccountSettings.getStoreToKeychainValue() + if value == LS_VALUE_STORE: + self.view.setCurrentStartupState(newLoginState(FlowType.AppLogin, nil)) + self.controller.tryToObtainDataFromKeychain() + else: + self.view.setCurrentStartupState(newLoginKeycardEnterPasswordState(FlowType.AppLogin, nil)) self.view.setSelectedLoginAccount(item) + self.controller.connectKeychain() method emitAccountLoginError*[T](self: Module[T], error: string) = self.view.emitAccountLoginError(error) diff --git a/src/app_service/service/accounts/service.nim b/src/app_service/service/accounts/service.nim index d3dcf95d20..fef63544ec 100644 --- a/src/app_service/service/accounts/service.nim +++ b/src/app_service/service/accounts/service.nim @@ -460,6 +460,7 @@ proc setupAccountKeycard*(self: Service, keycardData: KeycardEvent) = subaccountDataJson, settingsJson, nodeConfigJson) + self.setLocalAccountSettingsFile() except Exception as e: error "error: ", procName="setupAccount", errName = e.name, errDesription = e.msg diff --git a/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml b/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml index 50010a041f..32128690d2 100644 --- a/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml +++ b/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml @@ -66,12 +66,17 @@ OnboardingBasePage { if (root.startupStore.currentStartupState.stateType === Constants.startupState.login || root.startupStore.currentStartupState.stateType === Constants.startupState.loginPlugin || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardInsertKeycard || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardInsertedKeycard || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardReadingKeycard || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardRecognizedKeycard || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEnterPin || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEnterPassword || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardPinVerified || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardWrongKeycard || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardWrongPin || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPinRetriesReached || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPukRetriesReached || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPairingSlotsReached || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEmpty || root.startupStore.currentStartupState.stateType === Constants.startupState.loginNotKeycard) { diff --git a/ui/app/AppLayouts/Onboarding/views/LoginView.qml b/ui/app/AppLayouts/Onboarding/views/LoginView.qml index 2200d5b204..95c6e50afc 100644 --- a/ui/app/AppLayouts/Onboarding/views/LoginView.qml +++ b/ui/app/AppLayouts/Onboarding/views/LoginView.qml @@ -11,6 +11,8 @@ import StatusQ.Controls 0.1 import StatusQ.Controls.Validators 0.1 import StatusQ.Popups 0.1 +import shared.popups.keycard.helpers 1.0 + import SortFilterProxyModel 0.2 import shared.panels 1.0 @@ -36,8 +38,23 @@ Item { onStateChanged: { d.loading = false - pinInputField.statesInitialization() - pinInputField.forceFocus() + if(state === Constants.startupState.loginKeycardPinVerified) { + pinInputField.setPin("123456") // we are free to set fake pin in this case + pinInputField.enabled = false + } else { + pinInputField.statesInitialization() + pinInputField.forceFocus() + } + } + + Timer { + id: timer + interval: 1000 + running: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardRecognizedKeycard || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardPinVerified + onTriggered: { + root.startupStore.doPrimaryAction() + } } QtObject { @@ -47,14 +64,6 @@ Item { readonly property string stateLoginRegularUser: "regularUserLogin" readonly property string stateLoginKeycardUser: "keycardUserLogin" - property int index: 0 - property variant images : [ - Style.svg("keycard/card0@2x"), - Style.svg("keycard/card1@2x"), - Style.svg("keycard/card2@2x"), - Style.svg("keycard/card3@2x") - ] - property int remainingAttempts: parseInt(root.startupStore.startupModuleInst.keycardData, 10) onRemainingAttemptsChanged: { pinInputField.statesInitialization() @@ -91,31 +100,20 @@ Item { } } - Timer { - interval: 400 - running: root.state === d.stateLoginKeycardUser || - root.state === Constants.startupState.loginKeycardInsertKeycard || - root.state === Constants.startupState.loginKeycardReadingKeycard - repeat: true - onTriggered: { - d.index++ - image.source = d.images[d.index % d.images.length] - } - } - Connections{ target: root.startupStore.startupModuleInst onObtainingPasswordError: { - if (root.startupStore.selectedLoginAccount.keycardCreatedAccount) { - root.startupStore.doPrimaryAction() // in this case, switch to enter pin state - } - if (errorType === Constants.keychain.errorType.authentication) { // We are notifying user only about keychain errors. return } + image.source = Style.png("keycard/biometrics-fail") + info.icon = "" + info.color = Theme.palette.dangerColor1 + info.text = qsTr("Fingerprint not recognized") + obtainingPasswordErrorNotification.confirmationText = errorDescription obtainingPasswordErrorNotification.open() } @@ -164,14 +162,21 @@ Item { ColumnLayout { anchors.centerIn: parent + height: Constants.keycard.general.loginHeight spacing: Style.current.bigPadding - Image { + KeycardImage { id: image Layout.alignment: Qt.AlignHCenter - fillMode: Image.PreserveAspectFit - antialiasing: true - mipmap: true + Layout.preferredHeight: Constants.keycard.general.imageHeight + Layout.preferredWidth: Constants.keycard.general.imageWidth + + onAnimationCompleted: { + if (root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardInsertedKeycard || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardReadingKeycard) { + root.startupStore.doPrimaryAction() + } + } } StatusBaseText { @@ -184,10 +189,12 @@ Item { Item { id: userInfo - height: userImage.height - width: 318 + Layout.preferredHeight: userImage.height + Layout.preferredWidth: 318 Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Style.current.xlPadding + enabled: root.startupStore.currentStartupState.stateType !== Constants.startupState.loginKeycardReadingKeycard && + root.startupStore.currentStartupState.stateType !== Constants.startupState.loginKeycardRecognizedKeycard && + root.startupStore.currentStartupState.stateType !== Constants.startupState.loginKeycardPinVerified UserImage { id: userImage @@ -304,7 +311,7 @@ Item { asset.name: "add" onClicked: { accountsPopup.close() - root.startupStore.doSecondaryAction() + root.startupStore.doTertiaryAction() } } @@ -313,7 +320,7 @@ Item { asset.name: "wallet" onClicked: { accountsPopup.close() - root.startupStore.doTertiaryAction() + root.startupStore.doQuaternaryAction() } } } @@ -383,7 +390,10 @@ Item { Layout.alignment: Qt.AlignHCenter spacing: Style.current.padding + property alias text: pinText.text + StatusBaseText { + id: pinText anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: Constants.keycard.general.fontSize2 wrapMode: Text.WordWrap @@ -398,6 +408,11 @@ Item { enabled: !d.loading onPinInputChanged: { + if (root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardPinVerified) + return + if (root.state !== Constants.startupState.loginKeycardWrongPin) { + image.source = Style.png("keycard/enter-pin-%1".arg(pinInput.length)) + } if(pinInput.length == 0) return root.startupStore.setPin(pinInput) @@ -406,12 +421,34 @@ Item { } } - StatusBaseText { + Row { id: info - Layout.alignment: Qt.AlignHCenter - horizontalAlignment: Text.AlignHCenter - font.pixelSize: Constants.keycard.general.fontSize3 - wrapMode: Text.WordWrap + Layout.alignment: Qt.AlignCenter + spacing: Style.current.halfPadding + + property alias text: infoTxt.text + property alias font: infoTxt.font + property alias color: infoTxt.color + property alias icon: infoIcon.icon + + StatusIcon { + id: infoIcon + visible: icon !== "" + width: Style.current.padding + height: Style.current.padding + color: Theme.palette.baseColor1 + } + StatusLoadingIndicator { + id: loading + visible: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardReadingKeycard + } + StatusBaseText { + id: infoTxt + Layout.alignment: Qt.AlignHCenter + horizontalAlignment: Text.AlignHCenter + font.pixelSize: Constants.keycard.general.fontSize3 + wrapMode: Text.WordWrap + } } StatusBaseText { @@ -446,29 +483,42 @@ Item { parent.font.underline = false } onClicked: { - root.startupStore.doPrimaryAction() + root.startupStore.doSecondaryAction() } } } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + } } states: [ State { name: d.stateLoginRegularUser - when: !root.startupStore.selectedLoginAccount.keycardCreatedAccount + when: !root.startupStore.selectedLoginAccount.keycardCreatedAccount && + root.startupStore.currentStartupState.stateType === Constants.startupState.login PropertyChanges { target: image - source: Style.png("status-logo") - Layout.preferredHeight: 128 - Layout.preferredWidth: 128 + source: localAccountSettings.storeToKeychainValue === Constants.keychain.storedValue.store? + Style.png("keycard/biometrics-success") : Style.png("status-logo") + pattern: "" + Layout.preferredHeight: localAccountSettings.storeToKeychainValue === Constants.keychain.storedValue.store? + Constants.keycard.general.imageHeight : + Constants.keycard.general.loginStatusLogoHeight + Layout.preferredWidth: localAccountSettings.storeToKeychainValue === Constants.keychain.storedValue.store? + Constants.keycard.general.imageWidth : + Constants.keycard.general.loginStatusLogoWidth } PropertyChanges { target: title - text: qsTr("Welcome back") + text: localAccountSettings.storeToKeychainValue === Constants.keychain.storedValue.store? "" : qsTr("Welcome back") + visible: localAccountSettings.storeToKeychainValue !== Constants.keychain.storedValue.store } PropertyChanges { target: passwordSection - visible: true + visible: localAccountSettings.storeToKeychainValue !== Constants.keychain.storedValue.store } PropertyChanges { target: pinSection @@ -476,8 +526,12 @@ Item { } PropertyChanges { target: info - text: "" - visible: false + text: qsTr("Waiting for TouchID...") + visible: true + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "touch-id" } PropertyChanges { target: message @@ -491,8 +545,8 @@ Item { } PropertyChanges { target: link - text: "" - visible: false + text: qsTr("Use password instead") + visible: true } }, State { @@ -501,9 +555,8 @@ Item { root.startupStore.currentStartupState.stateType === Constants.startupState.login PropertyChanges { target: image - source: Style.svg("keycard/card3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + source: Style.png("keycard/biometrics-success") + pattern: "" } PropertyChanges { target: title @@ -520,7 +573,12 @@ Item { } PropertyChanges { target: info - visible: false + text: qsTr("Waiting for TouchID...") + visible: true + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "touch-id" } PropertyChanges { target: message @@ -534,8 +592,8 @@ Item { } PropertyChanges { target: link - text: "" - visible: false + text: qsTr("Use PIN instead") + visible: true } }, State { @@ -544,9 +602,8 @@ Item { root.startupStore.currentStartupState.stateType === Constants.startupState.loginPlugin PropertyChanges { target: image - source: Style.svg("keycard/card3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + source: Style.png("keycard/empty-reader") + pattern: "" } PropertyChanges { target: title @@ -567,6 +624,8 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" } PropertyChanges { target: message @@ -589,9 +648,13 @@ Item { when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardInsertKeycard PropertyChanges { target: image - source: Style.svg("keycard/card3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + pattern: "keycard/card_insert/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 0 + endImgIndex: 16 + duration: 1000 + loops: 1 } PropertyChanges { target: title @@ -612,6 +675,8 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" } PropertyChanges { target: message @@ -631,14 +696,69 @@ Item { visible: false } }, + State { + name: Constants.startupState.loginKeycardInsertedKeycard + when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardInsertedKeycard + PropertyChanges { + target: image + pattern: "keycard/card_inserted/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 0 + endImgIndex: 29 + duration: 1000 + loops: 1 + } + PropertyChanges { + target: title + text: "" + visible: false + } + PropertyChanges { + target: passwordSection + visible: false + } + PropertyChanges { + target: pinSection + visible: false + } + PropertyChanges { + target: info + text: qsTr("Keycard inserted...") + visible: true + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" + } + PropertyChanges { + target: message + text: "" + visible: false + } + PropertyChanges { + target: button + text: "" + visible: false + } + PropertyChanges { + target: link + text: "" + visible: false + } + }, State { name: Constants.startupState.loginKeycardReadingKeycard when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardReadingKeycard PropertyChanges { target: image - source: Style.svg("keycard/card3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + pattern: "keycard/warning/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 0 + endImgIndex: 55 + duration: 3000 + loops: 1 } PropertyChanges { target: title @@ -659,6 +779,103 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" + } + PropertyChanges { + target: message + text: "" + visible: false + } + PropertyChanges { + target: button + text: "" + visible: false + } + PropertyChanges { + target: link + text: "" + visible: false + } + }, + State { + name: Constants.startupState.loginKeycardRecognizedKeycard + when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardRecognizedKeycard + PropertyChanges { + target: image + pattern: "keycard/success/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 0 + endImgIndex: 29 + duration: 1300 + loops: 1 + } + PropertyChanges { + target: title + text: "" + visible: false + } + PropertyChanges { + target: passwordSection + visible: false + } + PropertyChanges { + target: pinSection + visible: false + } + PropertyChanges { + target: info + text: qsTr("Keycard recognized") + visible: true + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.baseColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "checkmark" + } + PropertyChanges { + target: message + text: "" + visible: false + } + PropertyChanges { + target: button + text: "" + visible: false + } + PropertyChanges { + target: link + text: "" + visible: false + } + }, + State { + name: Constants.startupState.loginKeycardEnterPassword + when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEnterPassword + PropertyChanges { + target: image + source: Style.png("status-logo") + pattern: "" + Layout.preferredHeight: Constants.keycard.general.loginStatusLogoHeight + Layout.preferredWidth: Constants.keycard.general.loginStatusLogoWidth + } + PropertyChanges { + target: title + text: qsTr("Welcome back") + visible: true + } + PropertyChanges { + target: passwordSection + visible: true + } + PropertyChanges { + target: pinSection + visible: false + } + PropertyChanges { + target: info + text: "" + visible: true } PropertyChanges { target: message @@ -681,9 +898,8 @@ Item { when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEnterPin PropertyChanges { target: image - source: Style.svg("keycard/card3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + source: Style.png("keycard/card-empty") + pattern: "" } PropertyChanges { target: title @@ -697,13 +913,59 @@ Item { PropertyChanges { target: pinSection visible: true + text: qsTr("Enter Keycard PIN") } PropertyChanges { target: info text: "" visible: false - font.pixelSize: Constants.keycard.general.fontSize2 - color: Theme.palette.baseColor1 + } + PropertyChanges { + target: message + text: "" + visible: false + } + PropertyChanges { + target: button + text: "" + visible: false + } + PropertyChanges { + target: link + text: "" + visible: false + } + }, + State { + name: Constants.startupState.loginKeycardPinVerified + when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardPinVerified + PropertyChanges { + target: image + pattern: "keycard/strong_success/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 0 + endImgIndex: 20 + duration: 1300 + loops: 1 + } + PropertyChanges { + target: title + text: "" + visible: false + } + PropertyChanges { + target: passwordSection + visible: false + } + PropertyChanges { + target: pinSection + visible: true + text: qsTr("PIN Verified") + } + PropertyChanges { + target: info + visible: false } PropertyChanges { target: message @@ -726,9 +988,13 @@ Item { when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardWrongKeycard PropertyChanges { target: image - source: Style.svg("keycard/card-wrong3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + pattern: "keycard/strong_error/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 18 + endImgIndex: 29 + duration: 1300 + loops: -1 } PropertyChanges { target: title @@ -749,10 +1015,12 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.dangerColor1 + height: Constants.keycard.general.loginInfoHeight2 + icon: "" } PropertyChanges { target: message - text: qsTr("Insert another Keycard") + text: qsTr("Insert proper Keycard") visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.baseColor1 @@ -773,9 +1041,8 @@ Item { when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardWrongPin PropertyChanges { target: image - source: Style.svg("keycard/card-wrong3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + source: Style.png("keycard/plain-error") + pattern: "" } PropertyChanges { target: title @@ -789,6 +1056,7 @@ Item { PropertyChanges { target: pinSection visible: true + text: qsTr("Enter Keycard PIN") } PropertyChanges { target: info @@ -796,6 +1064,8 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.dangerColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" } PropertyChanges { target: message @@ -819,12 +1089,18 @@ Item { }, State { name: Constants.startupState.loginKeycardMaxPinRetriesReached - when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPinRetriesReached + when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPinRetriesReached || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPukRetriesReached || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPairingSlotsReached PropertyChanges { target: image - source: Style.svg("keycard/card-error3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + pattern: "keycard/strong_error/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 18 + endImgIndex: 29 + duration: 1300 + loops: -1 } PropertyChanges { target: title @@ -845,6 +1121,8 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.dangerColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" } PropertyChanges { target: message @@ -853,52 +1131,7 @@ Item { } PropertyChanges { target: button - text: qsTr("Recover your Keycard") - visible: true - } - PropertyChanges { - target: link - text: "" - visible: false - } - }, - State { - name: Constants.startupState.loginKeycardMaxPukRetriesReached - when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardMaxPukRetriesReached - PropertyChanges { - target: image - source: Style.svg("keycard/card-error3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width - } - PropertyChanges { - target: title - text: "" - visible: false - } - PropertyChanges { - target: passwordSection - visible: false - } - PropertyChanges { - target: pinSection - visible: false - } - PropertyChanges { - target: info - text: qsTr("Keycard locked") - visible: true - font.pixelSize: Constants.keycard.general.fontSize2 - color: Theme.palette.dangerColor1 - } - PropertyChanges { - target: message - text: "" - visible: false - } - PropertyChanges { - target: button - text: qsTr("Recover with seed phrase") + text: qsTr("Unlock Keycard") visible: true } PropertyChanges { @@ -912,9 +1145,8 @@ Item { when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEmpty PropertyChanges { target: image - source: Style.svg("keycard/card-wrong3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + source: Style.png("keycard/card-empty") + pattern: "" } PropertyChanges { target: title @@ -931,10 +1163,12 @@ Item { } PropertyChanges { target: info - text: qsTr("The card inserted is empty") + text: qsTr("The card inserted is empty (has no profile linked).") visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.dangerColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" } PropertyChanges { target: message @@ -957,9 +1191,13 @@ Item { when: root.startupStore.currentStartupState.stateType === Constants.startupState.loginNotKeycard PropertyChanges { target: image - source: Style.svg("keycard/card-wrong3@2x") - Layout.preferredHeight: sourceSize.height - Layout.preferredWidth: sourceSize.width + pattern: "keycard/strong_error/img-%1" + source: "" + startImgIndexForTheFirstLoop: 0 + startImgIndexForOtherLoops: 18 + endImgIndex: 29 + duration: 1300 + loops: -1 } PropertyChanges { target: title @@ -980,6 +1218,8 @@ Item { visible: true font.pixelSize: Constants.keycard.general.fontSize2 color: Theme.palette.dangerColor1 + height: Constants.keycard.general.loginInfoHeight1 + icon: "" } PropertyChanges { target: message diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 6052788059..33993c3fe9 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -63,12 +63,17 @@ QtObject { readonly property string login: "Login" readonly property string loginPlugin: "LoginPlugin" readonly property string loginKeycardInsertKeycard: "LoginKeycardInsertKeycard" + readonly property string loginKeycardInsertedKeycard: "LoginKeycardInsertedKeycard" readonly property string loginKeycardReadingKeycard: "LoginKeycardReadingKeycard" + readonly property string loginKeycardRecognizedKeycard: "LoginKeycardRecognizedKeycard" readonly property string loginKeycardEnterPin: "LoginKeycardEnterPin" + readonly property string loginKeycardEnterPassword: "LoginKeycardEnterPassword" + readonly property string loginKeycardPinVerified: "LoginKeycardPinVerified" readonly property string loginKeycardWrongKeycard: "LoginKeycardWrongKeycard" readonly property string loginKeycardWrongPin: "LoginKeycardWrongPin" readonly property string loginKeycardMaxPinRetriesReached: "LoginKeycardMaxPinRetriesReached" readonly property string loginKeycardMaxPukRetriesReached: "LoginKeycardMaxPukRetriesReached" + readonly property string loginKeycardMaxPairingSlotsReached: "LoginKeycardMaxPairingSlotsReached" readonly property string loginKeycardEmpty: "LoginKeycardEmpty" readonly property string loginNotKeycard: "LoginNotKeycard" } @@ -388,6 +393,7 @@ QtObject { readonly property QtObject general: QtObject { readonly property int onboardingHeight: 460 + readonly property int loginHeight: 460 readonly property int imageWidth: 240 readonly property int imageHeight: 240 readonly property int seedPhraseWidth: 816 @@ -414,6 +420,10 @@ QtObject { readonly property int titleHeight: 44 readonly property int messageHeight: 48 readonly property int footerButtonsHeight: 44 + readonly property int loginInfoHeight1: 24 + readonly property int loginInfoHeight2: 44 + readonly property int loginStatusLogoWidth: 128 + readonly property int loginStatusLogoHeight: 128 } readonly property QtObject keyPairType: QtObject {