feat(@desktop/syncing): keypair syncing - migrate keypair to/from keycard if devices are already paired

Closes: #11706
This commit is contained in:
Sale Djenic 2023-09-06 11:16:23 +02:00 committed by saledjenic
parent 3f3c5a6ce1
commit 61f3d903ce
45 changed files with 692 additions and 235 deletions

View File

@ -420,7 +420,8 @@ proc init*(self: Controller) =
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_KEYCARD_SYNC_TERMINATED, Args())
return
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_SHARED_KEYCARD_MODULE_IDENTIFIER:
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow)
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow, args.continueWithNextFlow,
args.forceFlow, args.continueWithKeyUid, args.returnToFlow)
return
if args.uniqueIdentifier != UNIQUE_MAIN_MODULE_AUTHENTICATE_KEYPAIR_IDENTIFIER or
self.authenticateUserFlowRequestedBy.len == 0:

View File

@ -1,24 +1,25 @@
import NimQml, stint
import ../../../app_service/service/settings/service as settings_service
import ../../../app_service/service/node_configuration/service as node_configuration_service
import ../../../app_service/service/contacts/service as contacts_service
import ../../../app_service/service/chat/service as chat_service
import ../../../app_service/service/community/service as community_service
import ../../../app_service/service/message/service as message_service
import ../../../app_service/service/gif/service as gif_service
import ../../../app_service/service/mailservers/service as mailservers_service
import ../../../app_service/service/community_tokens/service as community_token_service
import ../../../app_service/service/wallet_account/service as wallet_account_service
import ../../../app_service/service/token/service as token_service
import ../../../app_service/service/community_tokens/service as community_tokens_service
import ../../../app_service/service/community_tokens/community_collectible_owner
from ../../../app_service/common/types import StatusType, ContractTransactionStatus
import app_service/service/settings/service as settings_service
import app_service/service/node_configuration/service as node_configuration_service
import app_service/service/contacts/service as contacts_service
import app_service/service/chat/service as chat_service
import app_service/service/community/service as community_service
import app_service/service/message/service as message_service
import app_service/service/gif/service as gif_service
import app_service/service/mailservers/service as mailservers_service
import app_service/service/community_tokens/service as community_token_service
import app_service/service/wallet_account/service as wallet_account_service
import app_service/service/token/service as token_service
import app_service/service/community_tokens/service as community_tokens_service
import app_service/service/community_tokens/community_collectible_owner
from app_service/common/types import StatusType, ContractTransactionStatus
import ../../global/app_signals
import ../../core/eventemitter
import ../../core/notifications/details
import ../shared_models/section_item
import app/global/app_signals
import app/core/eventemitter
import app/core/notifications/details
import app/modules/shared_models/section_item
import app/modules/shared_modules/keycard_popup/module as keycard_shared_module
type
AccessInterface* {.pure inheritable.} = ref object of RootObj
@ -276,7 +277,8 @@ method getKeycardSharedModule*(self: AccessInterface): QVariant {.base.} =
method onDisplayKeycardSharedModuleFlow*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool,
nextFlow: keycard_shared_module.FlowType, forceFlow: bool, nextKeyUid: string, returnToFlow: keycard_shared_module.FlowType) {.base.} =
raise newException(ValueError, "No implementation available")
method runAuthenticationPopup*(self: AccessInterface, keyUid: string, bip44Paths: seq[string] = @[]) {.base.} =

View File

@ -1342,11 +1342,15 @@ method getKeycardSharedModule*[T](self: Module[T]): QVariant =
if not self.keycardSharedModule.isNil:
return self.keycardSharedModule.getModuleAsVariant()
method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) =
method onSharedKeycarModuleFlowTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool, nextFlow: keycard_shared_module.FlowType,
forceFlow: bool, nextKeyUid: string, returnToFlow: keycard_shared_module.FlowType) =
if not self.keycardSharedModule.isNil:
self.view.emitDestroyKeycardSharedModuleFlow()
self.keycardSharedModule.delete
self.keycardSharedModule = nil
if nextFlow == keycard_shared_module.FlowType.General:
self.view.emitDestroyKeycardSharedModuleFlow()
self.keycardSharedModule.delete
self.keycardSharedModule = nil
return
self.keycardSharedModule.runFlow(nextFlow, nextKeyUid, bip44Paths = @[], txHash = "", forceFlow, returnToFlow)
method onDisplayKeycardSharedModuleFlow*[T](self: Module[T]) =
self.view.emitDisplayKeycardSharedModuleFlow()
@ -1360,6 +1364,16 @@ proc runStopUsingKeycardForProfilePopup[T](self: Module[T]) =
self.walletAccountService, self.keychainService)
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.MigrateFromKeycardToApp,
singletonInstance.userProfile.getKeyUid(), bip44Paths = @[], txHash = "", forceFlow = true)
proc runStartUsingKeycardForProfilePopup[T](self: Module[T]) =
if not self.keycardSharedModule.isNil:
info "shared keycard module is already running, cannot run start using keycard flow"
return
self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_SHARED_KEYCARD_MODULE_IDENTIFIER,
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.MigrateFromAppToKeycard,
singletonInstance.userProfile.getKeyUid(), bip44Paths = @[], txHash = "", forceFlow = true)
################################################################################
method checkAndPerformProfileMigrationIfNeeded*[T](self: Module[T]) =
@ -1371,8 +1385,9 @@ method checkAndPerformProfileMigrationIfNeeded*[T](self: Module[T]) =
if not migrationNeeded:
if not self.keycardSharedModule.isNil:
let currentFlow = self.keycardSharedModule.getCurrentFlowType()
if currentFlow == FlowType.MigrateFromKeycardToApp:
self.keycardSharedModule.onCancelActionClicked()
if currentFlow == FlowType.MigrateFromKeycardToApp or
currentFlow == FlowType.MigrateFromAppToKeycard:
self.keycardSharedModule.onCancelActionClicked()
return
if profileKeypair.keycards.len > 0:
if not self.keycardSharedModule.isNil:
@ -1383,8 +1398,14 @@ method checkAndPerformProfileMigrationIfNeeded*[T](self: Module[T]) =
info "run stop using keycard flow for the profile, cause profile was migrated on paired device"
self.runStopUsingKeycardForProfilePopup()
return
## TODO: we need to add a flow to handle migration to a Keycard
if not self.keycardSharedModule.isNil:
let currentFlow = self.keycardSharedModule.getCurrentFlowType()
if currentFlow == FlowType.MigrateFromAppToKeycard:
return
self.keycardSharedModule.onCancelActionClicked()
info "run migrate to a Keycard flow for the profile, cause profile was migrated on paired device"
self.runStartUsingKeycardForProfilePopup()
method activateStatusDeepLink*[T](self: Module[T], statusDeepLink: string) =
let urlData = self.sharedUrlsModule.parseSharedUrl(statusDeepLink)

View File

@ -37,7 +37,8 @@ proc init*(self: Controller) =
let args = SharedKeycarModuleFlowTerminatedArgs(e)
if args.uniqueIdentifier != UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER:
return
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow, args.continueWithNextFlow)
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow, args.continueWithNextFlow,
args.forceFlow, args.continueWithKeyUid, args.returnToFlow)
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_DISPLAY_POPUP) do(e: Args):
let args = SharedKeycarModuleBaseArgs(e)

View File

@ -25,7 +25,7 @@ method onDisplayKeycardSharedModuleFlow*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool,
nextFlow: FlowType) {.base.} =
nextFlow: FlowType, forceFlow: bool, nextKeyUid: string, returnToFlow: keycard_shared_module.FlowType) {.base.} =
raise newException(ValueError, "No implementation available")
method runSetupKeycardPopup*(self: AccessInterface, keyUid: string) {.base.} =

View File

