mirror of
https://github.com/status-im/status-desktop.git
synced 2025-02-22 03:28:52 +00:00
feature(@desktop/keycard): sync a Keycard state on every usage
Closes: #8759
This commit is contained in:
parent
93c90b8436
commit
cae2a5bea3
@ -26,6 +26,7 @@ logScope:
|
||||
topics = "main-module-controller"
|
||||
|
||||
const UNIQUE_MAIN_MODULE_IDENTIFIER* = "MainModule"
|
||||
const UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER* = "MainModule-KeycardSyncPurpose"
|
||||
|
||||
type
|
||||
Controller* = ref object of RootObj
|
||||
@ -270,6 +271,10 @@ proc init*(self: Controller) =
|
||||
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED) do(e: Args):
|
||||
let args = SharedKeycarModuleFlowTerminatedArgs(e)
|
||||
if args.uniqueIdentifier == UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER:
|
||||
self.delegate.onSharedKeycarModuleKeycardSyncPurposeTerminated(args.lastStepInTheCurrentFlow)
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_KEYCARD_SYNC_TERMINATED, Args())
|
||||
return
|
||||
if args.uniqueIdentifier != UNIQUE_MAIN_MODULE_IDENTIFIER or
|
||||
self.authenticateUserFlowRequestedBy.len == 0:
|
||||
return
|
||||
@ -293,6 +298,10 @@ proc init*(self: Controller) =
|
||||
self.authenticateUserFlowRequestedBy = args.uniqueIdentifier
|
||||
self.delegate.runAuthenticationPopup(args.keyUid)
|
||||
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC) do(e: Args):
|
||||
let args = SharedKeycarModuleArgs(e)
|
||||
self.delegate.tryKeycardSync(args.keyUid, args.pin)
|
||||
|
||||
proc isConnected*(self: Controller): bool =
|
||||
return self.nodeService.isConnected()
|
||||
|
||||
|
@ -232,6 +232,12 @@ method activateStatusDeepLink*(self: AccessInterface, statusDeepLink: string) {.
|
||||
method setCommunityIdToSpectate*(self: AccessInterface, commnityId: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method tryKeycardSync*(self: AccessInterface, keyUid: string, pin: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onSharedKeycarModuleKeycardSyncPurposeTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
# This way (using concepts) is used only for the modules managed by AppController
|
||||
type
|
||||
DelegateInterface* = concept c
|
||||
|
@ -94,6 +94,7 @@ type
|
||||
nodeSectionModule: node_section_module.AccessInterface
|
||||
networksModule: networks_module.AccessInterface
|
||||
keycardSharedModule: keycard_shared_module.AccessInterface
|
||||
keycardSharedModuleKeycardSyncPurpose: keycard_shared_module.AccessInterface
|
||||
moduleLoaded: bool
|
||||
statusUrlCommunityToSpectate: string
|
||||
|
||||
@ -209,6 +210,8 @@ method delete*[T](self: Module[T]) =
|
||||
self.networksModule.delete
|
||||
if not self.keycardSharedModule.isNil:
|
||||
self.keycardSharedModule.delete
|
||||
if not self.keycardSharedModuleKeycardSyncPurpose.isNil:
|
||||
self.keycardSharedModuleKeycardSyncPurpose.delete
|
||||
self.view.delete
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
@ -983,6 +986,19 @@ method runAuthenticationPopup*[T](self: Module[T], keyUid: string) =
|
||||
return
|
||||
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.Authentication, keyUid)
|
||||
|
||||
method onSharedKeycarModuleKeycardSyncPurposeTerminated*[T](self: Module[T], lastStepInTheCurrentFlow: bool) =
|
||||
if not self.keycardSharedModuleKeycardSyncPurpose.isNil:
|
||||
self.keycardSharedModuleKeycardSyncPurpose.delete
|
||||
self.keycardSharedModuleKeycardSyncPurpose = nil
|
||||
|
||||
method tryKeycardSync*[T](self: Module[T], keyUid: string, pin: string) =
|
||||
self.keycardSharedModuleKeycardSyncPurpose = keycard_shared_module.newModule[Module[T]](self, UNIQUE_MAIN_MODULE_KEYCARD_SYNC_IDENTIFIER,
|
||||
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService,
|
||||
self.walletAccountService, self.keychainService)
|
||||
if self.keycardSharedModuleKeycardSyncPurpose.isNil:
|
||||
return
|
||||
self.keycardSharedModuleKeycardSyncPurpose.syncKeycardBasedOnAppState(keyUid, pin)
|
||||
|
||||
method onDisplayKeycardSharedModuleFlow*[T](self: Module[T]) =
|
||||
self.view.emitDisplayKeycardSharedModuleFlow()
|
||||
|
||||
|
@ -55,19 +55,29 @@ proc init*(self: Controller) =
|
||||
|
||||
self.events.on(SIGNAL_KEYCARD_LOCKED) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
self.delegate.onKeycardLocked(args.keycardUid)
|
||||
self.delegate.onKeycardLocked(args.keyPair.keyUid, args.keyPair.keycardUid)
|
||||
|
||||
self.events.on(SIGNAL_KEYCARD_UNLOCKED) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
self.delegate.onKeycardUnlocked(args.keycardUid)
|
||||
self.delegate.onKeycardUnlocked(args.keyPair.keyUid, args.keyPair.keycardUid)
|
||||
|
||||
self.events.on(SIGNAL_KEYCARD_NAME_CHANGED) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
self.delegate.onKeycardNameChanged(args.keycardUid, args.keycardNewName)
|
||||
self.delegate.onKeycardNameChanged(args.keyPair.keycardUid, args.keyPair.keycardName)
|
||||
|
||||
self.events.on(SIGNAL_KEYCARD_UID_UPDATED) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
self.delegate.onKeycardUidUpdated(args.keycardUid, args.keycardNewUid)
|
||||
self.delegate.onKeycardUidUpdated(args.oldKeycardUid, args.keyPair.keycardUid)
|
||||
|
||||
self.events.on(SIGNAL_KEYCARD_ACCOUNTS_REMOVED) do(e: Args):
|
||||
let args = KeycardActivityArgs(e)
|
||||
if not args.success:
|
||||
return
|
||||
self.delegate.onKeycardAccountsRemoved(args.keyPair.keyUid, args.keyPair.keycardUid, args.keyPair.accountsAddresses)
|
||||
|
||||
self.events.on(SIGNAL_WALLET_ACCOUNT_UPDATED) do(e: Args):
|
||||
let args = WalletAccountUpdated(e)
|
||||
self.delegate.onWalletAccountUpdated(args.account)
|
||||
|
||||
proc getAllMigratedKeyPairs*(self: Controller): seq[KeyPairDto] =
|
||||
return self.walletAccountService.getAllMigratedKeyPairs()
|
||||
|
@ -1,5 +1,6 @@
|
||||
import NimQml
|
||||
from ../../../../../app_service/service/wallet_account/service import KeyPairDto
|
||||
from ../../../../../app_service/service/wallet_account/service import WalletAccountDto
|
||||
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
@ -68,10 +69,10 @@ method onLoggedInUserImageChanged*(self: AccessInterface) {.base.} =
|
||||
method onNewKeycardSet*(self: AccessInterface, keyPair: KeyPairDto) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onKeycardLocked*(self: AccessInterface, keycardUid: string) {.base.} =
|
||||
method onKeycardLocked*(self: AccessInterface, keyUid: string, keycardUid: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onKeycardUnlocked*(self: AccessInterface, keycardUid: string) {.base.} =
|
||||
method onKeycardUnlocked*(self: AccessInterface, keyUid: string, keycardUid: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onKeycardNameChanged*(self: AccessInterface, keycardUid: string, keycardNewName: string) {.base.} =
|
||||
@ -80,6 +81,12 @@ method onKeycardNameChanged*(self: AccessInterface, keycardUid: string, keycardN
|
||||
method onKeycardUidUpdated*(self: AccessInterface, keycardUid: string, keycardNewUid: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onKeycardAccountsRemoved*(self: AccessInterface, keyUid: string, keycardUid: string, accountsToRemove: seq[string]) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onWalletAccountUpdated*(self: AccessInterface, account: WalletAccountDto) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method prepareKeycardDetailsModel*(self: AccessInterface, keyUid: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
|
@ -89,17 +89,18 @@ method viewDidLoad*(self: Module) =
|
||||
method getModuleAsVariant*(self: Module): QVariant =
|
||||
return self.viewVariant
|
||||
|
||||
proc isSharedKeycardModuleFlowRunning(self: Module): bool =
|
||||
return not self.keycardSharedModule.isNil
|
||||
|
||||
method getKeycardSharedModule*(self: Module): QVariant =
|
||||
return self.keycardSharedModule.getModuleAsVariant()
|
||||
if self.isSharedKeycardModuleFlowRunning():
|
||||
return self.keycardSharedModule.getModuleAsVariant()
|
||||
|
||||
proc createSharedKeycardModule(self: Module) =
|
||||
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_SETTING_KEYCARD_MODULE_IDENTIFIER,
|
||||
self.events, self.keycardService, self.settingsService, self.privacyService, self.accountsService,
|
||||
self.walletAccountService, self.keychainService)
|
||||
|
||||
proc isSharedKeycardModuleFlowRunning(self: Module): bool =
|
||||
return not self.keycardSharedModule.isNil
|
||||
|
||||
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) =
|
||||
if self.isSharedKeycardModuleFlowRunning():
|
||||
self.view.emitDestroyKeycardSharedModuleFlow()
|
||||
@ -181,14 +182,14 @@ method runCreateNewPairingCodePopup*(self: Module, keyUid: string) =
|
||||
return
|
||||
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.ChangePairingCode, keyUid)
|
||||
|
||||
proc findAccountByAccountAddress(accounts: seq[WalletAccountDto], address: string): WalletAccountDto =
|
||||
for i in 0 ..< accounts.len:
|
||||
if cmpIgnoreCase(accounts[i].address, address) == 0:
|
||||
return accounts[i]
|
||||
return nil
|
||||
|
||||
proc buildKeycardItem(self: Module, walletAccounts: seq[WalletAccountDto], keyPair: KeyPairDto, reason: BuildItemReason):
|
||||
KeycardItem =
|
||||
let findAccountByAccountAddress = proc(accounts: seq[WalletAccountDto], address: string): WalletAccountDto =
|
||||
for i in 0 ..< accounts.len:
|
||||
if cmpIgnoreCase(accounts[i].address, address) == 0:
|
||||
return accounts[i]
|
||||
return nil
|
||||
|
||||
let isAccountInKnownAccounts = proc(knownAccounts: seq[WalletAccountDto], address: string): bool =
|
||||
for i in 0 ..< knownAccounts.len:
|
||||
if cmpIgnoreCase(knownAccounts[i].address, address) == 0:
|
||||
@ -196,11 +197,14 @@ proc buildKeycardItem(self: Module, walletAccounts: seq[WalletAccountDto], keyPa
|
||||
return false
|
||||
|
||||
var knownAccounts: seq[WalletAccountDto]
|
||||
var unknownAccountsAddresses: seq[string]
|
||||
for accAddr in keyPair.accountsAddresses:
|
||||
let account = findAccountByAccountAddress(walletAccounts, accAddr)
|
||||
if account.isNil:
|
||||
## we should never be here cause we need to remove deleted accounts from the `keypairs` table and sync
|
||||
## that state accross different app instances
|
||||
## We are here if the keycard is not sync yet with the app's state. That may happen if there are more copies of the
|
||||
## same keycard, then deleting an account for a keypair syncs the inserted keycard, but other copies of the card
|
||||
## remain with that account till the moment they are synced.
|
||||
unknownAccountsAddresses.add(accAddr)
|
||||
continue
|
||||
if reason == BuildItemReason.MainView and
|
||||
(isAccountInKnownAccounts(knownAccounts, accAddr) or
|
||||
@ -230,6 +234,12 @@ proc buildKeycardItem(self: Module, walletAccounts: seq[WalletAccountDto], keyPa
|
||||
item.setPairType(KeyPairType.PrivateKeyImport.int)
|
||||
item.setIcon("keycard")
|
||||
item.addAccount(newKeyPairAccountItem(ka.name, ka.path, ka.address, ka.publicKey, ka.emoji, ka.color, icon = icon, balance = 0.0))
|
||||
if reason == BuildItemReason.DetailsView:
|
||||
var i = 0
|
||||
for ua in unknownAccountsAddresses:
|
||||
i.inc
|
||||
let name = "acc" & $i
|
||||
item.addAccount(newKeyPairAccountItem(name, path = "", ua, pubKey = "", emoji = "", color = "#939BA1", icon = "wallet", balance = 0.0))
|
||||
return item
|
||||
|
||||
proc areAllKnownKeycardsLockedForKeypair(self: Module, keyUid: string): bool =
|
||||
@ -260,39 +270,76 @@ method onLoggedInUserImageChanged*(self: Module) =
|
||||
|
||||
method onNewKeycardSet*(self: Module, keyPair: KeyPairDto) =
|
||||
let walletAccounts = self.controller.getWalletAccounts()
|
||||
let mainViewItem = self.buildKeycardItem(walletAccounts, keyPair, BuildItemReason.MainView)
|
||||
if not mainViewItem.isNil:
|
||||
self.view.keycardModel().addItem(mainViewItem)
|
||||
var mainViewItem = self.view.keycardModel().getItemForKeyUid(keyPair.keyUid)
|
||||
if mainViewItem.isNil:
|
||||
mainViewItem = self.buildKeycardItem(walletAccounts, keyPair, BuildItemReason.MainView)
|
||||
if not mainViewItem.isNil:
|
||||
self.view.keycardModel().addItem(mainViewItem)
|
||||
else:
|
||||
for accAddr in keyPair.accountsAddresses:
|
||||
if mainViewItem.containsAccountAddress(accAddr):
|
||||
continue
|
||||
let account = findAccountByAccountAddress(walletAccounts, accAddr)
|
||||
if account.isNil:
|
||||
## we should never be here cause all keypairs are firstly added to wallet
|
||||
continue
|
||||
mainViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
|
||||
account.emoji, account.color, icon = "", balance = 0.0))
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
let detailsViewItem = self.buildKeycardItem(walletAccounts, keyPair, BuildItemReason.DetailsView)
|
||||
if not detailsViewItem.isNil:
|
||||
self.view.keycardDetailsModel().addItem(detailsViewItem)
|
||||
var detailsViewItem = self.view.keycardDetailsModel().getItemForKeycardUid(keyPair.keycardUid)
|
||||
if detailsViewItem.isNil:
|
||||
detailsViewItem = self.buildKeycardItem(walletAccounts, keyPair, BuildItemReason.DetailsView)
|
||||
if not detailsViewItem.isNil:
|
||||
self.view.keycardDetailsModel().addItem(detailsViewItem)
|
||||
else:
|
||||
for accAddr in keyPair.accountsAddresses:
|
||||
if detailsViewItem.containsAccountAddress(accAddr):
|
||||
continue
|
||||
let account = findAccountByAccountAddress(walletAccounts, accAddr)
|
||||
if account.isNil:
|
||||
## we should never be here cause all keypairs are firstly added to wallet
|
||||
continue
|
||||
detailsViewItem.addAccount(newKeyPairAccountItem(account.name, account.path, account.address, account.publicKey,
|
||||
account.emoji, account.color, icon = "", balance = 0.0))
|
||||
|
||||
method onKeycardLocked*(self: Module, keycardUid: string) =
|
||||
self.view.keycardModel().setLocked(keycardUid, true)
|
||||
method onKeycardLocked*(self: Module, keyUid: string, keycardUid: string) =
|
||||
self.view.keycardModel().setLockedForKeycardsWithKeyUid(keyUid, true)
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
self.view.keycardDetailsModel().setLocked(keycardUid, true)
|
||||
self.view.keycardDetailsModel().setLockedForKeycardWithKeycardUid(keycardUid, true)
|
||||
|
||||
method onKeycardUnlocked*(self: Module, keycardUid: string) =
|
||||
self.view.keycardModel().setLocked(keycardUid, false)
|
||||
method onKeycardUnlocked*(self: Module, keyUid: string, keycardUid: string) =
|
||||
self.view.keycardModel().setLockedForKeycardsWithKeyUid(keyUid, false)
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
self.view.keycardDetailsModel().setLocked(keycardUid, false)
|
||||
self.view.keycardDetailsModel().setLockedForKeycardWithKeycardUid(keycardUid, false)
|
||||
|
||||
method onKeycardNameChanged*(self: Module, keycardUid: string, keycardNewName: string) =
|
||||
self.view.keycardModel().setName(keycardUid, keycardNewName)
|
||||
self.view.keycardModel().setNameForKeycardWithKeycardUid(keycardUid, keycardNewName)
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
self.view.keycardDetailsModel().setName(keycardUid, keycardNewName)
|
||||
self.view.keycardDetailsModel().setNameForKeycardWithKeycardUid(keycardUid, keycardNewName)
|
||||
|
||||
method onKeycardUidUpdated*(self: Module, keycardUid: string, keycardNewUid: string) =
|
||||
self.view.keycardModel().setKeycardUid(keycardUid, keycardNewUid)
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
self.view.keycardDetailsModel().setKeycardUid(keycardUid, keycardNewUid)
|
||||
|
||||
method onKeycardAccountsRemoved*(self: Module, keyUid: string, keycardUid: string, accountsToRemove: seq[string]) =
|
||||
self.view.keycardModel().removeAccountsFromKeycardsWithKeyUid(keyUid, accountsToRemove, removeKeycardItemIfHasNoAccounts = true)
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
self.view.keycardDetailsModel().removeAccountsFromKeycardWithKeycardUid(keycardUid, accountsToRemove, removeKeycardItemIfHasNoAccounts = true)
|
||||
|
||||
method onWalletAccountUpdated*(self: Module, account: WalletAccountDto) =
|
||||
self.view.keycardModel().updateDetailsForAddressForKeyPairsWithKeyUid(account.keyUid, account.address, account.name,
|
||||
account.color, account.emoji)
|
||||
if self.view.keycardDetailsModel().isNil:
|
||||
return
|
||||
self.view.keycardDetailsModel().updateDetailsForAddressForKeyPairsWithKeyUid(account.keyUid, account.address, account.name,
|
||||
account.color, account.emoji)
|
||||
|
||||
method prepareKeycardDetailsModel*(self: Module, keyUid: string) =
|
||||
let walletAccounts = self.controller.getWalletAccounts()
|
||||
var items: seq[KeycardItem]
|
||||
|
@ -37,7 +37,10 @@ QtObject:
|
||||
self.delegate.viewDidLoad()
|
||||
|
||||
proc getKeycardSharedModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getKeycardSharedModule()
|
||||
let module = self.delegate.getKeycardSharedModule()
|
||||
if not module.isNil:
|
||||
return module
|
||||
return newQVariant()
|
||||
QtProperty[QVariant] keycardSharedModule:
|
||||
read = getKeycardSharedModule
|
||||
|
||||
|
@ -222,7 +222,10 @@ QtObject:
|
||||
self.displayUserProfile(publicKey)
|
||||
|
||||
proc getKeycardSharedModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getKeycardSharedModule()
|
||||
let module = self.delegate.getKeycardSharedModule()
|
||||
if not module.isNil:
|
||||
return module
|
||||
return newQVariant()
|
||||
QtProperty[QVariant] keycardSharedModule:
|
||||
read = getKeycardSharedModule
|
||||
|
||||
|
@ -51,7 +51,7 @@ proc init*(self: Controller) =
|
||||
let args = SharedKeycarModuleArgs(e)
|
||||
if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_AUTH_IDENTIFIER:
|
||||
return
|
||||
self.delegate.onUserAuthenticated(args.password)
|
||||
self.delegate.onUserAuthenticated(args.pin, args.password, args.keyUid)
|
||||
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED_AND_WALLET_ADDRESS_GENERATED) do(e: Args):
|
||||
let args = SharedKeycarModuleUserAuthenticatedAndWalletAddressGeneratedArgs(e)
|
||||
@ -66,6 +66,12 @@ proc init*(self: Controller) =
|
||||
derivedAddress = args.derivedAddresses[0]
|
||||
self.delegate.addressDetailsFetched(derivedAddress, args.error)
|
||||
|
||||
self.events.on(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED) do(e: Args):
|
||||
let args = SharedKeycarModuleFlowTerminatedArgs(e)
|
||||
if args.uniqueIdentifier != UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER:
|
||||
return
|
||||
self.delegate.onSharedKeycarModuleFlowTerminated(args.lastStepInTheCurrentFlow)
|
||||
|
||||
proc getWalletAccounts*(self: Controller): seq[wallet_account_service.WalletAccountDto] =
|
||||
return self.walletAccountService.getWalletAccounts()
|
||||
|
||||
@ -84,8 +90,8 @@ proc addAccountsFromSeed*(self: Controller, seedPhrase: string, password: string
|
||||
proc addWatchOnlyAccount*(self: Controller, address: string, accountName: string, color: string, emoji: string): string =
|
||||
return self.walletAccountService.addWatchOnlyAccount(address, accountName, color, emoji)
|
||||
|
||||
proc deleteAccount*(self: Controller, address: string) =
|
||||
self.walletAccountService.deleteAccount(address)
|
||||
proc deleteAccount*(self: Controller, address: string, keyPairMigratedToKeycard: bool) =
|
||||
self.walletAccountService.deleteAccount(address, keyPairMigratedToKeycard)
|
||||
|
||||
proc fetchDerivedAddressDetails*(self: Controller, address: string) =
|
||||
self.walletAccountService.fetchDerivedAddressDetails(address)
|
||||
@ -127,3 +133,7 @@ proc getCurrentCurrency*(self: Controller): string =
|
||||
|
||||
proc getCurrencyFormat*(self: Controller, symbol: string): CurrencyFormatDto =
|
||||
return self.currencyService.getCurrencyFormat(symbol)
|
||||
|
||||
proc getMigratedKeyPairByKeyUid*(self: Controller, keyUid: string): seq[KeyPairDto] =
|
||||
return self.walletAccountService.getMigratedKeyPairByKeyUid(keyUid)
|
||||
|
||||
|
@ -13,6 +13,9 @@ method load*(self: AccessInterface) {.base.} =
|
||||
method isLoaded*(self: AccessInterface): bool {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method syncKeycard*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method generateNewAccount*(self: AccessInterface, password: string, accountName: string, color: string, emoji: string, path: string, derivedFrom: string): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
@ -29,7 +32,7 @@ method addAccountsFromSeed*(self: AccessInterface, seedPhrase: string, password:
|
||||
method addWatchOnlyAccount*(self: AccessInterface, address: string, accountName: string, color: string, emoji: string): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method deleteAccount*(self: AccessInterface, address: string) {.base.} =
|
||||
method deleteAccount*(self: AccessInterface, keyUid: string, address: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method refreshWalletAccounts*(self: AccessInterface) {.base.} =
|
||||
@ -56,7 +59,7 @@ method validSeedPhrase*(self: AccessInterface, value: string): bool {.base.} =
|
||||
method authenticateUser*(self: AccessInterface) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onUserAuthenticated*(self: AccessInterface, password: string) {.base.} =
|
||||
method onUserAuthenticated*(self: AccessInterface, pin: string, password: string, keyUid: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method authenticateUserAndDeriveAddressOnKeycardForPath*(self: AccessInterface, keyUid: string, derivationPath: string) {.base.} =
|
||||
@ -73,4 +76,7 @@ method onUserAuthenticatedAndWalletAddressGenerated*(self: AccessInterface, addr
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method addressDetailsFetched*(self: AccessInterface, derivedAddress: DerivedAddressDto, error: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method onSharedKeycarModuleFlowTerminated*(self: AccessInterface, lastStepInTheCurrentFlow: bool) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
@ -13,12 +13,19 @@ import ../../../../../app_service/service/token/service as token_service
|
||||
import ../../../../../app_service/service/currency/service as currency_service
|
||||
import ../../../shared_models/token_model as token_model
|
||||
import ../../../shared_models/token_item as token_item
|
||||
import ../../../shared_modules/keycard_popup/models/key_pair_item as keycard_key_pair_item
|
||||
import ../../../shared_modules/keycard_popup/module as keycard_shared_module
|
||||
import ./compact_item as compact_item
|
||||
import ./compact_model as compact_model
|
||||
|
||||
export io_interface
|
||||
|
||||
type
|
||||
AuthenticationReason {.pure.} = enum
|
||||
LoggedInUserAuthentication = 0
|
||||
DeriveAccountForKeyPairAuthentication
|
||||
DeleteAccountAuthentication
|
||||
|
||||
type WalletAccountDetails = object
|
||||
address: string
|
||||
path: string
|
||||
@ -37,7 +44,8 @@ type
|
||||
accountsService: accounts_service.Service
|
||||
walletAccountService: wallet_account_service.Service
|
||||
keycardSharedModule: keycard_shared_module.AccessInterface
|
||||
walletAccountWhichIsAboutToBeAdded: WalletAccountDetails
|
||||
processingWalletAccount: WalletAccountDetails
|
||||
authentiactionReason: AuthenticationReason
|
||||
|
||||
proc newModule*(
|
||||
delegate: delegate_interface.AccessInterface,
|
||||
@ -58,6 +66,7 @@ proc newModule*(
|
||||
result.view = newView(result)
|
||||
result.controller = controller.newController(result, events, walletAccountService, accountsService, networkService, tokenService, currencyService)
|
||||
result.moduleLoaded = false
|
||||
result.authentiactionReason = AuthenticationReason.LoggedInUserAuthentication
|
||||
|
||||
method delete*(self: Module) =
|
||||
self.view.delete
|
||||
@ -65,6 +74,11 @@ method delete*(self: Module) =
|
||||
if not self.keycardSharedModule.isNil:
|
||||
self.keycardSharedModule.delete
|
||||
|
||||
method onSharedKeycarModuleFlowTerminated*(self: Module, lastStepInTheCurrentFlow: bool) =
|
||||
if not self.keycardSharedModule.isNil:
|
||||
self.keycardSharedModule.delete
|
||||
self.keycardSharedModule = nil
|
||||
|
||||
method refreshWalletAccounts*(self: Module) =
|
||||
let keyPairMigrated = proc(migratedKeyPairs: seq[KeyPairDto], keyUid: string): bool =
|
||||
for kp in migratedKeyPairs:
|
||||
@ -144,6 +158,10 @@ method viewDidLoad*(self: Module) =
|
||||
self.moduleLoaded = true
|
||||
self.delegate.accountsModuleDidLoad()
|
||||
|
||||
proc tryKeycardSync(self: Module, keyUid, pin: string) =
|
||||
let dataForKeycardToSync = SharedKeycarModuleArgs(pin: pin, keyUid: keyUid)
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC, dataForKeycardToSync)
|
||||
|
||||
method generateNewAccount*(self: Module, password: string, accountName: string, color: string, emoji: string,
|
||||
path: string, derivedFrom: string): string =
|
||||
let skipPasswordVerification = singletonInstance.userProfile.getIsKeycardUser()
|
||||
@ -162,8 +180,15 @@ method addAccountsFromSeed*(self: Module, seedPhrase: string, password: string,
|
||||
method addWatchOnlyAccount*(self: Module, address: string, accountName: string, color: string, emoji: string): string =
|
||||
return self.controller.addWatchOnlyAccount(address, accountName, color, emoji)
|
||||
|
||||
method deleteAccount*(self: Module, address: string) =
|
||||
self.controller.deleteAccount(address)
|
||||
method deleteAccount*(self: Module, keyUid: string, address: string) =
|
||||
let keyPair = self.controller.getMigratedKeyPairByKeyUid(keyUid)
|
||||
let keyPairMigratedToKeycard = keyPair.len > 0
|
||||
if not keyPairMigratedToKeycard:
|
||||
self.controller.deleteAccount(address, keyPairMigratedToKeycard)
|
||||
else:
|
||||
self.authentiactionReason = AuthenticationReason.DeleteAccountAuthentication
|
||||
self.processingWalletAccount = WalletAccountDetails(keyUid: keyUid, address: address)
|
||||
self.controller.authenticateUser(keyUid)
|
||||
|
||||
method getDerivedAddressList*(self: Module, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool) =
|
||||
self.controller.getDerivedAddressList(password, derivedFrom, path, pageSize, pageNumber, hashPassword)
|
||||
@ -178,26 +203,38 @@ method validSeedPhrase*(self: Module, value: string): bool =
|
||||
return self.controller.validSeedPhrase(value)
|
||||
|
||||
method authenticateUser*(self: Module) =
|
||||
self.authentiactionReason = AuthenticationReason.LoggedInUserAuthentication
|
||||
if singletonInstance.userProfile.getIsKeycardUser():
|
||||
let keyUid = singletonInstance.userProfile.getKeyUid()
|
||||
self.controller.authenticateUser(keyUid)
|
||||
else:
|
||||
self.controller.authenticateUser()
|
||||
|
||||
method onUserAuthenticated*(self: Module, password: string) =
|
||||
if password.len > 0:
|
||||
self.view.userAuthenticationSuccess(password)
|
||||
else:
|
||||
self.view.userAuthentiactionFail()
|
||||
method onUserAuthenticated*(self: Module, pin: string, password: string, keyUid: string) =
|
||||
if self.authentiactionReason == AuthenticationReason.LoggedInUserAuthentication or
|
||||
self.authentiactionReason == AuthenticationReason.DeriveAccountForKeyPairAuthentication:
|
||||
if password.len > 0:
|
||||
self.view.userAuthenticationSuccess(password)
|
||||
else:
|
||||
self.view.userAuthentiactionFail()
|
||||
elif self.authentiactionReason == AuthenticationReason.DeleteAccountAuthentication:
|
||||
if self.processingWalletAccount.keyUid == keyUid:
|
||||
self.controller.deleteAccount(self.processingWalletAccount.address, true)
|
||||
self.tryKeycardSync(keyUid, pin)
|
||||
|
||||
method createSharedKeycardModule*(self: Module) =
|
||||
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER,
|
||||
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService,
|
||||
self.walletAccountService, keychainService = nil)
|
||||
if self.keycardSharedModule.isNil:
|
||||
self.keycardSharedModule = keycard_shared_module.newModule[Module](self, UNIQUE_WALLET_SECTION_ACCOUNTS_MODULE_IDENTIFIER,
|
||||
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService,
|
||||
self.walletAccountService, keychainService = nil)
|
||||
|
||||
method destroySharedKeycarModule*(self: Module) =
|
||||
self.keycardSharedModule.delete
|
||||
self.keycardSharedModule = nil
|
||||
if not self.keycardSharedModule.isNil:
|
||||
let kpForProcessing = self.keycardSharedModule.getKeyPairForProcessing()
|
||||
if not kpForProcessing.isNil:
|
||||
self.tryKeycardSync(kpForProcessing.getKeyUid(), self.keycardSharedModule.getPin())
|
||||
self.keycardSharedModule.delete
|
||||
self.keycardSharedModule = nil
|
||||
|
||||
proc checkIfWalletAccountIsAlreadyCreated(self: Module, keyUid: string, derivationPath: string): bool =
|
||||
let walletAccounts = self.controller.getWalletAccounts()
|
||||
@ -221,12 +258,13 @@ proc findFirstAvaliablePathForWallet(self: Module, keyUid: string): string =
|
||||
error "we couldn't find available wallet account path"
|
||||
|
||||
method authenticateUserAndDeriveAddressOnKeycardForPath*(self: Module, keyUid: string, derivationPath: string) =
|
||||
self.authentiactionReason = AuthenticationReason.DeriveAccountForKeyPairAuthentication
|
||||
var finalPath = derivationPath
|
||||
if self.checkIfWalletAccountIsAlreadyCreated(keyUid, finalPath):
|
||||
finalPath = self.findFirstAvaliablePathForWallet(keyUid)
|
||||
if self.keycardSharedModule.isNil:
|
||||
self.createSharedKeycardModule()
|
||||
self.walletAccountWhichIsAboutToBeAdded = WalletAccountDetails(keyUid: keyUid, path: finalPath)
|
||||
self.processingWalletAccount = WalletAccountDetails(keyUid: keyUid, path: finalPath)
|
||||
self.view.setDerivedAddressesLoading(true)
|
||||
self.view.setDerivedAddressesError("")
|
||||
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.AuthenticateAndDeriveAccountAddress, keyUid, finalPath)
|
||||
@ -238,27 +276,27 @@ method onUserAuthenticatedAndWalletAddressGenerated*(self: Module, address: stri
|
||||
if password.len == 0:
|
||||
self.view.setDerivedAddressesLoading(false)
|
||||
return
|
||||
self.onUserAuthenticated(password)
|
||||
self.walletAccountWhichIsAboutToBeAdded.address = address
|
||||
self.walletAccountWhichIsAboutToBeAdded.addressAccountIsDerivedFrom = derivedFrom
|
||||
self.walletAccountWhichIsAboutToBeAdded.publicKey = publicKey
|
||||
self.onUserAuthenticated(pin = "", password, keyUid = "")
|
||||
self.processingWalletAccount.address = address
|
||||
self.processingWalletAccount.addressAccountIsDerivedFrom = derivedFrom
|
||||
self.processingWalletAccount.publicKey = publicKey
|
||||
self.controller.fetchDerivedAddressDetails(address)
|
||||
|
||||
method addressDetailsFetched*(self: Module, derivedAddress: DerivedAddressDto, error: string) =
|
||||
var derivedAddressDto = derivedAddress
|
||||
if error.len > 0:
|
||||
derivedAddressDto.address = self.walletAccountWhichIsAboutToBeAdded.address
|
||||
derivedAddressDto.address = self.processingWalletAccount.address
|
||||
derivedAddressDto.alreadyCreated = true
|
||||
self.view.setDerivedAddresses(@[derivedAddressDto], error)
|
||||
|
||||
method addNewWalletAccountGeneratedFromKeycard*(self: Module, accountType: string, accountName: string, color: string,
|
||||
emoji: string): string =
|
||||
return self.controller.addWalletAccount(accountName,
|
||||
self.walletAccountWhichIsAboutToBeAdded.address,
|
||||
self.walletAccountWhichIsAboutToBeAdded.path,
|
||||
self.walletAccountWhichIsAboutToBeAdded.addressAccountIsDerivedFrom,
|
||||
self.walletAccountWhichIsAboutToBeAdded.publicKey,
|
||||
self.walletAccountWhichIsAboutToBeAdded.keyUid,
|
||||
self.processingWalletAccount.address,
|
||||
self.processingWalletAccount.path,
|
||||
self.processingWalletAccount.addressAccountIsDerivedFrom,
|
||||
self.processingWalletAccount.publicKey,
|
||||
self.processingWalletAccount.keyUid,
|
||||
accountType,
|
||||
color,
|
||||
emoji)
|
@ -222,8 +222,8 @@ QtObject:
|
||||
proc addWatchOnlyAccount*(self: View, address: string, accountName: string, color: string, emoji: string): string {.slot.} =
|
||||
return self.delegate.addWatchOnlyAccount(address, accountName, color, emoji)
|
||||
|
||||
proc deleteAccount*(self: View, address: string) {.slot.} =
|
||||
self.delegate.deleteAccount(address)
|
||||
proc deleteAccount*(self: View, keyUid: string, address: string) {.slot.} =
|
||||
self.delegate.deleteAccount(keyUid, address)
|
||||
|
||||
proc getAccountNameByAddress*(self: View, address: string): string {.slot.} =
|
||||
return self.model.getAccountNameByAddress(address)
|
||||
|
@ -18,6 +18,7 @@ QtObject:
|
||||
delegate: io_interface.AccessInterface
|
||||
defaultAccount: account_item.Item
|
||||
name: string
|
||||
keyUid: string
|
||||
address: string
|
||||
mixedcaseAddress: string
|
||||
path: string
|
||||
@ -57,6 +58,13 @@ QtObject:
|
||||
read = getName
|
||||
notify = nameChanged
|
||||
|
||||
proc getKeyUid(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.keyUid)
|
||||
proc keyUidChanged(self: View) {.signal.}
|
||||
QtProperty[QVariant] keyUid:
|
||||
read = getKeyUid
|
||||
notify = keyUidChanged
|
||||
|
||||
proc getAddress(self: View): QVariant {.slot.} =
|
||||
return newQVariant(self.address)
|
||||
proc addressChanged(self: View) {.signal.}
|
||||
@ -182,6 +190,9 @@ QtObject:
|
||||
if(self.name != item.getName()):
|
||||
self.name = item.getName()
|
||||
self.nameChanged()
|
||||
if(self.keyUid != item.getKeyUid()):
|
||||
self.keyUid = item.getKeyUid()
|
||||
self.keyUidChanged()
|
||||
if(self.address != item.getAddress()):
|
||||
self.address = item.getAddress()
|
||||
self.addressChanged()
|
||||
|
@ -7,6 +7,8 @@ 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
|
||||
@ -34,6 +36,7 @@ type
|
||||
connectionIds: seq[UUID]
|
||||
keychainConnectionIds: seq[UUID]
|
||||
connectionKeycardResponse: UUID
|
||||
connectionKeycardSyncTerminatedSignal: UUID
|
||||
tmpKeycardContainsMetadata: bool
|
||||
tmpCardMetadata: CardMetadata
|
||||
tmpPin: string
|
||||
@ -49,6 +52,7 @@ type
|
||||
tmpSeedPhrase: string
|
||||
tmpSeedPhraseLength: int
|
||||
tmpKeyUidWhichIsBeingAuthenticating: string
|
||||
tmpKeyUidWhichIsBeingSyncing: string
|
||||
tmpUsePinFromBiometrics: bool
|
||||
tmpOfferToStoreUpdatedPinToKeychain: bool
|
||||
tmpKeycardUid: string
|
||||
@ -58,6 +62,8 @@ type
|
||||
tmpKeycardCopyCardMetadata: CardMetadata
|
||||
tmpKeycardCopyPin: string
|
||||
tmpKeycardCopyDestinationKeycardUid: string
|
||||
tmpKeycardSyncingInProgress: bool
|
||||
tmpFlowData: SharedKeycarModuleFlowTerminatedArgs
|
||||
|
||||
proc newController*(delegate: io_interface.AccessInterface,
|
||||
uniqueIdentifier: string,
|
||||
@ -87,6 +93,10 @@ proc newController*(delegate: io_interface.AccessInterface,
|
||||
result.tmpUsePinFromBiometrics = false
|
||||
result.tmpAddingMigratedKeypairSuccess = false
|
||||
result.tmpConvertingProfileSuccess = false
|
||||
result.tmpKeycardSyncingInProgress = false
|
||||
|
||||
## Forward declaration:
|
||||
proc finishFlowTermination(self: Controller)
|
||||
|
||||
proc serviceApplicable[T](service: T): bool =
|
||||
if not service.isNil:
|
||||
@ -115,6 +125,15 @@ proc connectKeycardReponseSignal(self: Controller) =
|
||||
let args = KeycardArgs(e)
|
||||
self.delegate.onKeycardResponse(args.flowType, args.flowEvent)
|
||||
|
||||
proc disconnectKeycardSyncSignal(self: Controller) =
|
||||
self.events.disconnect(self.connectionKeycardSyncTerminatedSignal)
|
||||
|
||||
proc connectKeycardSyncSignal(self: Controller) =
|
||||
self.connectionKeycardSyncTerminatedSignal = self.events.onWithUUID(SIGNAL_SHARED_KEYCARD_MODULE_KEYCARD_SYNC_TERMINATED) do(e: Args):
|
||||
self.disconnectKeycardSyncSignal()
|
||||
self.connectKeycardReponseSignal()
|
||||
self.finishFlowTermination()
|
||||
|
||||
proc connectKeychainSignals*(self: Controller) =
|
||||
var handlerId = self.events.onWithUUID(SIGNAL_KEYCHAIN_SERVICE_SUCCESS) do(e:Args):
|
||||
let args = KeyChainServiceArg(e)
|
||||
@ -248,7 +267,19 @@ proc getPairingCode*(self: Controller): string =
|
||||
return self.tmpPairingCode
|
||||
|
||||
proc getKeyUidWhichIsBeingAuthenticating*(self: Controller): string =
|
||||
self.tmpKeyUidWhichIsBeingAuthenticating
|
||||
return self.tmpKeyUidWhichIsBeingAuthenticating
|
||||
|
||||
proc getKeyUidWhichIsBeingSyncing*(self: Controller): string =
|
||||
return self.tmpKeyUidWhichIsBeingSyncing
|
||||
|
||||
proc setKeyUidWhichIsBeingSyncing*(self: Controller, value: string) =
|
||||
self.tmpKeyUidWhichIsBeingSyncing = value
|
||||
|
||||
proc keycardSyncingInProgress*(self: Controller): bool =
|
||||
return self.tmpKeycardSyncingInProgress
|
||||
|
||||
proc setKeycardSyncingInProgress*(self: Controller, value: bool) =
|
||||
self.tmpKeycardSyncingInProgress = value
|
||||
|
||||
proc setSelectedKeyPair*(self: Controller, isProfile: bool, paths: seq[string], keyPairDto: KeyPairDto) =
|
||||
if paths.len != keyPairDto.accountsAddresses.len:
|
||||
@ -410,11 +441,11 @@ proc runGetAppInfoFlow*(self: Controller, factoryReset = false) =
|
||||
self.cancelCurrentFlow()
|
||||
self.keycardService.startGetAppInfoFlow(factoryReset)
|
||||
|
||||
proc runGetMetadataFlow*(self: Controller, resolveAddress = false, exportMasterAddr = false) =
|
||||
proc runGetMetadataFlow*(self: Controller, resolveAddress = false, exportMasterAddr = false, pin = "") =
|
||||
if not serviceApplicable(self.keycardService):
|
||||
return
|
||||
self.cancelCurrentFlow()
|
||||
self.keycardService.startGetMetadataFlow(resolveAddress, exportMasterAddr)
|
||||
self.keycardService.startGetMetadataFlow(resolveAddress, exportMasterAddr, pin)
|
||||
|
||||
proc runChangePinFlow*(self: Controller) =
|
||||
if not serviceApplicable(self.keycardService):
|
||||
@ -491,7 +522,9 @@ proc readyToDisplayPopup*(self: Controller) =
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_DISPLAY_POPUP, data)
|
||||
|
||||
proc cleanTmpData(self: Controller) =
|
||||
# we should not reset here `tmpKeycardSyncingInProgress` property
|
||||
self.tmpKeyUidWhichIsBeingAuthenticating = ""
|
||||
self.tmpKeyUidWhichIsBeingSyncing = ""
|
||||
self.tmpAddingMigratedKeypairSuccess = false
|
||||
self.tmpConvertingProfileSuccess = false
|
||||
self.tmpCardMetadata = CardMetadata()
|
||||
@ -512,18 +545,40 @@ proc cleanTmpData(self: Controller) =
|
||||
self.setPinForKeycardCopy("")
|
||||
self.setDestinationKeycardUid("")
|
||||
|
||||
proc finishFlowTermination(self: Controller) =
|
||||
let data = self.tmpFlowData
|
||||
self.tmpFlowData = nil
|
||||
self.cleanTmpData()
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED, data)
|
||||
|
||||
proc terminateCurrentFlow*(self: Controller, lastStepInTheCurrentFlow: bool) =
|
||||
let flowType = self.delegate.getCurrentFlowType()
|
||||
self.cancelCurrentFlow()
|
||||
let (_, flowEvent) = self.getLastReceivedKeycardData()
|
||||
var data = SharedKeycarModuleFlowTerminatedArgs(uniqueIdentifier: self.uniqueIdentifier,
|
||||
self.tmpFlowData = SharedKeycarModuleFlowTerminatedArgs(uniqueIdentifier: self.uniqueIdentifier,
|
||||
lastStepInTheCurrentFlow: lastStepInTheCurrentFlow)
|
||||
if lastStepInTheCurrentFlow:
|
||||
let exportedEncryptionPubKey = flowEvent.generatedWalletAccount.publicKey
|
||||
data.password = if exportedEncryptionPubKey.len > 0: exportedEncryptionPubKey else: self.getPassword()
|
||||
data.pin = self.getPin()
|
||||
data.keyUid = flowEvent.keyUid
|
||||
self.cleanTmpData()
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED, data)
|
||||
self.tmpFlowData.password = if exportedEncryptionPubKey.len > 0: exportedEncryptionPubKey else: self.getPassword()
|
||||
self.tmpFlowData.pin = self.getPin()
|
||||
self.tmpFlowData.keyUid = flowEvent.keyUid
|
||||
|
||||
## we're trying to sync a keycard state on popup close if:
|
||||
## - shared module is not run from the onboarding flow
|
||||
## - the keycard syncing is not already in progress
|
||||
## - the flow which is terminating is one of the flows which we need to perform a sync process for
|
||||
## - the pin is known
|
||||
if self.uniqueIdentifier != startup_io.UNIQUE_STARTUP_MODULE_IDENTIFIER and
|
||||
not self.keycardSyncingInProgress() and
|
||||
not utils.arrayContains(FlowsWeShouldNotTryAKeycardSyncFor, flowType) and
|
||||
self.getPin().len == PINLengthForStatusApp and
|
||||
flowEvent.keyUid.len > 0:
|
||||
let dataForKeycardToSync = SharedKeycarModuleArgs(pin: self.getPin(), keyUid: flowEvent.keyUid)
|
||||
self.disconnectKeycardReponseSignal()
|
||||
self.connectKeycardSyncSignal()
|
||||
self.events.emit(SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC, dataForKeycardToSync)
|
||||
return
|
||||
self.finishFlowTermination()
|
||||
|
||||
proc authenticateUser*(self: Controller, keyUid = "") =
|
||||
self.disconnectKeycardReponseSignal()
|
||||
@ -554,6 +609,11 @@ proc addMigratedKeyPair*(self: Controller, keyPair: KeyPairDto) =
|
||||
let keystoreDir = self.accountsService.getKeyStoreDir()
|
||||
self.walletAccountService.addMigratedKeyPairAsync(keyPair, keystoreDir)
|
||||
|
||||
proc removeMigratedAccountsForKeycard*(self: Controller, keyUid: string, keycardUid: string, accountsToRemove: seq[string]) =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
return
|
||||
self.walletAccountService.removeMigratedAccountsForKeycard(keyUid, keycardUid, accountsToRemove)
|
||||
|
||||
proc getAddingMigratedKeypairSuccess*(self: Controller): bool =
|
||||
return self.tmpAddingMigratedKeypairSuccess
|
||||
|
||||
@ -572,30 +632,30 @@ proc getAllKnownKeycards*(self: Controller): seq[KeyPairDto] =
|
||||
return
|
||||
return self.walletAccountService.getAllKnownKeycards()
|
||||
|
||||
proc setCurrentKeycardStateToLocked*(self: Controller, keycardUid: string) =
|
||||
proc setCurrentKeycardStateToLocked*(self: Controller, keyUid: string, keycardUid: string) =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
return
|
||||
if not self.walletAccountService.setKeycardLocked(keycardUid):
|
||||
info "updating keycard locked state failed", keycardUid=keycardUid
|
||||
if not self.walletAccountService.setKeycardLocked(keyUid, keycardUid):
|
||||
info "updating keycard locked state failed", keyUid=keyUid, keycardUid=keycardUid
|
||||
|
||||
proc setCurrentKeycardStateToUnlocked*(self: Controller, keycardUid: string) =
|
||||
proc setCurrentKeycardStateToUnlocked*(self: Controller, keyUid: string, keycardUid: string) =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
return
|
||||
if not self.walletAccountService.setKeycardUnlocked(keycardUid):
|
||||
info "updating keycard unlocked state failed", keycardUid=keycardUid
|
||||
if not self.walletAccountService.setKeycardUnlocked(keyUid, keycardUid):
|
||||
info "updating keycard unlocked state failed", keyUid=keyUid, keycardUid=keycardUid
|
||||
|
||||
proc updateKeycardName*(self: Controller, keycardUid: string, keycardName: string): bool =
|
||||
proc updateKeycardName*(self: Controller, keyUid: string, keycardUid: string, keycardName: string): bool =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
return false
|
||||
if not self.walletAccountService.updateKeycardName(keycardUid, keycardName):
|
||||
info "updating keycard name failed", keycardUid=keycardUid
|
||||
if not self.walletAccountService.updateKeycardName(keyUid, keycardUid, keycardName):
|
||||
info "updating keycard name failed", keyUid=keyUid, keycardUid=keycardUid, keycardName=keycardName
|
||||
return false
|
||||
return true
|
||||
|
||||
proc updateKeycardUid*(self: Controller, keycardUid: string) =
|
||||
proc updateKeycardUid*(self: Controller, keyUid: string, keycardUid: string) =
|
||||
if not serviceApplicable(self.walletAccountService):
|
||||
return
|
||||
self.setCurrentKeycardStateToUnlocked(self.tmpKeycardUid)
|
||||
self.setCurrentKeycardStateToUnlocked(keyUid, self.tmpKeycardUid)
|
||||
if self.tmpKeycardUid != keycardUid:
|
||||
if not self.walletAccountService.updateKeycardUid(self.tmpKeycardUid, keycardUid):
|
||||
self.tmpKeycardUid = keycardUid
|
||||
|
@ -14,13 +14,15 @@ method executeCancelCommand*(self: KeycardEmptyMetadataState, controller: Contro
|
||||
self.flowType == FlowType.SetupNewKeycardNewSeedPhrase or
|
||||
self.flowType == FlowType.SetupNewKeycardOldSeedPhrase or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.UnlockKeycard 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
|
||||
if self.flowType == FlowType.UnlockKeycard or
|
||||
self.flowType == FlowType.DisplayKeycardContent or
|
||||
self.flowType == FlowType.ImportFromKeycard or
|
||||
self.flowType == FlowType.RenameKeycard:
|
||||
controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
|
@ -15,7 +15,7 @@ method executePrePrimaryStateCommand*(self: RenamingKeycardState, controller: Co
|
||||
let md = controller.getMetadataFromKeycard()
|
||||
let paths = md.walletAccounts.map(a => a.path)
|
||||
let name = controller.getKeyPairForProcessing().getName()
|
||||
self.success = controller.updateKeycardName(controller.getKeycardUid(), name)
|
||||
self.success = controller.updateKeycardName(controller.getKeyPairForProcessing().getKeyUid(), controller.getKeycardUid(), name)
|
||||
if self.success:
|
||||
controller.runStoreMetadataFlow(name, controller.getPin(), paths)
|
||||
else:
|
||||
|
@ -75,7 +75,7 @@ method resolveKeycardNextState*(self: RepeatPinState, keycardFlowType: string, k
|
||||
return createState(StateType.MaxPukRetriesReached, self.flowType, nil)
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
controller.setPukValid(true)
|
||||
controller.updateKeycardUid(keycardEvent.instanceUID)
|
||||
controller.updateKeycardUid(keycardEvent.keyUid, keycardEvent.instanceUID)
|
||||
return createState(StateType.PinSet, self.flowType, nil)
|
||||
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.LoadAccount:
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
@ -89,5 +89,5 @@ method resolveKeycardNextState*(self: RepeatPinState, keycardFlowType: string, k
|
||||
if controller.getCurrentKeycardServiceFlow() == KCSFlowType.StoreMetadata:
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult and
|
||||
keycardEvent.instanceUID.len > 0:
|
||||
controller.updateKeycardUid(keycardEvent.instanceUID)
|
||||
controller.updateKeycardUid(keycardEvent.keyUid, keycardEvent.instanceUID)
|
||||
return createState(StateType.PinSet, self.flowType, nil)
|
@ -307,6 +307,8 @@ proc ensureReaderAndCardPresenceAndResolveNextState*(state: State, keycardFlowTy
|
||||
keycardEvent.error.len > 0:
|
||||
if keycardEvent.error == ErrorNoKeys:
|
||||
return createState(StateType.KeycardEmpty, state.flowType, nil)
|
||||
if keycardEvent.error == ErrorNoData:
|
||||
return createState(StateType.KeycardEmptyMetadata, state.flowType, nil)
|
||||
|
||||
if state.flowType == FlowType.DisplayKeycardContent:
|
||||
controller.setKeyPairForProcessing(newKeyPairItem(keyUid = keycardEvent.keyUid)) # must set keypair in case of running some other flow which needs e.g. keyuid. like unlock flow
|
||||
|
@ -38,5 +38,5 @@ method resolveKeycardNextState*(self: WrongPukState, keycardFlowType: string, ke
|
||||
if keycardFlowType == ResponseTypeValueKeycardFlowResult:
|
||||
if keycardEvent.error.len == 0:
|
||||
controller.setPukValid(true)
|
||||
controller.updateKeycardUid(keycardEvent.instanceUID)
|
||||
controller.updateKeycardUid(keycardEvent.keyUid, keycardEvent.instanceUID)
|
||||
return createState(StateType.UnlockKeycardSuccess, self.flowType, nil)
|
@ -15,31 +15,30 @@ proc delete*(self: WrongSeedPhraseState) =
|
||||
method executePrePrimaryStateCommand*(self: WrongSeedPhraseState, controller: Controller) =
|
||||
if self.flowType == FlowType.SetupNewKeycard:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
|
||||
sleep(500) # just to shortly remove text on the UI side
|
||||
self.verifiedSeedPhrase = controller.validSeedPhrase(controller.getSeedPhrase()) and
|
||||
controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getSelectedKeyPairDto().keyUid
|
||||
if self.verifiedSeedPhrase:
|
||||
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase())
|
||||
else:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
|
||||
if self.flowType == FlowType.CreateCopyOfAKeycard:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
|
||||
sleep(500) # just to shortly remove text on the UI side
|
||||
self.verifiedSeedPhrase = controller.validSeedPhrase(controller.getSeedPhrase()) and
|
||||
controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getKeyPairForProcessing().getKeyUid()
|
||||
if self.verifiedSeedPhrase:
|
||||
controller.storeSeedPhraseToKeycard(controller.getSeedPhraseLength(), controller.getSeedPhrase())
|
||||
else:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
|
||||
if self.flowType == FlowType.UnlockKeycard:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = false))
|
||||
sleep(500) # just to shortly remove text on the UI side
|
||||
self.verifiedSeedPhrase = controller.validSeedPhrase(controller.getSeedPhrase()) and
|
||||
controller.getKeyUidForSeedPhrase(controller.getSeedPhrase()) == controller.getKeyPairForProcessing().getKeyUid()
|
||||
if self.verifiedSeedPhrase:
|
||||
controller.runGetMetadataFlow()
|
||||
else:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
|
||||
|
||||
method getNextPrimaryState*(self: WrongSeedPhraseState, controller: Controller): State =
|
||||
if self.flowType == FlowType.SetupNewKeycard or
|
||||
self.flowType == FlowType.CreateCopyOfAKeycard or
|
||||
self.flowType == FlowType.UnlockKeycard:
|
||||
if not self.verifiedSeedPhrase:
|
||||
controller.setKeycardData(updatePredefinedKeycardData(controller.getKeycardData(), PredefinedKeycardData.WrongSeedPhrase, add = true))
|
||||
return self
|
||||
|
||||
method executeCancelCommand*(self: WrongSeedPhraseState, controller: Controller) =
|
||||
if self.flowType == FlowType.SetupNewKeycard or
|
||||
|
@ -9,6 +9,8 @@ const SIGNAL_SHARED_KEYCARD_MODULE_DISPLAY_POPUP* = "sharedKeycarModuleDisplayPo
|
||||
const SIGNAL_SHARED_KEYCARD_MODULE_FLOW_TERMINATED* = "sharedKeycarModuleFlowTerminated"
|
||||
const SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER* = "sharedKeycarModuleAuthenticateUser"
|
||||
const SIGNAL_SHARED_KEYCARD_MODULE_USER_AUTHENTICATED* = "sharedKeycarModuleUserAuthenticated"
|
||||
const SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC* = "sharedKeycarModuleTryKeycardSync"
|
||||
const SIGNAL_SHARED_KEYCARD_MODULE_KEYCARD_SYNC_TERMINATED* = "sharedKeycarModuleKeycardSyncTerminated"
|
||||
|
||||
## Authentication in the app is a global thing and may be used from any part of the app. How to achieve that... it's enough just to send
|
||||
## `SIGNAL_SHARED_KEYCARD_MODULE_AUTHENTICATE_USER` signal with properly set `SharedKeycarModuleAuthenticationArgs` and props there:
|
||||
@ -45,6 +47,14 @@ type
|
||||
SharedKeycarModuleAuthenticationArgs* = ref object of SharedKeycarModuleBaseArgs
|
||||
keyUid*: string
|
||||
|
||||
type
|
||||
SharedKeycarModuleUserAuthenticatedAndWalletAddressGeneratedArgs* = ref object of Args
|
||||
uniqueIdentifier*: string
|
||||
address*: string
|
||||
publicKey*: string
|
||||
derivedFrom*: string
|
||||
password*: string
|
||||
|
||||
type FlowType* {.pure.} = enum
|
||||
General = "General"
|
||||
FactoryReset = "FactoryReset"
|
||||
@ -62,13 +72,17 @@ type FlowType* {.pure.} = enum
|
||||
AuthenticateAndDeriveAccountAddress = "AuthenticateAndDeriveAccountAddress"
|
||||
CreateCopyOfAKeycard = "CreateCopyOfAKeycard"
|
||||
|
||||
type
|
||||
SharedKeycarModuleUserAuthenticatedAndWalletAddressGeneratedArgs* = ref object of Args
|
||||
uniqueIdentifier*: string
|
||||
address*: string
|
||||
publicKey*: string
|
||||
derivedFrom*: string
|
||||
password*: string
|
||||
# For the following flows we don't run card syncing.
|
||||
const FlowsWeShouldNotTryAKeycardSyncFor* = @[
|
||||
FlowType.General,
|
||||
FlowType.FactoryReset,
|
||||
FlowType.SetupNewKeycard,
|
||||
FlowType.SetupNewKeycardNewSeedPhrase,
|
||||
FlowType.SetupNewKeycardOldSeedPhrase,
|
||||
FlowType.ImportFromKeycard,
|
||||
FlowType.Authentication,
|
||||
FlowType.AuthenticateAndDeriveAccountAddress
|
||||
]
|
||||
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
@ -79,6 +93,9 @@ method delete*(self: AccessInterface) {.base.} =
|
||||
method getModuleAsVariant*(self: AccessInterface): QVariant {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getCurrentFlowType*(self: AccessInterface): FlowType {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getKeycardData*(self: AccessInterface): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
@ -178,5 +195,11 @@ method keychainObtainedDataFailure*(self: AccessInterface, errorDescription: str
|
||||
method keychainObtainedDataSuccess*(self: AccessInterface, data: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method syncKeycardBasedOnAppState*(self: AccessInterface, keyUid: string, pin: string) {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
method getPin*(self: AccessInterface): string {.base.} =
|
||||
raise newException(ValueError, "No implementation available")
|
||||
|
||||
type
|
||||
DelegateInterface* = concept c
|
||||
|
@ -1,4 +1,4 @@
|
||||
import NimQml, Tables, strformat
|
||||
import NimQml, Tables, strformat, strutils
|
||||
import key_pair_account_item
|
||||
|
||||
export key_pair_account_item
|
||||
@ -72,6 +72,12 @@ QtObject:
|
||||
self.endInsertRows()
|
||||
self.countChanged()
|
||||
|
||||
proc containsAccountAddress*(self: KeyPairAccountModel, address: string): bool =
|
||||
for it in self.items:
|
||||
if cmpIgnoreCase(it.getAddress(), address) == 0:
|
||||
return true
|
||||
return false
|
||||
|
||||
proc getItemAtIndex*(self: KeyPairAccountModel, index: int): KeyPairAccountItem =
|
||||
if index < 0 or index >= self.items.len:
|
||||
return newKeyPairAccountItem()
|
||||
@ -85,4 +91,21 @@ QtObject:
|
||||
self.beginRemoveRows(parentModelIndex, index, index)
|
||||
self.items.delete(index)
|
||||
self.endRemoveRows()
|
||||
self.countChanged()
|
||||
self.countChanged()
|
||||
|
||||
proc removeItemByAddress*(self: KeyPairAccountModel, address: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if cmpIgnoreCase(self.items[i].getAddress(), address) == 0:
|
||||
self.removeItemAtIndex(i)
|
||||
return
|
||||
|
||||
proc updateDetailsForAddressIfTheyAreSet*(self: KeyPairAccountModel, address, name, color, emoji: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if cmpIgnoreCase(self.items[i].getAddress(), address) == 0:
|
||||
if name.len > 0:
|
||||
self.items[i].setName(name)
|
||||
if color.len > 0:
|
||||
self.items[i].setColor(color)
|
||||
if emoji.len > 0:
|
||||
self.items[i].setEmoji(emoji)
|
||||
return
|
@ -181,12 +181,19 @@ QtObject:
|
||||
proc removeAccountAtIndex*(self: KeyPairItem, index: int) {.slot.} =
|
||||
self.accounts.removeItemAtIndex(index)
|
||||
self.setLastAccountAsObservedAccount()
|
||||
proc removeAccountByAddress*(self: KeyPairItem, address: string) {.slot.} =
|
||||
self.accounts.removeItemByAddress(address)
|
||||
self.setLastAccountAsObservedAccount()
|
||||
proc addAccount*(self: KeyPairItem, item: KeyPairAccountItem) =
|
||||
self.accounts.addItem(item)
|
||||
self.setLastAccountAsObservedAccount()
|
||||
proc setAccounts*(self: KeyPairItem, items: seq[KeyPairAccountItem]) =
|
||||
self.accounts.setItems(items)
|
||||
self.setLastAccountAsObservedAccount()
|
||||
proc containsAccountAddress*(self: KeyPairItem, address: string): bool =
|
||||
return self.accounts.containsAccountAddress(address)
|
||||
proc updateDetailsForAccountWithAddressIfTheyAreSet*(self: KeyPairItem, address, name, color, emoji: string) =
|
||||
self.accounts.updateDetailsForAddressIfTheyAreSet(address, name, color, emoji)
|
||||
|
||||
proc setItem*(self: KeyPairItem, item: KeyPairItem) =
|
||||
self.setKeyUid(item.getKeyUid())
|
||||
|
@ -53,6 +53,16 @@ QtObject:
|
||||
self.countChanged()
|
||||
self.lockedItemsCountChanged()
|
||||
|
||||
proc removeItem*(self: KeycardModel, index: int) =
|
||||
if (index < 0 or index >= self.items.len):
|
||||
return
|
||||
let parentModelIndex = newQModelIndex()
|
||||
defer: parentModelIndex.delete
|
||||
self.beginRemoveRows(parentModelIndex, index, index)
|
||||
self.items.delete(index)
|
||||
self.endRemoveRows()
|
||||
self.countChanged()
|
||||
|
||||
proc `$`*(self: KeycardModel): string =
|
||||
for i in 0 ..< self.items.len:
|
||||
result &= fmt"""KeycardModel:
|
||||
@ -84,6 +94,12 @@ QtObject:
|
||||
return self.items[i]
|
||||
return nil
|
||||
|
||||
proc getItemForKeycardUid*(self: KeycardModel, keycardUid: string): KeycardItem =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeycardUid() == keycardUid):
|
||||
return self.items[i]
|
||||
return nil
|
||||
|
||||
proc findIndexForMember(self: KeycardModel, pubKey: string): int =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getPubKey() == pubKey):
|
||||
@ -96,12 +112,19 @@ QtObject:
|
||||
return
|
||||
self.items[ind].setImage(image)
|
||||
|
||||
proc setLocked*(self: KeycardModel, keycardUid: string, locked: bool) =
|
||||
proc setLockedForKeycardWithKeycardUid*(self: KeycardModel, keycardUid: string, locked: bool) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeycardUid() == keycardUid):
|
||||
self.items[i].setLocked(locked)
|
||||
self.lockedItemsCountChanged()
|
||||
|
||||
proc setName*(self: KeycardModel, keycardUid: string, name: string) =
|
||||
proc setLockedForKeycardsWithKeyUid*(self: KeycardModel, keyUid: string, locked: bool) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeyUid() == keyUid):
|
||||
self.items[i].setLocked(locked)
|
||||
self.lockedItemsCountChanged()
|
||||
|
||||
proc setNameForKeycardWithKeycardUid*(self: KeycardModel, keycardUid: string, name: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeycardUid() == keycardUid):
|
||||
self.items[i].setName(name)
|
||||
@ -109,4 +132,28 @@ QtObject:
|
||||
proc setKeycardUid*(self: KeycardModel, keycardUid: string, keycardNewUid: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeycardUid() == keycardUid):
|
||||
self.items[i].setKeycardUid(keycardNewUid)
|
||||
self.items[i].setKeycardUid(keycardNewUid)
|
||||
|
||||
proc removeAccountsFromKeycardWithKeycardUid*(self: KeycardModel, keycardUid: string, accountsToRemove: seq[string],
|
||||
removeKeycardItemIfHasNoAccounts: bool) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeycardUid() == keycardUid):
|
||||
for acc in accountsToRemove:
|
||||
self.items[i].removeAccountByAddress(acc)
|
||||
if removeKeycardItemIfHasNoAccounts and self.items[i].getAccountsModel().getCount() == 0:
|
||||
self.removeItem(i)
|
||||
|
||||
proc removeAccountsFromKeycardsWithKeyUid*(self: KeycardModel, keyUid: string, accountsToRemove: seq[string],
|
||||
removeKeycardItemIfHasNoAccounts: bool) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeyUid() == keyUid):
|
||||
for acc in accountsToRemove:
|
||||
self.items[i].removeAccountByAddress(acc)
|
||||
if removeKeycardItemIfHasNoAccounts and self.items[i].getAccountsModel().getCount() == 0:
|
||||
self.removeItem(i)
|
||||
|
||||
proc updateDetailsForAddressForKeyPairsWithKeyUid*(self: KeycardModel, keyUid: string, accAddress: string, accName: string,
|
||||
accColor: string, accEmoji: string) =
|
||||
for i in 0 ..< self.items.len:
|
||||
if(self.items[i].getKeyUid() == keyUid):
|
||||
self.items[i].updateDetailsForAccountWithAddressIfTheyAreSet(accAddress, accName, accColor, accEmoji)
|
@ -1,4 +1,4 @@
|
||||
import NimQml, random, strutils, marshal, chronicles
|
||||
import NimQml, random, strutils, marshal, sequtils, sugar, chronicles
|
||||
|
||||
import io_interface
|
||||
import view, controller
|
||||
@ -7,6 +7,8 @@ import models/[key_pair_model, key_pair_item]
|
||||
import ../../../global/global_singleton
|
||||
import ../../../core/eventemitter
|
||||
|
||||
import ../../../../app_service/common/utils
|
||||
import ../../../../app_service/service/keycard/constants
|
||||
import ../../../../app_service/service/keycard/service as keycard_service
|
||||
import ../../../../app_service/service/settings/service as settings_service
|
||||
import ../../../../app_service/service/privacy/service as privacy_service
|
||||
@ -62,9 +64,17 @@ method delete*[T](self: Module[T]) =
|
||||
self.viewVariant.delete
|
||||
self.controller.delete
|
||||
|
||||
proc init[T](self: Module[T]) =
|
||||
if not self.initialized:
|
||||
self.initialized = true
|
||||
self.controller.init()
|
||||
|
||||
method getModuleAsVariant*[T](self: Module[T]): QVariant =
|
||||
return self.viewVariant
|
||||
|
||||
method getPin*[T](self: Module[T]): string =
|
||||
return self.controller.getPin()
|
||||
|
||||
method getKeycardData*[T](self: Module[T]): string =
|
||||
return self.view.getKeycardData()
|
||||
|
||||
@ -125,15 +135,19 @@ method checkRepeatedKeycardPukWhileTyping*[T](self: Module[T], puk: string): boo
|
||||
self.controller.setPukMatch(match)
|
||||
return match
|
||||
|
||||
method getMnemonic*[T](self: Module[T]): string =
|
||||
method getCurrentFlowType*[T](self: Module[T]): FlowType =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "sm_cannot resolve current state in order to determine mnemonic"
|
||||
return
|
||||
if currStateObj.flowType() == FlowType.SetupNewKeycard:
|
||||
return FlowType.General
|
||||
return currStateObj.flowType()
|
||||
|
||||
method getMnemonic*[T](self: Module[T]): string =
|
||||
let flowType = self.getCurrentFlowType()
|
||||
if flowType == FlowType.SetupNewKeycard:
|
||||
return self.controller.getProfileMnemonic()
|
||||
if currStateObj.flowType() == FlowType.SetupNewKeycardNewSeedPhrase or
|
||||
currStateObj.flowType() == FlowType.SetupNewKeycardOldSeedPhrase:
|
||||
if flowType == FlowType.SetupNewKeycardNewSeedPhrase or
|
||||
flowType == FlowType.SetupNewKeycardOldSeedPhrase:
|
||||
return self.controller.getSeedPhrase()
|
||||
|
||||
method setSeedPhrase*[T](self: Module[T], value: string) =
|
||||
@ -151,6 +165,30 @@ method migratingProfileKeyPair*[T](self: Module[T]): bool =
|
||||
method getSigningPhrase*[T](self: Module[T]): string =
|
||||
return self.controller.getSigningPhrase()
|
||||
|
||||
proc preActionActivities[T](self: Module[T], currFlowType: FlowType, currStateType: StateType) =
|
||||
if currStateType == StateType.ManageKeycardAccounts or
|
||||
currStateType == StateType.CreatePin or
|
||||
currStateType == StateType.RepeatPin or
|
||||
currStateType == StateType.CreatePuk or
|
||||
currStateType == StateType.RepeatPuk or
|
||||
currStateType == StateType.EnterPuk or
|
||||
currStateType == StateType.WrongPuk:
|
||||
self.view.setDisablePopup(false)
|
||||
return
|
||||
if currStateType == StateType.EnterPin or
|
||||
currStateType == StateType.CreatePin or
|
||||
currStateType == StateType.RepeatPin or
|
||||
currStateType == StateType.WrongPin:
|
||||
let disable = self.controller.getPin().len == PINLengthForStatusApp
|
||||
self.view.setDisablePopup(disable)
|
||||
return
|
||||
if currStateType == StateType.CreatePuk or
|
||||
currStateType == StateType.RepeatPuk:
|
||||
let disable = self.controller.getPUK().len == PUKLengthForStatusApp
|
||||
self.view.setDisablePopup(disable)
|
||||
return
|
||||
self.view.setDisablePopup(true)
|
||||
|
||||
proc preStateActivities[T](self: Module[T], currFlowType: FlowType, nextStateType: StateType) =
|
||||
if nextStateType == StateType.MaxPinRetriesReached or
|
||||
nextStateType == StateType.MaxPukRetriesReached or
|
||||
@ -158,7 +196,7 @@ proc preStateActivities[T](self: Module[T], currFlowType: FlowType, nextStateTyp
|
||||
nextStateType == StateType.UnlockKeycardOptions:
|
||||
## in case the card is locked on another device, we're updating its state in the DB
|
||||
let (_, flowEvent) = self.controller.getLastReceivedKeycardData()
|
||||
self.controller.setCurrentKeycardStateToLocked(flowEvent.instanceUID)
|
||||
self.controller.setCurrentKeycardStateToLocked(flowEvent.keyUid, flowEvent.instanceUID)
|
||||
|
||||
if currFlowType == FlowType.Authentication:
|
||||
self.view.setLockedPropForKeyPairForProcessing(nextStateType == StateType.MaxPinRetriesReached)
|
||||
@ -185,12 +223,89 @@ proc reEvaluateKeyPairForProcessing[T](self: Module[T], currFlowType: FlowType,
|
||||
keycardUid = flowEvent.instanceUID
|
||||
self.prepareKeyPairForProcessing(self.getKeyPairForProcessing().getKeyUid(), keycardUid)
|
||||
|
||||
proc handleKeycardSyncing[T](self: Module[T]) =
|
||||
if not self.controller.keycardSyncingInProgress():
|
||||
return
|
||||
let kcsFlowType = self.controller.getCurrentKeycardServiceFlow()
|
||||
if kcsFlowType == KCSFlowType.GetMetadata:
|
||||
let (eventType, flowEvent) = self.controller.getLastReceivedKeycardData()
|
||||
if flowEvent.keyUid != self.controller.getKeyUidWhichIsBeingSyncing():
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
return
|
||||
if eventType == ResponseTypeValueKeycardFlowResult and flowEvent.error.len == 0:
|
||||
var kpDto = KeyPairDto(keycardUid: flowEvent.instanceUID,
|
||||
keycardName: flowEvent.cardMetadata.name,
|
||||
keycardLocked: false,
|
||||
accountsAddresses: @[],
|
||||
keyUid: flowEvent.keyUid)
|
||||
let alreadySetKeycards = self.controller.getAllKnownKeycards().filter(kp => kp.keycardUid == flowEvent.instanceUID)
|
||||
if alreadySetKeycards.len == 1:
|
||||
var accountsToRemove = alreadySetKeycards[0].accountsAddresses
|
||||
let appAccounts = self.controller.getWalletAccounts()
|
||||
var activeValidPathsToStoreToAKeycard: seq[string]
|
||||
for appAcc in appAccounts:
|
||||
if appAcc.keyUid != flowEvent.keyUid:
|
||||
continue
|
||||
activeValidPathsToStoreToAKeycard.add(appAcc.path)
|
||||
var index = -1
|
||||
var found = false
|
||||
for acc in accountsToRemove:
|
||||
index.inc
|
||||
if cmpIgnoreCase(acc, appAcc.address) == 0:
|
||||
found = true
|
||||
break
|
||||
if found and index > -1:
|
||||
# if account address which is present in the wallet is still present in accounts addresses of a keycard,
|
||||
# then it needs to be present in `keypairs` table in db, so remove it from the list
|
||||
accountsToRemove.delete(index)
|
||||
else:
|
||||
# we store to db only accounts we haven't stored before, accounts which are already on a keycard (in metadata)
|
||||
# we assume they are already in the db
|
||||
kpDto.accountsAddresses.add(appAcc.address)
|
||||
if accountsToRemove.len > 0:
|
||||
self.controller.removeMigratedAccountsForKeycard(kpDto.keyUid, kpDto.keycardUid, accountsToRemove)
|
||||
if kpDto.accountsAddresses.len > 0:
|
||||
self.controller.addMigratedKeyPair(kpDto)
|
||||
# if all accounts are removed from the app, there is no point in storing empty accounts list to a keycard, cause in that case
|
||||
# keypair which is on that keycard won't be known to the app, that means keypair was removed from the app
|
||||
if activeValidPathsToStoreToAKeycard.len > 0:
|
||||
## we need to store paths to a keycard if the num of paths in the app and on a keycard is diffrent
|
||||
## or if the paths are different
|
||||
var storeToKeycard = activeValidPathsToStoreToAKeycard.len != flowEvent.cardMetadata.walletAccounts.len
|
||||
if not storeToKeycard:
|
||||
for wa in flowEvent.cardMetadata.walletAccounts:
|
||||
if not utils.arrayContains(activeValidPathsToStoreToAKeycard, wa.path):
|
||||
storeToKeycard = true
|
||||
break
|
||||
if storeToKeycard:
|
||||
self.controller.runStoreMetadataFlow(flowEvent.cardMetadata.name, self.controller.getPin(), activeValidPathsToStoreToAKeycard)
|
||||
return
|
||||
elif alreadySetKeycards.len > 1:
|
||||
error "it's impossible to have more then one keycard with the same uid", keycarUid=flowEvent.instanceUID
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = true)
|
||||
|
||||
method syncKeycardBasedOnAppState*[T](self: Module[T], keyUid: string, pin: string) =
|
||||
## This method must not be called directly. If you want to initiate keycard syncing please emit
|
||||
## `SIGNAL_SHARED_KEYCARD_MODULE_TRY_KEYCARD_SYNC` signal
|
||||
if pin.len != PINLengthForStatusApp:
|
||||
debug "cannot sync with the pin which doesn't meet app expectations"
|
||||
return
|
||||
if keyUid.len == 0:
|
||||
debug "cannot sync with the empty keyUid"
|
||||
return
|
||||
self.init()
|
||||
self.controller.setKeyUidWhichIsBeingSyncing(keyUid)
|
||||
self.controller.setPin(pin)
|
||||
self.controller.setKeycardSyncingInProgress(true)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true, exportMasterAddr = true, pin)
|
||||
|
||||
method onBackActionClicked*[T](self: Module[T]) =
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if currStateObj.isNil:
|
||||
error "sm_cannot resolve current state"
|
||||
return
|
||||
debug "sm_back_action", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
||||
self.preActionActivities(currStateObj.flowType(), currStateObj.stateType())
|
||||
currStateObj.executePreBackStateCommand(self.controller)
|
||||
let backState = currStateObj.getBackState()
|
||||
self.preStateActivities(backState.flowType(), backState.stateType())
|
||||
@ -205,6 +320,7 @@ method onCancelActionClicked*[T](self: Module[T]) =
|
||||
error "sm_cannot resolve current state"
|
||||
return
|
||||
debug "sm_cancel_action", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
||||
self.preActionActivities(currStateObj.flowType(), currStateObj.stateType())
|
||||
currStateObj.executeCancelCommand(self.controller)
|
||||
|
||||
method onPrimaryActionClicked*[T](self: Module[T]) =
|
||||
@ -213,6 +329,7 @@ method onPrimaryActionClicked*[T](self: Module[T]) =
|
||||
error "sm_cannot resolve current state"
|
||||
return
|
||||
debug "sm_primary_action", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
||||
self.preActionActivities(currStateObj.flowType(), currStateObj.stateType())
|
||||
currStateObj.executePrePrimaryStateCommand(self.controller)
|
||||
let nextState = currStateObj.getNextPrimaryState(self.controller)
|
||||
if nextState.isNil:
|
||||
@ -229,6 +346,7 @@ method onSecondaryActionClicked*[T](self: Module[T]) =
|
||||
error "sm_cannot resolve current state"
|
||||
return
|
||||
debug "sm_secondary_action", currFlow=currStateObj.flowType(), currState=currStateObj.stateType()
|
||||
self.preActionActivities(currStateObj.flowType(), currStateObj.stateType())
|
||||
currStateObj.executePreSecondaryStateCommand(self.controller)
|
||||
let nextState = currStateObj.getNextSecondaryState(self.controller)
|
||||
if nextState.isNil:
|
||||
@ -240,6 +358,9 @@ method onSecondaryActionClicked*[T](self: Module[T]) =
|
||||
debug "sm_secondary_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()
|
||||
return
|
||||
if self.derivingAccountDetails.deriveAddressAfterAuthentication and
|
||||
self.derivingAccountDetails.addressRequested:
|
||||
# clearing...
|
||||
@ -390,9 +511,7 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path
|
||||
self.controller.terminateCurrentFlow(lastStepInTheCurrentFlow = false)
|
||||
error "sm_cannot run an general flow"
|
||||
return
|
||||
if not self.initialized:
|
||||
self.initialized = true
|
||||
self.controller.init()
|
||||
self.init()
|
||||
if flowToRun == FlowType.FactoryReset:
|
||||
self.tmpLocalState = newReadingKeycardState(flowToRun, nil)
|
||||
self.controller.runGetMetadataFlow(resolveAddress = true)
|
||||
@ -449,6 +568,7 @@ method runFlow*[T](self: Module[T], flowToRun: FlowType, keyUid = "", bip44Path
|
||||
self.controller.runChangePairingFlow()
|
||||
return
|
||||
if flowToRun == FlowType.AuthenticateAndDeriveAccountAddress:
|
||||
self.prepareKeyPairForProcessing(keyUid) ## needed for keycard sync
|
||||
self.derivingAccountDetails = DerivingAccountDetails(
|
||||
keyUid: keyUid,
|
||||
path: bip44Path,
|
||||
@ -517,6 +637,10 @@ proc buildKeyPairItemBasedOnCardMetadata[T](self: Module[T], cardMetadata: CardM
|
||||
icon = "keycard",
|
||||
pairType = KeyPairType.Unknown,
|
||||
derivedFrom = "")
|
||||
let currKp = self.getKeyPairForProcessing()
|
||||
if not currKp.isNil:
|
||||
result.item.setKeyUid(currKp.getKeyUid())
|
||||
result.item.setPubKey(currKp.getPubKey())
|
||||
result.knownKeyPair = true
|
||||
for wa in cardMetadata.walletAccounts:
|
||||
if self.updateKeyPairItemIfDataAreKnown(wa.address, result.item):
|
||||
@ -539,10 +663,11 @@ method onUserAuthenticated*[T](self: Module[T], password: string, pin: string) =
|
||||
if self.derivingAccountDetails.deriveAddressAfterAuthentication:
|
||||
self.derivingAccountDetails.addressRequested = true
|
||||
self.controller.setPassword(password)
|
||||
self.controller.setPin(pin) # we need to keep it in case new acc is added we need to sync accounts on the Keycard
|
||||
self.controller.runDeriveAccountFlow(self.derivingAccountDetails.path, pin)
|
||||
return
|
||||
let currStateObj = self.view.currentStateObj()
|
||||
if not currStateObj.isNil and currStateObj.flowType() == FlowType.SetupNewKeycard:
|
||||
let flowType = self.getCurrentFlowType()
|
||||
if flowType == FlowType.SetupNewKeycard:
|
||||
self.controller.setPassword(password)
|
||||
self.onSecondaryActionClicked()
|
||||
|
||||
@ -579,5 +704,4 @@ method keychainObtainedDataSuccess*[T](self: Module[T], data: string) =
|
||||
if data.len == PINLengthForStatusApp:
|
||||
self.controller.enterKeycardPin(data)
|
||||
else:
|
||||
self.view.setCurrentState(newBiometricsPinInvalidState(FlowType.Authentication, nil))
|
||||
|
||||
self.view.setCurrentState(newBiometricsPinInvalidState(FlowType.Authentication, nil))
|
@ -7,6 +7,7 @@ QtObject:
|
||||
type
|
||||
View* = ref object of QObject
|
||||
delegate: io_interface.AccessInterface
|
||||
disablePopup: bool # used to disable popup after each action, to block users do multiple clikcs which the action is ongoing
|
||||
currentState: StateWrapper
|
||||
currentStateVariant: QVariant
|
||||
keyPairModel: KeyPairModel
|
||||
@ -43,16 +44,28 @@ QtObject:
|
||||
result.currentState = newStateWrapper()
|
||||
result.currentStateVariant = newQVariant(result.currentState)
|
||||
result.remainingAttempts = -1
|
||||
result.disablePopup = false
|
||||
|
||||
signalConnect(result.currentState, "backActionClicked()", result, "onBackActionClicked()", 2)
|
||||
signalConnect(result.currentState, "cancelActionClicked()", result, "onCancelActionClicked()", 2)
|
||||
signalConnect(result.currentState, "primaryActionClicked()", result, "onPrimaryActionClicked()", 2)
|
||||
signalConnect(result.currentState, "secondaryActionClicked()", result, "onSecondaryActionClicked()", 2)
|
||||
|
||||
proc diablePopupChanged*(self: View) {.signal.}
|
||||
proc getDisablePopup*(self: View): bool {.slot.} =
|
||||
return self.disablePopup
|
||||
QtProperty[bool] disablePopup:
|
||||
read = getDisablePopup
|
||||
notify = diablePopupChanged
|
||||
proc setDisablePopup*(self: View, value: bool) =
|
||||
self.disablePopup = value
|
||||
self.diablePopupChanged()
|
||||
|
||||
proc currentStateObj*(self: View): State =
|
||||
return self.currentState.getStateObj()
|
||||
|
||||
proc setCurrentState*(self: View, state: State) =
|
||||
self.setDisablePopup(false)
|
||||
self.currentState.setStateObj(state)
|
||||
proc getCurrentState(self: View): QVariant {.slot.} =
|
||||
return self.currentStateVariant
|
||||
|
@ -17,8 +17,6 @@ import ../shared_modules/keycard_popup/io_interface as keycard_shared_module
|
||||
logScope:
|
||||
topics = "startup-controller"
|
||||
|
||||
const UNIQUE_STARTUP_MODULE_IDENTIFIER* = "SartupModule"
|
||||
|
||||
type ProfileImageDetails = object
|
||||
url*: string
|
||||
croppedImage*: string
|
||||
|
@ -3,6 +3,7 @@ import ../../../app_service/service/accounts/service as accounts_service
|
||||
import models/login_account_item as login_acc_item
|
||||
from ../../../app_service/service/keycard/service import KeycardEvent, KeyDetails
|
||||
|
||||
const UNIQUE_STARTUP_MODULE_IDENTIFIER* = "SartupModule"
|
||||
|
||||
type
|
||||
AccessInterface* {.pure inheritable.} = ref object of RootObj
|
||||
|
@ -111,17 +111,18 @@ method load*[T](self: Module[T]) =
|
||||
self.setSelectedLoginAccount(items[0])
|
||||
self.delegate.startupDidLoad()
|
||||
|
||||
proc isSharedKeycardModuleFlowRunning[T](self: Module[T]): bool =
|
||||
return not self.keycardSharedModule.isNil
|
||||
|
||||
method getKeycardSharedModule*[T](self: Module[T]): QVariant =
|
||||
return self.keycardSharedModule.getModuleAsVariant()
|
||||
if self.isSharedKeycardModuleFlowRunning():
|
||||
return self.keycardSharedModule.getModuleAsVariant()
|
||||
|
||||
proc createSharedKeycardModule[T](self: Module[T]) =
|
||||
self.keycardSharedModule = keycard_shared_module.newModule[Module[T]](self, UNIQUE_STARTUP_MODULE_IDENTIFIER,
|
||||
self.events, self.keycardService, settingsService = nil, privacyService = nil, self.accountsService,
|
||||
walletAccountService = nil, self.keychainService)
|
||||
|
||||
proc isSharedKeycardModuleFlowRunning[T](self: Module[T]): bool =
|
||||
return not self.keycardSharedModule.isNil
|
||||
|
||||
method moveToLoadingAppState*[T](self: Module[T]) =
|
||||
self.view.setAppState(AppState.AppLoadingState)
|
||||
|
||||
|
@ -82,7 +82,10 @@ QtObject:
|
||||
read = getCurrentStartupState
|
||||
|
||||
proc getKeycardSharedModule(self: View): QVariant {.slot.} =
|
||||
return self.delegate.getKeycardSharedModule()
|
||||
let module = self.delegate.getKeycardSharedModule()
|
||||
if not module.isNil:
|
||||
return module
|
||||
return newQVariant()
|
||||
QtProperty[QVariant] keycardSharedModule:
|
||||
read = getKeycardSharedModule
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
import json, random, times, strutils, os, re, chronicles
|
||||
import json, random, times, strutils, sugar, os, re, chronicles
|
||||
import nimcrypto
|
||||
import signing_phrases
|
||||
|
||||
const STATUS_DOMAIN* = ".stateofus.eth"
|
||||
const ETH_DOMAIN* = ".eth"
|
||||
|
||||
proc arrayContains*[T](arr: seq[T], value: T): bool =
|
||||
return arr.any(x => x == value)
|
||||
|
||||
proc hashPassword*(password: string): string =
|
||||
result = "0x" & $keccak_256.digest(password)
|
||||
|
||||
|
@ -219,12 +219,14 @@ QtObject:
|
||||
self.currentFlow = KCSFlowType.GetAppInfo
|
||||
self.startFlow(payload)
|
||||
|
||||
proc startGetMetadataFlow*(self: Service, resolveAddress: bool, exportMasterAddr = false) =
|
||||
proc startGetMetadataFlow*(self: Service, resolveAddress: bool, exportMasterAddr = false, pin = "") =
|
||||
var payload = %* { }
|
||||
if resolveAddress:
|
||||
payload[RequestParamResolveAddr] = %* resolveAddress
|
||||
if exportMasterAddr:
|
||||
payload[RequestParamExportMasterAddress] = %* exportMasterAddr
|
||||
if pin.len > 0:
|
||||
payload[RequestParamPIN] = %* pin
|
||||
self.currentFlow = KCSFlowType.GetMetadata
|
||||
self.startFlow(payload)
|
||||
|
||||
|
@ -122,7 +122,37 @@ const addMigratedKeyPairTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall
|
||||
arg.keyPair.accountsAddresses,
|
||||
arg.keyStoreDir
|
||||
)
|
||||
arg.finish(response)
|
||||
let success = responseHasNoErrors("addMigratedKeyPair", response)
|
||||
let responseJson = %*{
|
||||
"success": success,
|
||||
"keyPair": arg.keyPair.toJsonNode()
|
||||
}
|
||||
arg.finish(responseJson)
|
||||
except Exception as e:
|
||||
error "error adding new keypair: ", message = e.msg
|
||||
arg.finish("")
|
||||
|
||||
#################################################
|
||||
# Async add migrated keypair
|
||||
#################################################
|
||||
|
||||
type
|
||||
RemoveMigratedAccountsForKeycardTaskArg* = ref object of QObjectTaskArg
|
||||
keyPair: KeyPairDto
|
||||
|
||||
const removeMigratedAccountsForKeycardTask*: Task = proc(argEncoded: string) {.gcsafe, nimcall.} =
|
||||
let arg = decode[RemoveMigratedAccountsForKeycardTaskArg](argEncoded)
|
||||
try:
|
||||
let response = backend.removeMigratedAccountsForKeycard(
|
||||
arg.keyPair.keycardUid,
|
||||
arg.keyPair.accountsAddresses
|
||||
)
|
||||
let success = responseHasNoErrors("removeMigratedAccountsForKeycard", response)
|
||||
let responseJson = %*{
|
||||
"success": success,
|
||||
"keyPair": arg.keyPair.toJsonNode()
|
||||
}
|
||||
arg.finish(responseJson)
|
||||
except Exception as e:
|
||||
error "error remove accounts from keycard: ", message = e.msg
|
||||
arg.finish("")
|
@ -2,6 +2,13 @@ import json
|
||||
|
||||
include ../../common/json_utils
|
||||
|
||||
const KeycardUid = "keycard-uid"
|
||||
const KeycardName = "keycard-name"
|
||||
const KeycardLocked = "keycard-locked"
|
||||
const KeyUid = "key-uid"
|
||||
const AccountAddresses = "accounts-addresses"
|
||||
|
||||
|
||||
type KeyPairDto* = object
|
||||
keycardUid*: string
|
||||
keycardName*: string
|
||||
@ -11,12 +18,21 @@ type KeyPairDto* = object
|
||||
|
||||
proc toKeyPairDto*(jsonObj: JsonNode): KeyPairDto =
|
||||
result = KeyPairDto()
|
||||
discard jsonObj.getProp("keycard-uid", result.keycardUid)
|
||||
discard jsonObj.getProp("keycard-name", result.keycardName)
|
||||
discard jsonObj.getProp("keycard-locked", result.keycardLocked)
|
||||
discard jsonObj.getProp("key-uid", result.keyUid)
|
||||
discard jsonObj.getProp(KeycardUid, result.keycardUid)
|
||||
discard jsonObj.getProp(KeycardName, result.keycardName)
|
||||
discard jsonObj.getProp(KeycardLocked, result.keycardLocked)
|
||||
discard jsonObj.getProp(KeyUid, result.keyUid)
|
||||
|
||||
var jArr: JsonNode
|
||||
if(jsonObj.getProp("accounts-addresses", jArr) and jArr.kind == JArray):
|
||||
if(jsonObj.getProp(AccountAddresses, jArr) and jArr.kind == JArray):
|
||||
for addrObj in jArr:
|
||||
result.accountsAddresses.add(addrObj.getStr)
|
||||
|
||||
proc toJsonNode*(self: KeyPairDto): JsonNode =
|
||||
result = %* {
|
||||
KeycardUid: self.keycardUid,
|
||||
KeycardName: self.keycardName,
|
||||
KeycardLocked: self.keycardLocked,
|
||||
KeyUid: self.keyUid,
|
||||
AccountAddresses: self.accountsAddresses
|
||||
}
|
@ -34,6 +34,7 @@ const SIGNAL_WALLET_ACCOUNT_TOKENS_REBUILT* = "walletAccount/tokensRebuilt"
|
||||
const SIGNAL_WALLET_ACCOUNT_DERIVED_ADDRESS_DETAILS_FETCHED* = "walletAccount/derivedAddressDetailsFetched"
|
||||
|
||||
const SIGNAL_NEW_KEYCARD_SET* = "newKeycardSet"
|
||||
const SIGNAL_KEYCARD_ACCOUNTS_REMOVED* = "keycardAccountsRemoved"
|
||||
const SIGNAL_KEYCARD_LOCKED* = "keycardLocked"
|
||||
const SIGNAL_KEYCARD_UNLOCKED* = "keycardUnlocked"
|
||||
const SIGNAL_KEYCARD_UID_UPDATED* = "keycardUidUpdated"
|
||||
@ -77,8 +78,8 @@ type TokenVisibilityToggled = ref object of Args
|
||||
|
||||
type NetwordkEnabledToggled = ref object of Args
|
||||
|
||||
type WalletAccountUpdated = ref object of Args
|
||||
account: WalletAccountDto
|
||||
type WalletAccountUpdated* = ref object of Args
|
||||
account*: WalletAccountDto
|
||||
|
||||
type DerivedAddressesArgs* = ref object of Args
|
||||
derivedAddresses*: seq[DerivedAddressDto]
|
||||
@ -89,11 +90,20 @@ type TokensPerAccountArgs* = ref object of Args
|
||||
|
||||
type KeycardActivityArgs* = ref object of Args
|
||||
success*: bool
|
||||
keycardUid*: string
|
||||
keycardNewUid*: string
|
||||
keycardNewName*: string
|
||||
oldKeycardUid*: string
|
||||
keyPair*: KeyPairDto
|
||||
|
||||
proc responseHasNoErrors(procName: string, response: RpcResponse[JsonNode]): bool =
|
||||
var errMsg = ""
|
||||
if not response.error.isNil:
|
||||
errMsg = "(" & $response.error.code & ") " & response.error.message
|
||||
elif response.result.kind == JObject and response.result.contains("error"):
|
||||
errMsg = response.result["error"].getStr
|
||||
if(errMsg.len == 0):
|
||||
return true
|
||||
error "error: ", procName=procName, errDesription = errMsg
|
||||
return false
|
||||
|
||||
include async_tasks
|
||||
include ../../common/json_utils
|
||||
|
||||
@ -240,6 +250,17 @@ QtObject:
|
||||
self.buildAllTokens(@[newAccount.address])
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_SAVED, AccountSaved(account: newAccount))
|
||||
|
||||
proc addOrReplaceWalletAccount(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
|
||||
color, emoji: string, walletDefaultAccount = false, chatDefaultAccount = false): string =
|
||||
try:
|
||||
let response = status_go_accounts.saveAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid,
|
||||
accountType, color, emoji, walletDefaultAccount, chatDefaultAccount)
|
||||
if not response.error.isNil:
|
||||
return "(" & $response.error.code & ") " & response.error.message
|
||||
except Exception as e:
|
||||
error "error: ", procName="addWalletAccount", errName = e.name, errDesription = e.msg
|
||||
return "error: " & e.msg
|
||||
|
||||
proc generateNewAccount*(self: Service, password: string, accountName: string, color: string, emoji: string,
|
||||
path: string, derivedFrom: string, skipPasswordVerification: bool): string =
|
||||
try:
|
||||
@ -325,12 +346,17 @@ QtObject:
|
||||
|
||||
self.addNewAccountToLocalStore()
|
||||
|
||||
proc deleteAccount*(self: Service, address: string) =
|
||||
discard status_go_accounts.deleteAccount(address)
|
||||
let accountDeleted = self.walletAccounts[address]
|
||||
self.walletAccounts.del(address)
|
||||
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountDeleted(account: accountDeleted))
|
||||
proc deleteAccount*(self: Service, address: string, keyPairMigrated: bool) =
|
||||
try:
|
||||
if keyPairMigrated:
|
||||
discard status_go_accounts.deleteAccountForMigratedKeypair(address)
|
||||
else:
|
||||
discard status_go_accounts.deleteAccount(address)
|
||||
let accountDeleted = self.walletAccounts[address]
|
||||
self.walletAccounts.del(address)
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_DELETED, AccountDeleted(account: accountDeleted))
|
||||
except Exception as e:
|
||||
error "error: ", procName="deleteAccount", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc getCurrency*(self: Service): string =
|
||||
return self.settingsService.getCurrency()
|
||||
@ -351,20 +377,17 @@ QtObject:
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_NETWORK_ENABLED_UPDATED, NetwordkEnabledToggled())
|
||||
|
||||
proc updateWalletAccount*(self: Service, address: string, accountName: string, color: string, emoji: string) =
|
||||
let account = self.walletAccounts[address]
|
||||
status_go_accounts.updateAccount(
|
||||
accountName,
|
||||
account.address,
|
||||
account.publicKey,
|
||||
account.walletType,
|
||||
color,
|
||||
emoji
|
||||
)
|
||||
account.name = accountName
|
||||
account.color = color
|
||||
account.emoji = emoji
|
||||
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
|
||||
if not self.walletAccounts.hasKey(address):
|
||||
error "account's address is not among known addresses: ", address=address
|
||||
return
|
||||
var account = self.walletAccounts[address]
|
||||
let res = self.addOrReplaceWalletAccount(accountName, account.address, account.path, account.derivedfrom,
|
||||
account.publicKey, account.keyUid, account.walletType, color, emoji, account.isWallet, account.isChat)
|
||||
if res.len == 0:
|
||||
account.name = accountName
|
||||
account.color = color
|
||||
account.emoji = emoji
|
||||
self.events.emit(SIGNAL_WALLET_ACCOUNT_UPDATED, WalletAccountUpdated(account: account))
|
||||
|
||||
proc getDerivedAddressList*(self: Service, password: string, derivedFrom: string, path: string, pageSize: int, pageNumber: int, hashPassword: bool)=
|
||||
let arg = GetDerivedAddressesTaskArg(
|
||||
@ -453,8 +476,9 @@ QtObject:
|
||||
error "error: ", procName="onAllTokensBuilt", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc buildAllTokens(self: Service, accounts: seq[string]) =
|
||||
if(not singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled()):
|
||||
return
|
||||
if not singletonInstance.localAccountSensitiveSettings.getIsWalletEnabled() or
|
||||
accounts.len == 0:
|
||||
return
|
||||
|
||||
let arg = BuildTokensTaskArg(
|
||||
tptr: cast[ByteAddress](prepareTokensTask),
|
||||
@ -492,17 +516,6 @@ QtObject:
|
||||
let chainIds = self.networkService.getNetworks().filter(a => a.enabled).map(a => a.chainId)
|
||||
return self.getWalletAccounts().map(a => a.getCurrencyBalance(chainIds, self.getCurrentCurrencyIfEmpty(currency))).foldl(a + b, 0.0)
|
||||
|
||||
proc responseHasNoErrors(self: Service, procName: string, response: RpcResponse[JsonNode]): bool =
|
||||
var errMsg = ""
|
||||
if not response.error.isNil:
|
||||
errMsg = "(" & $response.error.code & ") " & response.error.message
|
||||
elif response.result.kind == JObject and response.result.contains("error"):
|
||||
errMsg = response.result["error"].getStr
|
||||
if(errMsg.len == 0):
|
||||
return true
|
||||
error "error: ", procName=procName, errDesription = errMsg
|
||||
return false
|
||||
|
||||
proc addMigratedKeyPairAsync*(self: Service, keyPair: KeyPairDto, keyStoreDir: string) =
|
||||
let arg = AddMigratedKeyPairTaskArg(
|
||||
tptr: cast[ByteAddress](addMigratedKeyPairTask),
|
||||
@ -511,18 +524,19 @@ QtObject:
|
||||
keyPair: keyPair,
|
||||
keyStoreDir: keyStoreDir
|
||||
)
|
||||
self.processedKeyPair = keyPair
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc onMigratedKeyPairAdded*(self: Service, response: string) {.slot.} =
|
||||
var result = false
|
||||
var data = KeycardActivityArgs()
|
||||
data.success = false
|
||||
try:
|
||||
let rpcResponse = Json.decode(response, RpcResponse[JsonNode])
|
||||
result = self.responseHasNoErrors("addMigratedKeyPair", rpcResponse)
|
||||
let responseObj = response.parseJson
|
||||
discard responseObj.getProp("success", data.success)
|
||||
var kpJson: JsonNode
|
||||
if responseObj.getProp("keyPair", kpJson):
|
||||
data.keyPair = kpJson.toKeyPairDto()
|
||||
except Exception as e:
|
||||
error "error handilng migrated keypair response", errDesription=e.msg
|
||||
let data = KeycardActivityArgs(success: result, keyPair: self.processedKeyPair)
|
||||
self.processedKeyPair = KeyPairDto()
|
||||
self.events.emit(SIGNAL_NEW_KEYCARD_SET, data)
|
||||
|
||||
proc addMigratedKeyPair*(self: Service, keyPair: KeyPairDto, keyStoreDir: string): bool =
|
||||
@ -534,16 +548,38 @@ QtObject:
|
||||
keyPair.accountsAddresses,
|
||||
keyStoreDir
|
||||
)
|
||||
result = self.responseHasNoErrors("addMigratedKeyPair", response)
|
||||
result = responseHasNoErrors("addMigratedKeyPair", response)
|
||||
if result:
|
||||
self.events.emit(SIGNAL_NEW_KEYCARD_SET, KeycardActivityArgs(success: true, keyPair: keyPair))
|
||||
except Exception as e:
|
||||
error "error: ", procName="addMigratedKeyPair", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc removeMigratedAccountsForKeycard*(self: Service, keyUid: string, keycardUid: string, accountsToRemove: seq[string]) =
|
||||
let arg = RemoveMigratedAccountsForKeycardTaskArg(
|
||||
tptr: cast[ByteAddress](removeMigratedAccountsForKeycardTask),
|
||||
vptr: cast[ByteAddress](self.vptr),
|
||||
slot: "onMigratedAccountsForKeycardRemoved",
|
||||
keyPair: KeyPairDto(keyUid: keyUid, keycardUid: keycardUid, accountsAddresses: accountsToRemove)
|
||||
)
|
||||
self.threadpool.start(arg)
|
||||
|
||||
proc onMigratedAccountsForKeycardRemoved*(self: Service, response: string) {.slot.} =
|
||||
var data = KeycardActivityArgs()
|
||||
data.success = false
|
||||
try:
|
||||
let responseObj = response.parseJson
|
||||
discard responseObj.getProp("success", data.success)
|
||||
var kpJson: JsonNode
|
||||
if responseObj.getProp("keyPair", kpJson):
|
||||
data.keyPair = kpJson.toKeyPairDto()
|
||||
except Exception as e:
|
||||
error "error handilng migrated keypair response", errDesription=e.msg
|
||||
self.events.emit(SIGNAL_KEYCARD_ACCOUNTS_REMOVED, data)
|
||||
|
||||
proc getAllKnownKeycards*(self: Service): seq[KeyPairDto] =
|
||||
try:
|
||||
let response = backend.getAllKnownKeycards()
|
||||
if self.responseHasNoErrors("getAllKnownKeycards", response):
|
||||
if responseHasNoErrors("getAllKnownKeycards", response):
|
||||
return map(response.result.getElems(), proc(x: JsonNode): KeyPairDto = toKeyPairDto(x))
|
||||
except Exception as e:
|
||||
error "error: ", procName="getAllKnownKeycards", errName = e.name, errDesription = e.msg
|
||||
@ -551,7 +587,7 @@ QtObject:
|
||||
proc getAllMigratedKeyPairs*(self: Service): seq[KeyPairDto] =
|
||||
try:
|
||||
let response = backend.getAllMigratedKeyPairs()
|
||||
if self.responseHasNoErrors("getAllMigratedKeyPairs", response):
|
||||
if responseHasNoErrors("getAllMigratedKeyPairs", response):
|
||||
return map(response.result.getElems(), proc(x: JsonNode): KeyPairDto = toKeyPairDto(x))
|
||||
except Exception as e:
|
||||
error "error: ", procName="getAllMigratedKeyPairs", errName = e.name, errDesription = e.msg
|
||||
@ -559,63 +595,62 @@ QtObject:
|
||||
proc getMigratedKeyPairByKeyUid*(self: Service, keyUid: string): seq[KeyPairDto] =
|
||||
try:
|
||||
let response = backend.getMigratedKeyPairByKeyUID(keyUid)
|
||||
if self.responseHasNoErrors("getMigratedKeyPairByKeyUid", response):
|
||||
if responseHasNoErrors("getMigratedKeyPairByKeyUid", response):
|
||||
return map(response.result.getElems(), proc(x: JsonNode): KeyPairDto = toKeyPairDto(x))
|
||||
except Exception as e:
|
||||
error "error: ", procName="getMigratedKeyPairByKeyUid", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc updateKeycardName*(self: Service, keycardUid: string, name: string): bool =
|
||||
proc updateKeycardName*(self: Service, keyUid: string, keycardUid: string, name: string): bool =
|
||||
try:
|
||||
let response = backend.setKeycardName(keycardUid, name)
|
||||
result = self.responseHasNoErrors("updateKeycardName", response)
|
||||
result = responseHasNoErrors("updateKeycardName", response)
|
||||
if result:
|
||||
self.events.emit(SIGNAL_KEYCARD_NAME_CHANGED, KeycardActivityArgs(keycardUid: keycardUid, keycardNewName: name))
|
||||
let data = KeycardActivityArgs(success: true, keyPair: KeyPairDto(keyUid: keyUid, keycardUid: keycardUid, keycardName: name))
|
||||
self.events.emit(SIGNAL_KEYCARD_NAME_CHANGED, data)
|
||||
except Exception as e:
|
||||
error "error: ", procName="updateKeycardName", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc setKeycardLocked*(self: Service, keycardUid: string): bool =
|
||||
proc setKeycardLocked*(self: Service, keyUid: string, keycardUid: string): bool =
|
||||
try:
|
||||
let response = backend.keycardLocked(keycardUid)
|
||||
result = self.responseHasNoErrors("setKeycardLocked", response)
|
||||
result = responseHasNoErrors("setKeycardLocked", response)
|
||||
if result:
|
||||
self.events.emit(SIGNAL_KEYCARD_LOCKED, KeycardActivityArgs(keycardUid: keycardUid))
|
||||
let data = KeycardActivityArgs(success: true, keyPair: KeyPairDto(keyUid: keyUid, keycardUid: keycardUid))
|
||||
self.events.emit(SIGNAL_KEYCARD_LOCKED, data)
|
||||
except Exception as e:
|
||||
error "error: ", procName="setKeycardLocked", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc setKeycardUnlocked*(self: Service, keycardUid: string): bool =
|
||||
proc setKeycardUnlocked*(self: Service, keyUid: string, keycardUid: string): bool =
|
||||
try:
|
||||
let response = backend.keycardUnlocked(keycardUid)
|
||||
result = self.responseHasNoErrors("setKeycardUnlocked", response)
|
||||
result = responseHasNoErrors("setKeycardUnlocked", response)
|
||||
if result:
|
||||
self.events.emit(SIGNAL_KEYCARD_UNLOCKED, KeycardActivityArgs(keycardUid: keycardUid))
|
||||
let data = KeycardActivityArgs(success: true, keyPair: KeyPairDto(keyUid: keyUid, keycardUid: keycardUid))
|
||||
self.events.emit(SIGNAL_KEYCARD_UNLOCKED, data)
|
||||
except Exception as e:
|
||||
error "error: ", procName="setKeycardUnlocked", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc updateKeycardUid*(self: Service, oldKeycardUid: string, newKeycardUid: string): bool =
|
||||
try:
|
||||
let response = backend.updateKeycardUID(oldKeycardUid, newKeycardUid)
|
||||
result = self.responseHasNoErrors("updateKeycardUid", response)
|
||||
result = responseHasNoErrors("updateKeycardUid", response)
|
||||
if result:
|
||||
self.events.emit(SIGNAL_KEYCARD_UID_UPDATED, KeycardActivityArgs(keycardUid: oldKeycardUid, keycardNewUid: newKeycardUid))
|
||||
let data = KeycardActivityArgs(success: true, oldKeycardUid: oldKeycardUid, keyPair: KeyPairDto(keycardUid: newKeycardUid))
|
||||
self.events.emit(SIGNAL_KEYCARD_UID_UPDATED, data)
|
||||
except Exception as e:
|
||||
error "error: ", procName="updateKeycardUid", errName = e.name, errDesription = e.msg
|
||||
|
||||
proc deleteKeycard*(self: Service, keycardUid: string): bool =
|
||||
try:
|
||||
let response = backend.deleteKeycard(keycardUid)
|
||||
return self.responseHasNoErrors("deleteKeycard", response)
|
||||
return responseHasNoErrors("deleteKeycard", response)
|
||||
except Exception as e:
|
||||
error "error: ", procName="deleteKeycard", errName = e.name, errDesription = e.msg
|
||||
return false
|
||||
|
||||
proc addWalletAccount*(self: Service, name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType,
|
||||
color, emoji: string): string =
|
||||
try:
|
||||
let response = status_go_accounts.saveAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid,
|
||||
accountType, color, emoji, walletDefaultAccount = false, chatDefaultAccount = false)
|
||||
if not response.error.isNil:
|
||||
return "(" & $response.error.code & ") " & response.error.message
|
||||
self.addNewAccountToLocalStore()
|
||||
except Exception as e:
|
||||
error "error: ", procName="addWalletAccount", errName = e.name, errDesription = e.msg
|
||||
return "error: " & e.msg
|
||||
result = self.addOrReplaceWalletAccount(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid,
|
||||
accountType, color, emoji)
|
||||
if result.len == 0:
|
||||
self.addNewAccountToLocalStore()
|
@ -24,6 +24,9 @@ proc getAccounts*(): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
proc deleteAccount*(address: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
return core.callPrivateRPC("accounts_deleteAccount", %* [address])
|
||||
|
||||
proc deleteAccountForMigratedKeypair*(address: string): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
return core.callPrivateRPC("accounts_deleteAccountForMigratedKeypair", %* [address])
|
||||
|
||||
proc saveAccount*(name, address, path, addressAccountIsDerivedFrom, publicKey, keyUid, accountType, color, emoji: string,
|
||||
walletDefaultAccount: bool, chatDefaultAccount: bool):
|
||||
RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
@ -44,19 +47,6 @@ proc saveAccount*(name, address, path, addressAccountIsDerivedFrom, publicKey, k
|
||||
]
|
||||
return core.callPrivateRPC("accounts_saveAccounts", payload)
|
||||
|
||||
proc updateAccount*(name, address, publicKey, walletType, color, emoji: string) {.raises: [Exception].} =
|
||||
discard core.callPrivateRPC("accounts_saveAccounts", %* [
|
||||
[{
|
||||
"emoji": emoji,
|
||||
"color": color,
|
||||
"name": name,
|
||||
"address": address,
|
||||
"public-key": publicKey,
|
||||
"type": walletType,
|
||||
"path": "m/44'/60'/0'/0/1" # <--- TODO: fix this. Derivation path is not supposed to change
|
||||
}]
|
||||
])
|
||||
|
||||
proc generateAddresses*(paths: seq[string]): RpcResponse[JsonNode] {.raises: [Exception].} =
|
||||
let payload = %* {
|
||||
"n": NUMBER_OF_ADDRESSES_TO_GENERATE,
|
||||
|
@ -231,6 +231,10 @@ rpc(addMigratedKeyPair, "accounts"):
|
||||
accountAddresses: seq[string]
|
||||
keyStoreDir: string
|
||||
|
||||
rpc(removeMigratedAccountsForKeycard, "accounts"):
|
||||
keycardUid: string
|
||||
accountsToRemove: seq[string]
|
||||
|
||||
rpc(getAllKnownKeycards, "accounts"):
|
||||
discard
|
||||
|
||||
|
@ -30,8 +30,8 @@ QtObject {
|
||||
walletSection.switchAccountByAddress(address)
|
||||
}
|
||||
|
||||
function deleteAccount(address) {
|
||||
return walletSectionAccounts.deleteAccount(address)
|
||||
function deleteAccount(keyUid, address) {
|
||||
return walletSectionAccounts.deleteAccount(keyUid, address)
|
||||
}
|
||||
|
||||
function updateCurrentAccount(address, accountName, color, emoji) {
|
||||
|
@ -157,7 +157,7 @@ Item {
|
||||
onConfirmButtonClicked: {
|
||||
confirmationPopup.close();
|
||||
root.goBack();
|
||||
root.walletStore.deleteAccount(walletStore.currentAccount.address);
|
||||
root.walletStore.deleteAccount(walletStore.currentAccount.keyUid, walletStore.currentAccount.address);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ ColumnLayout {
|
||||
}
|
||||
property bool pathError: Utils.isInvalidPath(RootStore.derivedAddressesError)
|
||||
property bool derivationAddressLoading: RootStore.derivedAddressesLoading
|
||||
property string defaultDerivationPath: "m/44'/60'/0'/0"
|
||||
property string defaultDerivationPath: "m/44'/60'/0'/0/0"
|
||||
}
|
||||
|
||||
spacing: 7
|
||||
|
@ -11,7 +11,15 @@ QtObject {
|
||||
property var sharedKeycardModule
|
||||
|
||||
property bool primaryButtonEnabled: false
|
||||
readonly property bool disablePopupClose: {
|
||||
|
||||
// disables action buttons (back, cancel, primary, secondary) and close button (upper right "X" button) as well
|
||||
readonly property bool disableActionPopupButtons: root.sharedKeycardModule.disablePopup
|
||||
|
||||
readonly property bool disablePopupClose: { // disables popup close button (upper right "X" button)
|
||||
if (root.disableActionPopupButtons) {
|
||||
return true
|
||||
}
|
||||
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
@ -38,6 +46,7 @@ QtObject {
|
||||
StatusBackButton {
|
||||
id: backButton
|
||||
visible: root.sharedKeycardModule.currentState.displayBackButton
|
||||
enabled: !root.disableActionPopupButtons
|
||||
height: Constants.keycard.general.footerButtonsHeight
|
||||
width: height
|
||||
onClicked: {
|
||||
@ -347,26 +356,7 @@ QtObject {
|
||||
|
||||
return false
|
||||
}
|
||||
enabled: {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.migratingKeyPair:
|
||||
case Constants.keycardSharedState.creatingAccountNewSeedPhrase:
|
||||
case Constants.keycardSharedState.creatingAccountOldSeedPhrase:
|
||||
case Constants.keycardSharedState.importingFromKeycard:
|
||||
case Constants.keycardSharedState.renamingKeycard:
|
||||
case Constants.keycardSharedState.changingKeycardPin:
|
||||
case Constants.keycardSharedState.changingKeycardPuk:
|
||||
case Constants.keycardSharedState.changingKeycardPairingCode:
|
||||
case Constants.keycardSharedState.copyingKeycard:
|
||||
if (root.disablePopupClose) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
enabled: !root.disableActionPopupButtons
|
||||
|
||||
onClicked: {
|
||||
root.sharedKeycardModule.currentState.doCancelAction()
|
||||
@ -462,21 +452,8 @@ QtObject {
|
||||
|
||||
visible: text !== ""
|
||||
enabled: {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.migratingKeyPair:
|
||||
case Constants.keycardSharedState.creatingAccountNewSeedPhrase:
|
||||
case Constants.keycardSharedState.creatingAccountOldSeedPhrase:
|
||||
case Constants.keycardSharedState.importingFromKeycard:
|
||||
case Constants.keycardSharedState.renamingKeycard:
|
||||
case Constants.keycardSharedState.changingKeycardPin:
|
||||
case Constants.keycardSharedState.changingKeycardPuk:
|
||||
case Constants.keycardSharedState.changingKeycardPairingCode:
|
||||
case Constants.keycardSharedState.copyingKeycard:
|
||||
if (root.disablePopupClose) {
|
||||
return false
|
||||
}
|
||||
if (root.disableActionPopupButtons) {
|
||||
return false
|
||||
}
|
||||
|
||||
switch (root.sharedKeycardModule.currentState.flowType) {
|
||||
@ -784,6 +761,7 @@ QtObject {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.keycardEmpty:
|
||||
case Constants.keycardSharedState.keycardEmptyMetadata:
|
||||
case Constants.keycardSharedState.keycardAlreadyUnlocked:
|
||||
case Constants.keycardSharedState.wrongKeycard:
|
||||
case Constants.keycardSharedState.unlockKeycardSuccess:
|
||||
@ -1000,21 +978,8 @@ QtObject {
|
||||
}
|
||||
visible: text !== ""
|
||||
enabled: {
|
||||
switch (root.sharedKeycardModule.currentState.stateType) {
|
||||
|
||||
case Constants.keycardSharedState.readingKeycard:
|
||||
case Constants.keycardSharedState.migratingKeyPair:
|
||||
case Constants.keycardSharedState.creatingAccountNewSeedPhrase:
|
||||
case Constants.keycardSharedState.creatingAccountOldSeedPhrase:
|
||||
case Constants.keycardSharedState.importingFromKeycard:
|
||||
case Constants.keycardSharedState.renamingKeycard:
|
||||
case Constants.keycardSharedState.changingKeycardPin:
|
||||
case Constants.keycardSharedState.changingKeycardPuk:
|
||||
case Constants.keycardSharedState.changingKeycardPairingCode:
|
||||
case Constants.keycardSharedState.copyingKeycard:
|
||||
if (root.disablePopupClose) {
|
||||
return false
|
||||
}
|
||||
if (root.disableActionPopupButtons) {
|
||||
return false
|
||||
}
|
||||
|
||||
switch (root.sharedKeycardModule.currentState.flowType) {
|
||||
|
@ -280,7 +280,7 @@ Item {
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
event.accepted = true
|
||||
if (d.allEntriesValid) {
|
||||
d.sharedKeycardModule.currentState.doPrimaryAction()
|
||||
root.sharedKeycardModule.currentState.doPrimaryAction()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
2
vendor/status-go
vendored
2
vendor/status-go
vendored
@ -1 +1 @@
|
||||
Subproject commit d95b2597773cc3678cb1594d960df8c4203b811f
|
||||
Subproject commit ccbd2866fe8ee3223cf1d39d1cb3bedb2222149b
|
Loading…
x
Reference in New Issue
Block a user