From a60e5d49cfd0ae757f1e371fd58b2301916f4949 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Tue, 18 Oct 2022 10:04:51 +0200 Subject: [PATCH] feat(@desktop/keycard): create a new pairing code Fixes: #7038 --- .../profile_section/keycard/io_interface.nim | 2 +- .../main/profile_section/keycard/module.nim | 10 +- .../main/profile_section/keycard/view.nim | 4 +- .../keycard_popup/controller.nim | 14 ++ .../changing_keycard_pairing_code_state.nim | 17 ++ .../internal/create_pairing_code_state.nim | 19 ++ .../internal/enter_pin_state.nim | 29 ++- .../internal/insert_keycard_state.nim | 3 +- ...card_change_pairing_code_failure_state.nim | 17 ++ ...card_change_pairing_code_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 | 3 +- .../keycard_popup/internal/state.nim | 4 + .../keycard_popup/internal/state_factory.nim | 46 ++++- .../internal/wrong_keycard_state.nim | 6 +- .../internal/wrong_pin_state.nim | 27 ++- .../keycard_popup/io_interface.nim | 4 + .../shared_modules/keycard_popup/module.nim | 8 + .../shared_modules/keycard_popup/view.nim | 3 + src/app_service/service/keycard/constants.nim | 2 +- src/app_service/service/keycard/service.nim | 16 ++ .../Profile/stores/KeycardStore.qml | 4 +- .../Profile/views/keycard/DetailsView.qml | 2 +- .../shared/popups/keycard/KeycardPopup.qml | 75 ++++++- .../keycard/states/EnterPairingCode.qml | 183 ++++++++++++++++++ .../popups/keycard/states/KeycardInit.qml | 50 ++++- ui/imports/utils/Constants.qml | 6 + 35 files changed, 569 insertions(+), 43 deletions(-) create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pairing_code_state.nim create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/create_pairing_code_state.nim create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_failure_state.nim create mode 100644 src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_success_state.nim create mode 100644 ui/imports/shared/popups/keycard/states/EnterPairingCode.qml 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 e464c53d02..54746dffb8 100644 --- a/src/app/modules/main/profile_section/keycard/io_interface.nim +++ b/src/app/modules/main/profile_section/keycard/io_interface.nim @@ -59,7 +59,7 @@ method runCreateBackupCopyOfAKeycardPopup*(self: AccessInterface) {.base.} = method runCreatePukPopup*(self: AccessInterface, keycardUid: string, keyUid: string) {.base.} = raise newException(ValueError, "No implementation available") -method runCreateNewPairingCodePopup*(self: AccessInterface) {.base.} = +method runCreateNewPairingCodePopup*(self: AccessInterface, keycardUid: string, keyUid: string) {.base.} = raise newException(ValueError, "No implementation available") method onLoggedInUserImageChanged*(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 f7362ab028..4375a4630a 100644 --- a/src/app/modules/main/profile_section/keycard/module.nim +++ b/src/app/modules/main/profile_section/keycard/module.nim @@ -160,10 +160,14 @@ method runCreatePukPopup*(self: Module, keycardUid: string, keyUid: string) = if self.keycardSharedModule.isNil: return self.keycardSharedModule.setUidOfAKeycardWhichNeedToBeProcessed(keycardUid) - self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ChangeKeycardPuk, keyUid) + self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ChangeKeycardPuk, keyUid) -method runCreateNewPairingCodePopup*(self: Module) = - info "TODO: Create New Pairing Code for a Keycard..." +method runCreateNewPairingCodePopup*(self: Module, keycardUid: string, keyUid: string) = + self.createSharedKeycardModule() + if self.keycardSharedModule.isNil: + return + self.keycardSharedModule.setUidOfAKeycardWhichNeedToBeProcessed(keycardUid) + self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ChangePairingCode, keyUid) proc buildKeycardItem(self: Module, walletAccounts: seq[WalletAccountDto], keyPair: KeyPairDto): KeycardItem = let findAccountByAccountAddress = proc(accounts: seq[WalletAccountDto], address: string): WalletAccountDto = diff --git a/src/app/modules/main/profile_section/keycard/view.nim b/src/app/modules/main/profile_section/keycard/view.nim index f7745a719b..51925810e7 100644 --- a/src/app/modules/main/profile_section/keycard/view.nim +++ b/src/app/modules/main/profile_section/keycard/view.nim @@ -76,8 +76,8 @@ QtObject: proc runCreatePukPopup*(self: View, keycardUid: string, keyUid: string) {.slot.} = self.delegate.runCreatePukPopup(keycardUid, keyUid) - proc runCreateNewPairingCodePopup*(self: View) {.slot.} = - self.delegate.runCreateNewPairingCodePopup() + proc runCreateNewPairingCodePopup*(self: View, keycardUid: string, keyUid: string) {.slot.} = + self.delegate.runCreateNewPairingCodePopup(keycardUid, keyUid) proc keycardModel*(self: View): KeycardModel = return self.keycardModel diff --git a/src/app/modules/shared_modules/keycard_popup/controller.nim b/src/app/modules/shared_modules/keycard_popup/controller.nim index 112f5d6de5..28ccdea377 100644 --- a/src/app/modules/shared_modules/keycard_popup/controller.nim +++ b/src/app/modules/shared_modules/keycard_popup/controller.nim @@ -39,6 +39,7 @@ type tmpValidPuk: bool tmpPassword: string tmpKeycardName: string + tmpPairingCode: string tmpSelectedKeyPairIsProfile: bool tmpSelectedKeyPairDto: KeyPairDto tmpSelectedKeyPairWalletPaths: seq[string] @@ -204,6 +205,12 @@ proc setKeycarName*(self: Controller, value: string) = proc getKeycarName*(self: Controller): string = return self.tmpKeycardName +proc setPairingCode*(self: Controller, value: string) = + self.tmpPairingCode = value + +proc getPairingCode*(self: Controller): string = + return self.tmpPairingCode + proc getKeyUidWhichIsBeingAuthenticating*(self: Controller): string = self.tmpKeyUidWhichIsBeingAuthenticating @@ -315,6 +322,10 @@ proc runChangePukFlow*(self: Controller) = self.cancelCurrentFlow() self.keycardService.startChangePukFlow() +proc runChangePairingFlow*(self: Controller) = + self.cancelCurrentFlow() + self.keycardService.startChangePairingFlow() + proc runStoreMetadataFlow*(self: Controller, cardName: string, pin: string, walletPaths: seq[string]) = self.cancelCurrentFlow() self.keycardService.startStoreMetadataFlow(cardName, pin, walletPaths) @@ -429,6 +440,9 @@ proc storePinToKeycard*(self: Controller, pin: string, puk: string) = proc storePukToKeycard*(self: Controller, puk: string) = self.keycardService.storePuk(puk) +proc storePairingCodeToKeycard*(self: Controller, pairingCode: string) = + self.keycardService.storePairingCode(pairingCode) + proc storeSeedPhraseToKeycard*(self: Controller, seedPhraseLength: int, seedPhrase: string) = self.keycardService.storeSeedPhrase(seedPhraseLength, seedPhrase) diff --git a/src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pairing_code_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pairing_code_state.nim new file mode 100644 index 0000000000..6cd0cc0bc5 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/changing_keycard_pairing_code_state.nim @@ -0,0 +1,17 @@ +type + ChangingKeycardPairingCodeState* = ref object of State + +proc newChangingKeycardPairingCodeState*(flowType: FlowType, backState: State): ChangingKeycardPairingCodeState = + result = ChangingKeycardPairingCodeState() + result.setup(flowType, StateType.ChangingKeycardPairingCode, backState) + +proc delete*(self: ChangingKeycardPairingCodeState) = + self.State.delete + +method executeSecondaryCommand*(self: ChangingKeycardPairingCodeState, controller: Controller) = + if self.flowType == FlowType.ChangePairingCode: + controller.storePairingCodeToKeycard(controller.getPairingCode()) + +method resolveKeycardNextState*(self: ChangingKeycardPairingCodeState, 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_pairing_code_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/create_pairing_code_state.nim new file mode 100644 index 0000000000..0838d854b0 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/create_pairing_code_state.nim @@ -0,0 +1,19 @@ +type + CreatePairingCodeState* = ref object of State + +proc newCreatePairingCodeState*(flowType: FlowType, backState: State): CreatePairingCodeState = + result = CreatePairingCodeState() + result.setup(flowType, StateType.CreatePairingCode, backState) + +proc delete*(self: CreatePairingCodeState) = + self.State.delete + +method getNextPrimaryState*(self: CreatePairingCodeState, controller: Controller): State = + if self.flowType == FlowType.ChangePairingCode: + if controller.getPairingCode().len >= 0: + return createState(StateType.ChangingKeycardPairingCode, self.flowType, nil) + return createState(StateType.ChangingKeycardPairingCodeFailure, self.flowType, nil) + +method executeTertiaryCommand*(self: CreatePairingCodeState, controller: Controller) = + if self.flowType == FlowType.ChangePairingCode: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) \ 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 34c3c901d3..60ea2f219b 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 @@ -22,7 +22,8 @@ method executeSecondaryCommand*(self: EnterPinState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: if controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) if self.flowType == FlowType.Authentication: @@ -36,7 +37,8 @@ method executeTertiaryCommand*(self: EnterPinState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent, @@ -186,4 +188,25 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke return createState(StateType.MaxPinRetriesReached, self.flowType, nil) if keycardFlowType == ResponseTypeValueEnterNewPUK: if keycardEvent.error == ErrorChangingCredentials: - return createState(StateType.PinVerified, self.flowType, nil) \ No newline at end of file + return createState(StateType.PinVerified, self.flowType, nil) + if self.flowType == FlowType.ChangePairingCode: + 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 == ResponseTypeValueEnterNewPair: + if keycardEvent.error == ErrorChangingCredentials: + return createState(StateType.PinVerified, self.flowType, nil) 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 23d391cd59..fe8bc2b929 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 @@ -21,7 +21,8 @@ method executeTertiaryCommand*(self: InsertKeycardState, controller: Controller) self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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_pairing_code_failure_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_failure_state.nim new file mode 100644 index 0000000000..0a51d28c94 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_failure_state.nim @@ -0,0 +1,17 @@ +type + ChangingKeycardPairingCodeFailureState* = ref object of State + +proc newChangingKeycardPairingCodeFailureState*(flowType: FlowType, backState: State): ChangingKeycardPairingCodeFailureState = + result = ChangingKeycardPairingCodeFailureState() + result.setup(flowType, StateType.ChangingKeycardPairingCodeFailure, backState) + +proc delete*(self: ChangingKeycardPairingCodeFailureState) = + self.State.delete + +method executePrimaryCommand*(self: ChangingKeycardPairingCodeFailureState, controller: Controller) = + if self.flowType == FlowType.ChangePairingCode: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) + +method executeTertiaryCommand*(self: ChangingKeycardPairingCodeFailureState, controller: Controller) = + if self.flowType == FlowType.ChangePairingCode: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) \ No newline at end of file diff --git a/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_success_state.nim b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_success_state.nim new file mode 100644 index 0000000000..75bf73f405 --- /dev/null +++ b/src/app/modules/shared_modules/keycard_popup/internal/keycard_change_pairing_code_success_state.nim @@ -0,0 +1,17 @@ +type + ChangingKeycardPairingCodeSuccessState* = ref object of State + +proc newChangingKeycardPairingCodeSuccessState*(flowType: FlowType, backState: State): ChangingKeycardPairingCodeSuccessState = + result = ChangingKeycardPairingCodeSuccessState() + result.setup(flowType, StateType.ChangingKeycardPairingCodeSuccess, backState) + +proc delete*(self: ChangingKeycardPairingCodeSuccessState) = + self.State.delete + +method executePrimaryCommand*(self: ChangingKeycardPairingCodeSuccessState, controller: Controller) = + if self.flowType == FlowType.ChangePairingCode: + controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) + +method executeTertiaryCommand*(self: ChangingKeycardPairingCodeSuccessState, controller: Controller) = + if self.flowType == FlowType.ChangePairingCode: + 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 89ad2406b9..8f711b9f95 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 @@ -15,7 +15,8 @@ method executePrimaryCommand*(self: KeycardEmptyState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method executeTertiaryCommand*(self: KeycardEmptyState, controller: Controller) = @@ -25,5 +26,6 @@ method executeTertiaryCommand*(self: KeycardEmptyState, controller: Controller) self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 a2a64bfd3e..94691a2b59 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 @@ -28,5 +28,6 @@ method executeTertiaryCommand*(self: KeycardInsertedState, controller: Controlle self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 3da0be266d..d00370afbb 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 @@ -16,7 +16,8 @@ method getNextPrimaryState*(self: MaxPairingSlotsReachedState, controller: Contr self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.runSharedModuleFlow(FlowType.UnlockKeycard) return nil @@ -28,5 +29,6 @@ method executeTertiaryCommand*(self: MaxPairingSlotsReachedState, controller: Co self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 ecade4f016..cbea373821 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 @@ -13,7 +13,8 @@ method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Control self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.runSharedModuleFlow(FlowType.UnlockKeycard) if self.flowType == FlowType.SetupNewKeycard: let currValue = extractPredefinedKeycardDataToNumber(controller.getKeycardData()) @@ -31,7 +32,8 @@ method executeTertiaryCommand*(self: MaxPinRetriesReachedState, controller: Cont self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 b6f8ce3984..e9192dd6ff 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 @@ -16,7 +16,8 @@ method getNextPrimaryState*(self: MaxPukRetriesReachedState, controller: Control self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.runSharedModuleFlow(FlowType.UnlockKeycard) if self.flowType == FlowType.UnlockKeycard: return createState(StateType.EnterSeedPhrase, self.flowType, self) @@ -29,5 +30,6 @@ method executeTertiaryCommand*(self: MaxPukRetriesReachedState, controller: Cont self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 149922b340..a071cf2cbf 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 @@ -16,5 +16,6 @@ method executeTertiaryCommand*(self: NotKeycardState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 75b64b7ef5..ed19efc49d 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 @@ -18,6 +18,8 @@ method getNextPrimaryState*(self: PinVerifiedState, controller: Controller): Sta return createState(StateType.CreatePin, self.flowType, nil) if self.flowType == FlowType.ChangeKeycardPuk: return createState(StateType.CreatePuk, self.flowType, nil) + if self.flowType == FlowType.ChangePairingCode: + return createState(StateType.CreatePairingCode, self.flowType, nil) method executeTertiaryCommand*(self: PinVerifiedState, controller: Controller) = if self.flowType == FlowType.FactoryReset or @@ -25,5 +27,6 @@ method executeTertiaryCommand*(self: PinVerifiedState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 e7f94885b3..a0a927b3e8 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 @@ -21,7 +21,8 @@ method executeTertiaryCommand*(self: PluginReaderState, controller: Controller) self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 20ef4fe094..14403d655c 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 @@ -26,7 +26,8 @@ method resolveKeycardNextState*(self: ReadingKeycardState, keycardFlowType: stri if self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: # 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 172cce32c4..6dce660a4e 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 @@ -26,7 +26,8 @@ method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controll if self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: return createState(StateType.EnterPin, self.flowType, nil) method executeTertiaryCommand*(self: RecognizedKeycardState, controller: Controller) = 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 3773232f18..d0658dcc7e 100644 --- a/src/app/modules/shared_modules/keycard_popup/internal/state.nim +++ b/src/app/modules/shared_modules/keycard_popup/internal/state.nim @@ -64,6 +64,10 @@ type StateType* {.pure.} = enum ChangingKeycardPuk = "ChangingKeycardPuk" ChangingKeycardPukSuccess = "ChangingKeycardPukSuccess" ChangingKeycardPukFailure = "ChangingKeycardPukFailure" + CreatePairingCode = "CreatePairingCode" + ChangingKeycardPairingCode = "ChangingKeycardPairingCode" + ChangingKeycardPairingCodeSuccess = "ChangingKeycardPairingCodeSuccess" + ChangingKeycardPairingCodeFailure = "ChangingKeycardPairingCodeFailure" ## 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 af78e878d5..3dd7977460 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 @@ -34,6 +34,8 @@ include biometrics_pin_invalid_state include biometrics_ready_to_sign_state include changing_keycard_pin_state include changing_keycard_puk_state +include changing_keycard_pairing_code_state +include create_pairing_code_state include create_pin_state include create_puk_state include enter_biometrics_password_state @@ -48,6 +50,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_pairing_code_failure_state +include keycard_change_pairing_code_success_state include keycard_change_pin_failure_state include keycard_change_pin_success_state include keycard_change_puk_failure_state @@ -120,10 +124,14 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newBiometricsPinInvalidState(flowType, backState) if stateToBeCreated == StateType.BiometricsReadyToSign: return newBiometricsReadyToSignState(flowType, backState) + if stateToBeCreated == StateType.ChangingKeycardPairingCode: + return newChangingKeycardPairingCodeState(flowType, backState) if stateToBeCreated == StateType.ChangingKeycardPin: return newChangingKeycardPinState(flowType, backState) if stateToBeCreated == StateType.ChangingKeycardPuk: return newChangingKeycardPukState(flowType, backState) + if stateToBeCreated == StateType.CreatePairingCode: + return newCreatePairingCodeState(flowType, backState) if stateToBeCreated == StateType.CreatePin: return newCreatePinState(flowType, backState) if stateToBeCreated == StateType.CreatePuk: @@ -152,6 +160,10 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St return newKeyPairMigrateFailureState(flowType, backState) if stateToBeCreated == StateType.KeyPairMigrateSuccess: return newKeyPairMigrateSuccessState(flowType, backState) + if stateToBeCreated == StateType.ChangingKeycardPairingCodeFailure: + return newChangingKeycardPairingCodeFailureState(flowType, backState) + if stateToBeCreated == StateType.ChangingKeycardPairingCodeSuccess: + return newChangingKeycardPairingCodeSuccessState(flowType, backState) if stateToBeCreated == StateType.ChangingKeycardPinFailure: return newChangingKeycardPinFailureState(flowType, backState) if stateToBeCreated == StateType.ChangingKeycardPinSuccess: @@ -237,7 +249,8 @@ proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycard state.flowType == FlowType.DisplayKeycardContent or state.flowType == FlowType.RenameKeycard or state.flowType == FlowType.ChangeKeycardPin or - state.flowType == FlowType.ChangeKeycardPuk: + state.flowType == FlowType.ChangeKeycardPuk or + state.flowType == FlowType.ChangePairingCode: if keycardFlowType == ResponseTypeValueKeycardFlowResult and keycardEvent.error.len > 0 and keycardEvent.error == ErrorConnection: @@ -532,3 +545,34 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy if keycardEvent.error.len == 0: return createState(StateType.ChangingKeycardPukSuccess, state.flowType, nil) return createState(StateType.ChangingKeycardPukFailure, state.flowType, nil) + + if state.flowType == FlowType.ChangePairingCode: + 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.ChangingKeycardPairingCodeSuccess, state.flowType, nil) + return createState(StateType.ChangingKeycardPairingCodeFailure, 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 30813958e4..c5f7760306 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 @@ -12,7 +12,8 @@ method executePrimaryCommand*(self: WrongKeycardState, controller: Controller) = if self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true) method executeTertiaryCommand*(self: WrongKeycardState, controller: Controller) = @@ -20,5 +21,6 @@ method executeTertiaryCommand*(self: WrongKeycardState, controller: Controller) self.flowType == FlowType.UnlockKeycard or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: 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 387405871f..31df35b6b2 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 @@ -18,7 +18,8 @@ method getNextPrimaryState*(self: WrongPinState, controller: Controller): State if self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.runSharedModuleFlow(FlowType.FactoryReset) method executeSecondaryCommand*(self: WrongPinState, controller: Controller) = @@ -27,7 +28,8 @@ method executeSecondaryCommand*(self: WrongPinState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: if controller.getPin().len == PINLengthForStatusApp: controller.enterKeycardPin(controller.getPin()) if self.flowType == FlowType.Authentication: @@ -41,7 +43,8 @@ method executeTertiaryCommand*(self: WrongPinState, controller: Controller) = self.flowType == FlowType.DisplayKeycardContent or self.flowType == FlowType.RenameKeycard or self.flowType == FlowType.ChangeKeycardPin or - self.flowType == FlowType.ChangeKeycardPuk: + self.flowType == FlowType.ChangeKeycardPuk or + self.flowType == FlowType.ChangePairingCode: controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false) method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, keycardEvent: KeycardEvent, @@ -163,3 +166,21 @@ method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, ke if keycardFlowType == ResponseTypeValueEnterNewPUK: if keycardEvent.error == ErrorChangingCredentials: return createState(StateType.PinVerified, self.flowType, nil) + if self.flowType == FlowType.ChangePairingCode: + 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 == ResponseTypeValueEnterNewPair: + if keycardEvent.error == ErrorChangingCredentials: + return createState(StateType.PinVerified, self.flowType, nil) + 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 7e86808388..a97c9490df 100644 --- a/src/app/modules/shared_modules/keycard_popup/io_interface.nim +++ b/src/app/modules/shared_modules/keycard_popup/io_interface.nim @@ -60,6 +60,7 @@ type FlowType* {.pure.} = enum RenameKeycard = "RenameKeycard" ChangeKeycardPin = "ChangeKeycardPin" ChangeKeycardPuk = "ChangeKeycardPuk" + ChangePairingCode = "ChangePairingCode" type AccessInterface* {.pure inheritable.} = ref object of RootObj @@ -109,6 +110,9 @@ method setPassword*(self: AccessInterface, value: string) {.base.} = method setKeycarName*(self: AccessInterface, value: string) {.base.} = raise newException(ValueError, "No implementation available") +method setPairingCode*(self: AccessInterface, value: string) {.base.} = + raise newException(ValueError, "No implementation available") + method checkRepeatedKeycardPinWhileTyping*(self: AccessInterface, pin: string): bool {.base.} = raise newException(ValueError, "No implementation available") diff --git a/src/app/modules/shared_modules/keycard_popup/module.nim b/src/app/modules/shared_modules/keycard_popup/module.nim index 35e5731e24..5dca311987 100644 --- a/src/app/modules/shared_modules/keycard_popup/module.nim +++ b/src/app/modules/shared_modules/keycard_popup/module.nim @@ -81,6 +81,9 @@ method setPassword*[T](self: Module[T], value: string) = method setKeycarName*[T](self: Module[T], value: string) = self.controller.setKeycarName(value) +method setPairingCode*[T](self: Module[T], value: string) = + self.controller.setPairingCode(value) + method checkRepeatedKeycardPinWhileTyping*[T](self: Module[T], pin: string): bool = self.controller.setPinMatch(false) let storedPin = self.controller.getPin() @@ -401,6 +404,11 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path self.tmpLocalState = newReadingKeycardState(flowToRun, nil) self.controller.runChangePukFlow() return + if flowToRun == FlowType.ChangePairingCode: + self.prepareKeyPairForProcessing(keyUid) + self.tmpLocalState = newReadingKeycardState(flowToRun, nil) + self.controller.runChangePairingFlow() + return method setSelectedKeyPair*[T](self: Module[T], item: KeyPairItem) = var paths: seq[string] diff --git a/src/app/modules/shared_modules/keycard_popup/view.nim b/src/app/modules/shared_modules/keycard_popup/view.nim index 1ca269748a..87adb0c97a 100644 --- a/src/app/modules/shared_modules/keycard_popup/view.nim +++ b/src/app/modules/shared_modules/keycard_popup/view.nim @@ -201,6 +201,9 @@ QtObject: proc setKeycarName*(self: View, value: string) {.slot.} = self.delegate.setKeycarName(value) + proc setPairingCode*(self: View, value: string) {.slot.} = + self.delegate.setPairingCode(value) + proc checkRepeatedKeycardPinWhileTyping*(self: View, pin: string): bool {.slot.} = return self.delegate.checkRepeatedKeycardPinWhileTyping(pin) diff --git a/src/app_service/service/keycard/constants.nim b/src/app_service/service/keycard/constants.nim index f3dfe80024..11e75aaf19 100644 --- a/src/app_service/service/keycard/constants.nim +++ b/src/app_service/service/keycard/constants.nim @@ -28,7 +28,7 @@ const RequestParamPINRetries* = "pin-retries" const RequestParamPUKRetries* = "puk-retries" const RequestParamPairingPass* = "pairing-pass" const RequestParamPaired* = "paired" -const RequestParamNewPairing* = "new-pairing-pass" +const RequestParamNewPairingPass* = "new-pairing-pass" const RequestParamDefPairing* = "KeycardDefaultPairing" const RequestParamPIN* = "pin" const RequestParamNewPIN* = "new-pin" diff --git a/src/app_service/service/keycard/service.nim b/src/app_service/service/keycard/service.nim index 59d2ff0312..2d28d56926 100644 --- a/src/app_service/service/keycard/service.nim +++ b/src/app_service/service/keycard/service.nim @@ -232,6 +232,11 @@ QtObject: self.currentFlow = KCSFlowType.ChangePUK self.startFlow(payload) + proc startChangePairingFlow*(self: Service) = + var payload = %* { } + self.currentFlow = KCSFlowType.ChangePairing + self.startFlow(payload) + proc startStoreMetadataFlow*(self: Service, cardName: string, pin: string, walletPaths: seq[string]) = var name = cardName if cardName.len > CardNameLength: @@ -299,6 +304,17 @@ QtObject: } self.resumeFlow(payload) + proc storePairingCode*(self: Service, pairingCode: string) = + if pairingCode.len == 0: + error "empty pairing code provided" + return + var payload = %* { + RequestParamOverwrite: true, + RequestParamPairingPass: pairingCode, + RequestParamNewPairingPass: pairingCode + } + self.resumeFlow(payload) + proc storeSeedPhrase*(self: Service, seedPhraseLength: int, seedPhrase: string) = if seedPhrase.len == 0: error "empty seed phrase provided" diff --git a/ui/app/AppLayouts/Profile/stores/KeycardStore.qml b/ui/app/AppLayouts/Profile/stores/KeycardStore.qml index 358eea8d26..87a0346a5a 100644 --- a/ui/app/AppLayouts/Profile/stores/KeycardStore.qml +++ b/ui/app/AppLayouts/Profile/stores/KeycardStore.qml @@ -50,8 +50,8 @@ QtObject { root.keycardModule.runCreatePukPopup(keycardUid, keyUid) } - function runCreateNewPairingCodePopup() { - root.keycardModule.runCreateNewPairingCodePopup() + function runCreateNewPairingCodePopup(keycardUid, keyUid) { + root.keycardModule.runCreateNewPairingCodePopup(keycardUid, keyUid) } function getKeycardDetailsAsJson(keycardUid) { diff --git a/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml b/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml index 2ffc0082d6..7012b30a84 100644 --- a/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml +++ b/ui/app/AppLayouts/Profile/views/keycard/DetailsView.qml @@ -179,7 +179,7 @@ ColumnLayout { } ] onClicked: { - root.keycardStore.runCreateNewPairingCodePopup() + root.keycardStore.runCreateNewPairingCodePopup(root.keycardUid, d.keyUid) } } } diff --git a/ui/imports/shared/popups/keycard/KeycardPopup.qml b/ui/imports/shared/popups/keycard/KeycardPopup.qml index 7cd7d44fa2..5a888a8fe8 100644 --- a/ui/imports/shared/popups/keycard/KeycardPopup.qml +++ b/ui/imports/shared/popups/keycard/KeycardPopup.qml @@ -67,6 +67,9 @@ StatusModal { if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPuk) { return qsTr("Create a 12-digit personal unblocking key (PUK)") } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode) { + return qsTr("Create a new pairing code") + } return "" } @@ -79,6 +82,7 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess && root.sharedKeycardModule.migratingProfileKeyPair()) @@ -113,6 +117,9 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukSuccess || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukFailure || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeSuccess || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeFailure || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmptyMetadata || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty || @@ -184,6 +191,9 @@ StatusModal { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterKeycardName) { return enterNameComponent } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPairingCode) { + return enterPairingCodeComponent + } return undefined } @@ -335,6 +345,21 @@ StatusModal { } } } + + Component { + id: enterPairingCodeComponent + EnterPairingCode { + sharedKeycardModule: root.sharedKeycardModule + + Component.onCompleted: { + d.primaryButtonEnabled = false + } + + onValidation: { + d.primaryButtonEnabled = result + } + } + } } leftButtons: [ @@ -493,6 +518,22 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached) return qsTr("Cancel") } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode) { + 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.createPairingCode || + 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 "" } @@ -502,7 +543,8 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk) { + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode) { if (d.disablePopupClose) { return false } @@ -555,7 +597,8 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk) { + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode) { if (d.disablePopupClose) { return false } @@ -801,6 +844,27 @@ StatusModal { return qsTr("Unlock Keycard") } } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode) { + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeSuccess || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeFailure) + 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") + } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPairingCode) { + return qsTr("Set paring code") + } + } return "" } @@ -810,7 +874,8 @@ StatusModal { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk) { + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode) { if (d.disablePopupClose) { return false } @@ -869,6 +934,10 @@ StatusModal { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterKeycardName) return d.primaryButtonEnabled } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode) { + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.createPairingCode) + return d.primaryButtonEnabled + } return true } icon.name: { diff --git a/ui/imports/shared/popups/keycard/states/EnterPairingCode.qml b/ui/imports/shared/popups/keycard/states/EnterPairingCode.qml new file mode 100644 index 0000000000..2e92e5b3a0 --- /dev/null +++ b/ui/imports/shared/popups/keycard/states/EnterPairingCode.qml @@ -0,0 +1,183 @@ +import QtQuick 2.14 +import QtQuick.Layouts 1.14 + +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Controls 0.1 + +import utils 1.0 + +Item { + id: root + + property var sharedKeycardModule + + signal validation(bool result) + + QtObject { + id: d + + property bool allEntriesValid: false + + function processText(text) { + if(text.length === 0) + return "" + if(/(^\s|^\r|^\n)|(\s$|^\r$|^\n$)/.test(text)) { + return text.trim() + } + else if(/\s|\r|\n/.test(text)) { + return "" + } + return text + } + + function update() { + let codeEntered = code0.text.length > 0 && code1.text.length > 0 + + if (codeEntered && code0.text !== code1.text) { + errorTxt.text = qsTr("The codes don’t match") + } + else { + errorTxt.text = "" + } + + d.allEntriesValid = codeEntered && code0.text === code1.text + if (d.allEntriesValid) { + root.sharedKeycardModule.setPairingCode(code0.text) + } + else { + root.sharedKeycardModule.setPairingCode("") + } + root.validation(d.allEntriesValid) + } + } + + ColumnLayout { + anchors.fill: parent + anchors.topMargin: Style.current.xlPadding + anchors.bottomMargin: Style.current.halfPadding + anchors.leftMargin: Style.current.xlPadding + anchors.rightMargin: Style.current.xlPadding + spacing: Style.current.padding + clip: true + + StatusBaseText { + id: title + Layout.preferredHeight: Constants.keycard.general.titleHeight + Layout.alignment: Qt.AlignHCenter + text: qsTr("Enter a new pairing code") + font.pixelSize: Constants.keycard.general.fontSize1 + font.weight: Font.Bold + color: Theme.palette.directColor1 + } + + StatusBaseText { + Layout.preferredWidth: code0.width + Layout.alignment: Qt.AlignCenter + text: qsTr("Pairing code") + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.directColor1 + } + + StatusPasswordInput { + id: code0 + + property bool showPassword: false + + Layout.preferredWidth: Constants.keycard.general.keycardPairingCodeInputWidth + Layout.alignment: Qt.AlignCenter + placeholderText: qsTr("Enter code") + echoMode: showPassword ? TextInput.Normal : TextInput.Password + rightPadding: showHideIcon0.width + showHideIcon0.anchors.rightMargin + Style.current.padding / 2 + + onTextChanged: { + text = d.processText(text) + d.update() + } + + onAccepted: { + if (d.allEntriesValid && + (input.edit.keyEvent === Qt.Key_Return || + input.edit.keyEvent === Qt.Key_Enter)) { + event.accepted = true + root.sharedKeycardModule.currentState.doPrimaryAction() + } + } + + StatusFlatRoundButton { + id: showHideIcon0 + visible: code0.text !== "" + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 16 + width: 24 + height: 24 + icon.name: code0.showPassword ? "hide" : "show" + icon.color: Theme.palette.baseColor1 + + onClicked: code0.showPassword = !code0.showPassword + } + } + + Item { + Layout.fillWidth: true + Layout.preferredHeight: Style.current.padding + } + + StatusBaseText { + Layout.preferredWidth: code1.width + Layout.alignment: Qt.AlignCenter + text: qsTr("Confirm pairing code") + font.pixelSize: Constants.keycard.general.fontSize2 + color: Theme.palette.directColor1 + } + + StatusPasswordInput { + id: code1 + + property bool showPassword: false + + Layout.preferredWidth: Constants.keycard.general.keycardPairingCodeInputWidth + Layout.alignment: Qt.AlignCenter + placeholderText: qsTr("Confirm code") + echoMode: showPassword ? TextInput.Normal : TextInput.Password + rightPadding: showHideIcon1.width + showHideIcon1.anchors.rightMargin + Style.current.padding / 2 + + onTextChanged: { + text = d.processText(text) + d.update() + } + + onAccepted: { + if (d.allEntriesValid && + (input.edit.keyEvent === Qt.Key_Return || + input.edit.keyEvent === Qt.Key_Enter)) { + event.accepted = true + root.sharedKeycardModule.currentState.doPrimaryAction() + } + } + + StatusFlatRoundButton { + id: showHideIcon1 + visible: code1.text !== "" + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: 16 + width: 24 + height: 24 + icon.name: code1.showPassword ? "hide" : "show" + icon.color: Theme.palette.baseColor1 + + onClicked: code1.showPassword = !code1.showPassword + } + } + + StatusBaseText { + id: errorTxt + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: true + font.pixelSize: Constants.keycard.general.fontSize3 + color: Theme.palette.dangerColor1 + } + } +} diff --git a/ui/imports/shared/popups/keycard/states/KeycardInit.qml b/ui/imports/shared/popups/keycard/states/KeycardInit.qml index 23e45194e2..1ce90dfbb4 100644 --- a/ui/imports/shared/popups/keycard/states/KeycardInit.qml +++ b/ui/imports/shared/popups/keycard/states/KeycardInit.qml @@ -33,7 +33,8 @@ Item { interval: 1000 running: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode onTriggered: { root.sharedKeycardModule.currentState.doSecondaryAction() } @@ -147,7 +148,8 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode } StatusBaseText { id: title @@ -243,6 +245,18 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard) return true } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode && !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 } @@ -335,6 +349,17 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard) return keyPairForProcessingComponent } + if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode) { + 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 } @@ -428,7 +453,8 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeyPair || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.renamingKeycard || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPin || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode PropertyChanges { target: title text: { @@ -447,6 +473,9 @@ Item { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPuk) { return qsTr("Setting your Keycard PUK...") } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCode) { + return qsTr("Setting your pairing code...") + } return "" } font.pixelSize: Constants.keycard.general.fontSize2 @@ -548,7 +577,8 @@ Item { if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication || root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.renameKeycard || root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin || - root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPuk) { + root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPuk || + root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changePairingCode) { return qsTr("Keycard inserted does not match the Keycard below") } if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.unlockKeycard) { @@ -730,7 +760,8 @@ Item { root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.unlockKeycardSuccess || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardRenameSuccess || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukSuccess + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukSuccess || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeSuccess PropertyChanges { target: title text: { @@ -751,6 +782,9 @@ Item { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukSuccess) { return qsTr("Keycard’s PUK successfully set") } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeSuccess) { + return qsTr("Pairing code successfully set") + } return "" } font.pixelSize: Constants.keycard.general.fontSize1 @@ -788,7 +822,8 @@ Item { name: "processing-failure" when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure || root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardRenameFailure || - root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukFailure + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukFailure || + root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeFailure PropertyChanges { target: title text: { @@ -801,6 +836,9 @@ Item { if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPukFailure) { return qsTr("Setting Keycard’s PUK failed") } + if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.changingKeycardPairingCodeFailure) { + return qsTr("Setting pairing code failed") + } return "" } font.pixelSize: Constants.keycard.general.fontSize1 diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index a204a58b1b..828b647731 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -99,6 +99,7 @@ QtObject { readonly property string renameKeycard: "RenameKeycard" readonly property string changeKeycardPin: "ChangeKeycardPin" readonly property string changeKeycardPuk: "ChangeKeycardPuk" + readonly property string changePairingCode: "ChangePairingCode" } readonly property QtObject keycardSharedState: QtObject { @@ -160,6 +161,10 @@ QtObject { readonly property string changingKeycardPuk: "ChangingKeycardPuk" readonly property string changingKeycardPukSuccess: "ChangingKeycardPukSuccess" readonly property string changingKeycardPukFailure: "ChangingKeycardPukFailure" + readonly property string createPairingCode: "CreatePairingCode" + readonly property string changingKeycardPairingCode: "ChangingKeycardPairingCode" + readonly property string changingKeycardPairingCodeSuccess: "ChangingKeycardPairingCodeSuccess" + readonly property string changingKeycardPairingCodeFailure: "ChangingKeycardPairingCodeFailure" } readonly property QtObject keycardAnimations: QtObject { @@ -455,6 +460,7 @@ QtObject { readonly property int keycardPukLength: 12 readonly property int keycardNameLength: 20 readonly property int keycardNameInputWidth: 448 + readonly property int keycardPairingCodeInputWidth: 512 readonly property int keycardPukAdditionalSpacingOnEvery4Items: 4 readonly property int keycardPukAdditionalSpacing: 32 readonly property int fontSize1: 22