Skip to content

Commit

Permalink
feature(@desktop/keycard): migrate an exsiting account from Keycard t…
Browse files Browse the repository at this point in the history
…o Status Desktop

Fixes: #7030
  • Loading branch information
saledjenic committed Jan 4, 2023
1 parent 6db0583 commit 32fcda4
Show file tree
Hide file tree
Showing 39 changed files with 651 additions and 50 deletions.
5 changes: 4 additions & 1 deletion src/app/modules/main/profile_section/keycard/module.nim
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,10 @@ method runImportOrRestoreViaSeedPhrasePopup*(self: Module) =
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.SetupNewKeycardOldSeedPhrase)

method runImportFromKeycardToAppPopup*(self: Module) =
info "TODO: Import from Keycard to Status Desktop..."
self.createSharedKeycardModule()
if self.keycardSharedModule.isNil:
return
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ImportFromKeycard)

method runUnlockKeycardPopupForKeycardWithUid*(self: Module, keyUid: string) =
self.createSharedKeycardModule()
Expand Down
21 changes: 19 additions & 2 deletions src/app/modules/shared_modules/keycard_popup/controller.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import chronicles, 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
Expand Down Expand Up @@ -52,6 +54,7 @@ type
tmpKeycardUid: string
tmpAddingMigratedKeypairSuccess: bool
tmpConvertingProfileSuccess: bool
tmpKeycardImportCardMetadata: CardMetadata
tmpKeycardCopyCardMetadata: CardMetadata
tmpKeycardCopyPin: string
tmpKeycardCopyDestinationKeycardUid: string
Expand Down Expand Up @@ -159,6 +162,10 @@ proc init*(self: Controller) =
self.delegate.onSecondaryActionClicked()
self.connectionIds.add(handlerId)

proc switchToWalletSection*(self: Controller) =
let data = ActiveSectionChatArgs(sectionId: conf.WALLET_SECTION_ID)
self.events.emit(SIGNAL_MAKE_SECTION_CHAT_ACTIVE, data)

proc getKeycardData*(self: Controller): string =
return self.delegate.getKeycardData()

Expand All @@ -183,6 +190,9 @@ proc prepareKeyPairForProcessing*(self: Controller, keyUid: string) =
proc getKeyPairForProcessing*(self: Controller): KeyPairItem =
return self.delegate.getKeyPairForProcessing()

proc getKeyPairHelper*(self: Controller): KeyPairItem =
return self.delegate.getKeyPairHelper()

proc setPin*(self: Controller, value: string) =
self.tmpPin = value

Expand Down Expand Up @@ -361,6 +371,13 @@ proc setMetadataForKeycardCopy*(self: Controller, cardMetadata: CardMetadata) =
self.tmpKeycardCopyCardMetadata = cardMetadata
self.setMetadataFromKeycard(cardMetadata)

proc getMetadataForKeycardImport*(self: Controller): CardMetadata =
return self.tmpKeycardImportCardMetadata

proc setMetadataForKeycardImport*(self: Controller, cardMetadata: CardMetadata) =
self.tmpKeycardImportCardMetadata = cardMetadata
self.delegate.updateKeyPairHelper(cardMetadata)

proc setPinForKeycardCopy*(self: Controller, value: string) =
self.tmpKeycardCopyPin = value

Expand Down Expand Up @@ -393,11 +410,11 @@ proc runGetAppInfoFlow*(self: Controller, factoryReset = false) =
self.cancelCurrentFlow()
self.keycardService.startGetAppInfoFlow(factoryReset)

proc runGetMetadataFlow*(self: Controller, resolveAddress = false) =
proc runGetMetadataFlow*(self: Controller, resolveAddress = false, exportMasterAddr = false) =
if not serviceApplicable(self.keycardService):
return
self.cancelCurrentFlow()
self.keycardService.startGetMetadataFlow(resolveAddress)
self.keycardService.startGetMetadataFlow(resolveAddress, exportMasterAddr)

