From e1d1880acac172838e712f3636e5c7ec49bdc08f Mon Sep 17 00:00:00 2001 From: emizzle Date: Mon, 25 May 2020 17:45:29 +1000 Subject: [PATCH] fix: change onboarding account to whisper key Previously, the displayed key for generated accounts was displaying the public key of the account, and not the whisper account. This has been fixed. Futher work has gone in to strongly-typing a lot of the responses from status-go and removed a lot of the manual string parsing. Simplified types and type-conversions by using the `nim-serialization` library. --- src/app/onboarding/view.nim | 4 +- src/app/profile/profileView.nim | 58 +++++++++++++++++++++++++++++ src/models/accounts.nim | 30 ++++++--------- src/nim_status_client.nim | 4 +- src/status/accounts.nim | 64 +++++++++++++++++--------------- src/status/types.nim | 64 ++++++++++++++------------------ ui/onboarding/GenKey.qml | 2 +- ui/onboarding/OnboardingMain.qml | 1 - 8 files changed, 136 insertions(+), 91 deletions(-) create mode 100644 src/app/profile/profileView.nim diff --git a/src/app/onboarding/view.nim b/src/app/onboarding/view.nim index dfe11d766f..b1fecc03a8 100644 --- a/src/app/onboarding/view.nim +++ b/src/app/onboarding/view.nim @@ -54,8 +54,8 @@ QtObject: AddressRoles.Identicon.int:"identicon", AddressRoles.Key.int:"key" }.toTable - proc storeAccountAndLogin(self: OnboardingView, selectedAccountIndex: int, password: string): string {.slot.} = - result = self.model.storeAccountAndLogin(selectedAccountIndex, password) + proc storeAccountAndLogin(self: OnboardingView, selectedAccountIndex: int, password: string) {.slot.} = + discard self.model.storeAccountAndLogin(selectedAccountIndex, password) # TODO: this is temporary and will be removed once accounts import and creation is working proc generateRandomAccountAndLogin*(self: OnboardingView) {.slot.} = diff --git a/src/app/profile/profileView.nim b/src/app/profile/profileView.nim new file mode 100644 index 0000000000..1e7936a80f --- /dev/null +++ b/src/app/profile/profileView.nim @@ -0,0 +1,58 @@ +import NimQml +import mailserversList + +QtObject: + type ProfileView* = ref object of QObject + username*: string + identicon*: string + mailserversList*: MailServersList + + proc setup(self: ProfileView) = + self.QObject.setup + + proc delete*(self: ProfileView) = + self.QObject.delete + + proc newProfileView*(): ProfileView = + new(result, delete) + result.username = "" + result.identicon = "" + result.mailserversList = newMailServersList() + result.setup + + proc username*(self: ProfileView): string {.slot.} = + result = self.username + + proc receivedUsername*(self: ProfileView, username: string) {.signal.} + + proc addMailserverToList*(self: ProfileView, name: string, endpoint: string) {.slot.} = + self.mailserversList.add(name, endpoint) + + proc setUsername*(self: ProfileView, username: string) {.slot.} = + self.username = username + self.receivedUsername(username) + + QtProperty[string] username: + read = username + write = setUsername + notify = receivedUsername + + proc identicon*(self: ProfileView): string {.slot.} = + result = self.identicon + + proc getMailserversList(self: ProfileView): QVariant {.slot.} = + return newQVariant(self.mailserversList) + + QtProperty[QVariant] mailserversList: + read = getMailserversList + + proc receivedIdenticon*(self: ProfileView, identicon: string) {.signal.} + + proc setIdenticon*(self: ProfileView, identicon: string) {.slot.} = + self.identicon = identicon + self.receivedIdenticon(identicon) + + QtProperty[string] identicon: + read = identicon + write = setIdenticon + notify = receivedIdenticon diff --git a/src/models/accounts.nim b/src/models/accounts.nim index 8e727beeb7..b88762f24d 100644 --- a/src/models/accounts.nim +++ b/src/models/accounts.nim @@ -1,5 +1,5 @@ -import json import eventemitter +import json_serialization import ../status/accounts as status_accounts import ../status/types @@ -14,37 +14,31 @@ type AccountModel* = ref object generatedAddresses*: seq[GeneratedAccount] events*: EventEmitter - subaccounts*: JsonNode #TODO use correct account, etc.. proc newAccountModel*(): AccountModel = result = AccountModel() result.events = createEventEmitter() result.generatedAddresses = @[] - result.subaccounts = %*{} proc delete*(self: AccountModel) = # delete self.generatedAddresses discard proc generateAddresses*(self: AccountModel): seq[GeneratedAccount] = - let accounts = status_accounts.generateAddresses().parseJson - for account in accounts: - var generatedAccount = account.toGeneratedAccount - - generatedAccount.name = status_accounts.generateAlias(account["publicKey"].str) - generatedAccount.photoPath = status_accounts.generateIdenticon(account["publicKey"].str) - - self.generatedAddresses.add(generatedAccount) + var accounts = status_accounts.generateAddresses() + for account in accounts.mitems: + account.name = status_accounts.generateAlias(account.derived.whisper.publicKey) + account.photoPath = status_accounts.generateIdenticon(account.derived.whisper.publicKey) + self.generatedAddresses.add(account) self.generatedAddresses # TODO: this is temporary and will be removed once accounts import and creation is working proc generateRandomAccountAndLogin*(self: AccountModel) = - let generatedAccounts = status_accounts.generateAddresses().parseJson - self.subaccounts = status_accounts.setupAccount(generatedAccounts[0], "qwerty").parseJson - self.events.emit("accountsReady", AccountArgs(account: self.subaccounts[1].toAccount)) + let generatedAccounts = status_accounts.generateAddresses() + let account = status_accounts.setupAccount(generatedAccounts[0], "qwerty") + self.events.emit("accountsReady", AccountArgs(account: account)) -proc storeAccountAndLogin*(self: AccountModel, selectedAccountIndex: int, password: string): string = +proc storeAccountAndLogin*(self: AccountModel, selectedAccountIndex: int, password: string): Account = let generatedAccount: GeneratedAccount = self.generatedAddresses[selectedAccountIndex] - result = status_accounts.setupAccount(%generatedAccount, password) - self.subaccounts = result.parseJson - self.events.emit("accountsReady", AccountArgs(account: generatedAccount.toAccount)) + result = status_accounts.setupAccount(generatedAccount, password) + self.events.emit("accountsReady", AccountArgs(account: result)) diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 94ca9b6cd0..628d339f37 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -7,7 +7,6 @@ import app/profile/core as profile import signals/core as signals import app/onboarding/core as onboarding import state -import json import status/accounts as status_accounts import status/core as status_core import status/chat as status_chat @@ -17,6 +16,7 @@ import models/accounts import state import status/types import eventemitter +import json_serialization var signalsQObjPointer: pointer @@ -24,7 +24,7 @@ logScope: topics = "main" proc mainProc() = - let nodeAccounts = parseJson(status_accounts.initNodeAccounts()).toNodeAccounts # to be used for login + let nodeAccounts = Json.decode(status_accounts.initNodeAccounts(), seq[NodeAccount]) # to be used for login let app = newQApplication() let engine = newQQmlApplicationEngine() let signalController = signals.newController(app) diff --git a/src/status/accounts.nim b/src/status/accounts.nim index f457edd0e7..82caaf9744 100644 --- a/src/status/accounts.nim +++ b/src/status/accounts.nim @@ -6,19 +6,22 @@ import accounts/constants import nimcrypto import os import uuids +import types +import json_serialization +import chronicles proc queryAccounts*(): string = var response = callPrivateRPC("eth_accounts") result = parseJson(response)["result"][0].getStr() -proc generateAddresses*(): string = +proc generateAddresses*(): seq[GeneratedAccount] = let multiAccountConfig = %* { "n": 5, "mnemonicPhraseLength": 12, "bip39Passphrase": "", - "paths": ["m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"] + "paths": [PATH_WHISPER, PATH_WALLET_ROOT, PATH_DEFAULT_WALLET] } - result = $libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig) + result = Json.decode($libstatus.multiAccountGenerateAndDeriveAddresses($multiAccountConfig), seq[GeneratedAccount]) proc generateAlias*(publicKey: string): string = result = $libstatus.generateAlias(publicKey.toGoString) @@ -43,20 +46,20 @@ proc initNodeAccounts*(): string = discard $libstatus.initKeystore(keystoredir); result = $libstatus.openAccounts(datadir); -proc saveAccountAndLogin*(multiAccounts: JsonNode, alias: string, identicon: string, accountData: string, password: string, configJSON: string, settingsJSON: string): JsonNode = +proc saveAccountAndLogin*(multiAccounts: MultiAccounts, alias: string, identicon: string, accountData: string, password: string, configJSON: string, settingsJSON: string): Account = let hashedPassword = "0x" & $keccak_256.digest(password) let subaccountData = %* [ { - "public-key": multiAccounts[constants.PATH_DEFAULT_WALLET]["publicKey"], - "address": multiAccounts[constants.PATH_DEFAULT_WALLET]["address"], + "public-key": multiAccounts.defaultWallet.publicKey, + "address": multiAccounts.defaultWallet.address, "color": "#4360df", "wallet": true, "path": constants.PATH_DEFAULT_WALLET, "name": "Status account" }, { - "public-key": multiAccounts[constants.PATH_WHISPER]["publicKey"], - "address": multiAccounts[constants.PATH_WHISPER]["address"], + "public-key": multiAccounts.whisper.publicKey, + "address": multiAccounts.whisper.address, "name": alias, "photo-path": identicon, "path": constants.PATH_WHISPER, @@ -68,38 +71,39 @@ proc saveAccountAndLogin*(multiAccounts: JsonNode, alias: string, identicon: str let parsedSavedResult = savedResult.parseJson if parsedSavedResult["error"].getStr == "": - echo "Account saved succesfully" - subaccountData + debug "Account saved succesfully" -proc generateMultiAccounts*(account: JsonNode, password: string): JsonNode = + result = Account(name: alias, photoPath: identicon) + +proc generateMultiAccounts*(account: GeneratedAccount, password: string): MultiAccounts = let hashedPassword = "0x" & $keccak_256.digest(password) let multiAccount = %* { - "accountID": account["id"].getStr, - "paths": ["m/44'/60'/0'/0", "m/43'/60'/1581'", "m/43'/60'/1581'/0'/0", "m/44'/60'/0'/0/0"], + "accountID": account.id, + "paths": [PATH_WALLET_ROOT, PATH_EIP_1581, PATH_WHISPER, PATH_DEFAULT_WALLET], "password": hashedPassword } var response = $libstatus.multiAccountStoreDerivedAccounts($multiAccount); - result = response.parseJson + result = Json.decode($response, MultiAccounts) -proc getAccountData*(account: JsonNode, alias: string, identicon: string): JsonNode = +proc getAccountData*(account: GeneratedAccount, alias: string, identicon: string): JsonNode = result = %* { "name": alias, - "address": account["address"].getStr, + "address": account.address, "photo-path": identicon, - "key-uid": account["keyUid"].getStr, + "key-uid": account.keyUid, "keycard-pairing": nil } -proc getAccountSettings*(account: JsonNode, alias: string, identicon: string, multiAccounts: JsonNode, defaultNetworks: JsonNode): JsonNode = +proc getAccountSettings*(account: GeneratedAccount, alias: string, identicon: string, multiAccounts: MultiAccounts, defaultNetworks: JsonNode): JsonNode = result = %* { - "key-uid": account["keyUid"].getStr, - "mnemonic": account["mnemonic"].getStr, - "public-key": multiAccounts[constants.PATH_WHISPER]["publicKey"].getStr, + "key-uid": account.keyUid, + "mnemonic": account.mnemonic, + "public-key": multiAccounts.whisper.publicKey, "name": alias, - "address": account["address"].getStr, - "eip1581-address": multiAccounts[constants.PATH_EIP_1581]["address"].getStr, - "dapps-address": multiAccounts[constants.PATH_DEFAULT_WALLET]["address"].getStr, - "wallet-root-address": multiAccounts[constants.PATH_WALLET_ROOT]["address"].getStr, + "address": account.address, + "eip1581-address": multiAccounts.eip1581.address, + "dapps-address": multiAccounts.defaultWallet.address, + "wallet-root-address": multiAccounts.walletRoot.address, "preview-privacy?": true, "signing-phrase": generateSigningPhrase(3), "log-level": "INFO", @@ -116,14 +120,14 @@ proc getAccountSettings*(account: JsonNode, alias: string, identicon: string, mu "installation-id": $genUUID() } -proc setupAccount*(account: JsonNode, password: string): string = +proc setupAccount*(account: GeneratedAccount, password: string): Account = let multiAccounts = generateMultiAccounts(account, password) - let whisperPubKey = account["derived"][constants.PATH_WHISPER]["publicKey"].getStr - let alias = $libstatus.generateAlias(whisperPubKey.toGoString) - let identicon = $libstatus.identicon(whisperPubKey.toGoString) + let whisperPubKey = account.derived.whisper.publicKey + let alias = generateAlias(whisperPubKey) + let identicon =generateIdenticon(whisperPubKey) let accountData = getAccountData(account, alias, identicon) var settingsJSON = getAccountSettings(account, alias, identicon, multiAccounts, constants.DEFAULT_NETWORKS) - $saveAccountAndLogin(multiAccounts, alias, identicon, $accountData, password, $constants.NODE_CONFIG, $settingsJSON) + saveAccountAndLogin(multiAccounts, alias, identicon, $accountData, password, $constants.NODE_CONFIG, $settingsJSON) diff --git a/src/status/types.nim b/src/status/types.nim index 70e66da5f3..9ef8295f25 100644 --- a/src/status/types.nim +++ b/src/status/types.nim @@ -1,5 +1,6 @@ -import json import eventemitter +import json_serialization +import accounts/constants type SignalCallback* = proc(eventMessage: cstring): void {.cdecl.} @@ -23,54 +24,43 @@ type str*: cstring length*: cint +type DerivedAccount* = object + publicKey*: string + address*: string + +type MultiAccounts* = object + whisper* {.serializedFieldName(PATH_WHISPER).}: DerivedAccount + walletRoot* {.serializedFieldName(PATH_WALLET_ROOT).}: DerivedAccount + defaultWallet* {.serializedFieldName(PATH_DEFAULT_WALLET).}: DerivedAccount + eip1581* {.serializedFieldName(PATH_EIP_1581).}: DerivedAccount + + type Account* = object of RootObj name*: string - keyUid*: string - photoPath*: string + keyUid* {.serializedFieldName("key-uid").}: string + photoPath* {.serializedFieldName("photo-path").}: string type - NodeAccount* = ref object of Account + NodeAccount* = object timestamp*: int - keycardPairing*: string + keycardPairing* {.serializedFieldName("keycard-pairing").}: string + # deserialisation does not handle base classes, so flatten + name*: string + keyUid* {.serializedFieldName("key-uid").}: string + photoPath* {.serializedFieldName("photo-path").}: string type - GeneratedAccount* = ref object of Account + GeneratedAccount* = object publicKey*: string address*: string id*: string mnemonic*: string - derived*: JsonNode - -proc toNodeAccount*(nodeAccount: JsonNode): NodeAccount = - result = NodeAccount( - name: nodeAccount["name"].getStr, - timestamp: nodeAccount["timestamp"].getInt, - photoPath: nodeAccount["photo-path"].getStr, - keycardPairing: nodeAccount["keycard-pairing"].getStr, - keyUid: nodeAccount["key-uid"].getStr) - -proc toNodeAccounts*(nodeAccounts: JsonNode): seq[NodeAccount] = - result = newSeq[NodeAccount]() - for v in nodeAccounts: - result.add v.toNodeAccount - -proc toGeneratedAccount*(generatedAccount: JsonNode): GeneratedAccount = - generatedAccount["name"] = %*"" - generatedAccount["photoPath"] = %*"" - result = generatedAccount.to(GeneratedAccount) - -proc toAccount*(generatedAccount: JsonNode): Account = - result = Account( - name: generatedAccount["name"].getStr, - keyUid: generatedAccount{"key-uid"}.getStr, - photoPath: generatedAccount["photo-path"].getStr) - -proc toAccount*(generatedAccount: GeneratedAccount): Account = - result = Account( - name: generatedAccount.name, - keyUid: generatedAccount.keyUid, - photoPath: generatedAccount.photoPath) + derived*: MultiAccounts + # deserialisation does not handle base classes, so flatten + name*: string + keyUid*: string + photoPath*: string type AccountArgs* = ref object of Args account*: Account diff --git a/ui/onboarding/GenKey.qml b/ui/onboarding/GenKey.qml index b05875d925..96db4be085 100644 --- a/ui/onboarding/GenKey.qml +++ b/ui/onboarding/GenKey.qml @@ -211,7 +211,7 @@ SwipeView { } const selectedAccountIndex = wizardStep2.selectedIndex - const storeResponse = onboardingModel.storeAccountAndLogin(selectedAccountIndex, txtPassword.text) + onboardingModel.storeAccountAndLogin(selectedAccountIndex, txtPassword.text) swipeView.loginDone(); } diff --git a/ui/onboarding/OnboardingMain.qml b/ui/onboarding/OnboardingMain.qml index 9bab027a5d..9dfcf667ad 100644 --- a/ui/onboarding/OnboardingMain.qml +++ b/ui/onboarding/OnboardingMain.qml @@ -54,7 +54,6 @@ Page { id: genKeyState onEntered: { genKey.visible = true - onboardingModel.generateAddresses() } onExited: genKey.visible = false