@ -105,17 +105,15 @@ proc createSharedKeycardModule(self: Module) =
self.events, self.keycardService, self.settingsService, self.networkService, self.privacyService, self.accountsService,
self.walletAccountService, self.keychainService)
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool, nextFlow: keycard_shared_module.FlowType) =
echo "onSharedKeycarModuleFlowTerminated lastStepInTheCurrentFlow=", lastStepInTheCurrentFlow, " nextFlow=", nextFlow
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool, nextFlow: keycard_shared_module.FlowType,
forceFlow: bool, nextKeyUid: string, returnToFlow: keycard_shared_module.FlowType) =
if self.isSharedKeycardModuleFlowRunning():
echo "onSharedKeycarModuleFlowTerminated isSharedKeycardModuleFlowRunning=true"
if nextFlow == keycard_shared_module.FlowType.General:
self.view.emitDestroyKeycardSharedModuleFlow()
self.keycardSharedModule.delete
self.keycardSharedModule = nil
return
let keyUid = self.keycardSharedModule.getKeyPairForProcessing().getKeyUid()
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.FactoryReset, keyUid)
self.keycardSharedModule.runFlow(nextFlow, nextKeyUid, bip44Paths = @[], txHash = "", forceFlow, returnToFlow)
method onDisplayKeycardSharedModuleFlow*(self: Module) =
self.view.emitDisplayKeycardSharedModuleFlow()

View File

@ -210,6 +210,12 @@ proc switchToWalletSection*(self: Controller) =
proc rebuildKeycards*(self: Controller) =
self.events.emit(SIGNAL_KEYCARD_REBUILD, Args())
proc getReturnToFlow*(self: Controller): FlowType =
return self.delegate.getReturnToFlow()
proc getForceFlow*(self: Controller): bool =
return self.delegate.getForceFlow()
proc getKeycardData*(self: Controller): string =
return self.delegate.getKeycardData()
@ -398,13 +404,22 @@ proc verifyPassword*(self: Controller, password: string): bool =
return
return self.accountsService.verifyPassword(password)
proc convertRegularProfileKeypairToKeycard*(self: Controller, keycardUid: string, currentPassword: string) =
proc convertRegularProfileKeypairToKeycard*(self: Controller) =
if not serviceApplicable(self.accountsService):
return
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true)
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
self.accountsService.convertRegularProfileKeypairToKeycard(keycardUid, currentPassword = currentPassword,
newPassword = acc.derivedAccounts.encryption.publicKey)
var newPassword: string
var keycardUid: string
let seedPhrase = self.getSeedPhrase()
if seedPhrase.len > 0:
let acc = self.accountsService.createAccountFromMnemonic(self.getSeedPhrase(), includeEncryption = true)
newPassword = acc.derivedAccounts.encryption.publicKey
keycardUid = self.getSelectedKeyPairDto().keycardUid
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NOT_NOW)
else:
keycardUid = self.getKeycardUid()
newPassword = self.getNewPassword()
self.accountsService.convertRegularProfileKeypairToKeycard(keycardUid, currentPassword = self.getPassword(), newPassword)
proc convertKeycardProfileKeypairToRegular*(self: Controller, seedPhrase: string, currentPassword: string, newPassword: string) =
if not serviceApplicable(self.accountsService):
@ -537,6 +552,12 @@ proc runLoadAccountFlow*(self: Controller, seedPhraseLength = 0, seedPhrase = ""
self.cancelCurrentFlow()
self.keycardService.startLoadAccountFlow(seedPhraseLength, seedPhrase, pin, puk, factoryReset)
proc runLoginFlow*(self: Controller) =
if not serviceApplicable(self.keycardService):
return
self.cancelCurrentFlow()
self.keycardService.startLoginFlow()
# This flow is not in use any more for authentication purpose, will be use later for signing a transaction, but
# we still do not support that. Going to keep this code, but as a comment.
#
@ -592,13 +613,17 @@ proc finishFlowTermination(self: Controller) =
self.cleanTmpData()
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED, data)
proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool, nextFlow = FlowType.General) =
proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool, nextFlow = FlowType.General, forceFlow = false,
nextKeyUid = "", returnToFlow = FlowType.General) =
let flowType = self.delegate.getCurrentFlowType()
self.cancelCurrentFlow()
let (_, flowEvent) = self.getLastReceivedKeycardData()
self.tmpFlowData = SharedKeycarModuleFlowTerminatedArgs(uniqueIdentifier: self.uniqueIdentifier,
lastStepInTheCurrentFlow: lastStepInTheCurrentFlow,
continueWithNextFlow: nextFlow)
continueWithNextFlow: nextFlow,
forceFlow: forceFlow,
continueWithKeyUid: nextKeyUid,
returnToFlow: returnToFlow)
if lastStepInTheCurrentFlow:
var exportedEncryptionPubKey: string
if flowEvent.generatedWalletAccounts.len > 0:

View File

@ -19,6 +19,10 @@ proc doAuthentication(self: BiometricsState, controller: Controller) =
if not migratingProfile:
return
controller.authenticateUser()
return
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.authenticateUser()
return
method executePrePrimaryStateCommand*(self: BiometricsState, controller: Controller) =
self.storeToKeychain = true
@ -35,8 +39,11 @@ method executePreTertiaryStateCommand*(self: BiometricsState, controller: Contro
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER)
method getNextTertiaryState*(self: BiometricsState, controller: Controller): State =
## Tertiary action is called after each async action during migration process.
if self.flowType == FlowType.MigrateFromKeycardToApp:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not migratingProfile:
return
return createState(StateType.MigratingKeypairToApp, self.flowType, nil)
return createState(StateType.MigratingKeypairToApp, self.flowType, nil)
if self.flowType == FlowType.MigrateFromAppToKeycard:
return createState(StateType.MigratingKeypairToKeycard, self.flowType, nil)

View File