proc runChangePinFlow*(self: Controller) =
if not serviceApplicable(self.keycardService):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ method getNextPrimaryState*(self: EnterPinState, controller: Controller): State
self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard:
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
if self.flowType == FlowType.CreateCopyOfAKeycard:
if isPredefinedKeycardDataFlagSet(controller.getKeycardData(), PredefinedKeycardData.CopyFromAKeycardPartDone):
Expand All @@ -26,6 +27,7 @@ method executePreSecondaryStateCommand*(self: EnterPinState, controller: Control
if self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
Expand All @@ -44,6 +46,7 @@ method executeCancelCommand*(self: EnterPinState, controller: Controller) =
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
Expand Down Expand Up @@ -142,6 +145,43 @@ method resolveKeycardNextState*(self: EnterPinState, keycardFlowType: string, ke
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
controller.setMetadataFromKeycard(keycardEvent.cardMetadata)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.ImportFromKeycard:
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
keycardEvent.error == ErrorPIN:
controller.setRemainingAttempts(keycardEvent.pinRetries)
if keycardEvent.pinRetries > 0:
return createState(StateType.WrongPin, self.flowType, nil)
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len == 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueEnterPUK and
keycardEvent.error.len == 0:
if keycardEvent.pinRetries == 0 and keycardEvent.pukRetries > 0:
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.DisableSeedPhraseForUnlock, add = true))
return createState(StateType.MaxPinRetriesReached, self.flowType, nil)
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
controller.setKeycardUid(keycardEvent.instanceUID)
controller.setMetadataForKeycardImport(keycardEvent.cardMetadata)
let accountItem = controller.getKeyPairHelper().getAccountsModel().getItemAtIndex(0)
if accountItem.isNil:
# should never be here (if keycard doesn't contain metadata we should not be able to proceed with this flow)
return createState(StateType.ImportingFromKeycardFailure, self.flowType, nil)
var item = newKeyPairItem(keyUid = keycardEvent.keyUid)
item.setDerivedFrom(keycardEvent.masterKeyAddress)
item.setName(keycardEvent.cardMetadata.name)
item.setIcon("keycard")
item.setPairType(KeyPairType.SeedImport.int)
item.addAccount(newKeyPairAccountItem(name = "",
path = accountItem.getPath(),
address = accountItem.getAddress(),
pubKey = accountItem.getPubKey()
)) # name and other params will be set by the user during the flow
controller.setKeyPairForProcessing(item)
return createState(StateType.PinVerified, self.flowType, nil)
if self.flowType == FlowType.Authentication:
if keycardFlowType == ResponseTypeValueEnterPIN and
keycardEvent.error.len > 0 and
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
type
ImportingFromKeycardFailureState* = ref object of State

proc newImportingFromKeycardFailureState*(flowType: FlowType, backState: State): ImportingFromKeycardFailureState =
result = ImportingFromKeycardFailureState()
result.setup(flowType, StateType.ImportingFromKeycardFailure, backState)

proc delete*(self: ImportingFromKeycardFailureState) =
self.State.delete

method executePrePrimaryStateCommand*(self: ImportingFromKeycardFailureState, controller: Controller) =
if self.flowType == FlowType.ImportFromKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)

method executeCancelCommand*(self: ImportingFromKeycardFailureState, controller: Controller) =
if self.flowType == FlowType.ImportFromKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
type
ImportingFromKeycardState* = ref object of State
paths: seq[string]
addresses: seq[string]

proc newImportingFromKeycardState*(flowType: FlowType, backState: State): ImportingFromKeycardState =
result = ImportingFromKeycardState()
result.setup(flowType, StateType.ImportingFromKeycard, backState)

proc delete*(self: ImportingFromKeycardState) =
self.State.delete

proc addAccountsToWallet(self: ImportingFromKeycardState, controller: Controller): bool =
let kpForProcessing = controller.getKeyPairForProcessing()
let kpHelper = controller.getKeyPairHelper()
for account in kpForProcessing.getAccountsModel().getItems():
self.addresses.add(account.getAddress())
if not controller.addWalletAccount(name = account.getName(),
address = account.getAddress(),
path = account.getPath(),
addressAccountIsDerivedFrom = kpForProcessing.getDerivedFrom(),
publicKey = account.getPubKey(),
keyUid = kpForProcessing.getKeyUid(),
accountType = if account.getPath() == PATH_DEFAULT_WALLET: SEED else: GENERATED,
color = account.getColor(),
emoji = account.getEmoji()):
return false
return true

proc doMigration(self: ImportingFromKeycardState, controller: Controller) =
let kpForProcessing = controller.getKeyPairForProcessing()
var kpDto = KeyPairDto(keycardUid: controller.getKeycardUid(),
keycardName: kpForProcessing.getName(),
keycardLocked: false,
accountsAddresses: self.addresses,
keyUid: kpForProcessing.getKeyUid())
controller.addMigratedKeyPair(kpDto)

method getNextPrimaryState*(self: ImportingFromKeycardState, controller: Controller): State =
if self.flowType == FlowType.ImportFromKeycard:
if not self.addAccountsToWallet(controller):
return createState(StateType.ImportingFromKeycardFailure, self.flowType, nil)
self.doMigration(controller)
return nil

method getNextSecondaryState*(self: ImportingFromKeycardState, controller: Controller): State =
if self.flowType == FlowType.ImportFromKeycard:
if controller.getAddingMigratedKeypairSuccess():
return createState(StateType.ImportingFromKeycardSuccess, self.flowType, nil)
return createState(StateType.ImportingFromKeycardFailure, self.flowType, nil)
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
type
ImportingFromKeycardSuccessState* = ref object of State

