feat(@desktop/wallet): account interaction - stop using a keycard for profile keypair (on device)

Part 3 of: #11737
This commit is contained in:
Sale Djenic 2023-09-01 15:32:21 +02:00 committed by saledjenic
parent cf7c3325e7
commit ef4a564fc7
27 changed files with 469 additions and 72 deletions

View File

@ -48,6 +48,7 @@ type
tmpPukMatch: bool
tmpValidPuk: bool
tmpPassword: string
tmpNewPassword: string
tmpPairingCode: string
tmpSelectedKeyPairIsProfile: bool
tmpSelectedKeycardDto: KeycardDto
@ -182,19 +183,19 @@ proc init*(self: Controller, fullConnect = true) =
handlerId = self.events.onWithUUID(SIGNAL_NEW_KEYCARD_SET) do(e: Args):
let args = KeycardArgs(e)
self.tmpAddingMigratedKeypairSuccess = args.success
self.delegate.onSecondaryActionClicked()
self.delegate.onTertiaryActionClicked()
self.connectionIds.add(handlerId)
handlerId = self.events.onWithUUID(SIGNAL_ALL_KEYCARDS_DELETED) do(e: Args):
let args = KeycardArgs(e)
self.tmpAddingMigratedKeypairSuccess = args.success
self.delegate.onSecondaryActionClicked()
self.delegate.onTertiaryActionClicked()
self.connectionIds.add(handlerId)
handlerId = self.events.onWithUUID(SIGNAL_CONVERTING_PROFILE_KEYPAIR) do(e: Args):
let args = ResultArgs(e)
self.tmpConvertingProfileSuccess = args.success
self.delegate.onSecondaryActionClicked()
self.delegate.onTertiaryActionClicked()
self.connectionIds.add(handlerId)
handlerId = self.events.onWithUUID(SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT) do(e:Args):
@ -284,6 +285,12 @@ proc setPassword*(self: Controller, value: string) =
proc getPassword*(self: Controller): string =
return self.tmpPassword
proc setNewPassword*(self: Controller, value: string) =
self.tmpNewPassword = value
proc getNewPassword*(self: Controller): string =
return self.tmpNewPassword
proc setPairingCode*(self: Controller, value: string) =
self.tmpPairingCode = value

View File

@ -0,0 +1,42 @@
type
BiometricsState* = ref object of State
storeToKeychain: bool
proc newBiometricsState*(flowType: FlowType, backState: State): BiometricsState =
result = BiometricsState()
result.setup(flowType, StateType.Biometrics, backState)
proc delete*(self: BiometricsState) =
self.State.delete
method executeCancelCommand*(self: BiometricsState, controller: Controller) =
if self.flowType == FlowType.MigrateFromKeycardToApp:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
proc doAuthentication(self: BiometricsState, controller: Controller) =
if self.flowType == FlowType.MigrateFromKeycardToApp:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not migratingProfile:
return
controller.authenticateUser()
method executePrePrimaryStateCommand*(self: BiometricsState, controller: Controller) =
self.storeToKeychain = true
self.doAuthentication(controller)
method executePreSecondaryStateCommand*(self: BiometricsState, controller: Controller) =
self.storeToKeychain = false
self.doAuthentication(controller)
method executePreTertiaryStateCommand*(self: BiometricsState, controller: Controller) =
if self.storeToKeychain:
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_STORE)
return
singletonInstance.localAccountSettings.setStoreToKeychainValue(LS_VALUE_NEVER)
method getNextTertiaryState*(self: BiometricsState, controller: Controller): State =
if self.flowType == FlowType.MigrateFromKeycardToApp:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not migratingProfile:
return
return createState(StateType.MigratingKeypairToApp, self.flowType, nil)

View File

@ -0,0 +1,20 @@
type
ConfirmPasswordState* = ref object of State
proc newConfirmPasswordState*(flowType: FlowType, backState: State): ConfirmPasswordState =
result = ConfirmPasswordState()
result.setup(flowType, StateType.ConfirmPassword, backState)
proc delete*(self: ConfirmPasswordState) =
self.State.delete
method executeCancelCommand*(self: ConfirmPasswordState, controller: Controller) =
if self.flowType == FlowType.MigrateFromKeycardToApp:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method getNextPrimaryState*(self: ConfirmPasswordState, controller: Controller): State =
if self.flowType == FlowType.MigrateFromKeycardToApp:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not migratingProfile:
return
return createState(StateType.Biometrics, self.flowType, self)

View File

