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:
Sale Djenic 2023-01-26 21:03:01 +01:00 committed by saledjenic
parent 6e656448ba
commit c8994fe175
5 changed files with 157 additions and 116 deletions

View File

@ -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)
} }

View File

@ -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,
&params.NodeConfig{}, &params.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) {

View File

@ -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
} }

View File

@ -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)
} }

View File

@ -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
} }