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 2b15d7b267..64660ce3e5 100644 --- a/src/app/modules/startup/internal/login_keycard_empty_state.nim +++ b/src/app/modules/startup/internal/login_keycard_empty_state.nim @@ -10,10 +10,7 @@ proc delete*(self: LoginKeycardEmptyState) = method executePrimaryCommand*(self: LoginKeycardEmptyState, controller: Controller) = if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - else: - controller.runLoadAccountFlow(factoryReset = true) + controller.runLoadAccountFlow(factoryReset = true) method getNextSecondaryState*(self: LoginKeycardEmptyState, controller: Controller): State = controller.cancelCurrentFlow() 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 363d79d0d4..6f9332143d 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 @@ -12,6 +12,12 @@ method executePrimaryCommand*(self: LoginKeycardInsertKeycardState, 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(): + return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) method getNextSecondaryState*(self: LoginKeycardInsertKeycardState, controller: Controller): State = controller.cancelCurrentFlow() 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 4c54d149cd..d8778d83ba 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 @@ -12,11 +12,6 @@ method executeBackCommand*(self: LoginKeycardMaxPinRetriesReachedState, controll if self.flowType == FlowType.AppLogin and controller.isKeycardCreatedAccountSelectedOne(): controller.runLoginFlow() -method executePrimaryCommand*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller) = - if self.flowType == FlowType.AppLogin: - if not controller.isSelectedLoginAccountKeycardAccount(): - controller.login() - method getNextPrimaryState*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller): State = return createState(StateType.KeycardRecover, self.flowType, self) @@ -26,4 +21,8 @@ method getNextSecondaryState*(self: LoginKeycardMaxPinRetriesReachedState, contr method getNextTertiaryState*(self: LoginKeycardMaxPinRetriesReachedState, controller: Controller): State = controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) \ No newline at end of file + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + +method resolveKeycardNextState*(self: LoginKeycardMaxPinRetriesReachedState, 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_puk_retries_reached_state.nim b/src/app/modules/startup/internal/login_keycard_max_puk_retries_reached_state.nim index 80c2fd6e23..e1e81d589e 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 @@ -11,4 +11,8 @@ proc delete*(self: LoginKeycardMaxPukRetriesReachedState) = method getNextPrimaryState*(self: LoginKeycardMaxPukRetriesReachedState, controller: Controller): State = if self.flowType == FlowType.AppLogin: controller.setRecoverUsingSeedPhraseWhileLogin(true) - return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, nil) \ No newline at end of file + return createState(StateType.UserProfileEnterSeedPhrase, self.flowType, nil) + +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_reading_keycard_state.nim b/src/app/modules/startup/internal/login_keycard_reading_keycard_state.nim index b968a1ff63..4c67544878 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 @@ -14,7 +14,7 @@ method executePrimaryCommand*(self: LoginKeycardReadingKeycardState, controller: if self.flowType == FlowType.AppLogin: if not controller.isSelectedLoginAccountKeycardAccount(): controller.login() - elif not controller.keychainErrorOccurred(): + elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) method getNextPrimaryState*(self: LoginKeycardReadingKeycardState, controller: Controller): State = 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 eeb7b60428..9efaf99ca8 100644 --- a/src/app/modules/startup/internal/login_keycard_wrong_keycard.nim +++ b/src/app/modules/startup/internal/login_keycard_wrong_keycard.nim @@ -12,6 +12,12 @@ method executePrimaryCommand*(self: LoginKeycardWrongKeycardState, controller: C 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(): + return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) method getNextSecondaryState*(self: LoginKeycardWrongKeycardState, controller: Controller): State = controller.cancelCurrentFlow() @@ -19,4 +25,8 @@ method getNextSecondaryState*(self: LoginKeycardWrongKeycardState, controller: C method getNextTertiaryState*(self: LoginKeycardWrongKeycardState, controller: Controller): State = controller.cancelCurrentFlow() - return createState(StateType.WelcomeOldStatusUser, self.flowType, self) \ No newline at end of file + return createState(StateType.WelcomeOldStatusUser, self.flowType, self) + +method resolveKeycardNextState*(self: LoginKeycardWrongKeycardState, 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_wrong_pin_state.nim b/src/app/modules/startup/internal/login_keycard_wrong_pin_state.nim index 24d3088318..06348f1b31 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 @@ -14,9 +14,13 @@ method executePrimaryCommand*(self: LoginKeycardWrongPinState, controller: Contr if self.flowType == FlowType.AppLogin: if not controller.isSelectedLoginAccountKeycardAccount(): controller.login() - elif controller.getPin().len == PINLengthForStatusApp: + elif not controller.keychainErrorOccurred() and controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) +method getNextPrimaryState*(self: LoginKeycardWrongPinState, controller: Controller): State = + if controller.keychainErrorOccurred(): + return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) + method getNextSecondaryState*(self: LoginKeycardWrongPinState, controller: Controller): State = controller.cancelCurrentFlow() return createState(StateType.WelcomeNewStatusUser, self.flowType, self) diff --git a/src/app/modules/startup/internal/login_not_keycard_state.nim b/src/app/modules/startup/internal/login_not_keycard_state.nim new file mode 100644 index 0000000000..620047ff51 --- /dev/null +++ b/src/app/modules/startup/internal/login_not_keycard_state.nim @@ -0,0 +1,25 @@ +type + LoginNotKeycardState* = ref object of State + +proc newLoginNotKeycardState*(flowType: FlowType, backState: State): LoginNotKeycardState = + result = LoginNotKeycardState() + result.setup(flowType, StateType.LoginNotKeycard, backState) + +proc delete*(self: LoginNotKeycardState) = + self.State.delete + +method executePrimaryCommand*(self: LoginNotKeycardState, controller: Controller) = + if self.flowType == FlowType.AppLogin: + controller.runLoadAccountFlow(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) + +method resolveKeycardNextState*(self: LoginNotKeycardState, 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_plugin_state.nim b/src/app/modules/startup/internal/login_plugin_state.nim new file mode 100644 index 0000000000..5c52118e0a --- /dev/null +++ b/src/app/modules/startup/internal/login_plugin_state.nim @@ -0,0 +1,32 @@ +type + LoginPluginState* = ref object of State + +proc newLoginPluginState*(flowType: FlowType, backState: State): LoginPluginState = + result = LoginPluginState() + result.setup(flowType, StateType.LoginPlugin, backState) + +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(): + 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) + +method resolveKeycardNextState*(self: LoginPluginState, 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_state.nim b/src/app/modules/startup/internal/login_state.nim index 29b592306e..667c0690ee 100644 --- a/src/app/modules/startup/internal/login_state.nim +++ b/src/app/modules/startup/internal/login_state.nim @@ -12,6 +12,12 @@ method executePrimaryCommand*(self: LoginState, 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: LoginState, controller: Controller): State = + if controller.keychainErrorOccurred(): + return createState(StateType.LoginKeycardEnterPin, self.flowType, nil) method getNextSecondaryState*(self: LoginState, controller: Controller): State = controller.cancelCurrentFlow() diff --git a/src/app/modules/startup/internal/state.nim b/src/app/modules/startup/internal/state.nim index db9226c848..e1552fd7c5 100644 --- a/src/app/modules/startup/internal/state.nim +++ b/src/app/modules/startup/internal/state.nim @@ -47,6 +47,7 @@ type StateType* {.pure.} = enum KeycardMaxPinRetriesReached = "KeycardMaxPinRetriesReached" KeycardMaxPukRetriesReached = "KeycardMaxPukRetriesReached" Login = "Login" + LoginPlugin = "LoginPlugin" LoginKeycardInsertKeycard = "LoginKeycardInsertKeycard" LoginKeycardReadingKeycard = "LoginKeycardReadingKeycard" LoginKeycardEnterPin = "LoginKeycardEnterPin" @@ -55,6 +56,7 @@ type StateType* {.pure.} = enum LoginKeycardMaxPinRetriesReached = "LoginKeycardMaxPinRetriesReached" LoginKeycardMaxPukRetriesReached = "LoginKeycardMaxPukRetriesReached" LoginKeycardEmpty = "LoginKeycardEmpty" + LoginNotKeycard = "LoginNotKeycard" ## This is the base class for all state we may have in onboarding/login flow. diff --git a/src/app/modules/startup/internal/state_factory.nim b/src/app/modules/startup/internal/state_factory.nim index dd0e8f54a4..6c5f39b1e3 100644 --- a/src/app/modules/startup/internal/state_factory.nim +++ b/src/app/modules/startup/internal/state_factory.nim @@ -47,6 +47,7 @@ include welcome_state_new_user include welcome_state_old_user include welcome_state include login_state +include login_plugin_state include login_keycard_insert_keycard_state include login_keycard_reading_keycard_state include login_keycard_enter_pin_state @@ -55,6 +56,7 @@ 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_empty_state +include login_not_keycard_state proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State = if stateToBeCreated == StateType.AllowNotifications: @@ -119,6 +121,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newKeycardMaxPukRetriesReachedState(flowType, backState) if stateToBeCreated == StateType.Login: return newLoginState(flowType, backState) + if stateToBeCreated == StateType.LoginPlugin: + return newLoginPluginState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardInsertKeycard: return newLoginKeycardInsertKeycardState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardReadingKeycard: @@ -135,6 +139,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newLoginKeycardMaxPukRetriesReachedState(flowType, backState) if stateToBeCreated == StateType.LoginKeycardEmpty: return newLoginKeycardEmptyState(flowType, backState) + if stateToBeCreated == StateType.LoginNotKeycard: + return newLoginNotKeycardState(flowType, backState) error "No implementation available for state ", state=stateToBeCreated @@ -161,9 +167,9 @@ proc ensureReaderAndCardPresenceLogin*(state: State, keycardFlowType: string, ke keycardEvent.error.len > 0 and keycardEvent.error == ErrorConnection: controller.resumeCurrentFlowLater() - if state.stateType == StateType.Login: + if state.stateType == StateType.LoginPlugin: return nil - return createState(StateType.Login, state.flowType, state) + return createState(StateType.LoginPlugin, state.flowType, nil) if keycardFlowType == ResponseTypeValueInsertCard and keycardEvent.error.len > 0 and keycardEvent.error == ErrorConnection: @@ -279,10 +285,10 @@ proc ensureReaderAndCardPresenceAndResolveNextLoginState*(state: State, keycardF if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: return createState(StateType.LoginKeycardMaxPinRetriesReached, state.flowType, nil) if keycardFlowType == ResponseTypeValueSwapCard and - keycardEvent.error.len > 0 and - keycardEvent.error == ErrorNoKeys: - return createState(StateType.LoginKeycardEmpty, state.flowType, nil) - if keycardFlowType == ResponseTypeValueSwapCard and - keycardEvent.error.len > 0 and - keycardEvent.error == RequestParamPUKRetries: - return createState(StateType.LoginKeycardMaxPukRetriesReached, state.flowType, nil) \ No newline at end of file + keycardEvent.error.len > 0: + if keycardEvent.error == ErrorNoKeys: + return createState(StateType.LoginKeycardEmpty, state.flowType, nil) + 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 diff --git a/src/app/modules/startup/module.nim b/src/app/modules/startup/module.nim index f88b57772b..59cc639a26 100644 --- a/src/app/modules/startup/module.nim +++ b/src/app/modules/startup/module.nim @@ -99,7 +99,6 @@ method load*[T](self: Module[T]) = error "cannot run the app in login flow cause list of login accounts is empty" quit() # quit the app self.setSelectedLoginAccount(items[0]) - self.view.setCurrentStartupState(newLoginState(FlowType.AppLogin, nil)) self.delegate.startupDidLoad() method getKeycardSharedModule*[T](self: Module[T]): QVariant = @@ -228,8 +227,8 @@ method importAccountSuccess*[T](self: Module[T]) = method setSelectedLoginAccount*[T](self: Module[T], item: login_acc_item.Item) = 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)) # nim garbage collector will handle all abandoned state objects self.controller.runLoginFlow() else: self.controller.tryToObtainDataFromKeychain() diff --git a/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml b/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml index be2a0cc47a..25d4907a8e 100644 --- a/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml +++ b/ui/app/AppLayouts/Onboarding/OnboardingLayout.qml @@ -64,6 +64,7 @@ OnboardingBasePage { return seedPhraseInputViewComponent } 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.loginKeycardReadingKeycard || root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEnterPin || @@ -71,7 +72,8 @@ OnboardingBasePage { 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.loginKeycardEmpty) + root.startupStore.currentStartupState.stateType === Constants.startupState.loginKeycardEmpty || + root.startupStore.currentStartupState.stateType === Constants.startupState.loginNotKeycard) { return loginViewComponent } diff --git a/ui/app/AppLayouts/Onboarding/views/LoginView.qml b/ui/app/AppLayouts/Onboarding/views/LoginView.qml index 11c3ff7c75..74d2241d17 100644 --- a/ui/app/AppLayouts/Onboarding/views/LoginView.qml +++ b/ui/app/AppLayouts/Onboarding/views/LoginView.qml @@ -518,6 +518,49 @@ Item { target: pinSection visible: false } + PropertyChanges { + target: info + visible: false + } + PropertyChanges { + target: message + text: "" + visible: false + } + PropertyChanges { + target: button + text: "" + visible: false + } + PropertyChanges { + target: link + text: "" + visible: false + } + }, + State { + name: Constants.startupState.loginPlugin + when: root.startupStore.selectedLoginAccount.keycardCreatedAccount && + root.startupStore.currentStartupState.stateType === Constants.startupState.loginPlugin + PropertyChanges { + target: image + source: Style.svg("keycard/card3@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("Plug in Keycard reader...") @@ -908,6 +951,53 @@ Item { text: qsTr("Generate keys for a new Keycard") visible: true } + }, + State { + name: Constants.startupState.loginNotKeycard + 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 + } + PropertyChanges { + target: title + text: "" + visible: false + } + PropertyChanges { + target: passwordSection + visible: false + } + PropertyChanges { + target: pinSection + visible: false + } + PropertyChanges { + target: info + text: qsTr("This is not a Keycard") + visible: true + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.dangerColor1 + } + PropertyChanges { + target: message + text: qsTr("The card inserted is not a recognised Keycard,\nplease remove and try and again") + visible: true + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.baseColor1 + } + PropertyChanges { + target: button + text: "" + visible: false + } + PropertyChanges { + target: link + text: "" + visible: false + } } ] } diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 45fd3f09df..528b808088 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -57,6 +57,7 @@ QtObject { readonly property string keycardMaxPinRetriesReached: "KeycardMaxPinRetriesReached" readonly property string keycardMaxPukRetriesReached: "KeycardMaxPukRetriesReached" readonly property string login: "Login" + readonly property string loginPlugin: "LoginPlugin" readonly property string loginKeycardInsertKeycard: "LoginKeycardInsertKeycard" readonly property string loginKeycardReadingKeycard: "LoginKeycardReadingKeycard" readonly property string loginKeycardEnterPin: "LoginKeycardEnterPin" @@ -65,6 +66,7 @@ QtObject { readonly property string loginKeycardMaxPinRetriesReached: "LoginKeycardMaxPinRetriesReached" readonly property string loginKeycardMaxPukRetriesReached: "LoginKeycardMaxPukRetriesReached" readonly property string loginKeycardEmpty: "LoginKeycardEmpty" + readonly property string loginNotKeycard: "LoginNotKeycard" } readonly property QtObject predefinedKeycardData: QtObject {