@ -31,13 +31,13 @@ method executePrePrimaryStateCommand*(self: CopyingKeycardState, controller: Con
if self.flowType == FlowType.CreateCopyOfAKeycard:
self.buildKeypairAndAddToMigratedKeypairs(controller)
method executePreSecondaryStateCommand*(self: CopyingKeycardState, controller: Controller) =
## Secondary action is called after each async action during migration process.
method executePreTertiaryStateCommand*(self: CopyingKeycardState, controller: Controller) =
## Tertiary action is called after each async action during migration process.
if self.flowType == FlowType.CreateCopyOfAKeycard:
if controller.getAddingMigratedKeypairSuccess():
self.runStoreMetadataFlow(controller)
method getNextSecondaryState*(self: CopyingKeycardState, controller: Controller): State =
method getNextTertiaryState*(self: CopyingKeycardState, controller: Controller): State =
if self.flowType == FlowType.CreateCopyOfAKeycard:
if not controller.getAddingMigratedKeypairSuccess():
return createState(StateType.CopyingKeycardFailure, self.flowType, nil)

View File

@ -0,0 +1,17 @@
type
CreatePasswordState* = ref object of State
proc newCreatePasswordState*(flowType: FlowType, backState: State): CreatePasswordState =
result = CreatePasswordState()
result.setup(flowType, StateType.CreatePassword, backState)
proc delete*(self: CreatePasswordState) =
self.State.delete
method executeCancelCommand*(self: CreatePasswordState, controller: Controller) =
if self.flowType == FlowType.MigrateFromKeycardToApp:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
method getNextPrimaryState*(self: CreatePasswordState, controller: Controller): State =
if self.flowType == FlowType.MigrateFromKeycardToApp:
return createState(StateType.ConfirmPassword, self.flowType, self)

View File

@ -49,16 +49,16 @@ proc addAccountsToWallet(self: CreatingAccountNewSeedPhraseState, controller: Co
address: account.getAddress(),
keyUid: kpForProcessing.getKeyUid(),
publicKey: account.getPubKey(),
walletType: SEED,
path: account.getPath(),
walletType: SEED,
path: account.getPath(),
name: account.getName(),
colorId: account.getColorId(),
colorId: account.getColorId(),
emoji: account.getEmoji()
))
return controller.addNewSeedPhraseKeypair(
seedPhrase = "",
keyUid = kpForProcessing.getKeyUid(),
keypairName = kpForProcessing.getName(),
keyUid = kpForProcessing.getKeyUid(),
keypairName = kpForProcessing.getName(),
rootWalletMasterKey = kpForProcessing.getDerivedFrom(),
accounts = walletAccounts
)
@ -81,25 +81,25 @@ method executePrePrimaryStateCommand*(self: CreatingAccountNewSeedPhraseState, c
self.resolvePaths(controller)
controller.runDeriveAccountFlow(bip44Paths = self.paths, controller.getPin())
method executePreSecondaryStateCommand*(self: CreatingAccountNewSeedPhraseState, controller: Controller) =
## Secondary action is called after each async action during migration process, in this case after `addKeycardOrAccounts`.
method executePreTertiaryStateCommand*(self: CreatingAccountNewSeedPhraseState, controller: Controller) =
## Tertiary action is called after each async action during migration process, in this case after `addKeycardOrAccounts`.
if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase:
if controller.getAddingMigratedKeypairSuccess():
self.runStoreMetadataFlow(controller)
method getNextSecondaryState*(self: CreatingAccountNewSeedPhraseState, controller: Controller): State =
method getNextTertiaryState*(self: CreatingAccountNewSeedPhraseState, controller: Controller): State =
if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase:
if not controller.getAddingMigratedKeypairSuccess():
return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil)
method resolveKeycardNextState*(self: CreatingAccountNewSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
method resolveKeycardNextState*(self: CreatingAccountNewSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
let state = ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
if not state.isNil:
return state
if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase:
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.ExportPublic:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0:
if not self.resolveAddresses(controller, keycardEvent):
return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil)
@ -108,7 +108,7 @@ method resolveKeycardNextState*(self: CreatingAccountNewSeedPhraseState, keycard
self.doMigration(controller)
return nil # returning nil, cause we need to remain in this state
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.StoreMetadata:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0:
return createState(StateType.CreatingAccountNewSeedPhraseSuccess, self.flowType, nil)
return createState(StateType.CreatingAccountNewSeedPhraseFailure, self.flowType, nil)

View File

@ -49,16 +49,16 @@ proc addAccountsToWallet(self: CreatingAccountOldSeedPhraseState, controller: Co
address: account.getAddress(),
keyUid: kpForProcessing.getKeyUid(),
publicKey: account.getPubKey(),
walletType: SEED,
path: account.getPath(),
walletType: SEED,
path: account.getPath(),
name: account.getName(),
colorId: account.getColorId(),
colorId: account.getColorId(),
emoji: account.getEmoji()
))
return controller.addNewSeedPhraseKeypair(
seedPhrase = "",
keyUid = kpForProcessing.getKeyUid(),
keypairName = kpForProcessing.getName(),
keyUid = kpForProcessing.getKeyUid(),
keypairName = kpForProcessing.getName(),
rootWalletMasterKey = kpForProcessing.getDerivedFrom(),
accounts = walletAccounts
)
@ -81,25 +81,25 @@ method executePrePrimaryStateCommand*(self: CreatingAccountOldSeedPhraseState, c
self.resolvePaths(controller)
controller.runDeriveAccountFlow(bip44Paths = self.paths, controller.getPin())
method executePreSecondaryStateCommand*(self: CreatingAccountOldSeedPhraseState, controller: Controller) =
## Secondary action is called after each async action during migration process, in this case after `addKeycardOrAccounts`.
method executePreTertiaryStateCommand*(self: CreatingAccountOldSeedPhraseState, controller: Controller) =
## Tertiary action is called after each async action during migration process, in this case after `addKeycardOrAccounts`.
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
if controller.getAddingMigratedKeypairSuccess():
self.runStoreMetadataFlow(controller)
method getNextSecondaryState*(self: CreatingAccountOldSeedPhraseState, controller: Controller): State =
method getNextTertiaryState*(self: CreatingAccountOldSeedPhraseState, controller: Controller): State =
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
if not controller.getAddingMigratedKeypairSuccess():
return createState(StateType.CreatingAccountOldSeedPhraseFailure, self.flowType, nil)
method resolveKeycardNextState*(self: CreatingAccountOldSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
method resolveKeycardNextState*(self: CreatingAccountOldSeedPhraseState, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State =
let state = ensureReaderAndCardPresenceAndResolveNextState(self, keycardFlowType, keycardEvent, controller)
if not state.isNil:
return state
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.ExportPublic:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0:
if not self.resolveAddresses(controller, keycardEvent):
return createState(StateType.CreatingAccountOldSeedPhraseFailure, self.flowType, nil)
@ -108,7 +108,7 @@ method resolveKeycardNextState*(self: CreatingAccountOldSeedPhraseState, keycard
self.doMigration(controller)
return nil # returning nil, cause we need to remain in this state
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.StoreMetadata:
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
keycardEvent.error.len == 0:
return createState(StateType.CreatingAccountOldSeedPhraseSuccess, self.flowType, nil)
return createState(StateType.CreatingAccountOldSeedPhraseFailure, self.flowType, nil)

View File

@ -14,15 +14,17 @@ proc newEnterSeedPhraseState*(flowType: FlowType, backState: State): EnterSeedPh
proc delete*(self: EnterSeedPhraseState) =
self.State.delete
method executePreBackStateCommand*(self: EnterSeedPhraseState, controller: Controller) =
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
method executePrePrimaryStateCommand*(self: EnterSeedPhraseState, controller: Controller) =
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
let sp = controller.getSeedPhrase()
if self.flowType == FlowType.SetupNewKeycard:
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getSelectedKeyPairDto().keyUid
if self.verifiedSeedPhrase:
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), sp)
else:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
self.verifiedSeedPhrase = controller.validSeedPhrase(sp)
if self.verifiedSeedPhrase:
@ -42,28 +44,27 @@ method executePrePrimaryStateCommand*(self: EnterSeedPhraseState, controller: Co
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getKeyPairForProcessing().getKeyUid()
if self.verifiedSeedPhrase:
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), sp)
else:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
if self.flowType == FlowType.UnlockKeycard:
controller.setUnlockUsingSeedPhrase(true)
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getKeyPairForProcessing().getKeyUid()
if not self.verifiedSeedPhrase:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
if self.flowType == FlowType.MigrateFromKeycardToApp:
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getKeyPairForProcessing().getKeyUid()
if self.verifiedSeedPhrase:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if migratingProfile:
return
controller.authenticateUser()
else:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
method getNextPrimaryState*(self: EnterSeedPhraseState, controller: Controller): State =
if self.flowType == FlowType.SetupNewKeycard:
if not self.verifiedSeedPhrase:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
return createState(StateType.WrongSeedPhrase, self.flowType, nil)
if self.flowType == FlowType.CreateCopyOfAKeycard:
if not self.verifiedSeedPhrase:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
return createState(StateType.WrongSeedPhrase, self.flowType, self.getBackState)
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
if not self.verifiedSeedPhrase:
@ -74,15 +75,24 @@ method getNextPrimaryState*(self: EnterSeedPhraseState, controller: Controller):
## but we need to check that with designers.
return createState(StateType.SeedPhraseAlreadyInUse, self.flowType, self)
if self.flowType == FlowType.UnlockKeycard:
if self.verifiedSeedPhrase:
return createState(StateType.CreatePin, self.flowType, nil)
return createState(StateType.WrongSeedPhrase, self.flowType, nil)
if not self.verifiedSeedPhrase:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
return createState(StateType.WrongSeedPhrase, self.flowType, nil)
return createState(StateType.CreatePin, self.flowType, nil)
if self.flowType == FlowType.MigrateFromKeycardToApp:
if not self.verifiedSeedPhrase:
return createState(StateType.WrongSeedPhrase, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
return createState(StateType.WrongSeedPhrase, self.flowType, self.getBackState)
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if not migratingProfile:
return
return createState(StateType.CreatePassword, self.flowType, self)
method getNextSecondaryState*(self: EnterSeedPhraseState, controller: Controller): State =
if self.flowType == FlowType.MigrateFromKeycardToApp:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if migratingProfile:
return
return createState(StateType.MigratingKeypairToApp, self.flowType, nil)
method executeCancelCommand*(self: EnterSeedPhraseState, controller: Controller) =

View File

@ -19,16 +19,16 @@ proc addAccountsToWallet(self: ImportingFromKeycardState, controller: Controller
address: account.getAddress(),
keyUid: kpForProcessing.getKeyUid(),
publicKey: account.getPubKey(),
walletType: SEED,
path: account.getPath(),
walletType: SEED,
path: account.getPath(),
name: account.getName(),
colorId: account.getColorId(),
colorId: account.getColorId(),
emoji: account.getEmoji()
))
return controller.addNewSeedPhraseKeypair(
seedPhrase = "",
keyUid = kpForProcessing.getKeyUid(),
keypairName = kpForProcessing.getName(),
keyUid = kpForProcessing.getKeyUid(),
keypairName = kpForProcessing.getName(),
rootWalletMasterKey = kpForProcessing.getDerivedFrom(),
accounts = walletAccounts
)
@ -49,7 +49,7 @@ method getNextPrimaryState*(self: ImportingFromKeycardState, controller: Control
self.doMigration(controller)
return nil
method getNextSecondaryState*(self: ImportingFromKeycardState, controller: Controller): State =
method getNextTertiaryState*(self: ImportingFromKeycardState, controller: Controller): State =
if self.flowType == FlowType.ImportFromKeycard:
if controller.getAddingMigratedKeypairSuccess():
return createState(StateType.ImportingFromKeycardSuccess, self.flowType, nil)

View File

@ -11,9 +11,19 @@ proc delete*(self: KeyPairMigrateFailureState) =
method executePrePrimaryStateCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.MigrateFromKeycardToApp:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
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
method executeCancelCommand*(self: KeyPairMigrateFailureState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.MigrateFromKeycardToApp:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
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

View File

@ -14,15 +14,21 @@ method executePrePrimaryStateCommand*(self: MigratingKeypairToAppState, controll
let sp = controller.getSeedPhrase()
let password = controller.getPassword()
let kpForProcessing = controller.getKeyPairForProcessing()
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if migratingProfile:
let newPassword = controller.getNewPassword()
controller.tryToStoreDataToKeychain(newPassword)
controller.convertKeycardProfileKeypairToRegular(sp, password, newPassword)
return
controller.migrateNonProfileKeycardKeypairToApp(kpForProcessing.getKeyUid(), sp, password,
doPasswordHashing = not singletonInstance.userProfile.getIsKeycardUser())
method executePreSecondaryStateCommand*(self: MigratingKeypairToAppState, controller: Controller) =
## Secondary action is called after each async action during migration process.
method executePreTertiaryStateCommand*(self: MigratingKeypairToAppState, controller: Controller) =
## Tertiary action is called after each async action during migration process.
if self.flowType == FlowType.MigrateFromKeycardToApp:
self.migrationOk = controller.getAddingMigratedKeypairSuccess()
self.migrationOk = controller.getConvertingProfileSuccess()
method getNextSecondaryState*(self: MigratingKeypairToAppState, controller: Controller): State =
method getNextTertiaryState*(self: MigratingKeypairToAppState, controller: Controller): State =
if self.flowType == FlowType.MigrateFromKeycardToApp:
if not self.migrationOk:
return createState(StateType.KeyPairMigrateFailure, self.flowType, nil)

View File

@ -40,8 +40,8 @@ method executePrePrimaryStateCommand*(self: MigratingKeypairToKeycardState, cont
return
self.doMigration(controller)
method executePreSecondaryStateCommand*(self: MigratingKeypairToKeycardState, controller: Controller) =
## Secondary action is called after each async action during migration process.
method executePreTertiaryStateCommand*(self: MigratingKeypairToKeycardState, controller: Controller) =
## Tertiary action is called after each async action during migration process.
if self.flowType == FlowType.SetupNewKeycard:
if controller.getSelectedKeyPairIsProfile():
if not self.authenticationDone:
@ -63,7 +63,7 @@ method executePreSecondaryStateCommand*(self: MigratingKeypairToKeycardState, co
if self.addingMigratedKeypairOk:
self.runStoreMetadataFlow(controller)
method getNextSecondaryState*(self: MigratingKeypairToKeycardState, controller: Controller): State =
method getNextTertiaryState*(self: MigratingKeypairToKeycardState, controller: Controller): State =
if self.flowType == FlowType.SetupNewKeycard:
if controller.getSelectedKeyPairIsProfile():
if self.authenticationDone and not self.authenticationOk or

View File

@ -6,6 +6,7 @@ export FlowType, KeycardEvent, KeyDetails
type StateType* {.pure.} = enum
NoState = "NoState"
Biometrics = "Biometrics"
NoPCSCService = "NoPCSCService"
PluginReader = "PluginReader"
ReadingKeycard = "ReadingKeycard"
@ -52,6 +53,8 @@ type StateType* {.pure.} = enum
MigratingKeypairToKeycard = "MigratingKeypairToKeycard"
EnterPassword = "EnterPassword"
WrongPassword = "WrongPassword"
CreatePassword = "CreatePassword"
ConfirmPassword = "ConfirmPassword"
BiometricsPasswordFailed = "BiometricsPasswordFailed"
BiometricsPinFailed = "BiometricsPinFailed"
BiometricsPinInvalid = "BiometricsPinInvalid"
@ -141,6 +144,10 @@ method getNextPrimaryState*(self: State, controller: Controller): State {.inlin
method getNextSecondaryState*(self: State, controller: Controller): State {.inline base.} =
return nil
## Returns next state instance in case the "tertiary" action is triggered
method getNextTertiaryState*(self: State, controller: Controller): State {.inline base.} =
return nil
## This method is executed if "cancel" action is triggered (invalidates current flow)
method executeCancelCommand*(self: State, controller: Controller) {.inline base.} =
discard
@ -169,6 +176,14 @@ method executePreSecondaryStateCommand*(self: State, controller: Controller) {.i
method executePostSecondaryStateCommand*(self: State, controller: Controller) {.inline base.} =
discard
## This method is executed before tertiary state is set, if "tertiary" action is triggered
method executePreTertiaryStateCommand*(self: State, controller: Controller) {.inline base.} =
discard
## This method is executed after tertiary state is set, if "tertiary" action is triggered
method executePostTertiaryStateCommand*(self: State, controller: Controller) {.inline base.} =
discard
## This method is used for handling aync responses for keycard related states
method resolveKeycardNextState*(self: State, keycardFlowType: string, keycardEvent: KeycardEvent,
controller: Controller): State {.inline base.} =

View File

@ -32,20 +32,24 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
proc extractPredefinedKeycardDataToNumber*(currValue: string): int
proc updatePredefinedKeycardData*(currValue: string, value: PredefinedKeycardData, add: bool): string
proc isPredefinedKeycardDataFlagSet*(currValue: string, value: PredefinedKeycardData): bool
proc findBackStateWithTargetedStateType*(currentState: State, targetedStateType: StateType): State
# Resolve state section
proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State
proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowType: string, keycardEvent: KeycardEvent, controller: Controller): State
include biometrics_state
include biometrics_password_failed_state
include biometrics_pin_failed_state
include biometrics_pin_invalid_state
include biometrics_ready_to_sign_state
include changing_keycard_pin_state
include changing_keycard_puk_state
include confirm_password_state
include copy_to_keycard_state
include copying_keycard_state
include changing_keycard_pairing_code_state
include create_pairing_code_state
include create_password_state
include create_pin_state
include create_puk_state
include creating_account_new_seed_phrase_state

View File

@ -31,6 +31,8 @@ proc isPredefinedKeycardDataFlagSet*(currValue: string, value: PredefinedKeycard
return (currNum and value.int) == value.int
proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: State): State =
if stateToBeCreated == StateType.Biometrics:
return newBiometricsState(flowType, backState)
if stateToBeCreated == StateType.BiometricsPasswordFailed:
return newBiometricsPasswordFailedState(flowType, backState)
if stateToBeCreated == StateType.BiometricsPinFailed:
@ -45,12 +47,16 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
return newChangingKeycardPinState(flowType, backState)
if stateToBeCreated == StateType.ChangingKeycardPuk:
return newChangingKeycardPukState(flowType, backState)
if stateToBeCreated == StateType.ConfirmPassword:
return newConfirmPasswordState(flowType, backState)
if stateToBeCreated == StateType.CopyToKeycard:
return newCopyToKeycardState(flowType, backState)
if stateToBeCreated == StateType.CopyingKeycard:
return newCopyingKeycardState(flowType, backState)
if stateToBeCreated == StateType.CreatePairingCode:
return newCreatePairingCodeState(flowType, backState)
if stateToBeCreated == StateType.CreatePassword:
return newCreatePasswordState(flowType, backState)
if stateToBeCreated == StateType.CreatePin:
return newCreatePinState(flowType, backState)
if stateToBeCreated == StateType.CreatePuk:
@ -198,4 +204,14 @@ proc createState*(stateToBeCreated: StateType, flowType: FlowType, backState: St
if stateToBeCreated == StateType.WrongSeedPhrase:
return newWrongSeedPhraseState(flowType, backState)
error "No implementation available for state ", state=stateToBeCreated
error "No implementation available for state ", state=stateToBeCreated
proc findBackStateWithTargetedStateType*(currentState: State, targetedStateType: StateType): State =
if currentState.isNil:
return nil
var state = currentState
while not state.isNil:
if state.stateType == targetedStateType:
return state
state = state.getBackState
return nil

View File

@ -59,4 +59,8 @@ QtObject:
proc secondaryActionClicked*(self: StateWrapper) {.signal.}
proc doSecondaryAction*(self: StateWrapper) {.slot.} =
self.secondaryActionClicked()
self.secondaryActionClicked()
proc tertiaryActionClicked*(self: StateWrapper) {.signal.}
proc doTertiaryAction*(self: StateWrapper) {.slot.} =
self.tertiaryActionClicked()

View File

@ -10,32 +10,35 @@ proc newWrongSeedPhraseState*(flowType: FlowType, backState: State): WrongSeedPh
proc delete*(self: WrongSeedPhraseState) =
self.State.delete
method executePreBackStateCommand*(self: WrongSeedPhraseState, controller: Controller) =
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
method executePrePrimaryStateCommand*(self: WrongSeedPhraseState, controller: Controller) =
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
let sp = controller.getSeedPhrase()
if self.flowType == FlowType.SetupNewKeycard:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getSelectedKeyPairDto().keyUid
if self.verifiedSeedPhrase:
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), sp)
if self.flowType == FlowType.CreateCopyOfAKeycard:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getKeyPairForProcessing().getKeyUid()
if self.verifiedSeedPhrase:
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), sp)
if self.flowType == FlowType.UnlockKeycard:
controller.setUnlockUsingSeedPhrase(true)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getKeyPairForProcessing().getKeyUid()
if not self.verifiedSeedPhrase:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
if self.flowType == FlowType.MigrateFromKeycardToApp:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
let keyUid = controller.getKeyUidForSeedPhrase(sp)
self.verifiedSeedPhrase = controller.validSeedPhrase(sp) and keyUid == controller.getKeyPairForProcessing().getKeyUid()
if self.verifiedSeedPhrase:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if migratingProfile:
return
controller.authenticateUser()
method getNextPrimaryState*(self: WrongSeedPhraseState, controller: Controller): State =
@ -45,6 +48,10 @@ method getNextPrimaryState*(self: WrongSeedPhraseState, controller: Controller):
if not self.verifiedSeedPhrase:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
return self
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if migratingProfile:
let backState = findBackStateWithTargetedStateType(self, StateType.EnterSeedPhrase)
return createState(StateType.CreatePassword, self.flowType, backState)
if self.flowType == FlowType.UnlockKeycard:
if self.verifiedSeedPhrase:
return createState(StateType.CreatePin, self.flowType, nil)
@ -52,6 +59,9 @@ method getNextPrimaryState*(self: WrongSeedPhraseState, controller: Controller):
method getNextSecondaryState*(self: WrongSeedPhraseState, controller: Controller): State =
if self.flowType == FlowType.MigrateFromKeycardToApp:
let migratingProfile = controller.getKeyPairForProcessing().getKeyUid() == singletonInstance.userProfile.getKeyUid()
if migratingProfile:
return
return createState(StateType.MigratingKeypairToApp, self.flowType, nil)
method executeCancelCommand*(self: WrongSeedPhraseState, controller: Controller) =

View File

@ -111,6 +111,9 @@ method onPrimaryActionClicked*(self: AccessInterface) {.base.} =
method onSecondaryActionClicked*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onTertiaryActionClicked*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method onCancelActionClicked*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
@ -129,6 +132,12 @@ method setPuk*(self: AccessInterface, value: string) {.base.} =
method setPassword*(self: AccessInterface, value: string) {.base.} =
raise newException(ValueError, "No implementation available")
method setNewPassword*(self: AccessInterface, value: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getNewPassword*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")
method setKeycardName*(self: AccessInterface, value: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -89,6 +89,12 @@ method setPuk*[T](self: Module[T], value: string) =
method setPassword*[T](self: Module[T], value: string) =
self.controller.setPassword(value)
method setNewPassword*[T](self: Module[T], value: string) =
self.controller.setNewPassword(value)
method getNewPassword*[T](self: Module[T]): string =
return self.controller.getNewPassword()
method getKeyPairForProcessing*[T](self: Module[T]): KeyPairItem =
return self.view.getKeyPairForProcessing()
@ -366,6 +372,23 @@ method onSecondaryActionClicked*[T](self: Module[T]) =
currStateObj.executePostSecondaryStateCommand(self.controller)
debug "sm_secondary_action - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
method onTertiaryActionClicked*[T](self: Module[T]) =
let currStateObj = self.view.currentStateObj()
if currStateObj.isNil:
error "sm_cannot resolve current state"
return
debug "sm_tertiary_action", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
self.preActionActivities(currStateObj.flowType(), currStateObj.stateType())
currStateObj.executePreTertiaryStateCommand(self.controller)
let nextState = currStateObj.getNextTertiaryState(self.controller)
if nextState.isNil:
return
self.preStateActivities(nextState.flowType(), nextState.stateType())
self.reEvaluateKeyPairForProcessing(currStateObj.flowType(), currStateObj.stateType())
self.view.setCurrentState(nextState)
currStateObj.executePostTertiaryStateCommand(self.controller)
debug "sm_tertiary_action - set state", setCurrFlow=nextState.flowType(), setCurrState=nextState.stateType()
method onKeycardResponse*[T](self: Module[T], keycardFlowType: string, keycardEvent: KeycardEvent) =
if self.controller.keycardSyncingInProgress():
self.handleKeycardSyncing()
@ -628,10 +651,10 @@ method onUserAuthenticated*[T](self: Module[T], password: string, pin: string) =
return
if flowType == FlowType.SetupNewKeycard:
self.controller.setPassword(password)
self.onSecondaryActionClicked()
self.onTertiaryActionClicked()
if flowType == FlowType.MigrateFromKeycardToApp:
self.controller.setPassword(password)
self.onSecondaryActionClicked()
self.onTertiaryActionClicked()
method keychainObtainedDataFailure*[T](self: Module[T], errorDescription: string, errorType: string) =
let currStateObj = self.view.currentStateObj()

View File

@ -50,6 +50,7 @@ QtObject:
signalConnect(result.currentState, "cancelActionClicked()", result, "onCancelActionClicked()", 2)
signalConnect(result.currentState, "primaryActionClicked()", result, "onPrimaryActionClicked()", 2)
signalConnect(result.currentState, "secondaryActionClicked()", result, "onSecondaryActionClicked()", 2)
signalConnect(result.currentState, "tertiaryActionClicked()", result, "onTertiaryActionClicked()", 2)
proc diablePopupChanged*(self: View) {.signal.}
proc getDisablePopup*(self: View): bool {.slot.} =
@ -109,6 +110,9 @@ QtObject:
proc onSecondaryActionClicked*(self: View) {.slot.} =
self.delegate.onSecondaryActionClicked()
proc onTertiaryActionClicked*(self: View) {.slot.} =
self.delegate.onTertiaryActionClicked()
proc keyPairModel*(self: View): KeyPairModel =
return self.keyPairModel
@ -183,6 +187,12 @@ QtObject:
proc setPassword*(self: View, value: string) {.slot.} =
self.delegate.setPassword(value)
proc setNewPassword*(self: View, value: string) {.slot.} =
self.delegate.setNewPassword(value)
proc getNewPassword*(self: View): string {.slot.} =
self.delegate.getNewPassword()
proc getNameFromKeycard*(self: View): string {.slot.} =
return self.delegate.getNameFromKeycard()
@ -206,7 +216,7 @@ QtObject:
proc validSeedPhrase*(self: View, value: string): bool {.slot.} =
return self.delegate.validSeedPhrase(value)
proc migratingProfileKeyPair*(self: View): bool {.slot.} =
return self.delegate.migratingProfileKeyPair()

View File

@ -23,6 +23,7 @@ Item {
anchors.fill: parent
sourceComponent: {
switch (root.sharedKeycardModule.currentState.stateType) {
case Constants.keycardSharedState.biometrics:
case Constants.keycardSharedState.noPCSCService:
case Constants.keycardSharedState.pluginReader:
case Constants.keycardSharedState.insertKeycard:
@ -121,6 +122,12 @@ Item {
case Constants.keycardSharedState.wrongPassword:
return passwordComponent
case Constants.keycardSharedState.createPassword:
return createPasswordComponent
case Constants.keycardSharedState.confirmPassword:
return confirmPasswordComponent
case Constants.keycardSharedState.enterKeycardName:
return enterNameComponent
@ -266,6 +273,36 @@ Item {
}
}
Component {
id: createPasswordComponent
CreatePassword {
sharedKeycardModule: root.sharedKeycardModule
Component.onCompleted: {
d.primaryButtonEnabled = false
}
onPasswordValid: {
d.primaryButtonEnabled = valid
}
}
}
Component {
id: confirmPasswordComponent
ConfirmPassword {
sharedKeycardModule: root.sharedKeycardModule
Component.onCompleted: {
d.primaryButtonEnabled = false
}
onPasswordMatch: {
d.primaryButtonEnabled = result
}
}
}
Component {
id: enterNameComponent
EnterName {

View File

@ -373,6 +373,8 @@ QtObject {
case Constants.keycardSharedState.migrateKeypairToApp:
case Constants.keycardSharedState.enterSeedPhrase:
case Constants.keycardSharedState.wrongSeedPhrase:
case Constants.keycardSharedState.createPassword:
case Constants.keycardSharedState.confirmPassword:
return true
}
break
@ -471,6 +473,9 @@ QtObject {
case Constants.keycardSharedFlow.migrateFromKeycardToApp:
switch (root.sharedKeycardModule.currentState.stateType) {
case Constants.keycardSharedState.biometrics:
return qsTr("I prefer to use my password")
case Constants.keycardSharedState.keyPairMigrateSuccess:
if (!root.sharedKeycardModule.migratingProfileKeyPair())
return qsTr("Factory reset this Keycard")
@ -594,9 +599,11 @@ QtObject {
return qsTr("Next")
case Constants.keycardSharedState.migratingKeypairToKeycard:
case Constants.keycardSharedState.keyPairMigrateFailure:
return qsTr("Done")
case Constants.keycardSharedState.keyPairMigrateFailure:
return qsTr("Close app")
case Constants.keycardSharedState.keyPairMigrateSuccess:
if (root.sharedKeycardModule.migratingProfileKeyPair())
return qsTr("Restart app & sign in using your new Keycard")
@ -1019,8 +1026,17 @@ QtObject {
case Constants.keycardSharedState.migratingKeypairToApp:
return qsTr("Done")
case Constants.keycardSharedState.createPassword:
return qsTr("Create Password")
case Constants.keycardSharedState.confirmPassword:
return qsTr("Finalize Status Password Creation")
case Constants.keycardSharedState.keyPairMigrateFailure:
return qsTr("Close")
return qsTr("Close app")
case Constants.keycardSharedState.biometrics:
return qsTr("Yes, use Touch ID")
case Constants.keycardSharedState.keyPairMigrateSuccess:
if (root.sharedKeycardModule.migratingProfileKeyPair())
@ -1174,6 +1190,8 @@ QtObject {
switch (root.sharedKeycardModule.currentState.stateType) {
case Constants.keycardSharedState.enterSeedPhrase:
case Constants.keycardSharedState.createPassword:
case Constants.keycardSharedState.confirmPassword:
return root.primaryButtonEnabled
}
break

View File

@ -30,6 +30,9 @@ StatusListItem {
property bool keyPairCardLocked: false
property var keyPairAccounts
property bool displayAdditionalInfoForProfileKeypair: true
property string additionalInfoForProfileKeypair: qsTr("Moving this key pair will require you to use your Keycard to login")
signal keyPairSelected()
signal removeAccount(int index, string name)
signal accountClicked(int index)
@ -60,8 +63,8 @@ StatusListItem {
return t
}
beneathTagsTitle: root.keyPairType === Constants.keycard.keyPairType.profile?
qsTr("Moving this key pair will require you to use your Keycard to login") :
beneathTagsTitle: root.keyPairType === Constants.keycard.keyPairType.profile && root.displayAdditionalInfoForProfileKeypair?
root.additionalInfoForProfileKeypair :
!root.canBeSelected?
qsTranslate("", "Contains account(s) with Keycard incompatible derivation paths", root.keyPairAccounts.count.toString()) :
""

View File

@ -0,0 +1,45 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import shared.views 1.0
import utils 1.0
Item {
id: root
property var sharedKeycardModule
signal passwordMatch(bool result)
ColumnLayout {
anchors.fill: parent
anchors.topMargin: Style.current.xlPadding
anchors.bottomMargin: Style.current.halfPadding
anchors.leftMargin: Style.current.xlPadding
anchors.rightMargin: Style.current.xlPadding
spacing: Style.current.padding
PasswordConfirmationView {
Layout.alignment: Qt.AlignHCenter
Layout.fillHeight: true
spacing: Style.current.bigPadding
expectedPassword: root.sharedKeycardModule.getNewPassword()
Component.onCompleted: {
forceInputFocus()
}
onPasswordMatchChanged: {
root.passwordMatch(passwordMatch)
}
onSubmit: {
if(passwordMatch) {
root.sharedKeycardModule.currentState.doPrimaryAction()
}
}
}
}
}

View File

@ -0,0 +1,54 @@
import QtQuick 2.14
import QtQuick.Layouts 1.14
import shared.stores 1.0
import shared.views 1.0
import utils 1.0
Item {
id: root
property var sharedKeycardModule
signal passwordValid(bool valid)
ColumnLayout {
anchors.fill: parent
anchors.topMargin: Style.current.xlPadding
anchors.bottomMargin: Style.current.halfPadding
anchors.leftMargin: 2*(Style.current.xlPadding + Style.current.bigPadding)
anchors.rightMargin: 2*(Style.current.xlPadding + Style.current.bigPadding)
spacing: Style.current.padding
PasswordView {
Layout.fillWidth: true
Layout.fillHeight: true
passwordStrengthScoreFunction: RootStore.getPasswordStrengthScore
highSizeIntro: true
newPswText: root.sharedKeycardModule.getNewPassword()
confirmationPswText: root.sharedKeycardModule.getNewPassword()
Component.onCompleted: {
forceNewPswInputFocus()
checkPasswordMatches()
root.passwordValid(ready)
}
onReadyChanged: {
root.passwordValid(ready)
if (!ready) {
return
}
root.sharedKeycardModule.setNewPassword(newPswText)
}
onReturnPressed: {
if(!ready) {
return
}
root.sharedKeycardModule.currentState.doPrimaryAction()
}
}
}
}

View File

@ -15,7 +15,11 @@ Item {
property var sharedKeycardModule
Component.onCompleted: {
onStateChanged: {
if (state != d.processingStateName) {
return
}
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToApp ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountNewSeedPhrase ||
@ -31,6 +35,10 @@ Item {
QtObject {
id: d
readonly property string processingStateName: "processing"
readonly property string processingSuccessStateName: "processing-success"
readonly property string processingFailureStateName: "processing-failure"
readonly property bool hideKeyPair: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.hideKeyPair
readonly property bool copyFromAKeycardPartDone: root.sharedKeycardModule.keycardData & Constants.predefinedKeycardData.copyFromAKeycardPartDone
readonly property bool continuousProcessingAnimation: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
@ -65,6 +73,7 @@ Item {
keyPairDerivedFrom: root.sharedKeycardModule.keyPairForProcessing.derivedFrom
keyPairAccounts: root.sharedKeycardModule.keyPairForProcessing.accounts
keyPairCardLocked: root.sharedKeycardModule.keyPairForProcessing.locked
displayAdditionalInfoForProfileKeypair: root.sharedKeycardModule.currentState.flowType !== Constants.keycardSharedFlow.migrateFromKeycardToApp
}
}
@ -589,7 +598,7 @@ Item {
}
},
State {
name: "processing"
name: d.processingStateName
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToKeycard ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.migratingKeypairToApp ||
@ -993,7 +1002,7 @@ Item {
}
},
State {
name: "processing-success"
name: d.processingSuccessStateName
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateSuccess ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountNewSeedPhraseSuccess ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountOldSeedPhraseSuccess ||
@ -1083,7 +1092,7 @@ Item {
}
},
State {
name: "processing-failure"
name: d.processingFailureStateName
when: root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keyPairMigrateFailure ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountNewSeedPhraseFailure ||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.creatingAccountOldSeedPhraseFailure ||
@ -1396,6 +1405,31 @@ Item {
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
PropertyChanges {
target: title
text: qsTr("Biometrics")
font.pixelSize: Constants.keycard.general.fontSize1
font.weight: Font.Bold
color: Theme.palette.directColor1
horizontalAlignment: Text.AlignHCenter
}
PropertyChanges {
target: image
source: Style.png("keycard/biometrics-success")
pattern: ""
}
PropertyChanges {
target: message
text: qsTr("Would you like to use Touch ID\nto login to Status?")
font.pixelSize: Constants.keycard.general.fontSize2
color: Theme.palette.baseColor1
horizontalAlignment: Text.AlignHCenter
Layout.preferredWidth: layout.width - 4 * Style.current.xlPadding
}
}
]
}

View File

@ -127,6 +127,7 @@ QtObject {
}
readonly property QtObject keycardSharedState: QtObject {
readonly property string biometrics: "Biometrics"
readonly property string noPCSCService: "NoPCSCService"
readonly property string noState: "NoState"
readonly property string pluginReader: "PluginReader"
@ -173,6 +174,8 @@ QtObject {
readonly property string migratingKeypairToKeycard: "MigratingKeypairToKeycard"
readonly property string enterPassword: "EnterPassword"
readonly property string wrongPassword: "WrongPassword"
readonly property string createPassword: "CreatePassword"
readonly property string confirmPassword: "ConfirmPassword"
readonly property string biometricsPasswordFailed: "BiometricsPasswordFailed"
readonly property string biometricsPinFailed: "BiometricsPinFailed"
readonly property string biometricsPinInvalid: "BiometricsPinInvalid"