feat: adapt create/restore/login endpoints for keycard usage (#5311)
* chore_: remove duplicated `StartNodeWithKey` * feat(KeycardPairing)_: added GetPairings method * chore_: simplify startNode... methods * chore_: added encryption path to be derived * fix_: error handling in StartNodeWithKey * feat_: added keycard properties to CreateAccount * feat_: moved KeycardWhisperPrivateKey to LoginAccount * fix_: LoginAccount during local pairing * feat_: added chat key handling to loginAccount * chore_: struct response from generateOrImportAccount * fix_: do not store keycard account to keystore * feat_: added Mnemonic parameter to LoginAccount * chore_: wrap loginAccount errors * feat_: RestoreKeycardAccountAndLogin endpoint * chore_: merge RestoreKeycardAccountRequest into RestoreAccountRequest * fix_: TestRestoreKeycardAccountAndLogin * fix_: MessengerRawMessageResendTest * chore_: cleanup * chore_: cleanup according to pr comments * chore_: better doc for Login.Mnemonic * chore_: add/fix comments * fix_: lint
This commit is contained in:
parent
1cdcc0dcc2
commit
49eaabaca5
|
@ -1,6 +1,8 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
|
||||
signercore "github.com/ethereum/go-ethereum/signer/core/apitypes"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/types"
|
||||
|
@ -18,8 +20,8 @@ type StatusBackend interface {
|
|||
// IsNodeRunning() bool // NOTE: Only used in tests
|
||||
StartNode(config *params.NodeConfig) error // NOTE: Only used in canary
|
||||
StartNodeWithKey(acc multiaccounts.Account, password string, keyHex string, conf *params.NodeConfig) error
|
||||
StartNodeWithAccount(acc multiaccounts.Account, password string, conf *params.NodeConfig) error
|
||||
StartNodeWithAccountAndInitialConfig(account multiaccounts.Account, password string, settings settings.Settings, conf *params.NodeConfig, subaccs []*accounts.Account) error
|
||||
StartNodeWithAccount(acc multiaccounts.Account, password string, conf *params.NodeConfig, chatKey *ecdsa.PrivateKey) error
|
||||
StartNodeWithAccountAndInitialConfig(account multiaccounts.Account, password string, settings settings.Settings, conf *params.NodeConfig, subaccs []*accounts.Account, chatKey *ecdsa.PrivateKey) error
|
||||
StopNode() error
|
||||
// RestartNode() error // NOTE: Only used in tests
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import (
|
|||
"github.com/status-im/status-go/protocol/requests"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/services/typeddata"
|
||||
"github.com/status-im/status-go/services/wallet"
|
||||
walletservice "github.com/status-im/status-go/services/wallet"
|
||||
"github.com/status-im/status-go/signal"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
|
@ -1073,7 +1074,7 @@ func TestConvertAccount(t *testing.T) {
|
|||
found = keystoreContainsFileForAccount(keyStoreDir, chatAddress)
|
||||
require.True(t, found)
|
||||
|
||||
defaultSettings, err := defaultSettings(genAccInfo, derivedAccounts)
|
||||
defaultSettings, err := defaultSettings(genAccInfo.KeyUID, genAccInfo.Address, derivedAccounts)
|
||||
require.NoError(t, err)
|
||||
nodeConfig, err := defaultNodeConfig(defaultSettings.InstallationID, &requests.CreateAccount{
|
||||
LogLevel: defaultSettings.LogLevel,
|
||||
|
@ -1135,7 +1136,7 @@ func TestConvertAccount(t *testing.T) {
|
|||
err = backend.ensureAppDBOpened(account, password)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, password, *defaultSettings, nodeConfig, profileKeypair.Accounts)
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, password, *defaultSettings, nodeConfig, profileKeypair.Accounts, nil)
|
||||
require.NoError(t, err)
|
||||
multiaccounts, err := backend.GetAccounts()
|
||||
require.NoError(t, err)
|
||||
|
@ -1294,7 +1295,7 @@ func loginDesktopUser(t *testing.T, conf *params.NodeConfig) {
|
|||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
err := b.StartNodeWithAccount(accounts[0], passwd, conf)
|
||||
err := b.StartNodeWithAccount(accounts[0], passwd, conf, nil)
|
||||
require.NoError(t, err)
|
||||
}()
|
||||
|
||||
|
@ -1682,3 +1683,168 @@ func TestCreateAccountPathsValidation(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, tmpdir, request.RootDataDir)
|
||||
}
|
||||
|
||||
func TestRestoreKeycardAccountAndLogin(t *testing.T) {
|
||||
utils.Init()
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
exampleKeycardEvent := map[string]interface{}{
|
||||
"error": "",
|
||||
"instanceUID": "a84599394887b742eed9a99d3834a797",
|
||||
"applicationInfo": map[string]interface{}{
|
||||
"initialized": false,
|
||||
"instanceUID": "",
|
||||
"version": 0,
|
||||
"availableSlots": 0,
|
||||
"keyUID": "",
|
||||
},
|
||||
"seedPhraseIndexes": []interface{}{},
|
||||
"freePairingSlots": 0,
|
||||
"keyUid": "0x579324c53f347e18961c775a00ec13ed7d59a225b1859d5125ff36b450b8778d",
|
||||
"pinRetries": 0,
|
||||
"pukRetries": 0,
|
||||
"cardMetadata": map[string]interface{}{
|
||||
"name": "",
|
||||
"walletAccounts": []interface{}{},
|
||||
},
|
||||
"generatedWalletAccount": map[string]interface{}{
|
||||
"address": "",
|
||||
"publicKey": "",
|
||||
"privateKey": "",
|
||||
},
|
||||
"generatedWalletAccounts": []interface{}{},
|
||||
"txSignature": map[string]interface{}{
|
||||
"r": "",
|
||||
"s": "",
|
||||
"v": "",
|
||||
},
|
||||
"eip1581Key": map[string]interface{}{
|
||||
"address": "0xA8d50f0B3bc581298446be8FBfF5c71684Ea6c01",
|
||||
"publicKey": "0x040d7e6e3761ab3d17c220e484ede2f3fa02998b859d4d0e9d34216c6e41b03dc94996fdea23a9233092cee50a768e7428d5de7bd42e8e32c10d6b0e36b10f0e7a",
|
||||
"privateKey": "",
|
||||
},
|
||||
"encryptionKey": map[string]interface{}{
|
||||
"address": "0x1ec12f2b323ddDD076A1127cEc8FA0B592c46cD3",
|
||||
"publicKey": "0x04c4b16f670b51702dc130673bf9c64ffd1f69383cef2127dfa05031b9b1359120f7342134af9a350465126a85e87cb003b7c4f93d2ba2ff98bb73277b119c7a87",
|
||||
"privateKey": "68c830d5b327382a65e6c302594744ec0d28b01d1ea8124f49714f05c9625ddd"},
|
||||
"masterKey": map[string]interface{}{
|
||||
"address": "0xbf9dE86774051537b2192Ce9c8d2496f129bA24b",
|
||||
"publicKey": "0x040d909a07ecca18bbfa7d53d10a86bd956f54b8b446eabd94940e642ae18421b516ec5b63677c4ce65e0e266b58bdb716d8266b25356154eb61713ecb23824075",
|
||||
"privateKey": "",
|
||||
},
|
||||
"walletKey": map[string]interface{}{
|
||||
"address": "0xB9E1998e1A8854887CA327D1aF5894B6CB0AC07D",
|
||||
"publicKey": "0x04c16e7748f34e0ab2c9c13350d7872d928e942934dd8b8abd3fb12b8c742a5ee8cf0919731e800907068afec25f577bde3a9c534795e359ee48097e4e55f4aaca",
|
||||
"privateKey": "",
|
||||
},
|
||||
"walletRootKey": map[string]interface{}{
|
||||
"address": "0xFf59db9F2f97Db7104A906C390D33C342a1309C8",
|
||||
"publicKey": "0x04c436532398e19ed14b4eb41545b82014435d60e7db4449a371fd80d0d5cd557f60d81f6c2b35ca5440aa60934c23b70489b0e7963e63ec66b51a7e52db711262",
|
||||
"privateKey": "",
|
||||
},
|
||||
"whisperKey": map[string]interface{}{
|
||||
"address": "0xBa122B9c0Ef560813b5D2C0961094aC36289f846",
|
||||
"publicKey": "0x0441468c39b579259676350b9736b01cdadb740f67bfd022fa2b985123b1d66fc3191cfe73205e3d3d84148f0248f9a2978afeeda16d7c3db90bd2579f0de33459",
|
||||
"privateKey": "5a42b4f15ff1a5da95d116442ce11a31e9020f562224bf60b1d8d3a99d90653d",
|
||||
},
|
||||
"masterKeyAddress": "",
|
||||
}
|
||||
|
||||
exampleRequest := map[string]interface{}{
|
||||
"mnemonic": "",
|
||||
"fetchBackup": true,
|
||||
"createAccountRequest": map[string]interface{}{
|
||||
"rootDataDir": tmpdir,
|
||||
"kdfIterations": 256000,
|
||||
"deviceName": "",
|
||||
"displayName": "",
|
||||
"password": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
|
||||
"imagePath": "",
|
||||
"imageCropRectangle": map[string]interface{}{
|
||||
"ax": 0, "ay": 0, "bx": 0, "by": 0},
|
||||
"customizationColor": "primary",
|
||||
"emoji": "",
|
||||
"wakuV2Nameserver": nil,
|
||||
"wakuV2LightClient": false,
|
||||
"logLevel": "DEBUG",
|
||||
"logFilePath": "",
|
||||
"logEnabled": false,
|
||||
"previewPrivacy": true,
|
||||
"verifyTransactionURL": nil,
|
||||
"verifyENSURL": nil,
|
||||
"verifyENSContractAddress": nil,
|
||||
"verifyTransactionChainID": nil,
|
||||
"upstreamConfig": "",
|
||||
"networkID": nil,
|
||||
"walletSecretsConfig": map[string]interface{}{
|
||||
"poktToken": "1234567890",
|
||||
"infuraToken": "1234567890",
|
||||
"infuraSecret": "",
|
||||
"openseaApiKey": "",
|
||||
"raribleMainnetApiKey": "",
|
||||
"raribleTestnetApiKey": "",
|
||||
"alchemyEthereumMainnetToken": "",
|
||||
"alchemyEthereumGoerliToken": "",
|
||||
"alchemyEthereumSepoliaToken": "",
|
||||
"alchemyArbitrumMainnetToken": "",
|
||||
"alchemyArbitrumGoerliToken": "",
|
||||
"alchemyArbitrumSepoliaToken": "",
|
||||
"alchemyOptimismMainnetToken": "",
|
||||
"alchemyOptimismGoerliToken": "",
|
||||
"alchemyOptimismSepoliaToken": "",
|
||||
},
|
||||
"torrentConfigEnabled": false,
|
||||
"torrentConfigPort": 0,
|
||||
"keycardInstanceUID": "a84599394887b742eed9a99d3834a797",
|
||||
"keycardPairingDataFile": path.Join(tmpdir, DefaultKeycardPairingDataFile),
|
||||
},
|
||||
}
|
||||
|
||||
require.NotNil(t, exampleKeycardEvent)
|
||||
require.NotNil(t, exampleRequest)
|
||||
|
||||
conf, err := params.NewNodeConfig(tmpdir, 1777)
|
||||
require.NoError(t, err)
|
||||
|
||||
backend := NewGethStatusBackend()
|
||||
|
||||
require.NoError(t, backend.AccountManager().InitKeystore(conf.KeyStoreDir))
|
||||
backend.UpdateRootDataDir(conf.DataDir)
|
||||
|
||||
require.NoError(t, backend.OpenAccounts())
|
||||
|
||||
keycardPairingDataFile := exampleRequest["createAccountRequest"].(map[string]interface{})["keycardPairingDataFile"].(string)
|
||||
|
||||
kp := wallet.NewKeycardPairings()
|
||||
kp.SetKeycardPairingsFile(keycardPairingDataFile)
|
||||
|
||||
err = kp.SetPairingsJSONFileContent([]byte(`{"a84599394887b742eed9a99d3834a797":{"key":"785d52957b05482477728380d9b4bbb5dc9a8ed978ab4a4098e1a279c855d3c6","index":1}}`))
|
||||
require.NoError(t, err)
|
||||
|
||||
request := &requests.RestoreAccount{
|
||||
Keycard: &requests.KeycardData{
|
||||
KeyUID: exampleKeycardEvent["keyUid"].(string),
|
||||
Address: exampleKeycardEvent["masterKey"].(map[string]interface{})["address"].(string),
|
||||
WhisperPrivateKey: exampleKeycardEvent["whisperKey"].(map[string]interface{})["privateKey"].(string),
|
||||
WhisperPublicKey: exampleKeycardEvent["whisperKey"].(map[string]interface{})["publicKey"].(string),
|
||||
WhisperAddress: exampleKeycardEvent["whisperKey"].(map[string]interface{})["address"].(string),
|
||||
WalletPublicKey: exampleKeycardEvent["walletKey"].(map[string]interface{})["publicKey"].(string),
|
||||
WalletAddress: exampleKeycardEvent["walletKey"].(map[string]interface{})["address"].(string),
|
||||
WalletRootAddress: exampleKeycardEvent["walletRootKey"].(map[string]interface{})["address"].(string),
|
||||
Eip1581Address: exampleKeycardEvent["eip1581Key"].(map[string]interface{})["address"].(string),
|
||||
EncryptionPublicKey: exampleKeycardEvent["encryptionKey"].(map[string]interface{})["publicKey"].(string),
|
||||
},
|
||||
CreateAccount: requests.CreateAccount{
|
||||
DisplayName: "User-1",
|
||||
Password: "password123",
|
||||
CustomizationColor: "#ffffff",
|
||||
RootDataDir: tmpdir,
|
||||
KeycardInstanceUID: exampleKeycardEvent["instanceUID"].(string),
|
||||
KeycardPairingDataFile: &keycardPairingDataFile,
|
||||
},
|
||||
}
|
||||
|
||||
acc, err := backend.RestoreKeycardAccountAndLogin(request)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, acc)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
const pathWalletRoot = "m/44'/60'/0'/0"
|
||||
const pathEIP1581 = "m/43'/60'/1581'"
|
||||
const pathDefaultChat = pathEIP1581 + "/0'/0"
|
||||
const pathEncryption = pathEIP1581 + "/1'/0"
|
||||
const pathDefaultWallet = pathWalletRoot + "/0"
|
||||
const defaultMnemonicLength = 12
|
||||
const shardsTestClusterID = 16
|
||||
|
@ -38,11 +39,11 @@ const DefaultListenAddr = ":0"
|
|||
const DefaultMaxMessageDeliveryAttempts = 3
|
||||
const DefaultVerifyTransactionChainID = 1
|
||||
|
||||
var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet}
|
||||
var paths = []string{pathWalletRoot, pathEIP1581, pathDefaultChat, pathDefaultWallet, pathEncryption}
|
||||
|
||||
var DefaultFleet = params.FleetShardsTest
|
||||
|
||||
func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo) (*settings.Settings, error) {
|
||||
func defaultSettings(keyUID string, address string, derivedAddresses map[string]generator.AccountInfo) (*settings.Settings, error) {
|
||||
chatKeyString := derivedAddresses[pathDefaultChat].PublicKey
|
||||
|
||||
s := &settings.Settings{}
|
||||
|
@ -51,8 +52,8 @@ func defaultSettings(generatedAccountInfo generator.GeneratedAccountInfo, derive
|
|||
s.LogLevel = &logLevel
|
||||
s.ProfilePicturesShowTo = settings.ProfilePicturesShowToEveryone
|
||||
s.ProfilePicturesVisibility = settings.ProfilePicturesVisibilityEveryone
|
||||
s.KeyUID = generatedAccountInfo.KeyUID
|
||||
s.Address = types.HexToAddress(generatedAccountInfo.Address)
|
||||
s.KeyUID = keyUID
|
||||
s.Address = types.HexToAddress(address)
|
||||
s.WalletRootAddress = types.HexToAddress(derivedAddresses[pathWalletRoot].Address)
|
||||
s.URLUnfurlingMode = settings.URLUnfurlingAlwaysAsk
|
||||
|
||||
|
@ -222,8 +223,11 @@ func defaultNodeConfig(installationID string, request *requests.CreateAccount, o
|
|||
nodeConfig.LogDir = request.LogFilePath
|
||||
nodeConfig.LogLevel = DefaultLogLevel
|
||||
nodeConfig.DataDir = DefaultDataDir
|
||||
nodeConfig.KeycardPairingDataFile = DefaultKeycardPairingDataFile
|
||||
nodeConfig.ProcessBackedupMessages = false
|
||||
nodeConfig.KeycardPairingDataFile = DefaultKeycardPairingDataFile
|
||||
if request.KeycardPairingDataFile != nil {
|
||||
nodeConfig.KeycardPairingDataFile = *request.KeycardPairingDataFile
|
||||
}
|
||||
|
||||
if request.LogLevel != nil {
|
||||
nodeConfig.LogLevel = *request.LogLevel
|
||||
|
|
|
@ -2,9 +2,9 @@ package api
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
|
@ -15,8 +15,7 @@ import (
|
|||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
|
||||
|
@ -48,10 +47,13 @@ import (
|
|||
"github.com/status-im/status-go/protocol/requests"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
"github.com/status-im/status-go/server/pairing/statecontrol"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/ext"
|
||||
"github.com/status-im/status-go/services/personal"
|
||||
"github.com/status-im/status-go/services/typeddata"
|
||||
"github.com/status-im/status-go/services/wallet"
|
||||
"github.com/status-im/status-go/signal"
|
||||
"github.com/status-im/status-go/sqlite"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
"github.com/status-im/status-go/walletdatabase"
|
||||
)
|
||||
|
@ -454,11 +456,8 @@ func (b *GethStatusBackend) setupLogSettings() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// StartNodeWithKey instead of loading addresses from database this method derives address from key
|
||||
// and uses it in application.
|
||||
// TODO: we should use a proper struct with optional values instead of duplicating the regular functions
|
||||
// with small variants for keycard, this created too many bugs
|
||||
func (b *GethStatusBackend) startNodeWithKey(acc multiaccounts.Account, password string, keyHex string, inputNodeCfg *params.NodeConfig) error {
|
||||
// Deprecated: Use StartNodeWithAccount instead.
|
||||
func (b *GethStatusBackend) StartNodeWithKey(acc multiaccounts.Account, password string, keyHex string, nodecfg *params.NodeConfig) error {
|
||||
if acc.KDFIterations == 0 {
|
||||
kdfIterations, err := b.multiaccountsDB.GetAccountKDFIterationsNumber(acc.KeyUID)
|
||||
if err != nil {
|
||||
|
@ -468,83 +467,21 @@ func (b *GethStatusBackend) startNodeWithKey(acc multiaccounts.Account, password
|
|||
acc.KDFIterations = kdfIterations
|
||||
}
|
||||
|
||||
err := b.ensureDBsOpened(acc, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.loadNodeConfig(inputNodeCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.setupLogSettings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accountsDB, err := accounts.NewDB(b.appDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if acc.ColorHash == nil {
|
||||
multiAccount, err := b.updateAccountColorHashAndColorID(acc.KeyUID, accountsDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
acc = *multiAccount
|
||||
}
|
||||
|
||||
b.account = &acc
|
||||
|
||||
walletAddr, err := accountsDB.GetWalletAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
watchAddrs, err := accountsDB.GetAddresses()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chatKey, err := ethcrypto.HexToECDSA(keyHex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = b.StartNode(b.config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := b.accountManager.SetChatAccount(chatKey); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = b.accountManager.SelectedChatAccount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.accountManager.SetAccountAddresses(walletAddr, watchAddrs...)
|
||||
err = b.injectAccountsIntoServices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = b.multiaccountsDB.UpdateAccountTimestamp(acc.KeyUID, time.Now().Unix())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) StartNodeWithKey(acc multiaccounts.Account, password string, keyHex string, nodecfg *params.NodeConfig) error {
|
||||
err := b.startNodeWithKey(acc, password, keyHex, nodecfg)
|
||||
err = b.startNodeWithAccount(acc, password, nodecfg, chatKey)
|
||||
if err != nil {
|
||||
// Stop node for clean up
|
||||
_ = b.StopNode()
|
||||
return err
|
||||
}
|
||||
// get logged in
|
||||
if !b.LocalPairingStateManager.IsPairing() {
|
||||
return b.LoggedIn(acc.KeyUID, err)
|
||||
if b.LocalPairingStateManager.IsPairing() {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
return b.LoggedIn(acc.KeyUID, err)
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) OverwriteNodeConfigValues(conf *params.NodeConfig, n *params.NodeConfig) (*params.NodeConfig, error) {
|
||||
|
@ -595,6 +532,9 @@ func (b *GethStatusBackend) LoginAccount(request *requests.Login) error {
|
|||
// Stop node for clean up
|
||||
_ = b.StopNode()
|
||||
}
|
||||
if b.LocalPairingStateManager.IsPairing() {
|
||||
return nil
|
||||
}
|
||||
return b.LoggedIn(request.KeyUID, err)
|
||||
}
|
||||
|
||||
|
@ -603,7 +543,20 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
|
|||
return err
|
||||
}
|
||||
|
||||
password := request.Password
|
||||
if request.Mnemonic != "" {
|
||||
info, err := b.generateAccountInfo(request.Mnemonic)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to generate account info")
|
||||
}
|
||||
|
||||
derivedAddresses, err := b.getDerivedAddresses(info.ID)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get derived addresses")
|
||||
}
|
||||
|
||||
request.Password = derivedAddresses[pathEncryption].PublicKey
|
||||
request.KeycardWhisperPrivateKey = derivedAddresses[pathDefaultChat].PrivateKey
|
||||
}
|
||||
|
||||
acc := multiaccounts.Account{
|
||||
KeyUID: request.KeyUID,
|
||||
|
@ -614,9 +567,9 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
|
|||
acc.KDFIterations = dbsetup.ReducedKDFIterationsNumber
|
||||
}
|
||||
|
||||
err := b.ensureDBsOpened(acc, password)
|
||||
err := b.ensureDBsOpened(acc, request.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to open database")
|
||||
}
|
||||
|
||||
defaultCfg := ¶ms.NodeConfig{
|
||||
|
@ -626,14 +579,14 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
|
|||
|
||||
defaultCfg.WalletConfig = buildWalletConfig(&request.WalletSecretsConfig)
|
||||
|
||||
err = b.UpdateNodeConfigFleet(acc, password, defaultCfg)
|
||||
err = b.UpdateNodeConfigFleet(acc, request.Password, defaultCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to update node config fleet")
|
||||
}
|
||||
|
||||
err = b.loadNodeConfig(defaultCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to load node config")
|
||||
}
|
||||
|
||||
if request.RuntimeLogLevel != "" {
|
||||
|
@ -650,34 +603,34 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
|
|||
|
||||
err = b.setupLogSettings()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to setup log settings")
|
||||
}
|
||||
|
||||
accountsDB, err := accounts.NewDB(b.appDB)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to create accounts db")
|
||||
}
|
||||
|
||||
multiAccount, err := b.updateAccountColorHashAndColorID(acc.KeyUID, accountsDB)
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to update account color hash and color id")
|
||||
}
|
||||
b.account = multiAccount
|
||||
|
||||
chatAddr, err := accountsDB.GetChatAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to get chat address")
|
||||
}
|
||||
walletAddr, err := accountsDB.GetWalletAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to get wallet address")
|
||||
}
|
||||
watchAddrs, err := accountsDB.GetWalletAddresses()
|
||||
if err != nil {
|
||||
return err
|
||||
return errors.Wrap(err, "failed to get wallet addresses")
|
||||
}
|
||||
login := account.LoginParams{
|
||||
Password: password,
|
||||
Password: request.Password,
|
||||
ChatAddress: chatAddr,
|
||||
WatchAddresses: watchAddrs,
|
||||
MainAccount: walletAddr,
|
||||
|
@ -686,17 +639,35 @@ func (b *GethStatusBackend) loginAccount(request *requests.Login) error {
|
|||
err = b.StartNode(b.config)
|
||||
if err != nil {
|
||||
b.log.Info("failed to start node")
|
||||
return err
|
||||
return errors.Wrap(err, "failed to start node")
|
||||
}
|
||||
|
||||
err = b.SelectAccount(login)
|
||||
if err != nil {
|
||||
return err
|
||||
if chatKey := request.ChatPrivateKey(); chatKey == nil {
|
||||
err = b.SelectAccount(login)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to select account")
|
||||
}
|
||||
} else {
|
||||
// In case of keycard, we don't have a keystore, instead we have private key loaded from the keycard
|
||||
if err := b.accountManager.SetChatAccount(chatKey); err != nil {
|
||||
return errors.Wrap(err, "failed to set chat account")
|
||||
}
|
||||
_, err = b.accountManager.SelectedChatAccount()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get selected chat account")
|
||||
}
|
||||
|
||||
b.accountManager.SetAccountAddresses(walletAddr, watchAddrs...)
|
||||
err = b.injectAccountsIntoServices()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to inject accounts into services")
|
||||
}
|
||||
}
|
||||
|
||||
err = b.multiaccountsDB.UpdateAccountTimestamp(acc.KeyUID, time.Now().Unix())
|
||||
if err != nil {
|
||||
b.log.Info("failed to update account")
|
||||
return err
|
||||
b.log.Error("failed to update account")
|
||||
return errors.Wrap(err, "failed to update account")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -737,7 +708,8 @@ func (b *GethStatusBackend) UpdateNodeConfigFleet(acc multiaccounts.Account, pas
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, password string, inputNodeCfg *params.NodeConfig) error {
|
||||
// Deprecated: Use loginAccount instead
|
||||
func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, password string, inputNodeCfg *params.NodeConfig, chatKey *ecdsa.PrivateKey) error {
|
||||
err := b.ensureDBsOpened(acc, password)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -793,10 +765,29 @@ func (b *GethStatusBackend) startNodeWithAccount(acc multiaccounts.Account, pass
|
|||
return err
|
||||
}
|
||||
|
||||
err = b.SelectAccount(login)
|
||||
if err != nil {
|
||||
return err
|
||||
if chatKey == nil {
|
||||
// Load account from keystore
|
||||
err = b.SelectAccount(login)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// In case of keycard, we don't have keystore, but we directly have the private key
|
||||
if err := b.accountManager.SetChatAccount(chatKey); err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = b.accountManager.SelectedChatAccount()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b.accountManager.SetAccountAddresses(walletAddr, watchAddrs...)
|
||||
err = b.injectAccountsIntoServices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = b.multiaccountsDB.UpdateAccountTimestamp(acc.KeyUID, time.Now().Unix())
|
||||
if err != nil {
|
||||
b.log.Info("failed to update account")
|
||||
|
@ -861,11 +852,11 @@ func (b *GethStatusBackend) MigrateKeyStoreDir(acc multiaccounts.Account, passwo
|
|||
}
|
||||
|
||||
func (b *GethStatusBackend) Login(keyUID, password string) error {
|
||||
return b.startNodeWithAccount(multiaccounts.Account{KeyUID: keyUID}, password, nil)
|
||||
return b.startNodeWithAccount(multiaccounts.Account{KeyUID: keyUID}, password, nil, nil)
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) StartNodeWithAccount(acc multiaccounts.Account, password string, nodecfg *params.NodeConfig) error {
|
||||
err := b.startNodeWithAccount(acc, password, nodecfg)
|
||||
func (b *GethStatusBackend) StartNodeWithAccount(acc multiaccounts.Account, password string, nodecfg *params.NodeConfig, chatKey *ecdsa.PrivateKey) error {
|
||||
err := b.startNodeWithAccount(acc, password, nodecfg, chatKey)
|
||||
if err != nil {
|
||||
// Stop node for clean up
|
||||
_ = b.StopNode()
|
||||
|
@ -993,9 +984,9 @@ func (b *GethStatusBackend) ChangeDatabasePassword(keyUID string, password strin
|
|||
// because UI calls Logout and Quit afterwards. It should not be UI-dependent
|
||||
// and should be handled gracefully here if it makes sense to run dummy node after
|
||||
// logout
|
||||
_ = b.startNodeWithAccount(*account, password, nil)
|
||||
_ = b.startNodeWithAccount(*account, password, nil, nil)
|
||||
} else {
|
||||
_ = b.startNodeWithAccount(*account, newPassword, nil)
|
||||
_ = b.startNodeWithAccount(*account, newPassword, nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1294,18 +1285,91 @@ func (b *GethStatusBackend) RestoreAccountAndLogin(request *requests.RestoreAcco
|
|||
return nil, err
|
||||
}
|
||||
|
||||
account, settings, nodeConfig, subAccounts, err := b.generateOrImportAccount(request.Mnemonic, 0, request.FetchBackup, &request.CreateAccount)
|
||||
response, err := b.generateOrImportAccount(request.Mnemonic, 0, request.FetchBackup, &request.CreateAccount)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = b.StartNodeWithAccountAndInitialConfig(*account, request.Password, *settings, nodeConfig, subAccounts)
|
||||
err = b.StartNodeWithAccountAndInitialConfig(
|
||||
*response.account,
|
||||
request.Password,
|
||||
*response.settings,
|
||||
response.nodeConfig,
|
||||
response.subAccounts,
|
||||
response.chatPrivateKey,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
b.log.Error("start node", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return account, nil
|
||||
return response.account, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) RestoreKeycardAccountAndLogin(request *requests.RestoreAccount) (*multiaccounts.Account, error) {
|
||||
if err := request.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyStoreDir, err := b.initKeyStoreDirWithAccount(request.RootDataDir, request.Keycard.KeyUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
derivedAddresses := map[string]generator.AccountInfo{
|
||||
pathDefaultChat: {
|
||||
Address: request.Keycard.WhisperAddress,
|
||||
PublicKey: request.Keycard.WhisperPublicKey,
|
||||
PrivateKey: request.Keycard.WhisperPrivateKey,
|
||||
},
|
||||
pathWalletRoot: {
|
||||
Address: request.Keycard.WalletRootAddress,
|
||||
},
|
||||
pathDefaultWallet: {
|
||||
Address: request.Keycard.WalletAddress,
|
||||
PublicKey: request.Keycard.WalletPublicKey,
|
||||
},
|
||||
pathEIP1581: {
|
||||
Address: request.Keycard.Eip1581Address,
|
||||
},
|
||||
pathEncryption: {
|
||||
PublicKey: request.Keycard.EncryptionPublicKey,
|
||||
},
|
||||
}
|
||||
|
||||
input := &prepareAccountInput{
|
||||
customizationColorClock: 0,
|
||||
accountID: "", // empty for keycard
|
||||
keyUID: request.Keycard.KeyUID,
|
||||
address: request.Keycard.Address,
|
||||
mnemonic: "",
|
||||
restoringAccount: true,
|
||||
derivedAddresses: derivedAddresses,
|
||||
fetchBackup: request.FetchBackup, // WARNING: Ensure this value is correct
|
||||
keyStoreDir: keyStoreDir,
|
||||
}
|
||||
|
||||
response, err := b.prepareNodeAccount(&request.CreateAccount, input)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = b.StartNodeWithAccountAndInitialConfig(
|
||||
*response.account,
|
||||
request.Password,
|
||||
*response.settings,
|
||||
response.nodeConfig,
|
||||
response.subAccounts,
|
||||
response.chatPrivateKey, //request.WhisperPrivateKey,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
b.log.Error("start node", err)
|
||||
return nil, errors.Wrap(err, "failed to start node")
|
||||
}
|
||||
|
||||
return response.account, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) GetKeyUIDByMnemonic(mnemonic string) (string, error) {
|
||||
|
@ -1319,44 +1383,104 @@ func (b *GethStatusBackend) GetKeyUIDByMnemonic(mnemonic string) (string, error)
|
|||
return info.KeyUID, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizationColorClock uint64, fetchBackup bool, request *requests.CreateAccount, opts ...params.Option) (*multiaccounts.Account, *settings.Settings, *params.NodeConfig, []*accounts.Account, error) {
|
||||
type prepareAccountInput struct {
|
||||
customizationColorClock uint64
|
||||
accountID string
|
||||
keyUID string
|
||||
address string
|
||||
mnemonic string
|
||||
restoringAccount bool
|
||||
derivedAddresses map[string]generator.AccountInfo
|
||||
fetchBackup bool
|
||||
keyStoreDir string
|
||||
opts []params.Option
|
||||
}
|
||||
|
||||
type accountBundle struct {
|
||||
account *multiaccounts.Account
|
||||
settings *settings.Settings
|
||||
nodeConfig *params.NodeConfig
|
||||
subAccounts []*accounts.Account
|
||||
chatPrivateKey *ecdsa.PrivateKey
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) generateOrImportAccount(mnemonic string, customizationColorClock uint64, fetchBackup bool, request *requests.CreateAccount, opts ...params.Option) (*accountBundle, error) {
|
||||
info, err := b.generateAccountInfo(mnemonic)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyStoreDir, err := b.initKeyStoreDirWithAccount(request.RootDataDir, info.KeyUID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
account, info, err := b.generateAccount(*info, customizationColorClock, request)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
derivedAddresses, err := b.getDerivedAddresses(info.ID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
settings, err := b.prepareSettings(*info, derivedAddresses, request, mnemonic)
|
||||
input := &prepareAccountInput{
|
||||
customizationColorClock: customizationColorClock,
|
||||
accountID: info.ID,
|
||||
keyUID: info.KeyUID,
|
||||
address: info.Address,
|
||||
mnemonic: info.Mnemonic,
|
||||
restoringAccount: mnemonic != "",
|
||||
derivedAddresses: derivedAddresses,
|
||||
fetchBackup: fetchBackup,
|
||||
keyStoreDir: keyStoreDir,
|
||||
opts: opts,
|
||||
}
|
||||
|
||||
return b.prepareNodeAccount(request, input)
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) prepareNodeAccount(request *requests.CreateAccount, input *prepareAccountInput) (*accountBundle, error) {
|
||||
var err error
|
||||
response := &accountBundle{}
|
||||
|
||||
if request.KeycardInstanceUID != "" {
|
||||
request.Password = input.derivedAddresses[pathEncryption].PublicKey
|
||||
}
|
||||
|
||||
// NOTE: I intentionally left this condition separately and not an `else` branch. Technically it's an `else`,
|
||||
// but the statements inside are not the opposite statement of the first statement. It's just kinda like this:
|
||||
// - replace password when we're using keycard
|
||||
// - store account when we're not using keycard
|
||||
if request.KeycardInstanceUID == "" {
|
||||
err = b.storeAccount(input.accountID, request.Password, paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
response.account, err = b.buildAccount(request, input)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, errors.Wrap(err, "failed to build account")
|
||||
}
|
||||
|
||||
processBackedupMessages := mnemonic != "" && fetchBackup
|
||||
nodeConfig, err := b.prepareConfig(processBackedupMessages, account.KeyUID, keyStoreDir, request, opts...)
|
||||
response.settings, err = b.prepareSettings(request, input)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, errors.Wrap(err, "failed to prepare settings")
|
||||
}
|
||||
|
||||
subAccounts, err := b.prepareSubAccounts(mnemonic, account.KeyUID, derivedAddresses, request)
|
||||
response.nodeConfig, err = b.prepareConfig(request, input, response.settings.InstallationID)
|
||||
if err != nil {
|
||||
return nil, nil, nil, nil, err
|
||||
return nil, errors.Wrap(err, "failed to prepare node config")
|
||||
}
|
||||
|
||||
return account, settings, nodeConfig, subAccounts, nil
|
||||
response.subAccounts, err = b.prepareSubAccounts(request, input)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prepare sub accounts")
|
||||
}
|
||||
|
||||
response, err = b.prepareForKeycard(request, input, response)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to prepare for keycard")
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) initKeyStoreDirWithAccount(rootDataDir, keyUID string) (string, error) {
|
||||
|
@ -1391,36 +1515,39 @@ func (b *GethStatusBackend) generateAccountInfo(mnemonic string) (*generator.Gen
|
|||
return &info, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) generateAccount(info generator.GeneratedAccountInfo, customizationColorClock uint64, request *requests.CreateAccount) (*multiaccounts.Account, *generator.GeneratedAccountInfo, error) {
|
||||
err := b.OpenAccounts()
|
||||
if err != nil {
|
||||
b.log.Error("failed open accounts", "err", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) storeAccount(id string, password string, paths []string) error {
|
||||
accountGenerator := b.accountManager.AccountsGenerator()
|
||||
|
||||
_, err = accountGenerator.StoreAccount(info.ID, request.Password)
|
||||
_, err := accountGenerator.StoreAccount(id, password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = accountGenerator.StoreDerivedAccounts(info.ID, request.Password, paths)
|
||||
_, err = accountGenerator.StoreDerivedAccounts(id, password, paths)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
account := multiaccounts.Account{
|
||||
KeyUID: info.KeyUID,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) buildAccount(request *requests.CreateAccount, input *prepareAccountInput) (*multiaccounts.Account, error) {
|
||||
err := b.OpenAccounts()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acc := &multiaccounts.Account{
|
||||
KeyUID: input.keyUID,
|
||||
Name: request.DisplayName,
|
||||
CustomizationColor: multiacccommon.CustomizationColor(request.CustomizationColor),
|
||||
CustomizationColorClock: customizationColorClock,
|
||||
CustomizationColorClock: input.customizationColorClock,
|
||||
KDFIterations: request.KdfIterations,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
|
||||
if account.KDFIterations == 0 {
|
||||
account.KDFIterations = dbsetup.ReducedKDFIterationsNumber
|
||||
if acc.KDFIterations == 0 {
|
||||
acc.KDFIterations = dbsetup.ReducedKDFIterationsNumber
|
||||
}
|
||||
|
||||
if request.ImagePath != "" {
|
||||
|
@ -1439,16 +1566,16 @@ func (b *GethStatusBackend) generateAccount(info generator.GeneratedAccountInfo,
|
|||
imageCropRectangle.Ax, imageCropRectangle.Ay, imageCropRectangle.Bx, imageCropRectangle.By)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, err
|
||||
}
|
||||
account.Images = iis
|
||||
acc.Images = iis
|
||||
}
|
||||
|
||||
return &account, &info, nil
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) prepareSettings(info generator.GeneratedAccountInfo, derivedAddresses map[string]generator.AccountInfo, request *requests.CreateAccount, mnemonic string) (*settings.Settings, error) {
|
||||
settings, err := defaultSettings(info, derivedAddresses)
|
||||
func (b *GethStatusBackend) prepareSettings(request *requests.CreateAccount, input *prepareAccountInput) (*settings.Settings, error) {
|
||||
settings, err := defaultSettings(input.keyUID, input.address, input.derivedAddresses)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -1459,9 +1586,8 @@ func (b *GethStatusBackend) prepareSettings(info generator.GeneratedAccountInfo,
|
|||
settings.CurrentNetwork = request.CurrentNetwork
|
||||
settings.TestNetworksEnabled = request.TestNetworksEnabled
|
||||
|
||||
// If restoring an account, we don't set the mnemonic
|
||||
if mnemonic == "" {
|
||||
settings.Mnemonic = &info.Mnemonic
|
||||
if !input.restoringAccount {
|
||||
settings.Mnemonic = &input.mnemonic
|
||||
settings.OmitTransfersHistoryScan = true
|
||||
// TODO(rasom): uncomment it as soon as address will be properly
|
||||
// marked as shown on mobile client
|
||||
|
@ -1471,41 +1597,38 @@ func (b *GethStatusBackend) prepareSettings(info generator.GeneratedAccountInfo,
|
|||
return settings, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) prepareConfig(processBackedupMessages bool, installationID string, userKeyStoreDir string, request *requests.CreateAccount, opts ...params.Option) (*params.NodeConfig, error) {
|
||||
nodeConfig, err := defaultNodeConfig(installationID, request, opts...)
|
||||
func (b *GethStatusBackend) prepareConfig(request *requests.CreateAccount, input *prepareAccountInput, installationID string) (*params.NodeConfig, error) {
|
||||
nodeConfig, err := defaultNodeConfig(installationID, request, input.opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeConfig.ProcessBackedupMessages = processBackedupMessages
|
||||
nodeConfig.ProcessBackedupMessages = input.fetchBackup
|
||||
|
||||
// when we set nodeConfig.KeyStoreDir, value of nodeConfig.KeyStoreDir should not contain the rootDataDir
|
||||
// loadNodeConfig will add rootDataDir to nodeConfig.KeyStoreDir
|
||||
nodeConfig.KeyStoreDir = userKeyStoreDir
|
||||
nodeConfig.KeyStoreDir = input.keyStoreDir
|
||||
|
||||
return nodeConfig, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) prepareSubAccounts(mnemonic, keyUID string, derivedAddresses map[string]generator.AccountInfo, request *requests.CreateAccount) ([]*accounts.Account, error) {
|
||||
walletDerivedAccount := derivedAddresses[pathDefaultWallet]
|
||||
func (b *GethStatusBackend) prepareSubAccounts(request *requests.CreateAccount, input *prepareAccountInput) ([]*accounts.Account, error) {
|
||||
walletDerivedAccount := input.derivedAddresses[pathDefaultWallet]
|
||||
walletAccount := &accounts.Account{
|
||||
PublicKey: types.Hex2Bytes(walletDerivedAccount.PublicKey),
|
||||
KeyUID: keyUID,
|
||||
Address: types.HexToAddress(walletDerivedAccount.Address),
|
||||
ColorID: multiacccommon.CustomizationColor(request.CustomizationColor),
|
||||
Emoji: request.Emoji,
|
||||
Wallet: true,
|
||||
Path: pathDefaultWallet,
|
||||
Name: walletAccountDefaultName,
|
||||
PublicKey: types.Hex2Bytes(walletDerivedAccount.PublicKey),
|
||||
KeyUID: input.keyUID,
|
||||
Address: types.HexToAddress(walletDerivedAccount.Address),
|
||||
ColorID: multiacccommon.CustomizationColor(request.CustomizationColor),
|
||||
Emoji: request.Emoji,
|
||||
Wallet: true,
|
||||
Path: pathDefaultWallet,
|
||||
Name: walletAccountDefaultName,
|
||||
AddressWasNotShown: !input.restoringAccount,
|
||||
}
|
||||
|
||||
if mnemonic == "" {
|
||||
walletAccount.AddressWasNotShown = true
|
||||
}
|
||||
|
||||
chatDerivedAccount := derivedAddresses[pathDefaultChat]
|
||||
chatDerivedAccount := input.derivedAddresses[pathDefaultChat]
|
||||
chatAccount := &accounts.Account{
|
||||
PublicKey: types.Hex2Bytes(chatDerivedAccount.PublicKey),
|
||||
KeyUID: keyUID,
|
||||
KeyUID: input.keyUID,
|
||||
Address: types.HexToAddress(chatDerivedAccount.Address),
|
||||
Name: request.DisplayName,
|
||||
Chat: true,
|
||||
|
@ -1515,14 +1638,40 @@ func (b *GethStatusBackend) prepareSubAccounts(mnemonic, keyUID string, derivedA
|
|||
return []*accounts.Account{walletAccount, chatAccount}, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) getDerivedAddresses(id string) (map[string]generator.AccountInfo, error) {
|
||||
accountGenerator := b.accountManager.AccountsGenerator()
|
||||
derivedAddresses, err := accountGenerator.DeriveAddresses(id, paths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func (b *GethStatusBackend) prepareForKeycard(request *requests.CreateAccount, input *prepareAccountInput, response *accountBundle) (*accountBundle, error) {
|
||||
if request.KeycardInstanceUID == "" {
|
||||
return response, nil
|
||||
}
|
||||
|
||||
return derivedAddresses, nil
|
||||
kp := wallet.NewKeycardPairings()
|
||||
kp.SetKeycardPairingsFile(response.nodeConfig.KeycardPairingDataFile)
|
||||
pairings, err := kp.GetPairings()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to get keycard pairings")
|
||||
}
|
||||
|
||||
keycard, ok := pairings[request.KeycardInstanceUID]
|
||||
if !ok {
|
||||
return nil, errors.New("keycard not found in pairings file")
|
||||
}
|
||||
|
||||
response.settings.KeycardInstanceUID = request.KeycardInstanceUID
|
||||
response.settings.KeycardPairedOn = time.Now().Unix()
|
||||
response.settings.KeycardPairing = keycard.Key
|
||||
response.account.KeycardPairing = keycard.Key
|
||||
|
||||
privateKeyHex := strings.TrimPrefix(input.derivedAddresses[pathDefaultChat].PrivateKey, "0x")
|
||||
response.chatPrivateKey, err = crypto.HexToECDSA(privateKeyHex)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to parse chat private key hex")
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) getDerivedAddresses(id string) (map[string]generator.AccountInfo, error) {
|
||||
accountGenerator := b.accountManager.AccountsGenerator()
|
||||
return accountGenerator.DeriveAddresses(id, paths)
|
||||
}
|
||||
|
||||
// CreateAccountAndLogin creates a new account and logs in with it.
|
||||
|
@ -1535,18 +1684,26 @@ func (b *GethStatusBackend) CreateAccountAndLogin(request *requests.CreateAccoun
|
|||
return nil, err
|
||||
}
|
||||
|
||||
account, settings, nodeConfig, subAccounts, err := b.generateOrImportAccount("", 1, false, request, opts...)
|
||||
response, err := b.generateOrImportAccount("", 1, false, request, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = b.StartNodeWithAccountAndInitialConfig(*account, request.Password, *settings, nodeConfig, subAccounts)
|
||||
err = b.StartNodeWithAccountAndInitialConfig(
|
||||
*response.account,
|
||||
request.Password,
|
||||
*response.settings,
|
||||
response.nodeConfig,
|
||||
response.subAccounts,
|
||||
response.chatPrivateKey,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
b.log.Error("start node", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return account, nil
|
||||
return response.account, nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPassword string, newPassword string) error {
|
||||
|
@ -1708,7 +1865,15 @@ func enrichMultiAccountByPublicKey(account *multiaccounts.Account, publicKey typ
|
|||
return nil
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) SaveAccountAndStartNodeWithKey(account multiaccounts.Account, password string, settings settings.Settings, nodecfg *params.NodeConfig, subaccs []*accounts.Account, keyHex string) error {
|
||||
// Deprecated: Use CreateAccountAndLogin instead
|
||||
func (b *GethStatusBackend) SaveAccountAndStartNodeWithKey(
|
||||
account multiaccounts.Account,
|
||||
password string,
|
||||
settings settings.Settings,
|
||||
nodecfg *params.NodeConfig,
|
||||
subaccs []*accounts.Account,
|
||||
keyHex string,
|
||||
) error {
|
||||
err := enrichMultiAccountBySubAccounts(&account, subaccs)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1731,15 +1896,15 @@ func (b *GethStatusBackend) SaveAccountAndStartNodeWithKey(account multiaccounts
|
|||
// StartNodeWithAccountAndInitialConfig is used after account and config was generated.
|
||||
// In current setup account name and config is generated on the client side. Once/if it will be generated on
|
||||
// status-go side this flow can be simplified.
|
||||
// TODO: Consider passing accountBundle here directly
|
||||
func (b *GethStatusBackend) StartNodeWithAccountAndInitialConfig(
|
||||
account multiaccounts.Account,
|
||||
password string,
|
||||
settings settings.Settings,
|
||||
nodecfg *params.NodeConfig,
|
||||
subaccs []*accounts.Account,
|
||||
chatKey *ecdsa.PrivateKey,
|
||||
) error {
|
||||
b.log.Info("node config", "config", nodecfg)
|
||||
|
||||
err := enrichMultiAccountBySubAccounts(&account, subaccs)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1756,7 +1921,7 @@ func (b *GethStatusBackend) StartNodeWithAccountAndInitialConfig(
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return b.StartNodeWithAccount(account, password, nodecfg)
|
||||
return b.StartNodeWithAccount(account, password, nodecfg, chatKey)
|
||||
}
|
||||
|
||||
// TODO: change in `saveAccountsAndSettings` function param `subaccs []*accounts.Account` parameter to `profileKeypair *accounts.Keypair` parameter
|
||||
|
|
|
@ -22,6 +22,8 @@ import (
|
|||
"github.com/status-im/status-go/protocol/requests"
|
||||
"github.com/status-im/status-go/protocol/tt"
|
||||
"github.com/status-im/status-go/services/utils"
|
||||
"github.com/status-im/status-go/signal"
|
||||
tutils "github.com/status-im/status-go/t/utils"
|
||||
"github.com/status-im/status-go/wakuv2"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -29,6 +31,7 @@ import (
|
|||
|
||||
type MessengerRawMessageResendTest struct {
|
||||
suite.Suite
|
||||
logger *zap.Logger
|
||||
aliceBackend *GethStatusBackend
|
||||
bobBackend *GethStatusBackend
|
||||
aliceMessenger *protocol.Messenger
|
||||
|
@ -43,9 +46,14 @@ func TestMessengerRawMessageResendTestSuite(t *testing.T) {
|
|||
}
|
||||
|
||||
func (s *MessengerRawMessageResendTest) SetupTest() {
|
||||
logger, err := zap.NewDevelopment()
|
||||
tutils.Init()
|
||||
|
||||
var err error
|
||||
s.logger, err = zap.NewDevelopment()
|
||||
s.Require().NoError(err)
|
||||
|
||||
signal.SetMobileSignalHandler(nil)
|
||||
|
||||
exchangeNodeConfig := &wakuv2.Config{
|
||||
Port: 0,
|
||||
EnableDiscV5: true,
|
||||
|
@ -54,7 +62,7 @@ func (s *MessengerRawMessageResendTest) SetupTest() {
|
|||
UseShardAsDefaultTopic: true,
|
||||
DefaultShardPubsubTopic: shard.DefaultShardPubsubTopic(),
|
||||
}
|
||||
s.exchangeBootNode, err = wakuv2.New(nil, "", exchangeNodeConfig, logger.Named("pxServerNode"), nil, nil, nil, nil)
|
||||
s.exchangeBootNode, err = wakuv2.New(nil, "", exchangeNodeConfig, s.logger.Named("pxServerNode"), nil, nil, nil, nil)
|
||||
s.Require().NoError(err)
|
||||
s.Require().NoError(s.exchangeBootNode.Start())
|
||||
|
||||
|
|
|
@ -449,7 +449,7 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
|||
|
||||
fmt.Println(nodeConfig)
|
||||
accounts := []*accounts.Account{walletAccount, chatAccount}
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts)
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts, nil)
|
||||
if err != nil {
|
||||
logger.Error("start node", err)
|
||||
return err
|
||||
|
|
|
@ -498,7 +498,7 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
|||
|
||||
fmt.Println(nodeConfig)
|
||||
accounts := []*accounts.Account{walletAccount, chatAccount}
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts)
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts, nil)
|
||||
if err != nil {
|
||||
logger.Error("start node", err)
|
||||
return err
|
||||
|
|
|
@ -420,9 +420,9 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
|||
fmt.Println(nodeConfig)
|
||||
accounts := []*accounts.Account{walletAccount, chatAccount}
|
||||
if !exist {
|
||||
return backend.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts)
|
||||
return backend.StartNodeWithAccountAndInitialConfig(account, "", *settings, nodeConfig, accounts, nil)
|
||||
}
|
||||
return backend.StartNodeWithAccount(account, "", nodeConfig)
|
||||
return backend.StartNodeWithAccount(account, "", nodeConfig, nil)
|
||||
}
|
||||
|
||||
func retrieveMessagesLoop(messenger *protocol.Messenger, tick time.Duration) {
|
||||
|
|
|
@ -18,7 +18,7 @@ type Key struct {
|
|||
// ExtendedKey is the extended key of the PrivateKey itself, and it's used
|
||||
// to derive child keys.
|
||||
ExtendedKey *extkeys.ExtendedKey
|
||||
// SubAccountIndex is DEPRECATED
|
||||
// Deprecated: SubAccountIndex
|
||||
// It was use in Status to keep track of the number of sub-account created
|
||||
// before having multi-account support.
|
||||
SubAccountIndex uint32
|
||||
|
|
|
@ -237,7 +237,7 @@ func login(accountData, password, configJSON string) error {
|
|||
return statusBackend.LoggedIn(account.KeyUID, err)
|
||||
}
|
||||
|
||||
err = statusBackend.StartNodeWithAccount(account, password, &conf)
|
||||
err = statusBackend.StartNodeWithAccount(account, password, &conf, nil)
|
||||
if err != nil {
|
||||
log.Error("failed to start a node", "key-uid", account.KeyUID, "error", err)
|
||||
return err
|
||||
|
@ -339,7 +339,13 @@ func RestoreAccountAndLogin(requestJSON string) string {
|
|||
|
||||
api.RunAsync(func() error {
|
||||
log.Debug("starting a node and restoring account")
|
||||
_, err := statusBackend.RestoreAccountAndLogin(&request)
|
||||
|
||||
if request.Keycard != nil {
|
||||
_, err = statusBackend.RestoreKeycardAccountAndLogin(&request)
|
||||
} else {
|
||||
_, err = statusBackend.RestoreAccountAndLogin(&request)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Error("failed to restore account", "error", err)
|
||||
return err
|
||||
|
@ -347,6 +353,7 @@ func RestoreAccountAndLogin(requestJSON string) string {
|
|||
log.Debug("started a node, and restored account")
|
||||
return nil
|
||||
})
|
||||
|
||||
return makeJSONResponse(nil)
|
||||
}
|
||||
|
||||
|
@ -382,7 +389,7 @@ func SaveAccountAndLogin(accountData, password, settingsJSON, configJSON, subacc
|
|||
|
||||
api.RunAsync(func() error {
|
||||
log.Debug("starting a node, and saving account with configuration", "key-uid", account.KeyUID)
|
||||
err := statusBackend.StartNodeWithAccountAndInitialConfig(account, password, settings, &conf, subaccs)
|
||||
err := statusBackend.StartNodeWithAccountAndInitialConfig(account, password, settings, &conf, subaccs, nil)
|
||||
if err != nil {
|
||||
log.Error("failed to start node and save account", "key-uid", account.KeyUID, "error", err)
|
||||
return err
|
||||
|
@ -419,7 +426,8 @@ func InitKeystore(keydir string) string {
|
|||
return makeJSONResponse(err)
|
||||
}
|
||||
|
||||
// SaveAccountAndLoginWithKeycard saves account in status-go database..
|
||||
// SaveAccountAndLoginWithKeycard saves account in status-go database.
|
||||
// Deprecated: Use CreateAndAccountAndLogin with required keycard properties.
|
||||
func SaveAccountAndLoginWithKeycard(accountData, password, settingsJSON, configJSON, subaccountData string, keyHex string) string {
|
||||
var account multiaccounts.Account
|
||||
err := json.Unmarshal([]byte(accountData), &account)
|
||||
|
@ -457,6 +465,7 @@ func SaveAccountAndLoginWithKeycard(accountData, password, settingsJSON, configJ
|
|||
|
||||
// LoginWithKeycard initializes an account with a chat key and encryption key used for PFS.
|
||||
// It purges all the previous identities from Whisper, and injects the key as shh identity.
|
||||
// Deprecated: Use LoginAccount instead.
|
||||
func LoginWithKeycard(accountData, password, keyHex string, configJSON string) string {
|
||||
var account multiaccounts.Account
|
||||
err := json.Unmarshal([]byte(accountData), &account)
|
||||
|
|
|
@ -328,6 +328,9 @@ type NodeConfig struct {
|
|||
KeyStoreDir string `validate:"required"`
|
||||
|
||||
// KeycardPairingDataFile is the file where we keep keycard pairings data.
|
||||
// It's specified by clients (and not in status-go) when creating a new account,
|
||||
// because this file is initialized by status-keycard-go and we need to use it before initializing the node.
|
||||
// I guess proper way would be to ask status-go for the file path, or just duplicate the file path in both backend and client.
|
||||
// note: this field won't be saved into db, it's local to the device.
|
||||
KeycardPairingDataFile string
|
||||
|
||||
|
|
|
@ -74,6 +74,9 @@ type CreateAccount struct {
|
|||
TelemetryServerURL string `json:"telemetryServerURL"`
|
||||
|
||||
APIConfig *APIConfig `json:"apiConfig"`
|
||||
|
||||
KeycardInstanceUID string `json:"keycardInstanceUID"`
|
||||
KeycardPairingDataFile *string `json:"keycardPairingDataFile"`
|
||||
}
|
||||
|
||||
type WalletSecretsConfig struct {
|
||||
|
|
|
@ -1,18 +1,38 @@
|
|||
package requests
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
var ErrLoginInvalidKeyUID = errors.New("login: invalid key-uid")
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrLoginInvalidKeyUID = errors.New("login: invalid key-uid")
|
||||
ErrLoginInvalidKeycardWhisperPrivateKey = errors.New("login: invalid keycard whisper private key")
|
||||
)
|
||||
|
||||
type Login struct {
|
||||
Password string `json:"password"`
|
||||
KeyUID string `json:"keyUid"`
|
||||
|
||||
KdfIterations int `json:"kdfIterations"`
|
||||
KdfIterations int `json:"kdfIterations"` // FIXME: KdfIterations should be loaded from multiaccounts db.
|
||||
RuntimeLogLevel string `json:"runtimeLogLevel"`
|
||||
WakuV2Nameserver string `json:"wakuV2Nameserver"`
|
||||
BandwidthStatsEnabled bool `json:"bandwidthStatsEnabled"`
|
||||
|
||||
KeycardWhisperPrivateKey string `json:"keycardWhisperPrivateKey"`
|
||||
|
||||
// Mnemonic allows to log in to an account when password is lost.
|
||||
// This is needed for the "Lost keycard -> Start using without keycard" flow, when a keycard account database
|
||||
// exists locally, but now the keycard is lost. In this case client is responsible for calling
|
||||
// `convertToRegularAccount` after a successful login. This could be improved in the future.
|
||||
// When non-empty, mnemonic is used to generate required keypairs and:
|
||||
// - Password is ignored and replaced with encryption public key
|
||||
// - KeycardWhisperPrivateKey is ignored and replaced with chat private key
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
|
||||
WalletSecretsConfig
|
||||
}
|
||||
|
||||
|
@ -20,5 +40,24 @@ func (c *Login) Validate() error {
|
|||
if c.KeyUID == "" {
|
||||
return ErrLoginInvalidKeyUID
|
||||
}
|
||||
|
||||
if c.KeycardWhisperPrivateKey != "" {
|
||||
_, err := parsePrivateKey(c.KeycardWhisperPrivateKey)
|
||||
if err != nil {
|
||||
return ErrLoginInvalidKeycardWhisperPrivateKey
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Login) ChatPrivateKey() *ecdsa.PrivateKey {
|
||||
// Skip error check, as it's already validated in Validate
|
||||
privateKey, _ := parsePrivateKey(c.KeycardWhisperPrivateKey)
|
||||
return privateKey
|
||||
}
|
||||
|
||||
func parsePrivateKey(privateKeyHex string) (*ecdsa.PrivateKey, error) {
|
||||
privateKeyHex = strings.TrimPrefix(privateKeyHex, "0x")
|
||||
return crypto.HexToECDSA(privateKeyHex)
|
||||
}
|
||||
|
|
|
@ -4,20 +4,46 @@ import (
|
|||
"errors"
|
||||
)
|
||||
|
||||
var ErrRestoreAccountInvalidMnemonic = errors.New("restore-account: invalid mnemonic")
|
||||
var (
|
||||
ErrRestoreAccountInvalidMnemonic = errors.New("restore-account: no mnemonic or keycard is set")
|
||||
ErrRestoreAccountMnemonicAndKeycard = errors.New("restore-account: both mnemonic and keycard info are set")
|
||||
)
|
||||
|
||||
type RestoreAccount struct {
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
FetchBackup bool `json:"fetchBackup"`
|
||||
Mnemonic string `json:"mnemonic"`
|
||||
|
||||
// Keycard info can be set instead of Mnemonic.
|
||||
// This is to log in using a keycard with existing account.
|
||||
Keycard *KeycardData `json:"keycard"`
|
||||
|
||||
FetchBackup bool `json:"fetchBackup"`
|
||||
|
||||
CreateAccount
|
||||
}
|
||||
|
||||
func (c *RestoreAccount) Validate() error {
|
||||
if len(c.Mnemonic) == 0 {
|
||||
if len(c.Mnemonic) == 0 && c.Keycard == nil {
|
||||
return ErrRestoreAccountInvalidMnemonic
|
||||
}
|
||||
|
||||
if len(c.Mnemonic) > 0 && c.Keycard != nil {
|
||||
return ErrRestoreAccountMnemonicAndKeycard
|
||||
}
|
||||
|
||||
return c.CreateAccount.Validate(&CreateAccountValidation{
|
||||
AllowEmptyDisplayName: true,
|
||||
})
|
||||
}
|
||||
|
||||
type KeycardData struct {
|
||||
KeyUID string `json:"keyUID"`
|
||||
Address string `json:"address"`
|
||||
WhisperPrivateKey string `json:"whisperPrivateKey"`
|
||||
WhisperPublicKey string `json:"whisperPublicKey"`
|
||||
WhisperAddress string `json:"whisperAddress"`
|
||||
WalletPublicKey string `json:"walletPublicKey"`
|
||||
WalletAddress string `json:"walletAddress"`
|
||||
WalletRootAddress string `json:"walletRootAddress"`
|
||||
Eip1581Address string `json:"eip1581Address"`
|
||||
EncryptionPublicKey string `json:"encryptionPublicKey"`
|
||||
}
|
||||
|
|
|
@ -2,8 +2,12 @@ package pairing
|
|||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"github.com/status-im/status-go/api"
|
||||
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||
|
@ -93,12 +97,18 @@ func (s *SyncRawMessageHandler) HandleRawMessage(accountPayload *AccountPayload,
|
|||
// because client don't know keyUID before received data, we need help client to update keystore dir
|
||||
keystoreDir := filepath.Join(nodeConfig.KeyStoreDir, account.KeyUID)
|
||||
nodeConfig.KeyStoreDir = keystoreDir
|
||||
if accountPayload.exist {
|
||||
if len(accountPayload.chatKey) == 0 {
|
||||
err = s.backend.StartNodeWithAccount(*account, accountPayload.password, nodeConfig)
|
||||
} else {
|
||||
err = s.backend.StartNodeWithKey(*account, accountPayload.password, accountPayload.chatKey, nodeConfig)
|
||||
|
||||
var chatKey *ecdsa.PrivateKey
|
||||
if accountPayload.chatKey != "" {
|
||||
chatKeyHex := strings.Trim(accountPayload.chatKey, "0x")
|
||||
chatKey, err = ethcrypto.HexToECDSA(chatKeyHex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if accountPayload.exist {
|
||||
err = s.backend.StartNodeWithAccount(*account, accountPayload.password, nodeConfig, chatKey)
|
||||
} else {
|
||||
accountManager := s.backend.AccountManager()
|
||||
err = accountManager.InitKeystore(filepath.Join(nodeConfig.RootDataDir, keystoreDir))
|
||||
|
@ -109,11 +119,7 @@ func (s *SyncRawMessageHandler) HandleRawMessage(accountPayload *AccountPayload,
|
|||
rmp.setting.InstallationID = nodeConfig.ShhextConfig.InstallationID
|
||||
rmp.setting.CurrentNetwork = settingCurrentNetwork
|
||||
|
||||
if len(accountPayload.chatKey) == 0 {
|
||||
err = s.backend.StartNodeWithAccountAndInitialConfig(*account, accountPayload.password, *rmp.setting, nodeConfig, rmp.profileKeypair.Accounts)
|
||||
} else {
|
||||
err = s.backend.SaveAccountAndStartNodeWithKey(*account, accountPayload.password, *rmp.setting, nodeConfig, rmp.profileKeypair.Accounts, accountPayload.chatKey)
|
||||
}
|
||||
err = s.backend.StartNodeWithAccountAndInitialConfig(*account, accountPayload.password, *rmp.setting, nodeConfig, rmp.profileKeypair.Accounts, chatKey)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -140,7 +140,7 @@ func (s *SyncDeviceSuite) prepareBackendWithAccount(mnemonic, tmpdir string) *ap
|
|||
}
|
||||
|
||||
accounts := []*accounts.Account{walletAccount, chatAccount}
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, s.password, *settings, nodeConfig, accounts)
|
||||
err = backend.StartNodeWithAccountAndInitialConfig(account, s.password, *settings, nodeConfig, accounts, nil)
|
||||
require.NoError(s.T(), err)
|
||||
multiaccounts, err := backend.GetAccounts()
|
||||
require.NoError(s.T(), err)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package wallet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -10,6 +11,11 @@ type KeycardPairings struct {
|
|||
pairingsFile string
|
||||
}
|
||||
|
||||
type KeycardPairing struct {
|
||||
Key string `json:"key"`
|
||||
Index int `json:"index"`
|
||||
}
|
||||
|
||||
func NewKeycardPairings() *KeycardPairings {
|
||||
return &KeycardPairings{}
|
||||
}
|
||||
|
@ -43,3 +49,22 @@ func (kp *KeycardPairings) SetPairingsJSONFileContent(content []byte) error {
|
|||
|
||||
return ioutil.WriteFile(kp.pairingsFile, content, 0600)
|
||||
}
|
||||
|
||||
func (kp *KeycardPairings) GetPairings() (map[string]KeycardPairing, error) {
|
||||
content, err := kp.GetPairingsJSONFileContent()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(content) == 0 {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
pairings := make(map[string]KeycardPairing)
|
||||
err = json.Unmarshal(content, &pairings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pairings, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue