feat(@desktop/keycard): check what’s on a Keycard

Fixes: #7032
This commit is contained in:
Sale Djenic 2022-09-21 15:11:39 +02:00 committed by saledjenic
parent 10c3b66336
commit f11ff29cb4
26 changed files with 258 additions and 54 deletions

View File

@ -28,6 +28,15 @@ method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheC
method runSetupKeycardPopup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method runGenerateSeedPhrasePopup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method runImportOrRestoreViaSeedPhrasePopup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method runImportFromKeycardToAppPopup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method runUnlockKeycardPopup*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -104,6 +104,15 @@ method runSetupKeycardPopup*(self: Module) =
return
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.SetupNewKeycard)
method runGenerateSeedPhrasePopup*(self: Module) =
info "TODO: Generate a seed phrase..."
method runImportOrRestoreViaSeedPhrasePopup*(self: Module) =
info "TODO: Import or restore via a seed phrase..."
method runImportFromKeycardToAppPopup*(self: Module) =
info "TODO: Import from Keycard to Status Desktop..."
method runUnlockKeycardPopup*(self: Module) =
self.createSharedKeycardModule()
if self.keycardSharedModule.isNil:
@ -111,7 +120,10 @@ method runUnlockKeycardPopup*(self: Module) =
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.UnlockKeycard)
method runDisplayKeycardContentPopup*(self: Module) =
info "TODO: Run display keycard content..."
self.createSharedKeycardModule()
if self.keycardSharedModule.isNil:
return
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.DisplayKeycardContent)
method runFactoryResetPopup*(self: Module) =
self.createSharedKeycardModule()

View File

@ -34,6 +34,15 @@ QtObject:
proc runSetupKeycardPopup*(self: View) {.slot.} =
self.delegate.runSetupKeycardPopup()
proc runGenerateSeedPhrasePopup*(self: View) {.slot.} =
self.delegate.runGenerateSeedPhrasePopup()
proc runImportOrRestoreViaSeedPhrasePopup*(self: View) {.slot.} =
self.delegate.runImportOrRestoreViaSeedPhrasePopup()
proc runImportFromKeycardToAppPopup*(self: View) {.slot.} =
self.delegate.runImportFromKeycardToAppPopup()
proc runUnlockKeycardPopup*(self: View) {.slot.} =
self.delegate.runUnlockKeycardPopup()

View File

