test: `TestConvertAccount` test update
This tests the entire process of converting a regular account to a keycard account and then converting that keycard account back to a regular account. For the need of this test I had to improve `DeleteAccount` function, cause the previous implementation didn't remove account from the keystore cache, but only from the keystore.
This commit is contained in:
parent
6e656448ba
commit
c8994fe175
|
@ -8,7 +8,6 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
@ -607,47 +606,6 @@ func (m *Manager) ReEncryptKeyStoreDir(keyDirPath, oldPass, newPass string) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) DeleteAccount(keyDirPath string, address types.Address, ignoreCase bool) error {
|
func (m *Manager) DeleteAccount(address types.Address, password string) error {
|
||||||
var err error
|
return m.keystore.Delete(types.Account{Address: address}, password)
|
||||||
var foundKeyFile string
|
|
||||||
err = filepath.Walk(keyDirPath, func(path string, fileInfo os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if len(foundKeyFile) > 0 || fileInfo.IsDir() {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
rawKeyFile, e := ioutil.ReadFile(path)
|
|
||||||
if e != nil {
|
|
||||||
return fmt.Errorf("invalid account key file: %v", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
var accountKey struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
}
|
|
||||||
if e := json.Unmarshal(rawKeyFile, &accountKey); e != nil {
|
|
||||||
return fmt.Errorf("failed to read key file: %s", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
if ignoreCase {
|
|
||||||
if strings.EqualFold("0x"+accountKey.Address, address.String()) {
|
|
||||||
foundKeyFile = path
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if types.HexToAddress("0x"+accountKey.Address).Hex() == address.Hex() {
|
|
||||||
foundKeyFile = path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("cannot traverse key store folder: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(foundKeyFile) == 0 {
|
|
||||||
return ErrCannotLocateKeyFile{fmt.Sprintf("cannot locate account for address: %s", address.Hex())}
|
|
||||||
}
|
|
||||||
return os.Remove(foundKeyFile)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -614,46 +614,125 @@ func TestDeleteMultiaccount(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConvertAccount(t *testing.T) {
|
func TestConvertAccount(t *testing.T) {
|
||||||
backend := NewGethStatusBackend()
|
const mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
|
||||||
password := "123123"
|
const password = "111111" // represents password for a regular user
|
||||||
|
const keycardPassword = "222222" // represents password for a keycard user
|
||||||
|
const pathMaster = "m"
|
||||||
|
const pathWalletRoot = "m/44'/60'/0'/0"
|
||||||
|
const pathEIP1581Root = "m/43'/60'/1581'"
|
||||||
|
const pathEIP1581Chat = "m/43'/60'/1581'/0/0"
|
||||||
|
const pathDefaultWalletAccount = "m/44'/60'/0'/0/0"
|
||||||
|
const customWalletPath1 = "m/44'/60'/0'/0/1"
|
||||||
|
const customWalletPath2 = "m/44'/60'/0'/0/2"
|
||||||
|
var allGeneratedPaths []string
|
||||||
|
allGeneratedPaths = append(allGeneratedPaths, customWalletPath1, customWalletPath2, pathWalletRoot, pathEIP1581Root, pathDefaultWalletAccount)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
keystoreContainsFileForAccount := func(keyStoreDir string, hexAddress string) bool {
|
||||||
|
addrWithoutPrefix := strings.ToLower(hexAddress[2:])
|
||||||
|
found := false
|
||||||
|
err = filepath.Walk(keyStoreDir, func(path string, fileInfo os.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !fileInfo.IsDir() && strings.Contains(strings.ToUpper(path), strings.ToUpper(addrWithoutPrefix)) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
return found
|
||||||
|
}
|
||||||
|
|
||||||
rootDataDir, err := os.MkdirTemp("", "test-keystore-dir")
|
rootDataDir, err := os.MkdirTemp("", "test-keystore-dir")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.Remove(rootDataDir)
|
defer os.Remove(rootDataDir)
|
||||||
|
|
||||||
keyStoreDir := filepath.Join(rootDataDir, "keystore")
|
keyStoreDir := filepath.Join(rootDataDir, "keystore")
|
||||||
|
|
||||||
|
utils.Init()
|
||||||
|
backend := NewGethStatusBackend()
|
||||||
backend.rootDataDir = rootDataDir
|
backend.rootDataDir = rootDataDir
|
||||||
|
config, err := utils.MakeTestNodeConfig(params.StatusChainNetworkID)
|
||||||
err = backend.AccountManager().InitKeystore(keyStoreDir)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
config.DataDir = rootDataDir
|
||||||
const path = "m/44'/60'/0'/0"
|
config.KeyStoreDir = keyStoreDir
|
||||||
backend.AccountManager()
|
require.NoError(t, backend.AccountManager().InitKeystore(config.KeyStoreDir))
|
||||||
accs, err := backend.AccountManager().
|
err = backend.StartNode(config)
|
||||||
AccountsGenerator().
|
|
||||||
GenerateAndDeriveAddresses(12, 1, "", []string{path})
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
defer func() {
|
||||||
|
require.NoError(t, backend.StopNode())
|
||||||
|
}()
|
||||||
|
|
||||||
generateAccount := accs[0]
|
genAccInfo, err := backend.AccountManager().AccountsGenerator().ImportMnemonic(mnemonic, "")
|
||||||
accountInfo, err := backend.AccountManager().
|
assert.NoError(t, err)
|
||||||
AccountsGenerator().
|
|
||||||
StoreAccount(generateAccount.ID, password)
|
accountInfo, err := backend.AccountManager().AccountsGenerator().StoreAccount(genAccInfo.ID, password)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
found := keystoreContainsFileForAccount(keyStoreDir, accountInfo.Address)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
require.True(t, found)
|
||||||
|
|
||||||
|
derivedAccounts, err := backend.AccountManager().AccountsGenerator().StoreDerivedAccounts(genAccInfo.ID, password, allGeneratedPaths)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
accs, err := backend.AccountManager().AccountsGenerator().DeriveAddresses(genAccInfo.ID, []string{pathMaster})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, 1, len(accs))
|
||||||
|
masterAddress := accs[pathMaster].Address
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, masterAddress)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, found)
|
||||||
|
|
||||||
|
var accountsToStore []*accounts.Account
|
||||||
|
accountsToStore = append(accountsToStore, &accounts.Account{
|
||||||
|
Address: types.HexToAddress(masterAddress),
|
||||||
|
KeyUID: genAccInfo.KeyUID,
|
||||||
|
Type: accounts.AccountTypeGenerated,
|
||||||
|
PublicKey: types.Hex2Bytes(accountInfo.PublicKey),
|
||||||
|
Path: pathEIP1581Chat,
|
||||||
|
Wallet: false,
|
||||||
|
Chat: false,
|
||||||
|
Name: "GeneratedAccount",
|
||||||
|
})
|
||||||
|
|
||||||
|
for p, dAccInfo := range derivedAccounts {
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, found)
|
||||||
|
|
||||||
|
if p == pathDefaultWalletAccount ||
|
||||||
|
p == customWalletPath1 ||
|
||||||
|
p == customWalletPath2 {
|
||||||
|
accountsToStore = append(accountsToStore, &accounts.Account{
|
||||||
|
Address: types.HexToAddress(dAccInfo.Address),
|
||||||
|
KeyUID: genAccInfo.KeyUID,
|
||||||
|
Wallet: false,
|
||||||
|
Chat: false,
|
||||||
|
Path: p,
|
||||||
|
Name: "derivacc" + p,
|
||||||
|
Hidden: false,
|
||||||
|
DerivedFrom: masterAddress,
|
||||||
|
Removed: false,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
account := multiaccounts.Account{
|
account := multiaccounts.Account{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Timestamp: 1,
|
Timestamp: 1,
|
||||||
KeyUID: generateAccount.KeyUID,
|
KeyUID: genAccInfo.KeyUID,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = backend.ensureAppDBOpened(account, password)
|
err = backend.ensureAppDBOpened(account, password)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
s := settings.Settings{
|
s := settings.Settings{
|
||||||
Address: types.HexToAddress(accountInfo.Address),
|
Address: types.HexToAddress(masterAddress),
|
||||||
CurrentNetwork: "mainnet_rpc",
|
CurrentNetwork: "mainnet_rpc",
|
||||||
DappsAddress: types.HexToAddress(accountInfo.Address),
|
DappsAddress: types.HexToAddress(derivedAccounts[pathDefaultWalletAccount].Address),
|
||||||
EIP1581Address: types.HexToAddress(accountInfo.Address),
|
EIP1581Address: types.HexToAddress(derivedAccounts[pathEIP1581Root].Address),
|
||||||
InstallationID: "d3efcff6-cffa-560e-a547-21d3858cbc51",
|
InstallationID: "d3efcff6-cffa-560e-a547-21d3858cbc51",
|
||||||
KeyUID: account.KeyUID,
|
KeyUID: account.KeyUID,
|
||||||
LatestDerivedPath: 0,
|
LatestDerivedPath: 0,
|
||||||
|
@ -663,24 +742,13 @@ func TestConvertAccount(t *testing.T) {
|
||||||
PreviewPrivacy: false,
|
PreviewPrivacy: false,
|
||||||
PublicKey: accountInfo.PublicKey,
|
PublicKey: accountInfo.PublicKey,
|
||||||
SigningPhrase: "yurt joey vibe",
|
SigningPhrase: "yurt joey vibe",
|
||||||
WalletRootAddress: types.HexToAddress(accountInfo.Address)}
|
WalletRootAddress: types.HexToAddress(derivedAccounts[pathWalletRoot].Address),
|
||||||
|
|
||||||
acc := accounts.Account{
|
|
||||||
Address: types.HexToAddress(generateAccount.Address),
|
|
||||||
KeyUID: generateAccount.KeyUID,
|
|
||||||
Type: accounts.AccountTypeGenerated,
|
|
||||||
PublicKey: types.Hex2Bytes(generateAccount.PublicKey),
|
|
||||||
Path: path,
|
|
||||||
Wallet: false,
|
|
||||||
Chat: false,
|
|
||||||
Name: "GeneratedAccount",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accounts := []*accounts.Account{&acc}
|
|
||||||
err = backend.saveAccountsAndSettings(
|
err = backend.saveAccountsAndSettings(
|
||||||
s,
|
s,
|
||||||
¶ms.NodeConfig{},
|
¶ms.NodeConfig{},
|
||||||
accounts)
|
accountsToStore)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = backend.OpenAccounts()
|
err = backend.OpenAccounts()
|
||||||
|
@ -693,8 +761,6 @@ func TestConvertAccount(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEqual(t, 3, len(files))
|
require.NotEqual(t, 3, len(files))
|
||||||
|
|
||||||
keycardPassword := "0xcafecafe"
|
|
||||||
|
|
||||||
keycardAccount := account
|
keycardAccount := account
|
||||||
keycardAccount.KeycardPairing = "pairing"
|
keycardAccount.KeycardPairing = "pairing"
|
||||||
|
|
||||||
|
@ -704,42 +770,59 @@ func TestConvertAccount(t *testing.T) {
|
||||||
KeycardPairing: "pairing",
|
KeycardPairing: "pairing",
|
||||||
}
|
}
|
||||||
|
|
||||||
addrWithoutPrefix := strings.ToLower(generateAccount.Address[2:len(generateAccount.Address)])
|
// Converting to a keycard account
|
||||||
found := false
|
err = backend.ConvertToKeycardAccount(keycardAccount, keycardSettings, password, keycardPassword)
|
||||||
err = filepath.Walk(keyStoreDir, func(path string, fileInfo os.FileInfo, err error) error {
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !fileInfo.IsDir() && strings.Contains(path, addrWithoutPrefix) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.True(t, found)
|
|
||||||
|
|
||||||
err = backend.ConvertToKeycardAccount(keyStoreDir, keycardAccount, keycardSettings, password, keycardPassword)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = filepath.Walk(keyStoreDir, func(path string, fileInfo os.FileInfo, err error) error {
|
// Validating results of converting to a keycard account.
|
||||||
if err != nil {
|
// All keystore files for the account which is migrated need to be removed.
|
||||||
return err
|
found = keystoreContainsFileForAccount(keyStoreDir, accountInfo.Address)
|
||||||
}
|
|
||||||
if !fileInfo.IsDir() && strings.Contains(path, addrWithoutPrefix) {
|
|
||||||
found = false
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, found)
|
require.False(t, found)
|
||||||
|
|
||||||
|
for _, dAccInfo := range derivedAccounts {
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, found)
|
||||||
|
}
|
||||||
|
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, masterAddress)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, found)
|
||||||
|
|
||||||
|
// Ensure we're able to open the DB
|
||||||
err = backend.ensureAppDBOpened(keycardAccount, keycardPassword)
|
err = backend.ensureAppDBOpened(keycardAccount, keycardPassword)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
b := NewGethStatusBackend()
|
b1 := NewGethStatusBackend()
|
||||||
require.NoError(t, b.OpenAccounts())
|
require.NoError(t, b1.OpenAccounts())
|
||||||
|
|
||||||
|
// Converting to a regular account
|
||||||
|
err = backend.ConvertToRegularAccount(mnemonic, keycardPassword, password)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Validating results of converting to a regular account.
|
||||||
|
// All keystore files for need to be created.
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, accountInfo.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, found)
|
||||||
|
|
||||||
|
for _, dAccInfo := range derivedAccounts {
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, dAccInfo.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, found)
|
||||||
|
}
|
||||||
|
|
||||||
|
found = keystoreContainsFileForAccount(keyStoreDir, masterAddress)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, found)
|
||||||
|
|
||||||
|
// Ensure we're able to open the DB
|
||||||
|
err = backend.ensureAppDBOpened(keycardAccount, password)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
b2 := NewGethStatusBackend()
|
||||||
|
require.NoError(t, b2.OpenAccounts())
|
||||||
}
|
}
|
||||||
|
|
||||||
func copyFile(srcFolder string, dstFolder string, fileName string, t *testing.T) {
|
func copyFile(srcFolder string, dstFolder string, fileName string, t *testing.T) {
|
||||||
|
|
|
@ -564,7 +564,7 @@ func (b *GethStatusBackend) ChangeDatabasePassword(keyUID string, password strin
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) ConvertToKeycardAccount(keyStoreDir string, account multiaccounts.Account, s settings.Settings, password string, newPassword string) error {
|
func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Account, s settings.Settings, password string, newPassword string) error {
|
||||||
err := b.multiaccountsDB.UpdateAccountKeycardPairing(account.KeyUID, account.KeycardPairing)
|
err := b.multiaccountsDB.UpdateAccountKeycardPairing(account.KeyUID, account.KeycardPairing)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -639,13 +639,13 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(keyStoreDir string, account
|
||||||
// whichever reason the account is still successfully migrated
|
// whichever reason the account is still successfully migrated
|
||||||
for _, acc := range knownAccounts {
|
for _, acc := range knownAccounts {
|
||||||
if account.KeyUID == acc.KeyUID {
|
if account.KeyUID == acc.KeyUID {
|
||||||
_ = b.accountManager.DeleteAccount(keyStoreDir, acc.Address, true)
|
_ = b.accountManager.DeleteAccount(acc.Address, newPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = b.accountManager.DeleteAccount(keyStoreDir, masterAddress, true)
|
_ = b.accountManager.DeleteAccount(masterAddress, newPassword)
|
||||||
_ = b.accountManager.DeleteAccount(keyStoreDir, dappsAddress, true)
|
_ = b.accountManager.DeleteAccount(dappsAddress, newPassword)
|
||||||
_ = b.accountManager.DeleteAccount(keyStoreDir, eip1581Address, true)
|
_ = b.accountManager.DeleteAccount(eip1581Address, newPassword)
|
||||||
_ = b.accountManager.DeleteAccount(keyStoreDir, walletRootAddress, true)
|
_ = b.accountManager.DeleteAccount(walletRootAddress, newPassword)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -828,7 +828,7 @@ func ChangeDatabasePassword(KeyUID, password, newPassword string) string {
|
||||||
return makeJSONResponse(nil)
|
return makeJSONResponse(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertToKeycardAccount(keyStoreDir, accountData, settingsJSON, password, newPassword string) string {
|
func ConvertToKeycardAccount(accountData, settingsJSON, password, newPassword string) string {
|
||||||
var account multiaccounts.Account
|
var account multiaccounts.Account
|
||||||
err := json.Unmarshal([]byte(accountData), &account)
|
err := json.Unmarshal([]byte(accountData), &account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -840,7 +840,7 @@ func ConvertToKeycardAccount(keyStoreDir, accountData, settingsJSON, password, n
|
||||||
return makeJSONResponse(err)
|
return makeJSONResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = statusBackend.ConvertToKeycardAccount(keyStoreDir, account, settings, password, newPassword)
|
err = statusBackend.ConvertToKeycardAccount(account, settings, password, newPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return makeJSONResponse(err)
|
return makeJSONResponse(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ func (api *API) DeleteAccount(ctx context.Context, address types.Address) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if acc.Type != accounts.AccountTypeWatch {
|
if acc.Type != accounts.AccountTypeWatch {
|
||||||
err = api.manager.DeleteAccount(api.config.KeyStoreDir, address, true)
|
err = api.manager.DeleteAccount(address, "")
|
||||||
var e *account.ErrCannotLocateKeyFile
|
var e *account.ErrCannotLocateKeyFile
|
||||||
if err != nil && !errors.As(err, &e) {
|
if err != nil && !errors.As(err, &e) {
|
||||||
return err
|
return err
|
||||||
|
@ -444,7 +444,7 @@ func (api *API) AddMigratedKeyPair(ctx context.Context, kcUID string, kpName str
|
||||||
for _, addr := range addresses {
|
for _, addr := range addresses {
|
||||||
// This action deletes an account from the keystore, no need to check for error in this context here, cause if this
|
// This action deletes an account from the keystore, no need to check for error in this context here, cause if this
|
||||||
// action fails from whichever reason the account is still successfully migrated since keystore won't be used any more.
|
// action fails from whichever reason the account is still successfully migrated since keystore won't be used any more.
|
||||||
_ = api.manager.DeleteAccount(keyStoreDir, addr, true)
|
_ = api.manager.DeleteAccount(addr, "")
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue