From 9b2a63c400fee747c6f045b4ee7a9e3bc47d5d89 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Mon, 17 Oct 2022 12:12:22 +0200 Subject: [PATCH] feat(@desktop/keycard): change pin flow added Fixes: #7034 --- .../profile_section/keycard/io_interface.nim | 2 +- .../main/profile_section/keycard/module.nim | 8 +- .../main/profile_section/keycard/view.nim | 4 +- .../keycard_popup/controller.nim | 4 + .../internal/changing_keycard_pin_state.nim | 17 +++ .../internal/create_pin_state.nim | 6 +- .../internal/enter_pin_state.nim | 29 ++++- .../internal/insert_keycard_state.nim | 4 +- .../keycard_change_pin_failure_state.nim | 17 +++ .../keycard_change_pin_success_state.nim | 17 +++ .../internal/keycard_empty_state.nim | 6 +- .../internal/keycard_inserted_state.nim | 3 +- .../max_pairing_slots_reached_state.nim | 6 +- .../max_pin_retries_reached_state.nim | 6 +- .../max_puk_retries_reached_state.nim | 6 +- .../internal/not_keycard_state.nim | 3 +- .../internal/pin_verified_state.nim | 5 +- .../internal/plugin_reader_state.nim | 3 +- .../internal/reading_keycard_state.nim | 3 +- .../internal/recognized_keycard_state.nim | 2 + .../internal/repeat_pin_state.nim | 13 +- .../keycard_popup/internal/state.nim | 3 + .../keycard_popup/internal/state_factory.nim | 43 ++++++- .../internal/wrong_keycard_state.nim | 6 +- .../internal/wrong_pin_state.nim | 28 ++++- .../keycard_popup/io_interface.nim | 1 + .../keycard_popup/models/keycard_model.nim | 6 + .../shared_modules/keycard_popup/module.nim | 8 +- src/app_service/service/keycard/constants.nim | 2 +- src/app_service/service/keycard/service.nim | 5 + .../Profile/stores/KeycardStore.qml | 4 +- .../Profile/views/keycard/DetailsView.qml | 2 +- .../shared/popups/keycard/KeycardPopup.qml | 52 +++++++- .../popups/keycard/states/KeycardInit.qml | 37 +++++- .../popups/keycard/states/KeycardPin.qml | 115 +++++++++++++----- ui/imports/utils/Constants.qml | 4 + 36 files changed, 406 insertions(+), 74 deletions(-) create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pin_state.nim create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_failure_state.nim create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_success_state.nim diff --git a/src/app/modules/main/profile_section/keycard/io_interface.nim b/src/app/modules/main/profile_section/keycard/io_interface.nim index e577b2889b..c1b849ad6e 100644 --- a/src/app/modules/main/profile_section/keycard/io_interface.nim +++ b/src/app/modules/main/profile_section/keycard/io_interface.nim @@ -50,7 +50,7 @@ method runFactoryResetPopup*(self: AccessInterface) {.base.} = method runRenameKeycardPopup*(self: AccessInterface, keycardUid: string, keyUid: string) {.base.} = raise newException(ValueError, "No implementation available") -method runChangePinPopup*(self: AccessInterface) {.base.} = +method runChangePinPopup*(self: AccessInterface, keycardUid: string, keyUid: string) {.base.} = raise newException(ValueError, "No implementation available") method runCreateBackupCopyOfAKeycardPopup*(self: AccessInterface) {.base.} = diff --git a/src/app/modules/main/profile_section/keycard/module.nim b/src/app/modules/main/profile_section/keycard/module.nim index 2126c5a9fa..1a8f004332 100644 --- a/src/app/modules/main/profile_section/keycard/module.nim +++ b/src/app/modules/main/profile_section/keycard/module.nim @@ -145,8 +145,12 @@ method runRenameKeycardPopup*(self: Module, keycardUid: string, keyUid: string) self.keycardSharedModule.setUidOfAKeycardWhichNeedToBeProcessed(keycardUid) self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.RenameKeycard, keyUid) -method runChangePinPopup*(self: Module) = - info "TODO: Change PIN for a Keycard..." +method runChangePinPopup*(self: Module, keycardUid: string, keyUid: string) = + self.createSharedKeycardModule() + if self.keycardSharedModule.isNil: + return + self.keycardSharedModule.setUidOfAKeycardWhichNeedToBeProcessed(keycardUid) + self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ChangeKeycardPin, keyUid) method runCreateBackupCopyOfAKeycardPopup*(self: Module) = info "TODO: Create a Backup Copy of a Keycard..." diff --git a/src/app/modules/main/profile_section/keycard/view.nim b/src/app/modules/main/profile_section/keycard/view.nim index 6081901623..bdc2e3c657 100644 --- a/src/app/modules/main/profile_section/keycard/view.nim +++ b/src/app/modules/main/profile_section/keycard/view.nim @@ -67,8 +67,8 @@ QtObject: proc runRenameKeycardPopup*(self: View, keycardUid: string, keyUid: string) {.slot.} = self.delegate.runRenameKeycardPopup(keycardUid, keyUid) - proc runChangePinPopup*(self: View) {.slot.} = - self.delegate.runChangePinPopup() + proc runChangePinPopup*(self: View, keycardUid: string, keyUid: string) {.slot.} = + self.delegate.runChangePinPopup(keycardUid, keyUid) proc runCreateBackupCopyOfAKeycardPopup*(self: View) {.slot.} = self.delegate.runCreateBackupCopyOfAKeycardPopup() diff --git a/src/app/modules/shared_modules/keycard_popup/controller.nim b/src/app/modules/shared_modules/keycard_popup/controller.nim index 8efa5df8ba..6f16ec0fec 100644 --- a/src/app/modules/shared_modules/keycard_popup/controller.nim +++ b/src/app/modules/shared_modules/keycard_popup/controller.nim @@ -300,6 +300,10 @@ proc runGetMetadataFlow*(self: Controller, resolveAddress = false) = self.cancelCurrentFlow() self.keycardService.startGetMetadataFlow(resolveAddress) +proc runChangePinFlow*(self: Controller) = + self.cancelCurrentFlow() + self.keycardService.startChangePinFlow() + proc runStoreMetadataFlow*(self: Controller, cardName: string, pin: string, walletPaths: seq[string]) = self.cancelCurrentFlow() self.keycardService.startStoreMetadataFlow(cardName, pin, walletPaths) diff --git a/src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pin_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pin_state.nim new file mode 100644 index 0000000000..64ee3b2043 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pin_state.nim @@ -0,0 +1,17 @@ +type + ChangingKeycardPinState* = ref object of State + +proc newChangingKeycardPinState*(flowType: FlowType, backState: State): ChangingKeycardPinState = + result = ChangingKeycardPinState() + result.setup(flowType, StateType.ChangingKeycardPin, backState) + +proc delete*(self: ChangingKeycardPinState) = + self.State.delete + +method executeSecondaryCommand*(self: ChangingKeycardPinState, controller: Controller) = + if self.flowType == FlowType.ChangeKeycardPin: + controller.storePinToKeycard(controller.getPin(), "") + +method resolveKeycardNextState*(self: ChangingKeycardPinState, keycardFlowType: string, keycardEvent: KeycardEvent, + controller: Controller): State = + return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/create_pin_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/create_pin_state.nim index 06ba411c7a..2739886afc 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/create_pin_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/create_pin_state.nim @@ -17,11 +17,13 @@ method executeBackCommand*(self: CreatePinState, controller: Controller) = method executeTertiaryCommand*(self: CreatePinState, controller: Controller) = if self.flowType == FlowType.SetupNewKeycard or - self.flowType == FlowType.UnlockKeycard: + self.flowType == FlowType.UnlockKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method getNextSecondaryState*(self: CreatePinState, controller: Controller): State = if self.flowType == FlowType.SetupNewKeycard or - self.flowType == FlowType.UnlockKeycard: + self.flowType == FlowType.UnlockKeycard or + self.flowType == FlowType.ChangeKeycardPin: if controller.getPin().len == PINLengthForStatusApp: return createState(StateType.RepeatPin, self.flowType, self) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/enter_pin_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/enter_pin_state.nim index ed212f5392..e115b636f9 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/enter_pin_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/enter_pin_state.nim @@ -20,7 +20,8 @@ method executeSecondaryCommand*(self: EnterPinState, controller: Controller) = if self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.FactoryReset or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: if controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) if self.flowType == FlowType.Authentication: @@ -32,7 +33,8 @@ method executeTertiaryCommand*(self: EnterPinState, controller: Controller) = self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.Authentication or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent, @@ -140,4 +142,25 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke return createState(StateType.MaxPinRetriesReached, self.flowType, nil) if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setMetadataFromKeycard(keycardEvent.cardMetadata, updateKeyPair = true) - return createState(StateType.PinVerified, self.flowType, nil) \ No newline at end of file + return createState(StateType.PinVerified, self.flowType, nil) + if self.flowType == FlowType.ChangeKeycardPin: + if keycardFlowType == ResponseTypeValueEnterPIN and + keycardEvent.error.len > 0 and + keycardEvent.error == ErrorPIN: + controller.setKeycardData($keycardEvent.pinRetries) + if keycardEvent.pinRetries > 0: + return createState(StateType.WrongPin, self.flowType, nil) + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true)) + return createState(StateType.MaxPinRetriesReached, self.flowType, nil) + if keycardFlowType == ResponseTypeValueEnterPIN and + keycardEvent.error.len == 0: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true)) + return createState(StateType.MaxPinRetriesReached, self.flowType, nil) + if keycardFlowType == ResponseTypeValueEnterPUK and + keycardEvent.error.len == 0: + if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true)) + return createState(StateType.MaxPinRetriesReached, self.flowType, nil) + if keycardFlowType == ResponseTypeValueEnterNewPIN: + if keycardEvent.error == ErrorChangingCredentials: + return createState(StateType.PinVerified, self.flowType, nil) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/insert_keycard_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/insert_keycard_state.nim index ee12cb7235..f8f9a1d925 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/insert_keycard_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/insert_keycard_state.nim @@ -18,7 +18,9 @@ method executeTertiaryCommand*(self: InsertKeycardState, controller: Controller) self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or - self.flowType == FlowType.DisplayKeycardContent: + self.flowType == FlowType.DisplayKeycardContent or + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent, diff --git a/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_failure_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_failure_state.nim new file mode 100644 index 0000000000..21e463d5a6 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_failure_state.nim @@ -0,0 +1,17 @@ +type + ChangingKeycardPinFailureState* = ref object of State + +proc newChangingKeycardPinFailureState*(flowType: FlowType, backState: State): ChangingKeycardPinFailureState = + result = ChangingKeycardPinFailureState() + result.setup(flowType, StateType.ChangingKeycardPinFailure, backState) + +proc delete*(self: ChangingKeycardPinFailureState) = + self.State.delete + +method executePrimaryCommand*(self: ChangingKeycardPinFailureState, controller: Controller) = + if self.flowType == FlowType.ChangeKeycardPin: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) + +method executeTertiaryCommand*(self: ChangingKeycardPinFailureState, controller: Controller) = + if self.flowType == FlowType.ChangeKeycardPin: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_success_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_success_state.nim new file mode 100644 index 0000000000..f019d88e78 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pin_success_state.nim @@ -0,0 +1,17 @@ +type + ChangingKeycardPinSuccessState* = ref object of State + +proc newChangingKeycardPinSuccessState*(flowType: FlowType, backState: State): ChangingKeycardPinSuccessState = + result = ChangingKeycardPinSuccessState() + result.setup(flowType, StateType.ChangingKeycardPinSuccess, backState) + +proc delete*(self: ChangingKeycardPinSuccessState) = + self.State.delete + +method executePrimaryCommand*(self: ChangingKeycardPinSuccessState, controller: Controller) = + if self.flowType == FlowType.ChangeKeycardPin: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) + +method executeTertiaryCommand*(self: ChangingKeycardPinSuccessState, controller: Controller) = + if self.flowType == FlowType.ChangeKeycardPin: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/keycard_empty_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/keycard_empty_state.nim index 569e4c3f03..57cbf5ae56 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/keycard_empty_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/keycard_empty_state.nim @@ -13,7 +13,8 @@ method executePrimaryCommand*(self: KeycardEmptyState, controller: Controller) = self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method executeTertiaryCommand*(self: KeycardEmptyState, controller: Controller) = @@ -21,5 +22,6 @@ method executeTertiaryCommand*(self: KeycardEmptyState, controller: Controller) self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/keycard_inserted_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/keycard_inserted_state.nim index 13d96fe730..06644ec600 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/keycard_inserted_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/keycard_inserted_state.nim @@ -26,5 +26,6 @@ method executeTertiaryCommand*(self: KeycardInsertedState, controller: Controlle self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) diff --git a/src/app/modules/shared_modules/keycard_popup/internal/max_pairing_slots_reached_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/max_pairing_slots_reached_state.nim index 69aced83ed..1999418f57 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/max_pairing_slots_reached_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/max_pairing_slots_reached_state.nim @@ -14,7 +14,8 @@ method getNextPrimaryState*(self: MaxPairingSlotsReachedState, controller: Contr return createState(StateType.FactoryResetConfirmation, self.flowType, self) if self.flowType == FlowType.Authentication or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.runSharedModuleFlow(FlowType.UnlockKeycard) return nil @@ -24,5 +25,6 @@ method executeTertiaryCommand*(self: MaxPairingSlotsReachedState, controller: Co self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/max_pin_retries_reached_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/max_pin_retries_reached_state.nim index 3f95659cc7..e115e1ee40 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/max_pin_retries_reached_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/max_pin_retries_reached_state.nim @@ -11,7 +11,8 @@ proc delete*(self: MaxPinRetriesReachedState) = method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Controller): State = if self.flowType == FlowType.FactoryReset or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.runSharedModuleFlow(FlowType.UnlockKeycard) if self.flowType == FlowType.SetupNewKeycard: let currValue = extractPredefinedKeycardDataToNumber(controller.getKeycardData()) @@ -27,7 +28,8 @@ method executeTertiaryCommand*(self: MaxPinRetriesReachedState, controller: Cont if self.flowType == FlowType.FactoryReset or self.flowType == FlowType.Authentication or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) if self.flowType == FlowType.SetupNewKeycard: controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseUnlockLabelForLockedState, add = false)) diff --git a/src/app/modules/shared_modules/keycard_popup/internal/max_puk_retries_reached_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/max_puk_retries_reached_state.nim index 22654c550f..5aa51a166b 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/max_puk_retries_reached_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/max_puk_retries_reached_state.nim @@ -14,7 +14,8 @@ method getNextPrimaryState*(self: MaxPukRetriesReachedState, controller: Control return createState(StateType.FactoryResetConfirmation, self.flowType, self) if self.flowType == FlowType.Authentication or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.runSharedModuleFlow(FlowType.UnlockKeycard) if self.flowType == FlowType.UnlockKeycard: return createState(StateType.EnterSeedPhrase, self.flowType, self) @@ -25,5 +26,6 @@ method executeTertiaryCommand*(self: MaxPukRetriesReachedState, controller: Cont self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/not_keycard_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/not_keycard_state.nim index 41d41ea95b..c2d13ac234 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/not_keycard_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/not_keycard_state.nim @@ -14,5 +14,6 @@ method executeTertiaryCommand*(self: NotKeycardState, controller: Controller) = self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/pin_verified_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/pin_verified_state.nim index 3b9938764b..3866cc1e5e 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/pin_verified_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/pin_verified_state.nim @@ -14,11 +14,14 @@ method getNextPrimaryState*(self: PinVerifiedState, controller: Controller): Sta self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard: return createState(StateType.KeycardMetadataDisplay, self.flowType, nil) + if self.flowType == FlowType.ChangeKeycardPin: + return createState(StateType.CreatePin, self.flowType, nil) return nil method executeTertiaryCommand*(self: PinVerifiedState, controller: Controller) = if self.flowType == FlowType.FactoryReset or self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/plugin_reader_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/plugin_reader_state.nim index d7fa7df1c8..e0ec5500d2 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/plugin_reader_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/plugin_reader_state.nim @@ -19,7 +19,8 @@ method executeTertiaryCommand*(self: PluginReaderState, controller: Controller) self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent, diff --git a/src/app/modules/shared_modules/keycard_popup/internal/reading_keycard_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/reading_keycard_state.nim index 48ed01169c..55a6c8b9c2 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/reading_keycard_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/reading_keycard_state.nim @@ -24,7 +24,8 @@ method getNextSecondaryState*(self: ReadingKeycardState, controller: Controller) method resolveKeycardNextState*(self: ReadingKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State = if self.flowType == FlowType.UnlockKeycard or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: # this part is only for the flows which are card specific (the card we're running a flow for is known in advance) let ensureKeycardPresenceState = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller) if ensureKeycardPresenceState.isNil: # means the keycard is inserted diff --git a/src/app/modules/shared_modules/keycard_popup/internal/recognized_keycard_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/recognized_keycard_state.nim index 9ed72476ff..6e3a003394 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/recognized_keycard_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/recognized_keycard_state.nim @@ -27,6 +27,8 @@ method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controll return createState(StateType.EnterPin, self.flowType, nil) if self.flowType == FlowType.RenameKeycard: return createState(StateType.EnterPin, self.flowType, nil) + if self.flowType == FlowType.ChangeKeycardPin: + return createState(StateType.EnterPin, self.flowType, nil) method executeTertiaryCommand*(self: RecognizedKeycardState, controller: Controller) = error "recognized state must not be canceled" \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim index d66f207214..4a89164d78 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/repeat_pin_state.nim @@ -17,11 +17,18 @@ method executeSecondaryCommand*(self: RepeatPinState, controller: Controller) = return if self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.UnlockKeycard: - controller.storePinToKeycard(controller.getPin(), controller.generateRandomPUK()) + controller.storePinToKeycard(controller.getPin(), controller.generateRandomPUK()) + +method getNextSecondaryState*(self: RepeatPinState, controller: Controller): State = + if not controller.getPinMatch(): + return + if self.flowType == FlowType.ChangeKeycardPin: + return createState(StateType.ChangingKeycardPin, self.flowType, nil) method executeTertiaryCommand*(self: RepeatPinState, controller: Controller) = if self.flowType == FlowType.SetupNewKeycard or - self.flowType == FlowType.UnlockKeycard: + self.flowType == FlowType.UnlockKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: RepeatPinState, keycardFlowType: string, keycardEvent: KeycardEvent, @@ -62,4 +69,4 @@ method resolveKeycardNextState*(self: RepeatPinState, keycardFlowType: string, k if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.instanceUID.len > 0: controller.updateKeycardUid(keycardEvent.instanceUID) - return createState(StateType.PinSet, self.flowType, nil) \ No newline at end of file + return createState(StateType.PinSet, self.flowType, nil) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/state.nim b/src/app/modules/shared_modules/keycard_popup/internal/state.nim index 45f2dba750..4fd80801a9 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/state.nim @@ -56,6 +56,9 @@ type StateType* {.pure.} = enum RenamingKeycard = "RenamingKeycard" KeycardRenameSuccess = "KeycardRenameSuccess" KeycardRenameFailure = "KeycardRenameFailure" + ChangingKeycardPin = "ChangingKeycardPin" + ChangingKeycardPinSuccess = "ChangingKeycardPinSuccess" + ChangingKeycardPinFailure = "ChangingKeycardPinFailure" ## This is the base class for all state we may have in onboarding/login flow. diff --git a/src/app/modules/shared_modules/keycard_popup/internal/state_factory.nim b/src/app/modules/shared_modules/keycard_popup/internal/state_factory.nim index 956eaba099..9025f4c302 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/state_factory.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/state_factory.nim @@ -32,6 +32,7 @@ include biometrics_password_failed_state include biometrics_pin_failed_state include biometrics_pin_invalid_state include biometrics_ready_to_sign_state +include changing_keycard_pin_state include create_pin_state include enter_biometrics_password_state include enter_keycard_name_state @@ -45,6 +46,8 @@ include factory_reset_success_state include insert_keycard_state include key_pair_migrate_failure_state include key_pair_migrate_success_state +include keycard_change_pin_failure_state +include keycard_change_pin_success_state include keycard_empty_metadata_state include keycard_empty_state include keycard_inserted_state @@ -112,6 +115,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newBiometricsPinInvalidState(flowType, backState) if stateToBeCreated == StateType.BiometricsReadyToSign: return newBiometricsReadyToSignState(flowType, backState) + if stateToBeCreated == StateType.ChangingKeycardPin: + return newChangingKeycardPinState(flowType, backState) if stateToBeCreated == StateType.CreatePin: return newCreatePinState(flowType, backState) if stateToBeCreated == StateType.EnterBiometricsPassword: @@ -138,6 +143,10 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newKeyPairMigrateFailureState(flowType, backState) if stateToBeCreated == StateType.KeyPairMigrateSuccess: return newKeyPairMigrateSuccessState(flowType, backState) + if stateToBeCreated == StateType.ChangingKeycardPinFailure: + return newChangingKeycardPinFailureState(flowType, backState) + if stateToBeCreated == StateType.ChangingKeycardPinSuccess: + return newChangingKeycardPinSuccessState(flowType, backState) if stateToBeCreated == StateType.KeycardInserted: return newKeycardInsertedState(flowType, backState) if stateToBeCreated == StateType.KeycardEmptyMetadata: @@ -211,7 +220,8 @@ proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycard state.flowType == FlowType.Authentication or state.flowType == FlowType.UnlockKeycard or state.flowType == FlowType.DisplayKeycardContent or - state.flowType == FlowType.RenameKeycard: + state.flowType == FlowType.RenameKeycard or + state.flowType == FlowType.ChangeKeycardPin: if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len > 0 and keycardEvent.error == ErrorConnection: @@ -444,3 +454,34 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy return createState(StateType.KeycardEmpty, state.flowType, nil) if keycardEvent.error == ErrorNoData: return createState(StateType.KeycardEmptyMetadata, state.flowType, nil) + + if state.flowType == FlowType.ChangeKeycardPin: + if keycardFlowType == ResponseTypeValueEnterPIN and + keycardEvent.error.len == 0: + return createState(StateType.RecognizedKeycard, state.flowType, nil) + if keycardFlowType == ResponseTypeValueEnterPUK and + keycardEvent.error.len == 0: + if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true)) + return createState(StateType.MaxPinRetriesReached, state.flowType, nil) + if keycardFlowType == ResponseTypeValueSwapCard and + keycardEvent.error.len > 0: + if keycardEvent.error == ErrorNotAKeycard: + return createState(StateType.NotKeycard, state.flowType, nil) + if keycardEvent.error == ErrorNoKeys: + return createState(StateType.KeycardEmpty, state.flowType, nil) + if keycardEvent.error == ErrorFreePairingSlots: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true)) + return createState(StateType.MaxPairingSlotsReached, state.flowType, nil) + if keycardEvent.error == ErrorPUKRetries: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true)) + return createState(StateType.MaxPukRetriesReached, state.flowType, nil) + if keycardFlowType == ResponseTypeValueKeycardFlowResult: + if keycardEvent.error.len > 0: + if keycardEvent.error == ErrorNoKeys: + return createState(StateType.KeycardEmpty, state.flowType, nil) + if keycardEvent.error == ErrorNoData: + return createState(StateType.KeycardEmptyMetadata, state.flowType, nil) + if keycardEvent.error.len == 0: + return createState(StateType.ChangingKeycardPinSuccess, state.flowType, nil) + return createState(StateType.ChangingKeycardPinFailure, state.flowType, nil) diff --git a/src/app/modules/shared_modules/keycard_popup/internal/wrong_keycard_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/wrong_keycard_state.nim index 341d78e10a..06fb6770c1 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/wrong_keycard_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/wrong_keycard_state.nim @@ -10,11 +10,13 @@ proc delete*(self: WrongKeycardState) = method executePrimaryCommand*(self: WrongKeycardState, controller: Controller) = if self.flowType == FlowType.UnlockKeycard or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) method executeTertiaryCommand*(self: WrongKeycardState, controller: Controller) = if self.flowType == FlowType.Authentication or self.flowType == FlowType.UnlockKeycard or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/wrong_pin_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/wrong_pin_state.nim index 4e21e84bd2..136e05258f 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/wrong_pin_state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/wrong_pin_state.nim @@ -16,14 +16,16 @@ method getNextPrimaryState*(self: WrongPinState, controller: Controller): State if controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) if self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.runSharedModuleFlow(FlowType.FactoryReset) method executeSecondaryCommand*(self: WrongPinState, controller: Controller) = if self.flowType == FlowType.FactoryReset or self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: if controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) if self.flowType == FlowType.Authentication: @@ -35,7 +37,8 @@ method executeTertiaryCommand*(self: WrongPinState, controller: Controller) = self.flowType == FlowType.SetupNewKeycard or self.flowType == FlowType.Authentication or self.flowType == FlowType.DisplayKeycardContent or - self.flowType == FlowType.RenameKeycard: + self.flowType == FlowType.RenameKeycard or + self.flowType == FlowType.ChangeKeycardPin: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, keycardEvent: KeycardEvent, @@ -122,4 +125,21 @@ method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, ke return createState(StateType.MaxPinRetriesReached, self.flowType, nil) if keycardFlowType == ResponseTypeValueKeycardFlowResult: controller.setMetadataFromKeycard(keycardEvent.cardMetadata, updateKeyPair = true) - return createState(StateType.PinVerified, self.flowType, nil) \ No newline at end of file + return createState(StateType.PinVerified, self.flowType, nil) + if self.flowType == FlowType.ChangeKeycardPin: + if keycardFlowType == ResponseTypeValueEnterPIN and + keycardEvent.error.len > 0 and + keycardEvent.error == ErrorPIN: + controller.setKeycardData($keycardEvent.pinRetries) + if keycardEvent.pinRetries > 0: + return self + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true)) + return createState(StateType.MaxPinRetriesReached, self.flowType, nil) + if keycardFlowType == ResponseTypeValueEnterPUK and + keycardEvent.error.len == 0: + if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0: + controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.HideKeyPair, add = true)) + return createState(StateType.MaxPinRetriesReached, self.flowType, nil) + if keycardFlowType == ResponseTypeValueEnterNewPIN: + if keycardEvent.error == ErrorChangingCredentials: + return createState(StateType.PinVerified, self.flowType, nil) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/io_interface.nim b/src/app/modules/shared_modules/keycard_popup/io_interface.nim index d3cfdb86d7..765e7556ca 100644 --- a/src/app/modules/shared_modules/keycard_popup/io_interface.nim +++ b/src/app/modules/shared_modules/keycard_popup/io_interface.nim @@ -58,6 +58,7 @@ type FlowType* {.pure.} = enum UnlockKeycard = "UnlockKeycard" DisplayKeycardContent = "DisplayKeycardContent" RenameKeycard = "RenameKeycard" + ChangeKeycardPin = "ChangeKeycardPin" type AccessInterface* {.pure inheritable.} = ref object of RootObj diff --git a/src/app/modules/shared_modules/keycard_popup/models/keycard_model.nim b/src/app/modules/shared_modules/keycard_popup/models/keycard_model.nim index 3d538ac305..a8d7d40719 100644 --- a/src/app/modules/shared_modules/keycard_popup/models/keycard_model.nim +++ b/src/app/modules/shared_modules/keycard_popup/models/keycard_model.nim @@ -44,6 +44,12 @@ QtObject: self.endResetModel() self.countChanged() + proc addItem*(self: KeycardModel, item: KeycardItem) = + self.beginInsertRows(newQModelIndex(), self.items.len, self.items.len) + self.items.add(item) + self.endInsertRows() + self.countChanged() + proc `$`*(self: KeycardModel): string = for i in 0 ..< self.items.len: result &= fmt"""KeycardModel: diff --git a/src/app/modules/shared_modules/keycard_popup/module.nim b/src/app/modules/shared_modules/keycard_popup/module.nim index c1edd361a5..fe12a39cbf 100644 --- a/src/app/modules/shared_modules/keycard_popup/module.nim +++ b/src/app/modules/shared_modules/keycard_popup/module.nim @@ -320,7 +320,8 @@ proc prepareKeyPairForProcessing[T](self: Module[T], keyUid: string) = error "sm_cannot find keypair among migrated keypairs for the given keyUid for processing", keyUid=keyUid else: item.setLocked(keyPairs[0].keycardLocked) - item.setIcon("keycard") + if item.pairType != KeyPairType.Profile: + item.setIcon("keycard") self.view.setKeyPairForProcessing(item) method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path = "", txHash = "") = @@ -375,6 +376,11 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path self.tmpLocalState = newReadingKeycardState(flowToRun, nil) self.controller.runGetMetadataFlow(resolveAddress = true) # we're firstly displaying the keycard content return + if flowToRun == FlowType.ChangeKeycardPin: + self.prepareKeyPairForProcessing(keyUid) + self.tmpLocalState = newReadingKeycardState(flowToRun, nil) + self.controller.runChangePinFlow() + return method setSelectedKeyPair*[T](self: Module[T], item: KeyPairItem) = var paths: seq[string] diff --git a/src/app_service/service/keycard/constants.nim b/src/app_service/service/keycard/constants.nim index fa287522bd..f3dfe80024 100644 --- a/src/app_service/service/keycard/constants.nim +++ b/src/app_service/service/keycard/constants.nim @@ -11,7 +11,7 @@ const ErrorPairing* = "pairing" const ErrorUnblocking* = "unblocking" const ErrorSigning* = "signing" const ErrorExporting* = "exporting" -const ErrorChanging* = "changing-credentials" +const ErrorChangingCredentials* = "changing-credentials" const ErrorLoadingKeys* = "loading-keys" const ErrorStoreMeta* = "storing-metadata" const ErrorNoData* = "no-data" diff --git a/src/app_service/service/keycard/service.nim b/src/app_service/service/keycard/service.nim index a4d3d879e7..6b2e98761f 100644 --- a/src/app_service/service/keycard/service.nim +++ b/src/app_service/service/keycard/service.nim @@ -222,6 +222,11 @@ QtObject: self.currentFlow = KCSFlowType.GetMetadata self.startFlow(payload) + proc startChangePinFlow*(self: Service) = + var payload = %* { } + self.currentFlow = KCSFlowType.ChangePIN + self.startFlow(payload) + proc startStoreMetadataFlow*(self: Service, cardName: string, pin: string, walletPaths: seq[string]) = var name = cardName if cardName.len > CardNameLength: diff --git a/ui/app/AppLayouts/Profile/stores/KeycardStore.qml b/ui/app/AppLayouts/Profile/stores/KeycardStore.qml index 8559ee00cf..a33ba361b5 100644 --- a/ui/app/AppLayouts/Profile/stores/KeycardStore.qml +++ b/ui/app/AppLayouts/Profile/stores/KeycardStore.qml @@ -38,8 +38,8 @@ QtObject { root.keycardModule.runRenameKeycardPopup(keycardUid, keyUid) } - function runChangePinPopup() { - root.keycardModule.runChangePinPopup() + function runChangePinPopup(keycardUid, keyUid) { + root.keycardModule.runChangePinPopup(keycardUid, keyUid) } function runCreateBackupCopyOfAKeycardPopup() { diff --git a/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml b/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml index e7f38e4d3e..ed13588dea 100644 --- a/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml +++ b/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml @@ -99,7 +99,7 @@ ColumnLayout { } ] onClicked: { - root.keycardStore.runChangePinPopup() + root.keycardStore.runChangePinPopup(root.keycardUid, d.keyUid) } } diff --git a/ui/imports/shared/popups/keycard/KeycardPopup.qml b/ui/imports/shared/popups/keycard/KeycardPopup.qml index df5557fa48..01fc99f05a 100644 --- a/ui/imports/shared/popups/keycard/KeycardPopup.qml +++ b/ui/imports/shared/popups/keycard/KeycardPopup.qml @@ -61,6 +61,9 @@ StatusModal { if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.renameKeycard) { return qsTr("Rename Keycard") } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + return qsTr("Change pin") + } return "" } @@ -71,6 +74,7 @@ StatusModal { readonly property bool disablePopupClose: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess && root.sharedKeycardModule.migratingProfileKeyPair()) @@ -101,6 +105,7 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardRenameSuccess || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardRenameFailure || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty || @@ -136,6 +141,8 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinSuccess || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinFailure || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified) { @@ -443,6 +450,23 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached) return qsTr("Cancel") } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPukRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached) + return qsTr("Cancel") + } return "" } @@ -450,7 +474,8 @@ StatusModal { enabled: { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard) { + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin) { if (d.disablePopupClose) { return false } @@ -501,7 +526,8 @@ StatusModal { enabled: { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard) { + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin) { if (d.disablePopupClose) { return false } @@ -711,13 +737,33 @@ StatusModal { return qsTr("Rename this Keycard") } } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinSuccess || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinFailure) + return qsTr("Done") + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin) { + return qsTr("I don’t know the PIN") + } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified) { + return qsTr("Next") + } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPukRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached) { + return qsTr("Unlock Keycard") + } + } + return "" } visible: text !== "" enabled: { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard) { + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin) { if (d.disablePopupClose) { return false } diff --git a/ui/imports/shared/popups/keycard/states/KeycardInit.qml b/ui/imports/shared/popups/keycard/states/KeycardInit.qml index 41cab9ec3c..1fc914cfb2 100644 --- a/ui/imports/shared/popups/keycard/states/KeycardInit.qml +++ b/ui/imports/shared/popups/keycard/states/KeycardInit.qml @@ -31,7 +31,8 @@ Item { Timer { id: timer interval: 1000 - running: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard + running: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin onTriggered: { root.sharedKeycardModule.currentState.doSecondaryAction() } @@ -143,7 +144,8 @@ Item { id: loading visible: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin } StatusBaseText { id: title @@ -217,6 +219,17 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardRenameFailure) return true } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin && !d.hideKeyPair) { + if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPukRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard) + return true + } return false } @@ -287,6 +300,17 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard) return keyPairForProcessingComponent } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPukRetriesReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard) + return keyPairForProcessingComponent + } return undefined } @@ -378,7 +402,8 @@ Item { name: "processing" when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin PropertyChanges { target: title text: { @@ -391,6 +416,9 @@ Item { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard) { return qsTr("Renaming keycard...") } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin) { + return qsTr("Updating PIN") + } return "" } font.pixelSize: Constants.keycard.general.fontSize2 @@ -488,7 +516,8 @@ Item { target: message text: { if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication || - root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.renameKeycard) { + root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.renameKeycard || + root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { return qsTr("Keycard inserted does not match the Keycard below") } if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.unlockKeycard) { diff --git a/ui/imports/shared/popups/keycard/states/KeycardPin.qml b/ui/imports/shared/popups/keycard/states/KeycardPin.qml index a723df2760..e9d9752a3a 100644 --- a/ui/imports/shared/popups/keycard/states/KeycardPin.qml +++ b/ui/imports/shared/popups/keycard/states/KeycardPin.qml @@ -30,8 +30,7 @@ Item { } onStateChanged: { - if(state === Constants.keycardSharedState.pinSet || - state === Constants.keycardSharedState.pinVerified) { + if(d.useFakePin) { pinInputField.setPin("123456") // we are free to set fake pin in this case } else { pinInputField.statesInitialization() @@ -39,7 +38,11 @@ Item { } } - Component.onCompleted: timer.start() + Component.onCompleted: { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication) { + timer.start() + } + } Timer { id: timer @@ -50,6 +53,16 @@ Item { } } + QtObject { + id: d + readonly property bool useFakePin: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinSuccess || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinFailure + readonly property string message1: qsTr("It is very important that you do not lose this PIN") + readonly property string message2: qsTr("Don’t lose your PIN! If you do, you may lose\naccess to your funds.") + } + Component { id: keyPairComponent KeyPairItem { @@ -111,31 +124,32 @@ Item { Layout.alignment: Qt.AlignHCenter validator: StatusIntValidator{bottom: 0; top: 999999;} pinLen: Constants.keycard.general.keycardPinLength - enabled: root.sharedKeycardModule.currentState.stateType !== Constants.keycardSharedState.pinSet && - root.sharedKeycardModule.currentState.stateType !== Constants.keycardSharedState.pinVerified - + enabled: !d.useFakePin onPinInputChanged: { root.pinUpdated(pinInput) - if (root.state !== Constants.keycardSharedState.wrongPin || - root.state === Constants.keycardSharedState.wrongKeychainPin) { + if (root.sharedKeycardModule.currentState.stateType !== Constants.keycardSharedState.wrongPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin) { image.source = Style.png("keycard/enter-pin-%1".arg(pinInput.length)) } if(pinInput.length == 0) { return } - if(root.state === Constants.keycardSharedState.createPin || - root.state === Constants.keycardSharedState.enterPin || - root.state === Constants.keycardSharedState.wrongPin || - root.state === Constants.keycardSharedState.wrongKeychainPin) { + if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin) { root.sharedKeycardModule.setPin(pinInput) if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication) return root.sharedKeycardModule.currentState.doSecondaryAction() } - else if(root.state === Constants.keycardSharedState.repeatPin) { + else if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.repeatPin) { let pinsMatch = root.sharedKeycardModule.checkRepeatedKeycardPinWhileTyping(pinInput) if (pinsMatch) { - info.text = qsTr("It is very important that you do not lose this PIN") + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) + info.text = d.message2 + else + info.text = d.message1 root.sharedKeycardModule.currentState.doSecondaryAction() } else { info.text = qsTr("PINs don't match") @@ -148,6 +162,7 @@ Item { StatusBaseText { id: info Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap visible: text !== "" } @@ -155,6 +170,7 @@ Item { StatusBaseText { id: message Layout.alignment: Qt.AlignCenter + horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap visible: text !== "" } @@ -220,7 +236,12 @@ Item { } PropertyChanges { target: title - text: qsTr("Enter this Keycard’s PIN") + text: { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + return qsTr("Enter the Keycard PIN") + } + return qsTr("Enter this Keycard’s PIN") + } font.pixelSize: Constants.keycard.general.fontSize1 color: Theme.palette.directColor1 } @@ -315,7 +336,12 @@ Item { } PropertyChanges { target: title - text: qsTr("Choose a Keycard PIN") + text: { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + return qsTr("Enter new Keycard PIN") + } + return qsTr("Choose a Keycard PIN") + } font.pixelSize: Constants.keycard.general.fontSize1 color: Theme.palette.directColor1 } @@ -325,7 +351,12 @@ Item { } PropertyChanges { target: info - text: qsTr("It is very important that you do not lose this PIN") + text: { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + return d.message2 + } + return d.message1 + } color: Theme.palette.dangerColor1 font.pixelSize: Constants.keycard.general.fontSize3 } @@ -344,7 +375,12 @@ Item { } PropertyChanges { target: title - text: qsTr("Repeat Keycard PIN") + text: { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + return qsTr("Repeat new Keycard PIN") + } + return qsTr("Repeat Keycard PIN") + } font.pixelSize: Constants.keycard.general.fontSize1 color: Theme.palette.directColor1 } @@ -354,7 +390,12 @@ Item { } PropertyChanges { target: info - text: qsTr("It is very important that you do not lose this PIN") + text: { + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin) { + return + } + return d.message1 + } color: Theme.palette.dangerColor1 font.pixelSize: Constants.keycard.general.fontSize3 } @@ -364,8 +405,10 @@ Item { } }, State { - name: Constants.keycardSharedState.pinSet - when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet + name: "success-state" + when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinSuccess PropertyChanges { target: image pattern: "keycard/strong_success/img-%1" @@ -378,7 +421,18 @@ Item { } PropertyChanges { target: title - text: qsTr("Keycard PIN set") + text: { + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinSet) { + return qsTr("Keycard PIN set") + } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified) { + return qsTr("Keycard PIN verified!") + } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinSuccess) { + return qsTr("PIN successfully changed") + } + return "" + } font.pixelSize: Constants.keycard.general.fontSize1 color: Theme.palette.directColor1 } @@ -396,21 +450,26 @@ Item { } }, State { - name: Constants.keycardSharedState.pinVerified - when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified + name: "error-state" + when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinFailure PropertyChanges { target: image - pattern: "keycard/strong_success/img-%1" + pattern: "keycard/strong_error/img-%1" source: "" startImgIndexForTheFirstLoop: 0 - startImgIndexForOtherLoops: 0 - endImgIndex: 20 + startImgIndexForOtherLoops: 18 + endImgIndex: 29 duration: 1300 loops: 1 } PropertyChanges { target: title - text: qsTr("Keycard PIN verified!") + text: { + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPinFailure) { + return qsTr("Changing PIN failed") + } + return "" + } font.pixelSize: Constants.keycard.general.fontSize1 color: Theme.palette.directColor1 } diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index bb3538da29..b429592f12 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -97,6 +97,7 @@ QtObject { readonly property string unlockKeycard: "UnlockKeycard" readonly property string displayKeycardContent: "DisplayKeycardContent" readonly property string renameKeycard: "RenameKeycard" + readonly property string changeKeycardPin: "ChangeKeycardPin" } readonly property QtObject keycardSharedState: QtObject { @@ -150,6 +151,9 @@ QtObject { readonly property string renamingKeycard: "RenamingKeycard" readonly property string keycardRenameSuccess: "KeycardRenameSuccess" readonly property string keycardRenameFailure: "KeycardRenameFailure" + readonly property string changingKeycardPin: "ChangingKeycardPin" + readonly property string changingKeycardPinSuccess: "ChangingKeycardPinSuccess" + readonly property string changingKeycardPinFailure: "ChangingKeycardPinFailure" } readonly property QtObject keychain: QtObject {