proc newImportingFromKeycardSuccessState*(flowType: FlowType, backState: State): ImportingFromKeycardSuccessState =
result = ImportingFromKeycardSuccessState()
result.setup(flowType, StateType.ImportingFromKeycardSuccess, backState)

proc delete*(self: ImportingFromKeycardSuccessState) =
self.State.delete

method executePrePrimaryStateCommand*(self: ImportingFromKeycardSuccessState, controller: Controller) =
if self.flowType == FlowType.ImportFromKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)

method executePreSecondaryStateCommand*(self: ImportingFromKeycardSuccessState, controller: Controller) =
if self.flowType == FlowType.ImportFromKeycard:
controller.switchToWalletSection()
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)

method executeCancelCommand*(self: ImportingFromKeycardSuccessState, controller: Controller) =
if self.flowType == FlowType.ImportFromKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ method executeCancelCommand*(self: InsertKeycardState, controller: Controller) =
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ method executeCancelCommand*(self: KeycardEmptyMetadataState, controller: Contro
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.CreateCopyOfAKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)

method executePrePrimaryStateCommand*(self: KeycardEmptyMetadataState, controller: Controller) =
if self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.RenameKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
if self.flowType == FlowType.CreateCopyOfAKeycard:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ proc delete*(self: KeycardEmptyState) =

method executePrePrimaryStateCommand*(self: KeycardEmptyState, controller: Controller) =
if self.flowType == FlowType.FactoryReset or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
Expand All @@ -22,6 +23,7 @@ method executePrePrimaryStateCommand*(self: KeycardEmptyState, controller: Contr

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.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ method executeCancelCommand*(self: KeycardInsertedState, controller: Controller)
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ method getNextPrimaryState*(self: KeycardMetadataDisplayState, controller: Contr
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
return createState(StateType.FactoryResetConfirmationDisplayMetadata, self.flowType, self)
if self.flowType == FlowType.ImportFromKeycard:
return createState(StateType.ManageKeycardAccounts, self.flowType, self)
if self.flowType == FlowType.DisplayKeycardContent:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
if self.flowType == FlowType.RenameKeycard:
Expand All @@ -33,6 +35,7 @@ method executeCancelCommand*(self: KeycardMetadataDisplayState, controller: Cont
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.CreateCopyOfAKeycard:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,21 @@ method getNextPrimaryState*(self: ManageKeycardAccountsState, controller: Contro
return createState(StateType.CreatingAccountNewSeedPhrase, self.flowType, nil)
if self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
return createState(StateType.CreatingAccountOldSeedPhrase, self.flowType, nil)
if self.flowType == FlowType.ImportFromKeycard:
let numOfProcessedAccounts = controller.getKeyPairForProcessing().getAccountsModel().getCount()
let totalNumOfAccountsToBeProcessed = controller.getKeyPairHelper().getAccountsModel().getCount()
if numOfProcessedAccounts < totalNumOfAccountsToBeProcessed:
let accountItem = controller.getKeyPairHelper().getAccountsModel().getItemAtIndex(numOfProcessedAccounts) # numOfProcessedAccounts is index of next acc which need to be processed
if accountItem.isNil:
# should never be here
return createState(StateType.ImportingFromKeycardFailure, self.flowType, nil)
controller.getKeyPairForProcessing().addAccount(newKeyPairAccountItem(name = "",
path = accountItem.getPath(),
address = accountItem.getAddress(),
pubKey = accountItem.getPubKey()
))
elif numOfProcessedAccounts == totalNumOfAccountsToBeProcessed:
return createState(StateType.ImportingFromKeycard, self.flowType, nil)

method executePreSecondaryStateCommand*(self: ManageKeycardAccountsState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
Expand All @@ -23,5 +38,6 @@ method executePreSecondaryStateCommand*(self: ManageKeycardAccountsState, contro

method executeCancelCommand*(self: ManageKeycardAccountsState, controller: Controller) =
if self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard:
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ method getNextPrimaryState*(self: MaxPairingSlotsReachedState, controller: Contr
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase:
return createState(StateType.FactoryResetConfirmation, self.flowType, self)
if self.flowType == FlowType.Authentication or
if self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.DisplayKeycardContent or
self.flowType == FlowType.RenameKeycard or
self.flowType == FlowType.ChangeKeycardPin or
Expand All @@ -30,6 +31,7 @@ method executeCancelCommand*(self: MaxPairingSlotsReachedState, controller: Cont
self.flowType == FlowType.SetupNewKeycard or
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
self.flowType == FlowType.ImportFromKeycard or
self.flowType == FlowType.Authentication or
self.flowType == FlowType.UnlockKeycard or
self.flowType == FlowType.DisplayKeycardContent or
Expand Down
Loading

0 comments on commit 32fcda4

Please sign in to comment.