@ -15,10 +15,13 @@ method getNextPrimaryState*(self: EnterPinState, controller: Controller): State
if self.flowType == FlowType.Authentication:
if controller.getPin().len == PINLengthForStatusApp:
controller.enterKeycardPin(controller.getPin())
if self.flowType == FlowType.DisplayKeycardContent:
controller.runSharedModuleFlow(FlowType.FactoryReset)
method executeSecondaryCommand*(self: EnterPinState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.FactoryReset:
self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.DisplayKeycardContent:
if controller.getPin().len == PINLengthForStatusApp:
controller.enterKeycardPin(controller.getPin())
if self.flowType == FlowType.Authentication:
@ -28,7 +31,8 @@ method executeSecondaryCommand*(self: EnterPinState, controller: Controller) =
method executeTertiaryCommand*(self: EnterPinState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication:
self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
@ -96,3 +100,21 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
if keycardEvent.error.len == 0:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return nil
if self.flowType == FlowType.DisplayKeycardContent:
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)
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
controller.setMetadataFromKeycard(keycardEvent.cardMetadata, updateKeyPair = true)
return createState(StateType.PinVerified, self.flowType, nil)

View File

@ -17,7 +17,8 @@ method executeTertiaryCommand*(self: InsertKeycardState, controller: Controller)
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,

View File

@ -8,9 +8,16 @@ proc newKeycardEmptyState*(flowType: FlowType, backState: State): KeycardEmptySt
proc delete*(self: KeycardEmptyState) =
self.State.delete
method executePrimaryCommand*(self: KeycardEmptyState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method executeTertiaryCommand*(self: KeycardEmptyState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -24,5 +24,6 @@ method executeTertiaryCommand*(self: KeycardInsertedState, controller: Controlle
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -12,9 +12,11 @@ method getNextPrimaryState*(self: KeycardMetadataDisplayState, controller: Contr
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
return createState(StateType.FactoryResetConfirmationDisplayMetadata, self.flowType, self)
return nil
if self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
method executeTertiaryCommand*(self: KeycardMetadataDisplayState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -12,13 +12,15 @@ method getNextPrimaryState*(self: MaxPairingSlotsReachedState, controller: Contr
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
if self.flowType == FlowType.Authentication:
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
if self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent:
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
return nil
method executeTertiaryCommand*(self: MaxPairingSlotsReachedState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -9,7 +9,8 @@ proc delete*(self: MaxPinRetriesReachedState) =
self.State.delete
method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Controller): State =
if self.flowType == FlowType.FactoryReset:
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.DisplayKeycardContent:
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
if self.flowType == FlowType.SetupNewKeycard:
let currValue = extractPredefinedKeycardDataToNumber(controller.getKeycardData())
@ -23,7 +24,8 @@ method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Control
method executeTertiaryCommand*(self: MaxPinRetriesReachedState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.Authentication:
self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
if self.flowType == FlowType.SetupNewKeycard:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseUnlockLabelForLockedState, add = false))

View File

@ -12,8 +12,9 @@ method getNextPrimaryState*(self: MaxPukRetriesReachedState, controller: Control
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
if self.flowType == FlowType.Authentication:
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
if self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent:
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
if self.flowType == FlowType.UnlockKeycard:
return createState(StateType.EnterSeedPhrase, self.flowType, self)
@ -21,5 +22,6 @@ method executeTertiaryCommand*(self: MaxPukRetriesReachedState, controller: Cont
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -12,5 +12,6 @@ method executeTertiaryCommand*(self: NotKeycardState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -10,11 +10,13 @@ proc delete*(self: PinVerifiedState) =
method getNextPrimaryState*(self: PinVerifiedState, controller: Controller): State =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.DisplayKeycardContent:
return createState(StateType.KeycardMetadataDisplay, self.flowType, nil)
return nil
method executeTertiaryCommand*(self: PinVerifiedState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -17,7 +17,8 @@ method executeTertiaryCommand*(self: PluginReaderState, controller: Controller)
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,

View File

@ -17,7 +17,8 @@ method executeTertiaryCommand*(self: ReadingKeycardState, controller: Controller
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method getNextSecondaryState*(self: ReadingKeycardState, controller: Controller): State =

View File

@ -23,9 +23,12 @@ method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controll
return createState(StateType.CreatePin, self.flowType, self.getBackState)
if self.flowType == FlowType.UnlockKeycard:
return createState(StateType.UnlockKeycardOptions, self.flowType, nil)
if self.flowType == FlowType.DisplayKeycardContent:
return createState(StateType.EnterPin, self.flowType, nil)
method executeTertiaryCommand*(self: RecognizedKeycardState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.UnlockKeycard:
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -17,6 +17,7 @@ type PredefinedKeycardData* {.pure.} = enum
WrongPassword = 8
OfferPukForUnlock = 16
UseUnlockLabelForLockedState = 32
UseGeneralMessageForLockedState = 64
# Forward declaration
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State
@ -194,7 +195,8 @@ proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycard
## Handling factory reset or authentication or unlock keycard flow
if state.flowType == FlowType.FactoryReset or
state.flowType == FlowType.Authentication or
state.flowType == FlowType.UnlockKeycard:
state.flowType == FlowType.UnlockKeycard or
state.flowType == FlowType.DisplayKeycardContent:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorConnection:
@ -277,8 +279,10 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardEvent.error == ErrorHasKeys:
return createState(StateType.KeycardNotEmpty, 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 == ResponseTypeValueEnterPIN:
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
@ -287,6 +291,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
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 == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0:
@ -313,9 +318,11 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmpty, state.flowType, nil)
if keycardEvent.error == ErrorFreePairingSlots:
return createState(StateType.MaxPairingSlotsReached, state.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true))
return createState(StateType.MaxPairingSlotsReached, state.flowType, nil)
if keycardEvent.error == ErrorPUKRetries:
return createState(StateType.MaxPukRetriesReached, state.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true))
return createState(StateType.MaxPukRetriesReached, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN:
if keycardEvent.keyUid == controller.getKeyUidWhichIsBeingAuthenticating():
if controller.loggedInUserUsesBiometricLogin():
@ -326,6 +333,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if not controller.usePinFromBiometrics():
return createState(StateType.WrongKeychainPin, state.flowType, nil)
return createState(StateType.WrongPin, state.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true))
return createState(StateType.MaxPinRetriesReached, state.flowType, nil)
return createState(StateType.BiometricsReadyToSign, state.flowType, nil)
return createState(StateType.EnterPin, state.flowType, nil)
@ -333,6 +341,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
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 == ResponseTypeValueKeycardFlowResult:
if keycardEvent.error.len == 0:
@ -364,3 +373,29 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmpty, state.flowType, nil)
if state.flowType == FlowType.DisplayKeycardContent:
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 or
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmpty, state.flowType, nil)

View File

@ -15,11 +15,13 @@ method getNextPrimaryState*(self: WrongPinState, controller: Controller): State
if self.flowType == FlowType.Authentication:
if controller.getPin().len == PINLengthForStatusApp:
controller.enterKeycardPin(controller.getPin())
return nil
if self.flowType == FlowType.DisplayKeycardContent:
controller.runSharedModuleFlow(FlowType.FactoryReset)
method executeSecondaryCommand*(self: WrongPinState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard:
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.DisplayKeycardContent:
if controller.getPin().len == PINLengthForStatusApp:
controller.enterKeycardPin(controller.getPin())
if self.flowType == FlowType.Authentication:
@ -29,7 +31,8 @@ method executeSecondaryCommand*(self: WrongPinState, controller: Controller) =
method executeTertiaryCommand*(self: WrongPinState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.Authentication:
self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
@ -85,3 +88,18 @@ method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, ke
if keycardEvent.error.len == 0:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return nil
if self.flowType == FlowType.DisplayKeycardContent:
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setKeycardData($keycardEvent.pinRetries)
if keycardEvent.pinRetries > 0:
return self
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
controller.setMetadataFromKeycard(keycardEvent.cardMetadata, updateKeyPair = true)
return createState(StateType.PinVerified, self.flowType, nil)

View File

@ -36,6 +36,7 @@ type FlowType* {.pure.} = enum
SetupNewKeycard = "SetupNewKeycard"
Authentication = "Authentication"
UnlockKeycard = "UnlockKeycard"
DisplayKeycardContent = "DisplayKeycardContent"
type
AccessInterface* {.pure inheritable.} = ref object of RootObj

View File

@ -317,13 +317,13 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path
self.initialized = true
self.controller.init()
if flowToRun == FlowType.FactoryReset:
let items = self.buildKeyPairsList(excludeAlreadyMigratedPairs = false)
self.view.createKeyPairModel(items)
self.view.createKeyPairStoredOnKeycard()
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
self.controller.runGetMetadataFlow(resolveAddress = true)
return
if flowToRun == FlowType.SetupNewKeycard:
let items = self.buildKeyPairsList(excludeAlreadyMigratedPairs = true)
self.view.createKeyPairStoredOnKeycard()
self.view.createKeyPairModel(items)
self.view.setCurrentState(newSelectExistingKeyPairState(flowToRun, nil))
self.controller.readyToDisplayPopup()
@ -346,6 +346,11 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
self.controller.runGetMetadataFlow(resolveAddress = true)
return
if flowToRun == FlowType.DisplayKeycardContent:
self.view.createKeyPairStoredOnKeycard()
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
self.controller.runGetMetadataFlow(resolveAddress = true)
return
method setSelectedKeyPair*[T](self: Module[T], item: KeyPairItem) =
var paths: seq[string]

View File

@ -100,6 +100,12 @@ QtObject:
read = getKeyPairModel
notify = keyPairModelChanged
proc createKeyPairStoredOnKeycard*(self: View) =
if self.keyPairStoredOnKeycard.isNil:
self.keyPairStoredOnKeycard = newKeyPairSelectedItem()
if self.keyPairStoredOnKeycardVariant.isNil:
self.keyPairStoredOnKeycardVariant = newQVariant(self.keyPairStoredOnKeycard)
proc createKeyPairModel*(self: View, items: seq[KeyPairItem]) =
if self.keyPairModel.isNil:
self.keyPairModel = newKeyPairModel()
@ -109,10 +115,6 @@ QtObject:
self.selectedKeyPairItem = newKeyPairSelectedItem()
if self.selectedKeyPairItemVariant.isNil:
self.selectedKeyPairItemVariant = newQVariant(self.selectedKeyPairItem)
if self.keyPairStoredOnKeycard.isNil:
self.keyPairStoredOnKeycard = newKeyPairSelectedItem()
if self.keyPairStoredOnKeycardVariant.isNil:
self.keyPairStoredOnKeycardVariant = newQVariant(self.keyPairStoredOnKeycard)
self.keyPairModel.setItems(items)
self.keyPairModelChanged()

View File

@ -10,6 +10,18 @@ QtObject {
root.keycardModule.runSetupKeycardPopup()
}
function runGenerateSeedPhrasePopup() {
root.keycardModule.runGenerateSeedPhrasePopup()
}
function runImportOrRestoreViaSeedPhrasePopup() {
root.keycardModule.runImportOrRestoreViaSeedPhrasePopup()
}
function runImportFromKeycardToAppPopup() {
root.keycardModule.runImportFromKeycardToAppPopup()
}
function runUnlockKeycardPopup() {
root.keycardModule.runUnlockKeycardPopup()
}

View File

@ -115,7 +115,7 @@ SettingsContentBase {
}
]
onClicked: {
console.warn("TODO: Generate a seed phrase...")
root.keycardStore.runGenerateSeedPhrasePopup()
}
}
@ -130,7 +130,7 @@ SettingsContentBase {
}
]
onClicked: {
console.warn("TODO: Import or restore via a seed phrase...")
root.keycardStore.runImportOrRestoreViaSeedPhrasePopup()
}
}
@ -145,7 +145,7 @@ SettingsContentBase {
}
]
onClicked: {
console.warn("TODO: Import from Keycard to Status Desktop...")
root.keycardStore.runImportFromKeycardToAppPopup()
}
}

View File

@ -30,6 +30,11 @@ StatusModal {
return Constants.keycard.general.popupBiggerHeight
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.displayKeycardContent) {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
return Constants.keycard.general.popupBiggerHeight
}
}
}
return Constants.keycard.general.popupHeight
}
@ -50,6 +55,9 @@ StatusModal {
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.unlockKeycard) {
return qsTr("Unlock Keycard")
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.displayKeycardContent) {
return qsTr("Check whats on a Keycard")
}
return ""
}
@ -327,7 +335,6 @@ StatusModal {
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.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pinVerified ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
@ -347,7 +354,6 @@ StatusModal {
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.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.biometricsReadyToSign ||
@ -374,12 +380,26 @@ StatusModal {
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.recognizedKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPuk ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPuk ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.unlockKeycardOptions ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterSeedPhrase)
return qsTr("Cancel")
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.displayKeycardContent) {
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.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 ""
}
@ -508,7 +528,6 @@ StatusModal {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPukRetriesReached ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached) {
let a = root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.useUnlockLabelForLockedState
if (root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.useUnlockLabelForLockedState)
return qsTr("Unlock Keycard")
return qsTr("Next")
@ -542,7 +561,8 @@ StatusModal {
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPairingSlotsReached) {
return qsTr("Unlock Keycard")
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess) {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess) {
return qsTr("Done")
}
}
@ -551,7 +571,6 @@ StatusModal {
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.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.biometricsReadyToSign ||
@ -561,6 +580,9 @@ StatusModal {
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin) {
return qsTr("Authenticate")
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty) {
return qsTr("Done")
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterBiometricsPassword ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongBiometricsPassword) {
return qsTr("Update password & authenticate")
@ -580,7 +602,8 @@ StatusModal {
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.unlockKeycard) {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardAlreadyUnlocked ||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardAlreadyUnlocked ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.unlockKeycardSuccess)
return qsTr("Done")
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.unlockKeycardOptions)
@ -599,6 +622,23 @@ StatusModal {
return qsTr("Unlock Keycard")
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.displayKeycardContent) {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
return qsTr("Done")
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin) {
return qsTr("I dont 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 !== ""
@ -638,7 +678,6 @@ StatusModal {
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.keycardEmpty ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
@ -684,8 +723,7 @@ StatusModal {
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.biometricsPinInvalid ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.biometricsReadyToSign ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.notKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardEmpty)
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard)
return "touch-id"
}
}

View File

@ -182,6 +182,11 @@ Item {
return true
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.displayKeycardContent) {
if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
return true
}
}
return false
}
@ -226,6 +231,14 @@ Item {
return keyPairForAuthenticationComponent
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.displayKeycardContent) {
if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardMetadataDisplay) {
if (root.sharedKeycardModule.keyPairStoredOnKeycardIsKnown) {
return knownKeyPairComponent
}
return unknownKeyPairCompontnt
}
}
return undefined
}
@ -513,10 +526,11 @@ Item {
PropertyChanges {
target: message
text: {
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard)
return qsTr("The Keycard you have inserted is locked,\nyou will need to factory reset it before proceeding")
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication)
if (root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.useGeneralMessageForLockedState) {
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.setupNewKeycard)
return qsTr("The Keycard you have inserted is locked,\nyou will need to factory reset it before proceeding")
return qsTr("You will need to unlock it before proceeding")
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPinRetriesReached)
return qsTr("Pin entered incorrectly too many times")
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.maxPukRetriesReached)

View File

@ -76,6 +76,7 @@ QtObject {
readonly property int wrongPassword: 8
readonly property int offerPukForUnlock: 16
readonly property int useUnlockLabelForLockedState: 32
readonly property int useGeneralMessageForLockedState: 64
}
readonly property QtObject keycardSharedFlow: QtObject {
@ -84,6 +85,7 @@ QtObject {
readonly property string setupNewKeycard: "SetupNewKeycard"
readonly property string authentication: "Authentication"
readonly property string unlockKeycard: "UnlockKeycard"
readonly property string displayKeycardContent: "DisplayKeycardContent"
}
readonly property QtObject keycardSharedState: QtObject {