feat(@desktop/keycard): sign flow added to the shared keycard module
This commit is contained in:
parent
52d760d1b3
commit
9c9bcef6d2
|
@ -2,24 +2,24 @@ import chronicles, tables, strutils, os, sequtils, sugar
|
|||
import uuids
|
||||
import io_interface
|
||||
|
||||
import ../../../global/app_sections_config as conf
|
||||
import ../../../global/app_signals
|
||||
import ../../../global/global_singleton
|
||||
import ../../../core/signals/types
|
||||
import ../../../core/eventemitter
|
||||
import ../../startup/io_interface as startup_io
|
||||
import ../../../../app_service/common/utils
|
||||
import ../../../../app_service/common/account_constants
|
||||
import ../../../../app_service/service/keycard/service as keycard_service
|
||||
import ../../../../app_service/service/settings/service as settings_service
|
||||
import ../../../../app_service/service/network/service as network_service
|
||||
import ../../../../app_service/service/privacy/service as privacy_service
|
||||
import ../../../../app_service/service/accounts/service as accounts_service
|
||||
import ../../../../app_service/service/wallet_account/service as wallet_account_service
|
||||
import ../../../../app_service/service/keychain/service as keychain_service
|
||||
import ../../../../app_service/service/currency/dto
|
||||
import app/global/app_sections_config as conf
|
||||
import app/global/app_signals
|
||||
import app/global/global_singleton
|
||||
import app/core/signals/types
|
||||
import app/core/eventemitter
|
||||
import app/modules/startup/io_interface as startup_io
|
||||
import app_service/common/utils
|
||||
import app_service/common/account_constants
|
||||
import app_service/service/keycard/service as keycard_service
|
||||
import app_service/service/settings/service as settings_service
|
||||
import app_service/service/network/service as network_service
|
||||
import app_service/service/privacy/service as privacy_service
|
||||
import app_service/service/accounts/service as accounts_service
|
||||
import app_service/service/wallet_account/service as wallet_account_service
|
||||
import app_service/service/keychain/service as keychain_service
|
||||
import app_service/service/currency/dto
|
||||
|
||||
import ../../shared_models/[keypair_item]
|
||||
import app/modules/shared_models/[keypair_item]
|
||||
|
||||
logScope:
|
||||
topics = "keycard-popup-controller"
|
||||
|
@ -56,6 +56,7 @@ type
|
|||
tmpSeedPhrase: string
|
||||
tmpSeedPhraseLength: int
|
||||
tmpKeyUidWhichIsBeingAuthenticating: string
|
||||
tmpKeyUidWhichIsBeingSigning: string
|
||||
tmpKeyUidWhichIsBeingSyncing: string
|
||||
tmpUsePinFromBiometrics: bool
|
||||
tmpOfferToStoreUpdatedPinToKeychain: bool
|
||||
|
@ -69,6 +70,7 @@ type
|
|||
tmpKeycardSyncingInProgress: bool
|
||||
tmpFlowData: SharedKeycarModuleFlowTerminatedArgs
|
||||
tmpRequestedPathsAlongWithAuthentication: seq[string]
|
||||
tmpPathUsedForSigning: string
|
||||
tmpUnlockUsingSeedPhrase: bool # true - sp, false - puk
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface,
|
||||
|
@ -306,6 +308,9 @@ proc getPairingCode*(self: Controller): string =
|
|||
proc getKeyUidWhichIsBeingAuthenticating*(self: Controller): string =
|
||||
return self.tmpKeyUidWhichIsBeingAuthenticating
|
||||
|
||||
proc getKeyUidWhichIsBeingSigning*(self: Controller): string =
|
||||
return self.tmpKeyUidWhichIsBeingSigning
|
||||
|
||||
proc getKeyUidWhichIsBeingSyncing*(self: Controller): string =
|
||||
return self.tmpKeyUidWhichIsBeingSyncing
|
||||
|
||||
|
@ -531,9 +536,8 @@ proc runDeriveAccountFlow*(self: Controller, bip44Paths: seq[string], pin: strin
|
|||
self.keycardService.startExportPublicFlow(bip44Paths, exportMasterAddr=true, exportPrivateAddr=false, pin)
|
||||
|
||||
proc runAuthenticationFlow*(self: Controller, keyUid = "", bip44Paths: seq[string] = @[]) =
|
||||
## For 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.
|
||||
## In case of `Authentication` flow, if keyUid is provided, that keypair will be authenticated,
|
||||
## otherwise the logged in profile will be authenticated.
|
||||
if not serviceApplicable(self.keycardService):
|
||||
return
|
||||
self.tmpKeyUidWhichIsBeingAuthenticating = keyUid
|
||||
|
@ -546,6 +550,19 @@ proc runAuthenticationFlow*(self: Controller, keyUid = "", bip44Paths: seq[strin
|
|||
self.tmpRequestedPathsAlongWithAuthentication = self.tmpRequestedPathsAlongWithAuthentication.deduplicate()
|
||||
self.keycardService.startExportPublicFlow(self.tmpRequestedPathsAlongWithAuthentication, exportMasterAddr = false, exportPrivateAddr = true)
|
||||
|
||||
proc runSignFlow*(self: Controller, keyUid, bip44Path, txHash: string) =
|
||||
if not serviceApplicable(self.keycardService):
|
||||
return
|
||||
self.tmpKeyUidWhichIsBeingSigning = keyUid
|
||||
if self.tmpKeyUidWhichIsBeingSigning.len == 0:
|
||||
self.tmpKeyUidWhichIsBeingSigning = singletonInstance.userProfile.getKeyUid()
|
||||
self.cancelCurrentFlow()
|
||||
if bip44Path.len == 0:
|
||||
error "path must be set"
|
||||
return
|
||||
self.tmpPathUsedForSigning = bip44Path
|
||||
self.keycardService.startSignFlow(bip44Path, txHash)
|
||||
|
||||
proc runLoadAccountFlow*(self: Controller, seedPhraseLength = 0, seedPhrase = "", pin = "", puk = "", factoryReset = false) =
|
||||
if not serviceApplicable(self.keycardService):
|
||||
return
|
||||
|
@ -575,6 +592,7 @@ proc readyToDisplayPopup*(self: Controller) =
|
|||
proc cleanTmpData(self: Controller) =
|
||||
# we should not reset here `tmpKeycardSyncingInProgress` property
|
||||
self.tmpKeyUidWhichIsBeingAuthenticating = ""
|
||||
self.tmpKeyUidWhichIsBeingSigning = ""
|
||||
self.tmpKeyUidWhichIsBeingSyncing = ""
|
||||
self.tmpAddingMigratedKeypairSuccess = false
|
||||
self.tmpConvertingProfileSuccess = false
|
||||
|
@ -614,21 +632,26 @@ proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool, nex
|
|||
continueWithKeyUid: nextKeyUid,
|
||||
returnToFlow: returnToFlow)
|
||||
if lastStepInTheCurrentFlow:
|
||||
var exportedEncryptionPubKey: string
|
||||
if flowEvent.generatedWalletAccounts.len > 0:
|
||||
exportedEncryptionPubKey = flowEvent.generatedWalletAccounts[0].publicKey # encryption key is at position 0
|
||||
if exportedEncryptionPubKey.len > 0:
|
||||
self.tmpFlowData.password = exportedEncryptionPubKey
|
||||
self.tmpFlowData.pin = self.getPin()
|
||||
self.tmpFlowData.keyUid = flowEvent.keyUid
|
||||
self.tmpFlowData.keycardUid = flowEvent.instanceUID
|
||||
for i in 0..< self.tmpRequestedPathsAlongWithAuthentication.len:
|
||||
var path = self.tmpRequestedPathsAlongWithAuthentication[i]
|
||||
self.tmpFlowData.additinalPathsDetails[path] = KeyDetails(
|
||||
address: flowEvent.generatedWalletAccounts[i].address,
|
||||
publicKey: flowEvent.generatedWalletAccounts[i].publicKey,
|
||||
privateKey: flowEvent.generatedWalletAccounts[i].privateKey
|
||||
)
|
||||
if flowEvent.instanceUID.len > 0:
|
||||
self.tmpFlowData.keyUid = flowEvent.keyUid
|
||||
self.tmpFlowData.keycardUid = flowEvent.instanceUID
|
||||
self.tmpFlowData.pin = self.getPin()
|
||||
self.tmpFlowData.path = self.tmpPathUsedForSigning
|
||||
self.tmpFlowData.r = flowEvent.txSignature.r
|
||||
self.tmpFlowData.s = flowEvent.txSignature.s
|
||||
self.tmpFlowData.v = flowEvent.txSignature.v
|
||||
var exportedEncryptionPubKey: string
|
||||
if flowEvent.generatedWalletAccounts.len > 0:
|
||||
exportedEncryptionPubKey = flowEvent.generatedWalletAccounts[0].publicKey # encryption key is at position 0
|
||||
if exportedEncryptionPubKey.len > 0:
|
||||
self.tmpFlowData.password = exportedEncryptionPubKey
|
||||
for i in 0..< self.tmpRequestedPathsAlongWithAuthentication.len:
|
||||
var path = self.tmpRequestedPathsAlongWithAuthentication[i]
|
||||
self.tmpFlowData.additinalPathsDetails[path] = KeyDetails(
|
||||
address: flowEvent.generatedWalletAccounts[i].address,
|
||||
publicKey: flowEvent.generatedWalletAccounts[i].publicKey,
|
||||
privateKey: flowEvent.generatedWalletAccounts[i].privateKey
|
||||
)
|
||||
else:
|
||||
self.tmpFlowData.password = self.getPassword()
|
||||
self.tmpFlowData.keyUid = singletonInstance.userProfile.getKeyUid()
|
||||
|
|
|
@ -9,20 +9,24 @@ proc delete*(self: BiometricsPinFailedState) =
|
|||
self.State.delete
|
||||
|
||||
method executePrePrimaryStateCommand*(self: BiometricsPinFailedState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
|
||||
method executePreSecondaryStateCommand*(self: BiometricsPinFailedState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.setUsePinFromBiometrics(true)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.setUsePinFromBiometrics(true)
|
||||
|
||||
method getNextSecondaryState*(self: BiometricsPinFailedState, controller: Controller): State =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
return createState(StateType.EnterPin, self.flowType, nil)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
return createState(StateType.EnterPin, self.flowType, nil)
|
||||
|
||||
method executeCancelCommand*(self: BiometricsPinFailedState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
|
||||
method resolveKeycardNextState*(self: BiometricsPinFailedState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
|
|
|
@ -9,21 +9,25 @@ proc delete*(self: BiometricsPinInvalidState) =
|
|||
self.State.delete
|
||||
|
||||
method executePrePrimaryStateCommand*(self: BiometricsPinInvalidState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
|
||||
method executePreSecondaryStateCommand*(self: BiometricsPinInvalidState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.setUsePinFromBiometrics(true)
|
||||
controller.setOfferToStoreUpdatedPinToKeychain(true)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.setUsePinFromBiometrics(true)
|
||||
controller.setOfferToStoreUpdatedPinToKeychain(true)
|
||||
|
||||
method getNextSecondaryState*(self: BiometricsPinInvalidState, controller: Controller): State =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
return createState(StateType.EnterPin, self.flowType, nil)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
return createState(StateType.EnterPin, self.flowType, nil)
|
||||
|
||||
method executeCancelCommand*(self: BiometricsPinInvalidState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
|
||||
method resolveKeycardNextState*(self: BiometricsPinInvalidState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
|
|
|
@ -9,44 +9,49 @@ proc delete*(self: BiometricsReadyToSignState) =
|
|||
self.State.delete
|
||||
|
||||
method executePrePrimaryStateCommand*(self: BiometricsReadyToSignState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
|
||||
method executePreSecondaryStateCommand*(self: BiometricsReadyToSignState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.setUsePinFromBiometrics(true)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.setUsePinFromBiometrics(true)
|
||||
|
||||
method getNextSecondaryState*(self: BiometricsReadyToSignState, controller: Controller): State =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
return createState(StateType.EnterPin, self.flowType, nil)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
return createState(StateType.EnterPin, self.flowType, nil)
|
||||
|
||||
method executeCancelCommand*(self: BiometricsReadyToSignState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
|
||||
method resolveKeycardNextState*(self: BiometricsReadyToSignState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||
if not state.isNil:
|
||||
return state
|
||||
if self.flowType == FlowType.Authentication:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin() and not controller.usePinFromBiometrics():
|
||||
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
|
||||
keycardEvent.error.len == 0:
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin() and not controller.usePinFromBiometrics():
|
||||
return createState(StateType.WrongKeychainPin, self.flowType, nil)
|
||||
return createState(StateType.WrongPin, self.flowType, nil)
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len == 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
|
@ -19,9 +19,10 @@ method getNextPrimaryState*(self: EnterPinState, controller: Controller): State
|
|||
if self.flowType == FlowType.CreateCopyOfAKeycard:
|
||||
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
|
||||
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||
if self.flowType == FlowType.Authentication:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
|
||||
method executePreSecondaryStateCommand*(self: EnterPinState, controller: Controller) =
|
||||
if self.flowType == FlowType.SetupNewKeycard or
|
||||
|
@ -38,9 +39,10 @@ method executePreSecondaryStateCommand*(self: EnterPinState, controller: Control
|
|||
self.flowType == FlowType.MigrateFromAppToKeycard:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.setUsePinFromBiometrics(false)
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.setUsePinFromBiometrics(false)
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
|
||||
method executeCancelCommand*(self: EnterPinState, controller: Controller) =
|
||||
if self.flowType == FlowType.FactoryReset or
|
||||
|
@ -49,6 +51,7 @@ method executeCancelCommand*(self: EnterPinState, controller: Controller) =
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
|
@ -184,29 +187,30 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
|
|||
)) # 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
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin() and not controller.usePinFromBiometrics():
|
||||
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
|
||||
keycardEvent.error.len == 0:
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin() and not controller.usePinFromBiometrics():
|
||||
return createState(StateType.WrongKeychainPin, self.flowType, nil)
|
||||
return createState(StateType.WrongPin, self.flowType, nil)
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len == 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
if controller.offerToStoreUpdatedPinToKeychain():
|
||||
controller.tryToStoreDataToKeychain(controller.getPin())
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
if controller.offerToStoreUpdatedPinToKeychain():
|
||||
controller.tryToStoreDataToKeychain(controller.getPin())
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
if self.flowType == FlowType.DisplayKeycardContent:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
|
|
|
@ -20,6 +20,7 @@ method executeCancelCommand*(self: InsertKeycardState, controller: Controller) =
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -12,6 +12,7 @@ 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.Sign or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
|
@ -35,6 +36,7 @@ method executeCancelCommand*(self: KeycardEmptyState, controller: Controller) =
|
|||
if self.flowType == FlowType.FactoryReset or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -27,6 +27,7 @@ method executeCancelCommand*(self: KeycardInsertedState, controller: Controller)
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -21,6 +21,7 @@ method getNextPrimaryState*(self: MaxPairingSlotsReachedState, controller: Contr
|
|||
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||
if self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
|
@ -38,6 +39,7 @@ method executeCancelCommand*(self: MaxPairingSlotsReachedState, controller: Cont
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -33,12 +33,14 @@ method getNextPrimaryState*(self: MaxPinRetriesReachedState, controller: Control
|
|||
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
|
||||
return
|
||||
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
|
||||
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
|
||||
controller.runSharedModuleFlow(FlowType.UnlockKeycard)
|
||||
|
||||
method executeCancelCommand*(self: MaxPinRetriesReachedState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
self.flowType == FlowType.ChangeKeycardPuk or
|
||||
|
|
|
@ -21,6 +21,7 @@ method getNextPrimaryState*(self: MaxPukRetriesReachedState, controller: Control
|
|||
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||
if self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
|
@ -38,6 +39,7 @@ method executeCancelCommand*(self: MaxPukRetriesReachedState, controller: Contro
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -15,6 +15,7 @@ method executeCancelCommand*(self: NotKeycardState, controller: Controller) =
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -20,6 +20,7 @@ method executeCancelCommand*(self: PluginReaderState, controller: Controller) =
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
|
|
@ -7,6 +7,7 @@ proc ensureReaderAndCardPresence*(state: State, keycardFlowType: string, keycard
|
|||
## Handling factory reset or authentication or unlock keycard flow
|
||||
if state.flowType == FlowType.FactoryReset or
|
||||
state.flowType == FlowType.Authentication or
|
||||
state.flowType == FlowType.Sign or
|
||||
state.flowType == FlowType.UnlockKeycard or
|
||||
state.flowType == FlowType.DisplayKeycardContent or
|
||||
state.flowType == FlowType.RenameKeycard or
|
||||
|
@ -292,6 +293,45 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
|
|||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
|
||||
## Handling sign flow
|
||||
if state.flowType == FlowType.Sign:
|
||||
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:
|
||||
if keycardEvent.keyUid == controller.getKeyUidWhichIsBeingSigning():
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
if keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
if not controller.usePinFromBiometrics():
|
||||
return createState(StateType.WrongKeychainPin, state.flowType, nil)
|
||||
return createState(StateType.WrongPin, state.flowType, nil)
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true))
|
||||
return createState(StateType.MaxPinRetriesReached, state.flowType, nil)
|
||||
return createState(StateType.BiometricsReadyToSign, state.flowType, nil)
|
||||
return createState(StateType.EnterPin, state.flowType, nil)
|
||||
return createState(StateType.WrongKeycard, state.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.UseGeneralMessageForLockedState, add = true))
|
||||
return createState(StateType.MaxPinRetriesReached, state.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
|
||||
## Handling unlock keycard flow
|
||||
if state.flowType == FlowType.UnlockKeycard:
|
||||
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.GetMetadata:
|
||||
|
|
|
@ -28,6 +28,7 @@ method executePrePrimaryStateCommand*(self: WrongKeycardState, controller: Contr
|
|||
|
||||
method executeCancelCommand*(self: WrongKeycardState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
|
|
|
@ -9,34 +9,37 @@ proc delete*(self: WrongKeychainPinState) =
|
|||
self.State.delete
|
||||
|
||||
method getNextPrimaryState*(self: WrongKeychainPinState, controller: Controller): State =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
return nil
|
||||
|
||||
method executeCancelCommand*(self: WrongKeychainPinState, controller: Controller) =
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
|
||||
method resolveKeycardNextState*(self: WrongKeychainPinState, keycardFlowType: string, keycardEvent: KeycardEvent,
|
||||
controller: Controller): State =
|
||||
let state = ensureReaderAndCardPresence(self, keycardFlowType, keycardEvent, controller)
|
||||
if not state.isNil:
|
||||
return state
|
||||
if self.flowType == FlowType.Authentication:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
return self
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.tryToStoreDataToKeychain(controller.getPin())
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
return self
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.tryToStoreDataToKeychain(controller.getPin())
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
|
@ -17,9 +17,10 @@ method getNextPrimaryState*(self: WrongPinState, controller: Controller): State
|
|||
if self.flowType == FlowType.CreateCopyOfAKeycard:
|
||||
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
|
||||
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
|
||||
if self.flowType == FlowType.Authentication:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
if self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
|
@ -43,9 +44,10 @@ method executePreSecondaryStateCommand*(self: WrongPinState, controller: Control
|
|||
self.flowType == FlowType.MigrateFromAppToKeycard:
|
||||
if controller.getPin().len == PINLengthForStatusApp:
|
||||
controller.enterKeycardPin(controller.getPin())
|
||||
if self.flowType == FlowType.Authentication:
|
||||
controller.setUsePinFromBiometrics(false)
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
controller.setUsePinFromBiometrics(false)
|
||||
controller.tryToObtainDataFromKeychain()
|
||||
|
||||
method executeCancelCommand*(self: WrongPinState, controller: Controller) =
|
||||
if self.flowType == FlowType.FactoryReset or
|
||||
|
@ -54,6 +56,7 @@ method executeCancelCommand*(self: WrongPinState, controller: Controller) =
|
|||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.RenameKeycard or
|
||||
self.flowType == FlowType.ChangeKeycardPin or
|
||||
|
@ -168,22 +171,23 @@ method resolveKeycardNextState*(self: WrongPinState, keycardFlowType: string, ke
|
|||
)) # 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
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
return self
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
if self.flowType == FlowType.Authentication or
|
||||
self.flowType == FlowType.Sign:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
keycardEvent.error == ErrorPIN:
|
||||
controller.setRemainingAttempts(keycardEvent.pinRetries)
|
||||
if keycardEvent.pinRetries > 0:
|
||||
return self
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueEnterPUK and
|
||||
keycardEvent.error.len == 0:
|
||||
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
|
||||
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
return nil
|
||||
if self.flowType == FlowType.DisplayKeycardContent:
|
||||
if keycardFlowType == ResponseTypeValueEnterPIN and
|
||||
keycardEvent.error.len > 0 and
|
||||
|
|
|
@ -21,6 +21,7 @@ type FlowType* {.pure.} = enum
|
|||
CreateCopyOfAKeycard = "CreateCopyOfAKeycard"
|
||||
MigrateFromKeycardToApp = "MigrateFromKeycardToApp"
|
||||
MigrateFromAppToKeycard = "MigrateFromAppToKeycard"
|
||||
Sign = "Sign"
|
||||
|
||||
# For the following flows we don't run card syncing.
|
||||
const FlowsWeShouldNotTryAKeycardSyncFor* = @[
|
||||
|
@ -35,6 +36,7 @@ const FlowsWeShouldNotTryAKeycardSyncFor* = @[
|
|||
FlowType.CreateCopyOfAKeycard,
|
||||
FlowType.MigrateFromKeycardToApp,
|
||||
FlowType.MigrateFromAppToKeycard,
|
||||
FlowType.Sign,
|
||||
]
|
||||
|
||||
const SIGNAL_SHARED_KEYCARD_MODULE_DISPLAY_POPUP* = "sharedKeycarModuleDisplayPopup"
|
||||
|
|
|
@ -33,6 +33,7 @@ type
|
|||
initialized: bool
|
||||
tmpLocalState: State # used when flow is run, until response arrives to determine next state appropriatelly
|
||||
authenticationPopupIsAlreadyRunning: bool
|
||||
runningFlow: FlowType # in general used to mark the global shared flow that is being running (`Authentication` or `Sign`)
|
||||
|
||||
proc newModule*[T](delegate: T,
|
||||
uniqueIdentifier: string,
|
||||
|
@ -53,6 +54,7 @@ proc newModule*[T](delegate: T,
|
|||
networkService, privacyService, accountsService, walletAccountService, keychainService)
|
||||
result.initialized = false
|
||||
result.authenticationPopupIsAlreadyRunning = false
|
||||
result.runningFlow = FlowType.General
|
||||
|
||||
method delete*[T](self: Module[T]) =
|
||||
self.view.delete
|
||||
|
@ -209,8 +211,9 @@ proc preStateActivities[T](self: Module[T], currFlowType: FlowType, nextStateTyp
|
|||
let (_, flowEvent) = self.controller.getLastReceivedKeycardData()
|
||||
self.controller.setCurrentKeycardStateToLocked(flowEvent.keyUid, flowEvent.instanceUID)
|
||||
|
||||
if currFlowType == FlowType.Authentication:
|
||||
self.view.setLockedPropForKeyPairForProcessing(nextStateType == StateType.MaxPinRetriesReached)
|
||||
if currFlowType == FlowType.Authentication or
|
||||
currFlowType == FlowType.Sign:
|
||||
self.view.setLockedPropForKeyPairForProcessing(nextStateType == StateType.MaxPinRetriesReached)
|
||||
|
||||
if currFlowType == FlowType.UnlockKeycard:
|
||||
if nextStateType == StateType.UnlockKeycardOptions:
|
||||
|
@ -467,9 +470,8 @@ method prepareKeyPairForProcessing*[T](self: Module[T], keyUid: string, keycardU
|
|||
self.view.setKeyPairForProcessing(item)
|
||||
|
||||
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.
|
||||
## In case of `Authentication` or `Sign` flow, if keyUid is provided, that keypair will be authenticated,
|
||||
## otherwise the logged in profile will be authenticated.
|
||||
if flowToRun == FlowType.General:
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
error "sm_cannot run an general flow"
|
||||
|
@ -501,15 +503,15 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths
|
|||
self.controller.runLoadAccountFlow()
|
||||
return
|
||||
if flowToRun == FlowType.Authentication:
|
||||
self.controller.connectKeychainSignals()
|
||||
self.runningFlow = flowToRun
|
||||
if keyUid.len == 0 or keyUid == singletonInstance.userProfile.getKeyUid():
|
||||
if singletonInstance.userProfile.getIsKeycardUser():
|
||||
self.prepareKeyPairItemForAuthentication(singletonInstance.userProfile.getKeyUid())
|
||||
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
|
||||
self.controller.runAuthenticationFlow(singletonInstance.userProfile.getKeyUid(), bip44Paths)
|
||||
return
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
self.controller.tryToObtainDataFromKeychain()
|
||||
if singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
self.controller.connectKeychainSignals()
|
||||
self.controller.tryToObtainDataFromKeychain()
|
||||
return
|
||||
self.view.setCurrentState(newEnterPasswordState(flowToRun, nil))
|
||||
self.authenticationPopupIsAlreadyRunning = true
|
||||
|
@ -520,6 +522,36 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Paths
|
|||
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
|
||||
self.controller.runAuthenticationFlow(keyUid, bip44Paths)
|
||||
return
|
||||
if flowToRun == FlowType.Sign:
|
||||
if bip44Paths.len == 0 or bip44Paths[0].len == 0:
|
||||
error "sm_cannot path must be set when signing"
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
return
|
||||
if txHash.len == 0:
|
||||
error "sm_cannot txHash must be set when signing"
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
return
|
||||
var finalKeyUid = keyUid
|
||||
if keyUid.len == 0:
|
||||
finalKeyUid = singletonInstance.userProfile.getKeyUid()
|
||||
let keypair = self.controller.getKeypairByKeyUid(finalKeyUid)
|
||||
if keypair.isNil:
|
||||
error "sm_cannot resolve a keypair for signing"
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
return
|
||||
if not keypair.migratedToKeycard():
|
||||
error "sm_cannot sign flow is spcified only for keycard migrated keypairs"
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
return
|
||||
self.runningFlow = flowToRun
|
||||
self.prepareKeyPairItemForAuthentication(keyUid)
|
||||
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
|
||||
self.controller.runSignFlow(keyUid, bip44Paths[0], txHash)
|
||||
if finalKeyUid == singletonInstance.userProfile.getKeyUid() and
|
||||
singletonInstance.userProfile.getUsingBiometricLogin():
|
||||
self.controller.connectKeychainSignals()
|
||||
self.controller.tryToObtainDataFromKeychain()
|
||||
return
|
||||
if flowToRun == FlowType.UnlockKeycard:
|
||||
## since we can run unlock keycard flow from an already running flow, in order to avoid changing displayed keypair
|
||||
## (locked keypair) we have to set keycard uid of a keycard used in the flow we're jumping from to `UnlockKeycard` flow.
|
||||
|
@ -684,7 +716,7 @@ method keychainObtainedDataFailure*[T](self: Module[T], errorDescription: string
|
|||
self.controller.readyToDisplayPopup()
|
||||
return
|
||||
if not currStateObj.isNil:
|
||||
self.view.setCurrentState(newBiometricsPinFailedState(FlowType.Authentication, nil))
|
||||
self.view.setCurrentState(newBiometricsPinFailedState(self.runningFlow, nil))
|
||||
|
||||
method keychainObtainedDataSuccess*[T](self: Module[T], data: string) =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
|
@ -706,4 +738,4 @@ method keychainObtainedDataSuccess*[T](self: Module[T], data: string) =
|
|||
self.controller.setPin(data)
|
||||
self.controller.enterKeycardPin(data)
|
||||
else:
|
||||
self.view.setCurrentState(newBiometricsPinInvalidState(FlowType.Authentication, nil))
|
||||
self.view.setCurrentState(newBiometricsPinInvalidState(self.runningFlow, nil))
|
||||
|
|
|
@ -32,7 +32,12 @@ StatusStackModal {
|
|||
|
||||
required property bool requirementsCheckPending
|
||||
|
||||
signal joined(string airdropAddress, var sharedAddresses)
|
||||
property var keypairSigningModel
|
||||
|
||||
signal prepareForSigning(string airdropAddress, var sharedAddresses)
|
||||
signal joinCommunity()
|
||||
signal signSharedAddressesForAllNonKeycardKeypairs()
|
||||
signal signSharedAddressesForKeypair(string keyUid)
|
||||
signal cancelMembershipRequest()
|
||||
signal sharedAddressesUpdated(var sharedAddresses)
|
||||
|
||||
|
@ -43,21 +48,24 @@ StatusStackModal {
|
|||
rightButtons: [d.shareButton, finishButton]
|
||||
|
||||
finishButton: StatusButton {
|
||||
text: root.isInvitationPending ? qsTr("Cancel Membership Request")
|
||||
: (root.accessType === Constants.communityChatOnRequestAccess
|
||||
? qsTr("Share your addresses to join")
|
||||
: qsTr("Join %1").arg(root.name) )
|
||||
text: root.isInvitationPending ?
|
||||
qsTr("Cancel Membership Request")
|
||||
: root.accessType === Constants.communityChatOnRequestAccess?
|
||||
qsTr("Prove ownership")
|
||||
: qsTr("Join %1").arg(root.name)
|
||||
|
||||
type: root.isInvitationPending ? StatusBaseButton.Type.Danger
|
||||
: StatusBaseButton.Type.Normal
|
||||
icon.name: root.accessType === Constants.communityChatOnRequestAccess && !root.isInvitationPending ? Constants.authenticationIconByType[root.loginType] : ""
|
||||
|
||||
onClicked: {
|
||||
if (root.isInvitationPending) {
|
||||
root.cancelMembershipRequest()
|
||||
} else {
|
||||
root.joined(d.selectedAirdropAddress, d.selectedSharedAddresses)
|
||||
root.close()
|
||||
return
|
||||
}
|
||||
|
||||
root.close()
|
||||
root.prepareForSigning(d.selectedAirdropAddress, d.selectedSharedAddresses)
|
||||
root.replace(sharedAddressesSigningPanelComponent)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,6 +147,27 @@ StatusStackModal {
|
|||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: sharedAddressesSigningPanelComponent
|
||||
SharedAddressesSigningPanel {
|
||||
|
||||
keypairSigningModel: root.keypairSigningModel
|
||||
|
||||
onSignSharedAddressesForAllNonKeycardKeypairs: {
|
||||
root.signSharedAddressesForAllNonKeycardKeypairs()
|
||||
}
|
||||
|
||||
onSignSharedAddressesForKeypair: {
|
||||
root.signSharedAddressesForKeypair(keyUid)
|
||||
}
|
||||
|
||||
onJoinCommunity: {
|
||||
root.joinCommunity()
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stackItems: [
|
||||
StatusScrollView {
|
||||
id: scrollView
|
||||
|
|
|
@ -32,6 +32,8 @@ StatusModal {
|
|||
return qsTr("Factory reset a Keycard")
|
||||
case Constants.keycardSharedFlow.authentication:
|
||||
return qsTr("Authenticate")
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
return qsTr("Signing")
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
return qsTr("Unlock Keycard")
|
||||
case Constants.keycardSharedFlow.displayKeycardContent:
|
||||
|
|
|
@ -220,6 +220,27 @@ QtObject {
|
|||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
case Constants.keycardSharedState.wrongPin:
|
||||
case Constants.keycardSharedState.wrongKeychainPin:
|
||||
case Constants.keycardSharedState.biometricsReadyToSign:
|
||||
case Constants.keycardSharedState.maxPinRetriesReached:
|
||||
case Constants.keycardSharedState.maxPukRetriesReached:
|
||||
case Constants.keycardSharedState.maxPairingSlotsReached:
|
||||
case Constants.keycardSharedState.notKeycard:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
case Constants.keycardSharedState.biometricsPinFailed:
|
||||
case Constants.keycardSharedState.biometricsPinInvalid:
|
||||
case Constants.keycardSharedState.enterPin:
|
||||
return true
|
||||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
|
@ -429,6 +450,32 @@ QtObject {
|
|||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
if (userProfile.usingBiometricLogin) {
|
||||
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.enterPin:
|
||||
case Constants.keycardSharedState.wrongPin:
|
||||
return qsTr("Use biometrics")
|
||||
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.biometricsReadyToSign:
|
||||
case Constants.keycardSharedState.notKeycard:
|
||||
case Constants.keycardSharedState.biometricsPinFailed:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
case Constants.keycardSharedState.keycardEmpty:
|
||||
return qsTr("Use PIN")
|
||||
|
||||
case Constants.keycardSharedState.biometricsPinInvalid:
|
||||
return qsTr("Update PIN")
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
|
@ -514,6 +561,19 @@ QtObject {
|
|||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
if (userProfile.usingBiometricLogin) {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.notKeycard:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
case Constants.keycardSharedState.keycardEmpty:
|
||||
return false
|
||||
}
|
||||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
case Constants.keycardSharedState.unlockKeycardOptions:
|
||||
|
@ -805,6 +865,38 @@ QtObject {
|
|||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
case Constants.keycardSharedState.wrongPin:
|
||||
case Constants.keycardSharedState.notKeycard:
|
||||
case Constants.keycardSharedState.biometricsReadyToSign:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
case Constants.keycardSharedState.enterPin:
|
||||
return qsTr("Sign")
|
||||
|
||||
case Constants.keycardSharedState.keycardEmpty:
|
||||
return qsTr("Done")
|
||||
|
||||
case Constants.keycardSharedState.wrongKeychainPin:
|
||||
return qsTr("Update PIN & authenticate")
|
||||
|
||||
case Constants.keycardSharedState.biometricsPinFailed:
|
||||
case Constants.keycardSharedState.biometricsPinInvalid:
|
||||
return qsTr("Try biometrics again")
|
||||
|
||||
case Constants.keycardSharedState.maxPinRetriesReached:
|
||||
case Constants.keycardSharedState.maxPukRetriesReached:
|
||||
case Constants.keycardSharedState.maxPairingSlotsReached:
|
||||
return qsTr("Unlock Keycard")
|
||||
|
||||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
|
@ -1178,6 +1270,20 @@ QtObject {
|
|||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.wrongPin:
|
||||
case Constants.keycardSharedState.wrongKeychainPin:
|
||||
case Constants.keycardSharedState.notKeycard:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
case Constants.keycardSharedState.enterPin:
|
||||
return root.primaryButtonEnabled
|
||||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.unlockKeycard:
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
|
@ -1270,6 +1376,24 @@ QtObject {
|
|||
}
|
||||
}
|
||||
break
|
||||
|
||||
case Constants.keycardSharedFlow.sign:
|
||||
if (userProfile.usingBiometricLogin) {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.pluginReader:
|
||||
case Constants.keycardSharedState.insertKeycard:
|
||||
case Constants.keycardSharedState.keycardInserted:
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.biometricsPinFailed:
|
||||
case Constants.keycardSharedState.biometricsPinInvalid:
|
||||
case Constants.keycardSharedState.biometricsReadyToSign:
|
||||
case Constants.keycardSharedState.notKeycard:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
return "touch-id"
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return ""
|
||||
|
|
|
@ -48,6 +48,8 @@ Item {
|
|||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.importingFromKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.unlockingKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.copyingKeycard
|
||||
readonly property bool authenticationOrSigning: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.sign
|
||||
}
|
||||
|
||||
Timer {
|
||||
|
@ -236,7 +238,7 @@ Item {
|
|||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard))
|
||||
return true
|
||||
}
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication &&
|
||||
if (d.authenticationOrSigning &&
|
||||
!!root.sharedKeycardModule.keyPairForProcessing &&
|
||||
root.sharedKeycardModule.keyPairForProcessing.name !== "") {
|
||||
if(root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||
|
@ -429,7 +431,7 @@ Item {
|
|||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeycard))
|
||||
return keyPairForProcessingComponent
|
||||
}
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication) {
|
||||
if (d.authenticationOrSigning) {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.keycardInserted ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.insertKeycard ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.readingKeycard ||
|
||||
|
@ -758,19 +760,19 @@ Item {
|
|||
}
|
||||
PropertyChanges {
|
||||
target: image
|
||||
pattern: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
pattern: d.authenticationOrSigning?
|
||||
"" : Constants.keycardAnimations.strongError.pattern
|
||||
source: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
source: d.authenticationOrSigning?
|
||||
Style.png("keycard/plain-error") : ""
|
||||
startImgIndexForTheFirstLoop: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
startImgIndexForTheFirstLoop: d.authenticationOrSigning?
|
||||
0 : Constants.keycardAnimations.strongError.startImgIndexForTheFirstLoop
|
||||
startImgIndexForOtherLoops: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
startImgIndexForOtherLoops: d.authenticationOrSigning?
|
||||
0 : Constants.keycardAnimations.strongError.startImgIndexForOtherLoops
|
||||
endImgIndex: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
endImgIndex: d.authenticationOrSigning?
|
||||
0 : Constants.keycardAnimations.strongError.endImgIndex
|
||||
duration: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
duration: d.authenticationOrSigning?
|
||||
0 : Constants.keycardAnimations.strongError.duration
|
||||
loops: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
loops: d.authenticationOrSigning?
|
||||
-1 : Constants.keycardAnimations.strongError.loops
|
||||
}
|
||||
PropertyChanges {
|
||||
|
@ -831,7 +833,7 @@ Item {
|
|||
PropertyChanges {
|
||||
target: message
|
||||
text: {
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
if (d.authenticationOrSigning ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.renameKeycard ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPin ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.changeKeycardPuk ||
|
||||
|
|
|
@ -40,6 +40,7 @@ Item {
|
|||
|
||||
Component.onCompleted: {
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.sign ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.factoryReset) {
|
||||
timer.start()
|
||||
}
|
||||
|
@ -84,7 +85,8 @@ Item {
|
|||
anchors.bottomMargin: Style.current.halfPadding
|
||||
anchors.leftMargin: Style.current.xlPadding
|
||||
anchors.rightMargin: Style.current.xlPadding
|
||||
spacing: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication?
|
||||
spacing: root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.sign?
|
||||
Style.current.halfPadding : Style.current.padding
|
||||
|
||||
KeycardImage {
|
||||
|
@ -127,7 +129,8 @@ Item {
|
|||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin) {
|
||||
root.sharedKeycardModule.setPin(pinInput)
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication)
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.sign)
|
||||
return
|
||||
root.sharedKeycardModule.currentState.doSecondaryAction()
|
||||
}
|
||||
|
@ -174,7 +177,8 @@ Item {
|
|||
return true
|
||||
}
|
||||
}
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication) {
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.sign) {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin) {
|
||||
|
@ -193,7 +197,8 @@ Item {
|
|||
return keyPairForProcessingComponent
|
||||
}
|
||||
}
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication) {
|
||||
if (root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.authentication ||
|
||||
root.sharedKeycardModule.currentState.flowType === Constants.keycardSharedFlow.sign) {
|
||||
if (root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.enterPin ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongPin ||
|
||||
root.sharedKeycardModule.currentState.stateType === Constants.keycardSharedState.wrongKeychainPin) {
|
||||
|
|
|
@ -125,6 +125,7 @@ QtObject {
|
|||
readonly property string createCopyOfAKeycard: "CreateCopyOfAKeycard"
|
||||
readonly property string migrateFromKeycardToApp: "MigrateFromKeycardToApp"
|
||||
readonly property string migrateFromAppToKeycard: "MigrateFromAppToKeycard"
|
||||
readonly property string sign: "Sign"
|
||||
}
|
||||
|
||||
readonly property QtObject keycardSharedState: QtObject {
|
||||
|
|
Loading…
Reference in New Issue