@ -9,7 +9,7 @@ proc delete*(self: EnterPinState) =
self.State.delete
method getNextPrimaryState*(self: EnterPinState, controller: Controller): State =
if self.flowType == FlowType.DisplayKeycardContent or
if self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
@ -34,9 +34,10 @@ method executePreSecondaryStateCommand*(self: EnterPinState, controller: Control
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
if controller.getPin().len == PINLengthForStatusApp:
controller.enterKeycardPin(controller.getPin())
controller.enterKeycardPin(controller.getPin())
if self.flowType == FlowType.Authentication:
controller.setUsePinFromBiometrics(false)
controller.tryToObtainDataFromKeychain()
@ -53,16 +54,17 @@ method executeCancelCommand*(self: EnterPinState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
if not state.isNil:
return state
if self.flowType == FlowType.FactoryReset:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -70,11 +72,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
@ -83,7 +85,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.SetupNewKeycard:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -91,11 +93,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
@ -104,7 +106,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -112,11 +114,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
@ -125,7 +127,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -133,11 +135,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
@ -146,7 +148,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.ImportFromKeycard:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -154,11 +156,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
@ -175,15 +177,15 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
item.setName(keycardEvent.cardMetadata.name)
item.setIcon("keycard")
item.setPairType(KeyPairType.SeedImport.int)
item.addAccount(newKeyPairAccountItem(name = "",
path = accountItem.getPath(),
item.addAccount(newKeyPairAccountItem(name = "",
path = accountItem.getPath(),
address = accountItem.getAddress(),
pubKey = accountItem.getPubKey()
)) # name and other params will be set by the user during the flow
controller.setKeyPairForProcessing(item)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.Authentication:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -192,10 +194,10 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongKeychainPin, self.flowType, nil)
return createState(StateType.WrongPin, self.flowType, nil)
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
@ -206,7 +208,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return nil
if self.flowType == FlowType.DisplayKeycardContent:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -214,11 +216,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
@ -227,7 +229,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.RenameKeycard:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -235,11 +237,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
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
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
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))
@ -248,7 +250,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.ChangeKeycardPin:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -256,11 +258,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
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
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
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))
@ -269,7 +271,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
if keycardEvent.error == ErrorChangingCredentials:
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.ChangeKeycardPuk:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -277,11 +279,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
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
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
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))
@ -290,7 +292,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
if keycardEvent.error == ErrorChangingCredentials:
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.ChangePairingCode:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -298,11 +300,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
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
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
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))
@ -312,7 +314,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.CreateCopyOfAKeycard:
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -320,11 +322,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
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
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
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))
@ -333,7 +335,7 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
else:
if keycardFlowType == ResponseTypeValueEnterPIN and
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
@ -341,11 +343,11 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
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
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
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))
@ -355,3 +357,25 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
controller.setPinForKeycardCopy(controller.getPin())
controller.setMetadataForKeycardCopy(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.MigrateFromAppToKeycard:
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(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 == ResponseTypeValueKeycardFlowResult:
controller.setKeycardUid(keycardEvent.instanceUID)
controller.setNewPassword(keycardEvent.encryptionKey.publicKey)
return createState(StateType.PinVerified, self.flowType, nil)

View File

@ -26,15 +26,16 @@ method executeCancelCommand*(self: InsertKeycardState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
method resolveKeycardNextState*(self: InsertKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
let state = ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
if not state.isNil:
return state
if keycardFlowType == ResponseTypeValueInsertCard and
if keycardFlowType == ResponseTypeValueInsertCard and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorConnection:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WronglyInsertedCard, add = true))

View File

@ -9,21 +9,29 @@ proc delete*(self: KeyPairMigrateFailureState) =
self.State.delete
method executePrePrimaryStateCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.MigrateFromKeycardToApp:
let profileMigrated = controller.getSelectedKeyPairIsProfile()
if not profileMigrated:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
info "quit the app because of profile migration failure"
quit() # quit the app
var profileMigrated = false
if self.flowType == FlowType.SetupNewKeycard:
profileMigrated = controller.getSelectedKeyPairIsProfile()
elif self.flowType == FlowType.MigrateFromKeycardToApp or
self.flowType == FlowType.MigrateFromAppToKeycard:
profileMigrated = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not profileMigrated:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
info "quit the app because of profile migration failure"
quit() # quit the app
method executeCancelCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.MigrateFromKeycardToApp:
let profileMigrated = controller.getSelectedKeyPairIsProfile()
if not profileMigrated:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
info "quit the app because of profile migration failure"
quit() # quit the app
var profileMigrated = false
if self.flowType == FlowType.SetupNewKeycard:
profileMigrated = controller.getSelectedKeyPairIsProfile()
elif self.flowType == FlowType.MigrateFromKeycardToApp or
self.flowType == FlowType.MigrateFromAppToKeycard:
profileMigrated = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not profileMigrated:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
info "quit the app because of profile migration failure"
quit() # quit the app

View File

@ -12,12 +12,19 @@ method executeCancelCommand*(self: KeyPairMigrateSuccessState, controller: Contr
if self.flowType == FlowType.SetupNewKeycard:
let profileMigrated = controller.getSelectedKeyPairIsProfile()
if profileMigrated:
info "quit the app cause this is not an available option in the context of SetupNewKeycard flow for profile keypair"
quit() # quit the app
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
if self.flowType == FlowType.MigrateFromKeycardToApp:
if controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid():
info "quit the app cause this is not an available option in the context of MigrateFromKeycardToApp flow for profile keypair"
quit() # quit the app
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
if self.flowType == FlowType.MigrateFromAppToKeycard:
info "quit the app cause this is not an available option in the context of MigrateFromAppToKeycard"
quit() # quit the app
method executePrePrimaryStateCommand*(self: KeyPairMigrateSuccessState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard:
@ -32,10 +39,14 @@ method executePrePrimaryStateCommand*(self: KeyPairMigrateSuccessState, controll
if profileMigrated:
info "restart the app because of successfully migrated profile keypair"
quit() # quit the app
if self.flowType == FlowType.MigrateFromAppToKeycard:
info "restart the app because of successfully migrated profile keypair"
quit() # quit the app
method executePreSecondaryStateCommand*(self: KeyPairMigrateSuccessState, controller: Controller) =
if self.flowType == FlowType.MigrateFromKeycardToApp:
let profileMigrated = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if profileMigrated:
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, FlowType.FactoryReset)
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.FactoryReset,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())

View File

@ -10,7 +10,12 @@ proc delete*(self: KeycardAlreadyUnlockedState) =
method executePrePrimaryStateCommand*(self: KeycardAlreadyUnlockedState, controller: Controller) =
if self.flowType == FlowType.UnlockKeycard:
if controller.getReturnToFlow() == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.MigrateFromAppToKeycard,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
method executeCancelCommand*(self: KeycardAlreadyUnlockedState, controller: Controller) =
if self.flowType == FlowType.UnlockKeycard:

View File

@ -17,18 +17,30 @@ method executeCancelCommand*(self: KeycardEmptyMetadataState, controller: Contro
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method executePrePrimaryStateCommand*(self: KeycardEmptyMetadataState, controller: Controller) =
if self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
if self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.RenameKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
if self.flowType == FlowType.UnlockKeycard:
if controller.getReturnToFlow() == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.MigrateFromAppToKeycard,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
if self.flowType == FlowType.CreateCopyOfAKeycard:
if not isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.runLoginFlow()
return
method getNextPrimaryState*(self: KeycardEmptyMetadataState, controller: Controller): State =
if self.flowType == FlowType.FactoryReset or
@ -38,4 +50,9 @@ method getNextPrimaryState*(self: KeycardEmptyMetadataState, controller: Control
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
if self.flowType == FlowType.CreateCopyOfAKeycard:
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
method resolveKeycardNextState*(self: KeycardEmptyMetadataState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
if self.flowType == FlowType.MigrateFromAppToKeycard:
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)

View File

@ -12,7 +12,6 @@ method executePrePrimaryStateCommand*(self: KeycardEmptyState, controller: Contr
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.ChangeKeycardPin or
@ -20,6 +19,17 @@ method executePrePrimaryStateCommand*(self: KeycardEmptyState, controller: Contr
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
return
if self.flowType == FlowType.UnlockKeycard:
if controller.getReturnToFlow() == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.MigrateFromAppToKeycard,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
return
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.runLoginFlow()
return
method executeCancelCommand*(self: KeycardEmptyState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
@ -31,5 +41,11 @@ method executeCancelCommand*(self: KeycardEmptyState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: KeycardEmptyState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
if self.flowType == FlowType.MigrateFromAppToKeycard:
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)

View File

@ -7,7 +7,7 @@ proc newKeycardInsertedState*(flowType: FlowType, backState: State): KeycardInse
proc delete*(self: KeycardInsertedState) =
self.State.delete
method executePreBackStateCommand*(self: KeycardInsertedState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard:
if not self.getBackState.isNil and self.getBackState.stateType == StateType.SelectExistingKeyPair:
@ -33,5 +33,6 @@ method executeCancelCommand*(self: KeycardInsertedState, controller: Controller)
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -8,6 +8,11 @@ proc newMaxPairingSlotsReachedState*(flowType: FlowType, backState: State): MaxP
proc delete*(self: MaxPairingSlotsReachedState) =
self.State.delete
method executePrePrimaryStateCommand*(self: MaxPairingSlotsReachedState, controller: Controller) =
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.UnlockKeycard, forceFlow = controller.getForceFlow(),
nextKeyUid = controller.getKeyPairForProcessing().getKeyUid(), returnToFlow = FlowType.MigrateFromAppToKeycard)
method getNextPrimaryState*(self: MaxPairingSlotsReachedState, controller: Controller): State =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
@ -39,5 +44,6 @@ method executeCancelCommand*(self: MaxPairingSlotsReachedState, controller: Cont
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -8,6 +8,11 @@ proc newMaxPinRetriesReachedState*(flowType: FlowType, backState: State): MaxPin
proc delete*(self: MaxPinRetriesReachedState) =
self.State.delete
method executePrePrimaryStateCommand*(self: MaxPinRetriesReachedState, controller: Controller) =
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.UnlockKeycard, forceFlow = controller.getForceFlow(),
nextKeyUid = controller.getKeyPairForProcessing().getKeyUid(), returnToFlow = FlowType.MigrateFromAppToKeycard)
method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Controller): State =
if self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.ChangeKeycardPin or
@ -15,7 +20,7 @@ method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Control
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
controller.runSharedModuleFlow(FlowType.UnlockKeycard, controller.getKeyPairForProcessing().getKeyUid())
if self.flowType == FlowType.ImportFromKeycard or
if self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.DisplayKeycardContent:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
@ -38,7 +43,8 @@ method executeCancelCommand*(self: MaxPinRetriesReachedState, controller: Contro
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.ImportFromKeycard or

View File

@ -8,13 +8,18 @@ proc newMaxPukRetriesReachedState*(flowType: FlowType, backState: State): MaxPuk
proc delete*(self: MaxPukRetriesReachedState) =
self.State.delete
method executePrePrimaryStateCommand*(self: MaxPukRetriesReachedState, controller: Controller) =
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.UnlockKeycard, forceFlow = controller.getForceFlow(),
nextKeyUid = controller.getKeyPairForProcessing().getKeyUid(), returnToFlow = FlowType.MigrateFromAppToKeycard)
method getNextPrimaryState*(self: MaxPukRetriesReachedState, controller: Controller): State =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
if self.flowType == FlowType.ImportFromKeycard or
if self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
@ -39,5 +44,6 @@ method executeCancelCommand*(self: MaxPukRetriesReachedState, controller: Contro
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -0,0 +1,21 @@
type
MigrateKeypairToKeycardState* = ref object of State
proc newMigrateKeypairToKeycardState*(flowType: FlowType, backState: State): MigrateKeypairToKeycardState =
result = MigrateKeypairToKeycardState()
result.setup(flowType, StateType.MigrateKeypairToKeycard, backState)
proc delete*(self: MigrateKeypairToKeycardState) =
self.State.delete
method executeCancelCommand*(self: MigrateKeypairToKeycardState, controller: Controller) =
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
method executePrePrimaryStateCommand*(self: MigrateKeypairToKeycardState, controller: Controller) =
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.runLoginFlow()
method resolveKeycardNextState*(self: MigrateKeypairToKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)

View File

@ -24,11 +24,6 @@ proc doMigration(self: MigratingKeypairToKeycardState, controller: Controller) =
let selectedKeyPairDto = controller.getSelectedKeyPairDto()
controller.addKeycardOrAccounts(selectedKeyPairDto)
proc doConversion(self: MigratingKeypairToKeycardState, controller: Controller) =
let password = controller.getPassword()
let selectedKeyPairDto = controller.getSelectedKeyPairDto()
controller.convertRegularProfileKeypairToKeycard(selectedKeyPairDto.keycardUid, password)
proc runStoreMetadataFlow(self: MigratingKeypairToKeycardState, controller: Controller) =
let selectedKeyPairDto = controller.getSelectedKeyPairDto()
controller.runStoreMetadataFlow(selectedKeyPairDto.keycardName, controller.getPin(), controller.getSelectedKeyPairWalletPaths())
@ -39,6 +34,9 @@ method executePrePrimaryStateCommand*(self: MigratingKeypairToKeycardState, cont
controller.authenticateUser()
return
self.doMigration(controller)
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.convertRegularProfileKeypairToKeycard()
return
method executePreTertiaryStateCommand*(self: MigratingKeypairToKeycardState, controller: Controller) =
## Tertiary action is called after each async action during migration process.
@ -49,7 +47,7 @@ method executePreTertiaryStateCommand*(self: MigratingKeypairToKeycardState, con
let password = controller.getPassword()
self.authenticationOk = controller.verifyPassword(password)
if self.authenticationOk:
self.doConversion(controller)
controller.convertRegularProfileKeypairToKeycard()
return
if not self.profileConversionDone:
self.profileConversionDone = true
@ -62,6 +60,12 @@ method executePreTertiaryStateCommand*(self: MigratingKeypairToKeycardState, con
self.addingMigratedKeypairOk = controller.getAddingMigratedKeypairSuccess()
if self.addingMigratedKeypairOk:
self.runStoreMetadataFlow(controller)
return
if self.flowType == FlowType.MigrateFromAppToKeycard:
if not self.profileConversionDone:
self.profileConversionDone = true
self.profileConversionOk = controller.getConvertingProfileSuccess()
method getNextTertiaryState*(self: MigratingKeypairToKeycardState, controller: Controller): State =
if self.flowType == FlowType.SetupNewKeycard:
@ -72,6 +76,11 @@ method getNextTertiaryState*(self: MigratingKeypairToKeycardState, controller: C
else:
if self.addingMigratedKeypairDone and not self.addingMigratedKeypairOk:
return createState(StateType.KeyPairMigrateFailure, self.flowType, nil)
if self.flowType == FlowType.MigrateFromAppToKeycard:
if self.profileConversionDone and not self.profileConversionOk:
return createState(StateType.KeyPairMigrateFailure, self.flowType, nil)
if self.profileConversionOk:
return createState(StateType.KeyPairMigrateSuccess, self.flowType, nil)
method resolveKeycardNextState*(self: MigratingKeypairToKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =

View File

@ -21,14 +21,19 @@ method executeCancelCommand*(self: NotKeycardState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method executePrePrimaryStateCommand*(self: NotKeycardState, controller: Controller) =
if self.flowType == FlowType.CreateCopyOfAKeycard:
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
controller.runLoadAccountFlow(seedPhraseLength = 0, seedPhrase = "", pin = controller.getPin())
return
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.runLoginFlow()
return
method resolveKeycardNextState*(self: NotKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
method resolveKeycardNextState*(self: NotKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)

View File

@ -24,6 +24,8 @@ method getNextPrimaryState*(self: PinVerifiedState, controller: Controller): Sta
return createState(StateType.CreatePuk, self.flowType, nil)
if self.flowType == FlowType.ChangePairingCode:
return createState(StateType.CreatePairingCode, self.flowType, nil)
if self.flowType == FlowType.MigrateFromAppToKeycard:
return createState(StateType.Biometrics, self.flowType, nil)
method executeCancelCommand*(self: PinVerifiedState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
@ -36,5 +38,6 @@ method executeCancelCommand*(self: PinVerifiedState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

View File

@ -26,9 +26,10 @@ method executeCancelCommand*(self: PluginReaderState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,
method resolveKeycardNextState*(self: PluginReaderState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)

View File

@ -28,6 +28,7 @@ method resolveKeycardNextState*(self: ReadingKeycardState, keycardFlowType: stri
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.MigrateFromAppToKeycard or
(self.flowType == FlowType.CreateCopyOfAKeycard and
not isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone)) or
self.flowType == FlowType.FactoryReset and

View File

@ -27,13 +27,14 @@ method getNextSecondaryState*(self: RecognizedKeycardState, controller: Controll
return createState(StateType.EnterSeedPhrase, self.flowType, nil)
if self.flowType == FlowType.UnlockKeycard:
return createState(StateType.UnlockKeycardOptions, self.flowType, nil)
if self.flowType == FlowType.ImportFromKeycard or
if self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
return createState(StateType.EnterPin, self.flowType, nil)
method executeCancelCommand*(self: RecognizedKeycardState, controller: Controller) =

View File

@ -49,6 +49,7 @@ type StateType* {.pure.} = enum
KeyPairMigrateSuccess = "KeyPairMigrateSuccess"
KeyPairMigrateFailure = "KeyPairMigrateFailure"
MigrateKeypairToApp = "MigrateKeypairToApp"
MigrateKeypairToKeycard = "MigrateKeypairToKeycard"
MigratingKeypairToApp = "MigratingKeypairToApp"
MigratingKeypairToKeycard = "MigratingKeypairToKeycard"
EnterPassword = "EnterPassword"

View File

@ -1,13 +1,16 @@
import parseutils, sequtils, sugar, chronicles
import ../../../../global/global_singleton
import ../../../../../app_service/service/keycard/constants
from ../../../../../app_service/service/keycard/service import KCSFlowType
from ../../../../../app_service/service/keycard/service import PINLengthForStatusApp
from ../../../../../app_service/service/keycard/service import PUKLengthForStatusApp
import ../../../../../app_service/common/account_constants
import ../../../../../app_service/service/wallet_account/dto/[keypair_dto]
import app/global/global_singleton
import app_service/service/keycard/constants
import app_service/common/account_constants
import app_service/service/wallet_account/dto/[keypair_dto]
import app/modules/shared_models/[keypair_model]
from app_service/service/keycard/service import KCSFlowType
from app_service/service/keycard/service import PINLengthForStatusApp
from app_service/service/keycard/service import PUKLengthForStatusApp
import ../controller
import ../../../shared_models/[keypair_model]
import state
logScope:
@ -94,6 +97,7 @@ include max_pin_retries_reached_state
include max_puk_retries_reached_state
include max_pairing_slots_reached_state
include migrate_keypair_to_app_state
include migrate_keypair_to_keycard_state
include migrating_keypair_to_app_state
include migrating_keypair_to_keycard_state
include no_pcsc_service_state

View File

@ -151,6 +151,8 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
return newMaxPairingSlotsReachedState(flowType, backState)
if stateToBeCreated == StateType.MigrateKeypairToApp:
return newMigrateKeypairToAppState(flowType, backState)
if stateToBeCreated == StateType.MigrateKeypairToKeycard:
return newMigrateKeypairToKeycardState(flowType, backState)
if stateToBeCreated == StateType.MigratingKeypairToApp:
return newMigratingKeypairToAppState(flowType, backState)
if stateToBeCreated == StateType.MigratingKeypairToKeycard:

View File

@ -1,6 +1,6 @@
proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State =
## Check for some specific errors
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPCSC:
return createState(StateType.NoPCSCService, state.flowType, nil)
@ -16,8 +16,9 @@ proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycard
state.flowType == FlowType.CreateCopyOfAKeycard or
state.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
state.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
state.flowType == FlowType.ImportFromKeycard:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
state.flowType == FlowType.ImportFromKeycard or
state.flowType == FlowType.MigrateFromAppToKeycard:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorNoReader:
controller.reRunCurrentFlowLater()
@ -37,9 +38,9 @@ proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycard
## Handling setup new keycard flow
if state.flowType == FlowType.SetupNewKeycard:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorConnection or
keycardEvent.error == ErrorConnection or
keycardEvent.error == ErrorNoReader:
controller.reRunCurrentFlowLater()
if state.stateType == StateType.PluginReader:
@ -68,11 +69,11 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if state.flowType == FlowType.FactoryReset:
if keycardFlowType == ResponseTypeValueEnterPIN:
return createState(StateType.EnterPin, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
return createState(StateType.FactoryResetConfirmation, state.flowType, nil)
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -86,7 +87,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
## the cahnge made in that one.
## That flow is not a subject of MVP and will be handled after MVP accross app properly,
## issue: https://github.com/status-im/status-desktop/issues/8065
if keycardFlowType == ResponseTypeValueEnterPairing and
if keycardFlowType == ResponseTypeValueEnterPairing and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorPairing:
return createState(StateType.FactoryResetConfirmation, state.flowType, nil)
@ -106,7 +107,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
## Handling setup new keycard flow
if state.flowType == FlowType.SetupNewKeycard:
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -122,12 +123,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
return createState(StateType.EnterPin, state.flowType, nil)
return createState(StateType.KeycardNotEmpty, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0:
controller.setKeycardData("")
if keycardEvent.error == ErrorOk:
@ -136,7 +137,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterNewPIN and
if keycardFlowType == ResponseTypeValueEnterNewPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorRequireInit:
if state.stateType == StateType.SelectExistingKeyPair:
@ -145,7 +146,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
## Handling setup new keycard new seed phrase flow
if state.flowType == FlowType.SetupNewKeycardNewSeedPhrase:
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -161,12 +162,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
return createState(StateType.EnterPin, state.flowType, nil)
return createState(StateType.KeycardNotEmpty, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0:
controller.setKeycardData("")
if keycardEvent.error == ErrorOk:
@ -175,14 +176,14 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterNewPIN and
if keycardFlowType == ResponseTypeValueEnterNewPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorRequireInit:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
## Handling setup new keycard old seed phrase flow
if state.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -198,12 +199,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
return createState(StateType.EnterPin, state.flowType, nil)
return createState(StateType.KeycardNotEmpty, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0:
controller.setKeycardData("")
if keycardEvent.error == ErrorOk:
@ -212,7 +213,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterNewPIN and
if keycardFlowType == ResponseTypeValueEnterNewPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorRequireInit:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
@ -226,12 +227,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -254,7 +255,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
## Handling authentiaction flow
if state.flowType == FlowType.Authentication:
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -281,7 +282,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.BiometricsReadyToSign, state.flowType, nil)
return createState(StateType.EnterPin, state.flowType, nil)
return createState(StateType.WrongKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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))
@ -297,7 +298,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.KeycardAlreadyUnlocked, state.flowType, nil)
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -307,7 +308,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardEvent.error == ErrorPUKRetries:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
controller.setKeycardUid(keycardEvent.instanceUID)
return createState(StateType.RecognizedKeycard, state.flowType, nil)
@ -323,12 +324,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -353,12 +354,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -381,12 +382,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -406,21 +407,21 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error.len == 0:
return createState(StateType.ChangingKeycardPinSuccess, state.flowType, nil)
## in all other cases if we fall through here, we assume it's changing pin failor, but that we not interfare with
## in all other cases if we fall through here, we assume it's changing pin failor, but that we not interfare with
## `nil` for `ensureState` we just do this `if` cause we can get here only from `ChangingKeycardPin` state.
if state.stateType == StateType.ChangingKeycardPin:
return createState(StateType.ChangingKeycardPinFailure, state.flowType, nil)
if state.flowType == FlowType.ChangeKeycardPuk:
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -440,21 +441,21 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error.len == 0:
return createState(StateType.ChangingKeycardPukSuccess, state.flowType, nil)
## in all other cases if we fall through here, we assume it's changing puk failor, but that we not interfare with
## in all other cases if we fall through here, we assume it's changing puk failor, but that we not interfare with
## `nil` for `ensureState` we just do this `if` cause we can get here only from `ChangingKeycardPuk` state.
if state.stateType == StateType.ChangingKeycardPuk:
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
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -474,7 +475,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error.len == 0:
return createState(StateType.ChangingKeycardPairingCodeSuccess, state.flowType, nil)
## in all other cases if we fall through here, we assume it's changing pairing code failor, but that we not interfare with
## in all other cases if we fall through here, we assume it's changing pairing code failor, but that we not interfare with
## `nil` for `ensureState` we just do this `if` cause we can get here only from `ChangingKeycardPairingCode` state.
if state.stateType == StateType.ChangingKeycardPairingCode:
return createState(StateType.ChangingKeycardPairingCodeFailure, state.flowType, nil)
@ -483,7 +484,7 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
if controller.getKeycardUid().len > 0 and controller.getKeycardUid() == keycardEvent.instanceUID:
return createState(StateType.SameKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueSwapCard and
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -499,12 +500,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
return createState(StateType.EnterPin, state.flowType, nil)
return createState(StateType.KeycardNotEmpty, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len > 0:
controller.setKeycardData("")
# we're still in part 2, so set kc data appropriatelly after cleaning
@ -515,11 +516,11 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterNewPIN and
if keycardFlowType == ResponseTypeValueEnterNewPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorRequireInit:
return createState(StateType.CopyToKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterMnemonic and
if keycardFlowType == ResponseTypeValueEnterMnemonic and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorLoadingKeys:
return createState(StateType.CopyToKeycard, state.flowType, nil)
@ -527,12 +528,12 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
return createState(StateType.RecognizedKeycard, state.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
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
if keycardFlowType == ResponseTypeValueSwapCard and
keycardEvent.error.len > 0:
if keycardEvent.error == ErrorNotAKeycard:
return createState(StateType.NotKeycard, state.flowType, nil)
@ -549,4 +550,29 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
if keycardEvent.error == ErrorNoKeys:
return createState(StateType.KeycardEmpty, state.flowType, nil)
if keycardEvent.error == ErrorNoData:
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
## Handling migration from the app to a Keycard flow
if state.flowType == FlowType.MigrateFromAppToKeycard:
if keycardEvent.keyUid.len > 0 and keycardEvent.keyUid != controller.getKeyPairForProcessing().getKeyUid():
return createState(StateType.WrongKeycard, 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 == 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)

View File

@ -10,6 +10,10 @@ proc delete*(self: UnlockKeycardFailureState) =
method executePrePrimaryStateCommand*(self: UnlockKeycardFailureState, controller: Controller) =
if self.flowType == FlowType.UnlockKeycard:
if controller.getReturnToFlow() == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.MigrateFromAppToKeycard,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
method executeCancelCommand*(self: UnlockKeycardFailureState, controller: Controller) =

View File

@ -10,6 +10,10 @@ proc delete*(self: UnlockKeycardSuccessState) =
method executePrePrimaryStateCommand*(self: UnlockKeycardSuccessState, controller: Controller) =
if self.flowType == FlowType.UnlockKeycard:
if controller.getReturnToFlow() == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.MigrateFromAppToKeycard,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())
return
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
method executeCancelCommand*(self: UnlockKeycardSuccessState, controller: Controller) =

View File

@ -9,14 +9,22 @@ proc delete*(self: WrongKeycardState) =
self.State.delete
method executePrePrimaryStateCommand*(self: WrongKeycardState, controller: Controller) =
if self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.RenameKeycard or
if self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.FactoryReset:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
return
if self.flowType == FlowType.UnlockKeycard:
if controller.getReturnToFlow() == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true, nextFlow = FlowType.MigrateFromAppToKeycard,
forceFlow = controller.getForceFlow(), nextKeyUid = controller.getKeyPairForProcessing().getKeyUid())
return
if self.flowType == FlowType.MigrateFromAppToKeycard:
controller.runLoginFlow()
return
method executeCancelCommand*(self: WrongKeycardState, controller: Controller) =
if self.flowType == FlowType.Authentication or
@ -26,5 +34,11 @@ method executeCancelCommand*(self: WrongKeycardState, controller: Controller) =
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.FactoryReset:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.MigrateFromAppToKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method resolveKeycardNextState*(self: WrongKeycardState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
if self.flowType == FlowType.MigrateFromAppToKeycard:
return ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)

View File

@ -39,7 +39,8 @@ method executePreSecondaryStateCommand*(self: WrongPinState, controller: Control
self.flowType == FlowType.ChangeKeycardPin or
self.flowType == FlowType.ChangeKeycardPuk or
self.flowType == FlowType.ChangePairingCode or
self.flowType == FlowType.CreateCopyOfAKeycard:
self.flowType == FlowType.CreateCopyOfAKeycard or
self.flowType == FlowType.MigrateFromAppToKeycard:
if controller.getPin().len == PINLengthForStatusApp:
controller.enterKeycardPin(controller.getPin())
if self.flowType == FlowType.Authentication:
@ -302,4 +303,22 @@ method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, ke
controller.setKeycardUid(keycardEvent.instanceUID)
controller.setPinForKeycardCopy(controller.getPin())
controller.setMetadataForKeycardCopy(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.MigrateFromAppToKeycard:
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(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 == ResponseTypeValueKeycardFlowResult:
controller.setKeycardUid(keycardEvent.instanceUID)
controller.setNewPassword(keycardEvent.encryptionKey.publicKey)
return createState(StateType.PinVerified, self.flowType, nil)

View File

@ -20,6 +20,7 @@ type FlowType* {.pure.} = enum
ChangePairingCode = "ChangePairingCode"
CreateCopyOfAKeycard = "CreateCopyOfAKeycard"
MigrateFromKeycardToApp = "MigrateFromKeycardToApp"
MigrateFromAppToKeycard = "MigrateFromAppToKeycard"
# For the following flows we don't run card syncing.
const FlowsWeShouldNotTryAKeycardSyncFor* = @[
@ -32,7 +33,8 @@ const FlowsWeShouldNotTryAKeycardSyncFor* = @[
FlowType.ImportFromKeycard,
FlowType.Authentication,
FlowType.CreateCopyOfAKeycard,
FlowType.MigrateFromKeycardToApp
FlowType.MigrateFromKeycardToApp,
FlowType.MigrateFromAppToKeycard,
]
const SIGNAL_SHARED_KEYCARD_MODULE_DISPLAY_POPUP* = "sharedKeycarModuleDisplayPopup"
@ -75,6 +77,9 @@ type
SharedKeycarModuleFlowTerminatedArgs* = ref object of SharedKeycarModuleArgs
lastStepInTheCurrentFlow*: bool
continueWithNextFlow*: FlowType
forceFlow*: bool
continueWithKeyUid*: string
returnToFlow*: FlowType
type
SharedKeycarModuleAuthenticationArgs* = ref object of SharedKeycarModuleBaseArgs
@ -93,6 +98,12 @@ method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
method getCurrentFlowType*(self: AccessInterface): FlowType {.base.} =
raise newException(ValueError, "No implementation available")
method getReturnToFlow*(self: AccessInterface): FlowType {.base.} =
raise newException(ValueError, "No implementation available")
method getForceFlow*(self: AccessInterface): bool {.base.} =
raise newException(ValueError, "No implementation available")
method getKeycardData*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
@ -120,8 +131,9 @@ method onCancelActionClicked*(self: AccessInterface) {.base.} =
method onKeycardResponse*(self: AccessInterface, keycardFlowType: string, keycardEvent: KeycardEvent) {.base.} =
raise newException(ValueError, "No implementation available")
method runFlow*(self: AccessInterface, flowToRun: FlowType, keyUid = "", bip44Paths: seq[string] = @[], txHash = "", forceFlow = false) {.base.} =
raise newException(ValueError, "No implementation available")
method runFlow*(self: AccessInterface, flowToRun: FlowType, keyUid = "", bip44Paths: seq[string] = @[], txHash = "",
forceFlow = false, returnToFlow = FlowType.General) {.base.} =
raise newException(ValueError, "No implementation available")
method setPin*(self: AccessInterface, value: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -68,6 +68,12 @@ proc init[T](self: Module[T], fullConnect = true) =
method getModuleAsVariant*[T](self: Module[T]): QVariant =
return self.viewVariant
method getReturnToFlow*[T](self: Module[T]): FlowType =
return self.view.getReturnToFlow()
method getForceFlow*[T](self: Module[T]): bool =
return self.view.getForceFlow()
method getPin*[T](self: Module[T]): string =
return self.controller.getPin()
@ -460,7 +466,7 @@ method prepareKeyPairForProcessing*[T](self: Module[T], keyUid: string, keycardU
item.setIcon("keycard")
self.view.setKeyPairForProcessing(item)
method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths: seq[string] = @[], txHash = "", forceFlow = false) =
method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths: seq[string] = @[], txHash = "", forceFlow = false, returnToFlow = FlowType.General) =
## In case of `Authentication` if we're signing a transaction we need to provide a key uid of a keypair that an account
## we want to sign a transaction for belongs to. If we're just doing an authentication for a logged in user, then
## default key uid is always the key uid of the logged in user.
@ -470,6 +476,7 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths
return
self.init()
self.view.setForceFlow(forceFlow)
self.view.setReturnToFlow(returnToFlow)
if flowToRun == FlowType.FactoryReset:
if keyUid.len > 0:
self.prepareKeyPairForProcessing(keyUid)
@ -570,6 +577,15 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths
self.view.setCurrentState(newMigrateKeypairToAppState(flowToRun, nil))
self.controller.readyToDisplayPopup()
return
if flowToRun == FlowType.MigrateFromAppToKeycard:
if keyUid != singletonInstance.userProfile.getKeyUid():
error "sm_cannot MigrateFromAppToKeycard flow can be run only for the profile keypair and should not be run directly"
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
quit() # quit the app
self.prepareKeyPairForProcessing(keyUid)
self.view.setCurrentState(newMigrateKeypairToKeycardState(flowToRun, nil))
self.controller.readyToDisplayPopup()
return
method setSelectedKeyPair*[T](self: Module[T], item: KeyPairItem) =
var paths: seq[string]
@ -646,16 +662,15 @@ method updateKeyPairHelper*[T](self: Module[T], cardMetadata: CardMetadata) =
self.view.setKeyPairHelper(item)
method onUserAuthenticated*[T](self: Module[T], password: string, pin: string) =
let flowType = self.getCurrentFlowType()
if password.len == 0:
self.view.setDisablePopup(false)
return
if flowType == FlowType.SetupNewKeycard:
self.controller.setPassword(password)
self.onTertiaryActionClicked()
if flowType == FlowType.MigrateFromKeycardToApp:
self.controller.setPassword(password)
self.onTertiaryActionClicked()
let flowType = self.getCurrentFlowType()
if flowType == FlowType.SetupNewKeycard or
flowType == FlowType.MigrateFromKeycardToApp or
flowType == FlowType.MigrateFromAppToKeycard:
self.controller.setPassword(password)
self.onTertiaryActionClicked()
method keychainObtainedDataFailure*[T](self: Module[T], errorDescription: string, errorType: string) =
let currStateObj = self.view.currentStateObj()

View File

@ -7,6 +7,7 @@ QtObject:
type
View* = ref object of QObject
delegate: io_interface.AccessInterface
returnToFlow: FlowType
forceFlow: bool # used to disable any possibility of closing the popup, the user is forced to complete the flow or forcibly close the app (no other way to close the popup)
disablePopup: bool # used to disable popup after each action, to block users do multiple clikcs which the action is ongoing
currentState: StateWrapper
@ -45,6 +46,7 @@ QtObject:
result.currentState = newStateWrapper()
result.currentStateVariant = newQVariant(result.currentState)
result.remainingAttempts = -1
result.returnToFlow = FlowType.General
result.forceFlow = false
result.disablePopup = false
@ -54,6 +56,18 @@ QtObject:
signalConnect(result.currentState, "secondaryActionClicked()", result, "onSecondaryActionClicked()", 2)
signalConnect(result.currentState, "tertiaryActionClicked()", result, "onTertiaryActionClicked()", 2)
proc returnToFlowChanged*(self: View) {.signal.}
proc getReturnToFlowStr(self: View): string {.slot.} =
return $self.returnToFlow
QtProperty[string] returnToFlow:
read = getReturnToFlowStr
notify = returnToFlowChanged
proc getReturnToFlow*(self: View): FlowType =
return self.returnToFlow
proc setReturnToFlow*(self: View, value: FlowType) =
self.returnToFlow = value
self.returnToFlowChanged()
proc forceFlowChanged*(self: View) {.signal.}
proc getForceFlow*(self: View): bool {.slot.} =
return self.forceFlow

View File

@ -13,19 +13,21 @@ type
const convertRegularProfileKeypairToKeycardTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
let arg = decode[ConvertRegularProfileKeypairToKeycardTaskArg](argEncoded)
try:
var response: RpcResponse[JsonNode]
var errMsg: string
if arg.accountDataJson.isNil or arg.settingsJson.isNil:
response.error.message = "at least one json object is not prepared well"
error "error: ", errDescription=response.error.message
errMsg = "at least one json object is not prepared well"
elif arg.keycardUid.len == 0:
response.error.message = "provided keycardUid must not be empty"
error "error: ", errDescription=response.error.message
errMsg = "provided keycardUid must not be empty"
elif arg.hashedCurrentPassword.len == 0:
response.error.message = "provided password must not be empty"
error "error: ", errDescription=response.error.message
errMsg = "provided password must not be empty"
elif arg.newPassword.len == 0:
response.error.message = "provided new password must not be empty"
error "error: ", errDescription=response.error.message
errMsg = "provided new password must not be empty"
var response: RpcResponse[JsonNode]
if errMsg.len > 0:
response.result = newJNull()
response.error = RpcError(message: errMsg)
error "error: ", errDescription=errMsg
else:
response = status_account.convertRegularProfileKeypairToKeycard(arg.accountDataJson, arg.settingsJson,
arg.keycardUid, arg.hashedCurrentPassword, arg.newPassword)

View File

@ -4,7 +4,7 @@ type
KeyDetails* = object
address*: string
publicKey*: string
privateKey*: string
privateKey*: string
ApplicationInfo* = object
initialized*: bool
@ -98,8 +98,10 @@ proc toKeycardEvent(jsonObj: JsonNode): KeycardEvent =
discard jsonObj.getProp(ResponseParamPINRetries, result.pinRetries)
discard jsonObj.getProp(ResponseParamPUKRetries, result.pukRetries)
discard jsonObj.getProp(ResponseParamMasterKeyAddress, result.masterKeyAddress)
if jsonObj.getProp(ResponseParamKeyUID, result.keyUid) and not result.keyUid.startsWith("0x"):
result.keyUid = "0x" & result.keyUid
if jsonObj.getProp(ResponseParamKeyUID, result.keyUid) and
result.keyUid.len > 0 and
not result.keyUid.startsWith("0x"):
result.keyUid = "0x" & result.keyUid
var obj: JsonNode
if(jsonObj.getProp(ResponseParamAppInfo, obj)):
@ -130,7 +132,7 @@ proc toKeycardEvent(jsonObj: JsonNode): KeycardEvent =
if(jsonObj.getProp(ResponseParamCardMeta, obj)):
result.cardMetadata = toCardMetadata(obj)
if jsonObj.getProp(ResponseParamExportedKey, obj):
if obj.kind == JArray:
for o in obj:

View File

@ -1,13 +1,13 @@
import NimQml, chronicles, json, strutils, sequtils, tables
import ../../common/types as common_types
import ../../common/social_links
import ../../common/utils as common_utils
import ../../../app/core/eventemitter
import ../../../app/core/fleets/fleet_configuration
import ../../../app/core/signals/types
import ../../../backend/settings as status_settings
import ../../../backend/status_update as status_update
import app_service/common/types as common_types
import app_service/common/social_links
import app_service/common/utils as common_utils
import app/core/eventemitter
import app/core/fleets/fleet_configuration
import app/core/signals/types
import backend/settings as status_settings
import backend/status_update as status_update
import ./dto/settings as settings_dto
import ../stickers/dto/stickers as stickers_dto

View File

@ -52,6 +52,10 @@ StatusModal {
return qsTr("Enable password login on this device")
}
return qsTr("Migrate a keypair from Keycard to Status")
case Constants.keycardSharedFlow.migrateFromAppToKeycard:
if (root.sharedKeycardModule.forceFlow) {
return qsTr("Enable Keycard login on this device")
}
}
return ""

View File

@ -32,6 +32,7 @@ Item {
case Constants.keycardSharedState.keyPairMigrateSuccess:
case Constants.keycardSharedState.keyPairMigrateFailure:
case Constants.keycardSharedState.migrateKeypairToApp:
case Constants.keycardSharedState.migrateKeypairToKeycard:
case Constants.keycardSharedState.migratingKeypairToApp:
case Constants.keycardSharedState.migratingKeypairToKeycard:
case Constants.keycardSharedState.creatingAccountNewSeedPhraseSuccess:

View File

@ -481,6 +481,13 @@ QtObject {
return qsTr("Factory reset this Keycard")
}
break
case Constants.keycardSharedFlow.migrateFromAppToKeycard:
switch (root.sharedKeycardModule.currentState.stateType) {
case Constants.keycardSharedState.biometrics:
return qsTr("I prefer to use my PIN")
}
break
}
return ""
@ -1033,7 +1040,7 @@ QtObject {
return qsTr("Finalize Status Password Creation")
case Constants.keycardSharedState.keyPairMigrateFailure:
return qsTr("Close app")
return qsTr("Close App")
case Constants.keycardSharedState.biometrics:
return qsTr("Yes, use Touch ID")
@ -1044,6 +1051,34 @@ QtObject {
return qsTr("Done")
}
break
case Constants.keycardSharedFlow.migrateFromAppToKeycard:
switch (root.sharedKeycardModule.currentState.stateType) {
case Constants.keycardSharedState.migrateKeypairToKeycard:
case Constants.keycardSharedState.pinVerified:
return qsTr("Next")
case Constants.keycardSharedState.notKeycard:
case Constants.keycardSharedState.wrongKeycard:
case Constants.keycardSharedState.keycardEmpty:
case Constants.keycardSharedState.keycardEmptyMetadata:
return qsTr("Try again")
case Constants.keycardSharedState.maxPinRetriesReached:
case Constants.keycardSharedState.maxPukRetriesReached:
case Constants.keycardSharedState.maxPairingSlotsReached:
return qsTr("Unlock Keycard")
case Constants.keycardSharedState.biometrics:
return qsTr("Yes, use Touch ID")
case Constants.keycardSharedState.keyPairMigrateFailure:
return qsTr("Close App")
case Constants.keycardSharedState.keyPairMigrateSuccess:
return qsTr("Restart App & Sign In Using Your Keycard")
}
break
}
return ""

View File

@ -73,7 +73,8 @@ Item {
keyPairDerivedFrom: root.sharedKeycardModule.keyPairForProcessing.derivedFrom
keyPairAccounts: root.sharedKeycardModule.keyPairForProcessing.accounts
keyPairCardLocked: root.sharedKeycardModule.keyPairForProcessing.locked
displayAdditionalInfoForProfileKeypair: root.sharedKeycardModule.currentState.flowType !== Constants.keycardSharedFlow.migrateFromKeycardToApp
displayAdditionalInfoForProfileKeypair: root.sharedKeycardModule.currentState.flowType !== Constants.keycardSharedFlow.migrateFromKeycardToApp &&
root.sharedKeycardModule.currentState.flowType !== Constants.keycardSharedFlow.migrateFromAppToKeycard
}
}
@ -117,6 +118,7 @@ Item {
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: Constants.keycard.shared.imageHeight
Layout.preferredWidth: Constants.keycard.shared.imageWidth
visible: pattern != "" || source != ""
onAnimationCompleted: {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
@ -328,6 +330,23 @@ Item {
return true
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromAppToKeycard) {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migrateKeypairToKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
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 ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure) {
return true
}
}
return false
}
@ -512,6 +531,23 @@ Item {
return keyPairForProcessingComponent
}
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromAppToKeycard) {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migrateKeypairToKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.pluginReader ||
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 ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure) {
return keyPairForProcessingComponent
}
}
return undefined
}
@ -804,6 +840,9 @@ Item {
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
return qsTr("Keycard inserted does not match the Keycard below")
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromAppToKeycard) {
return qsTr("Keycard inserted does not match the Keycard below,\nplease remove and try and again")
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.unlockKeycard) {
return qsTr("Keycard inserted does not match the Keycard you're trying to unlock")
}
@ -830,7 +869,13 @@ Item {
}
PropertyChanges {
target: message
text: qsTr("This Keycard already stores keys\nbut doesn't store any metadata")
text: {
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromAppToKeycard) {
return qsTr("This Keycard already stores keys\nbut doesn't store any metadata,\nplease remove and try and again")
}
return qsTr("This Keycard already stores keys\nbut doesn't store any metadata")
}
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.directColor1
}
@ -852,7 +897,13 @@ Item {
}
PropertyChanges {
target: message
text: qsTr("There is no key pair on this Keycard")
text: {
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromAppToKeycard) {
return qsTr("There is no key pair on this Keycard,\nplease remove and try and again")
}
return qsTr("There is no key pair on this Keycard")
}
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.directColor1
}
@ -1075,6 +1126,9 @@ Item {
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromKeycardToApp) {
return qsTr("Keypair was removed from Keycard and is now stored on device.\nYou no longer need this Keycard to transact with the below accounts.")
}
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.migrateFromAppToKeycard) {
return qsTr("To complete migration close Status and sign in with your Keycard")
}
return qsTr("To complete migration close Status and log in with your new Keycard")
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.factoryResetSuccess) {
@ -1387,7 +1441,8 @@ Item {
}
PropertyChanges {
target: image
visible: false
pattern: ""
source: ""
}
PropertyChanges {
target: message
@ -1423,6 +1478,50 @@ Item {
Layout.preferredWidth: layout.width - 4 * Style.current.xlPadding
}
},
State {
name: Constants.keycardSharedState.migrateKeypairToKeycard
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migrateKeypairToKeycard
PropertyChanges {
target: title
text: {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migrateKeypairToKeycard) {
if (root.sharedKeycardModule.keyPairForProcessing.pairType === Constants.keycard.keyPairType.profile) {
if (root.sharedKeycardModule.forceFlow) {
return qsTr("Your profile keypair has been\nmigrated from Status to Keycard")
}
}
}
return ""
}
font.pixelSize: Constants.keycard.general.fontSize1
font.weight: Font.Bold
color: Theme.palette.directColor1
horizontalAlignment: Text.AlignHCenter
}
PropertyChanges {
target: image
pattern: ""
source: ""
}
PropertyChanges {
target: message
text: {
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migrateKeypairToKeycard) {
if (root.sharedKeycardModule.keyPairForProcessing.pairType === Constants.keycard.keyPairType.profile) {
if (root.sharedKeycardModule.forceFlow) {
return qsTr("In order to continue using this profile on this device, you need to login using the Keycard that this profile keypair was migrated to.")
}
}
}
return ""
}
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.directColor1
Layout.leftMargin: 2 * Style.current.xlPadding
Layout.rightMargin: 2* Style.current.xlPadding
Layout.preferredWidth: layout.width - 4 * Style.current.xlPadding
}
},
State {
name: Constants.keycardSharedState.biometrics
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.biometrics

View File

@ -124,6 +124,7 @@ QtObject {
readonly property string changePairingCode: "ChangePairingCode"
readonly property string createCopyOfAKeycard: "CreateCopyOfAKeycard"
readonly property string migrateFromKeycardToApp: "MigrateFromKeycardToApp"
readonly property string migrateFromAppToKeycard: "MigrateFromAppToKeycard"
}
readonly property QtObject keycardSharedState: QtObject {
@ -170,6 +171,7 @@ QtObject {
readonly property string keyPairMigrateSuccess: "KeyPairMigrateSuccess"
readonly property string keyPairMigrateFailure: "KeyPairMigrateFailure"
readonly property string migrateKeypairToApp: "MigrateKeypairToApp"
readonly property string migrateKeypairToKeycard: "MigrateKeypairToKeycard"
readonly property string migratingKeypairToApp: "MigratingKeypairToApp"
readonly property string migratingKeypairToKeycard: "MigratingKeypairToKeycard"
readonly property string enterPassword: "EnterPassword"