chore_:Don't rely on the master key when generating accounts (#5279)

* chore_:Don't rely on the master key when generating accounts under the bip 0044 path m/44'/60'/0'/0/0

* fix_: lint issue

* fix_: failed test TestBackendStartNodeConcurrently
This commit is contained in:
frank 2024-06-04 08:57:11 +08:00
parent 71e778507d
commit 763ed552ed
4 changed files with 98 additions and 15 deletions

View File

@ -17,6 +17,9 @@ import (
"testing" "testing"
"time" "time"
"github.com/status-im/status-go/multiaccounts/common"
"github.com/status-im/status-go/protocol/tt"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -63,6 +66,11 @@ var (
WalletRootAddress: types.HexToAddress("0xeB591fd819F86D0A6a2EF2Bcb94f77807a7De1a6")} WalletRootAddress: types.HexToAddress("0xeB591fd819F86D0A6a2EF2Bcb94f77807a7De1a6")}
) )
const (
oldMobileUserKeyUID = "0x855ab0a932e5325daab7a550b9fcd78d2a17de5e2b7a52241f82505ea9d87629"
oldMobileUserPasswd = "0x20756cad9b728c8225fd8cedb6badaf8731e174506950219ea657cd54f35f46c" // #nosec G101
)
func setupTestDB() (*sql.DB, func() error, error) { func setupTestDB() (*sql.DB, func() error, error) {
return helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "tests") return helpers.SetupTestSQLDB(appdatabase.DbInitializer{}, "tests")
} }
@ -1337,14 +1345,11 @@ func loginMobileUser(t *testing.T, rootDataDir string) {
// Wallet: 0, Chat: 0, Type: 'seed', Path: m/44'/60'/0'/0/0, Name: 'seed', Derived_from: '', Pubkey: 0x04FDE3E5... // Wallet: 0, Chat: 0, Type: 'seed', Path: m/44'/60'/0'/0/0, Name: 'seed', Derived_from: '', Pubkey: 0x04FDE3E5...
// seed phrase for 0xB7A1233D1309CE665A3A4DB088E4A046EB333545: vocal blouse script census island armor seek catch wool narrow peasant attract // seed phrase for 0xB7A1233D1309CE665A3A4DB088E4A046EB333545: vocal blouse script census island armor seek catch wool narrow peasant attract
// private key for 0x516312D69737C5E6EF16F22E0097FF5D9F0C4196: c3ad0b50652318f845565c13761e5369ce75dcbc2a94616e15b829d4b07410fe // private key for 0x516312D69737C5E6EF16F22E0097FF5D9F0C4196: c3ad0b50652318f845565c13761e5369ce75dcbc2a94616e15b829d4b07410fe
keyUID := "0x855ab0a932e5325daab7a550b9fcd78d2a17de5e2b7a52241f82505ea9d87629"
passwd := "0x20756cad9b728c8225fd8cedb6badaf8731e174506950219ea657cd54f35f46c" // #nosec G101
b := NewGethStatusBackend() b := NewGethStatusBackend()
b.UpdateRootDataDir(rootDataDir) b.UpdateRootDataDir(rootDataDir)
require.NoError(t, b.OpenAccounts()) require.NoError(t, b.OpenAccounts())
require.NoError(t, b.Login(keyUID, passwd)) require.NoError(t, b.Login(oldMobileUserKeyUID, oldMobileUserPasswd))
db, err := accounts.NewDB(b.appDB) db, err := accounts.NewDB(b.appDB)
require.NoError(t, err) require.NoError(t, err)
accs, err := db.GetAllAccounts() accs, err := db.GetAllAccounts()
@ -1366,7 +1371,7 @@ func loginMobileUser(t *testing.T, rootDataDir string) {
require.True(t, len(profileKps) == 1, "Unexpected number of profile keypairs") require.True(t, len(profileKps) == 1, "Unexpected number of profile keypairs")
require.True(t, len(profileKps[0].Accounts) == 3) require.True(t, len(profileKps[0].Accounts) == 3)
for _, a := range profileKps[0].Accounts { for _, a := range profileKps[0].Accounts {
require.Equal(t, a.KeyUID, keyUID) require.Equal(t, a.KeyUID, oldMobileUserKeyUID)
} }
generator := b.AccountManager().AccountsGenerator() generator := b.AccountManager().AccountsGenerator()
@ -1375,7 +1380,7 @@ func loginMobileUser(t *testing.T, rootDataDir string) {
require.True(t, ok, "Seed keypair not found") require.True(t, ok, "Seed keypair not found")
require.True(t, len(seedKps) == 1, "Unexpected number of seed keypairs") require.True(t, len(seedKps) == 1, "Unexpected number of seed keypairs")
require.True(t, len(seedKps[0].Accounts) == 1) require.True(t, len(seedKps[0].Accounts) == 1)
info, err := generator.LoadAccount(seedKps[0].Accounts[0].Address.Hex(), passwd) info, err := generator.LoadAccount(seedKps[0].Accounts[0].Address.Hex(), oldMobileUserPasswd)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, seedKps[0].KeyUID, info.KeyUID) require.Equal(t, seedKps[0].KeyUID, info.KeyUID)
require.Equal(t, seedKps[0].Accounts[0].KeyUID, info.KeyUID) require.Equal(t, seedKps[0].Accounts[0].KeyUID, info.KeyUID)
@ -1393,7 +1398,7 @@ func loginMobileUser(t *testing.T, rootDataDir string) {
require.True(t, ok, "Key keypair not found") require.True(t, ok, "Key keypair not found")
require.True(t, len(keyKps) == 1, "Unexpected number of key keypairs") require.True(t, len(keyKps) == 1, "Unexpected number of key keypairs")
require.True(t, len(keyKps[0].Accounts) == 1) require.True(t, len(keyKps[0].Accounts) == 1)
info, err = generator.LoadAccount(keyKps[0].Accounts[0].Address.Hex(), passwd) info, err = generator.LoadAccount(keyKps[0].Accounts[0].Address.Hex(), oldMobileUserPasswd)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, keyKps[0].KeyUID, info.KeyUID) require.Equal(t, keyKps[0].KeyUID, info.KeyUID)
require.Equal(t, keyKps[0].Accounts[0].KeyUID, info.KeyUID) require.Equal(t, keyKps[0].Accounts[0].KeyUID, info.KeyUID)
@ -1406,17 +1411,75 @@ func loginMobileUser(t *testing.T, rootDataDir string) {
func TestLoginAndMigrationsStillWorkWithExistingMobileUser(t *testing.T) { func TestLoginAndMigrationsStillWorkWithExistingMobileUser(t *testing.T) {
utils.Init() utils.Init()
srcFolder := "../static/test-mobile-release-1.20.x-aa6e4b2-account/" srcFolder := "../static/test-mobile-release-1.20.x-aa6e4b2-account/"
tmpdir := t.TempDir() tmpdir := t.TempDir()
copyDir(srcFolder, tmpdir, t) copyDir(srcFolder, tmpdir, t)
loginMobileUser(t, tmpdir) loginMobileUser(t, tmpdir)
loginMobileUser(t, tmpdir) // Login twice to catch weird errors that only appear after logout loginMobileUser(t, tmpdir) // Login twice to catch weird errors that only appear after logout
} }
// TestAddWalletAccount for test data description pls see comments within loginMobileUser
func TestAddWalletAccountAfterUpgradingFromMobileV1(t *testing.T) {
utils.Init()
srcFolder := "../static/test-mobile-release-1.20.x-aa6e4b2-account/"
tmpdir := t.TempDir()
copyDir(srcFolder, tmpdir, t)
b := NewGethStatusBackend()
b.UpdateRootDataDir(tmpdir)
require.NoError(t, b.OpenAccounts())
require.NoError(t, b.Login(oldMobileUserKeyUID, oldMobileUserPasswd))
db, _ := accounts.NewDB(b.appDB)
walletRootAddress, err := db.GetWalletRootAddress()
require.NoError(t, err)
masterAddress, err := db.GetMasterAddress()
require.NoError(t, err)
kps, _ := db.GetAllKeypairs()
// Create a map to categorize keypairs by their type
keypairMap := make(map[accounts.KeypairType][]*accounts.Keypair)
for _, kp := range kps {
keypairMap[kp.Type] = append(keypairMap[kp.Type], kp)
}
profileKps := keypairMap[accounts.KeypairTypeProfile]
profileKp := profileKps[0]
require.True(t, profileKp.DerivedFrom == walletRootAddress.Hex())
require.False(t, masterAddress.Hex() == walletRootAddress.Hex())
// simulate mobile frontend adding a wallet account
suggestedPath, err := db.ResolveSuggestedPathForKeypair(oldMobileUserKeyUID)
require.NoError(t, err)
generator := b.AccountManager().AccountsGenerator()
accountInfo, err := generator.LoadAccount(profileKp.DerivedFrom, oldMobileUserPasswd)
require.NoError(t, err)
infoMap, err := generator.DeriveAddresses(accountInfo.ID, []string{suggestedPath})
require.NoError(t, err)
require.Len(t, infoMap, 1)
deriveAccountInfo := infoMap[suggestedPath]
derivedAddress := types.HexToAddress(deriveAccountInfo.Address)
accountsAPI := b.StatusNode().AccountService().AccountsAPI()
err = accountsAPI.AddAccount(context.Background(), oldMobileUserPasswd, &accounts.Account{
Address: derivedAddress,
KeyUID: oldMobileUserKeyUID,
Wallet: false,
Chat: false,
Type: accounts.AccountTypeGenerated,
Path: suggestedPath,
PublicKey: types.Hex2Bytes(deriveAccountInfo.PublicKey),
Name: "GeneratedAccount2",
Emoji: "emoji",
ColorID: common.CustomizationColorBlue,
})
require.NoError(t, err)
// need retry since there's a possible of getting "no key for given address or file" error
err = tt.RetryWithBackOff(func() error {
return accountsAPI.DeleteAccount(context.Background(), derivedAddress)
})
require.NoError(t, err)
require.NoError(t, b.Logout())
}
func TestChangeDatabasePassword(t *testing.T) { func TestChangeDatabasePassword(t *testing.T) {
oldPassword := "password" oldPassword := "password"
newPassword := "newPassword" newPassword := "newPassword"

View File

@ -89,6 +89,11 @@ func InitializeDB(path, password string, kdfIterationsNumber int) (*sql.DB, erro
func fixMissingKeyUIDForAccounts(sqlTx *sql.Tx) error { func fixMissingKeyUIDForAccounts(sqlTx *sql.Tx) error {
rows, err := sqlTx.Query(`SELECT address,pubkey FROM accounts WHERE pubkey IS NOT NULL AND type != '' AND type != 'generated'`) rows, err := sqlTx.Query(`SELECT address,pubkey FROM accounts WHERE pubkey IS NOT NULL AND type != '' AND type != 'generated'`)
if err == sql.ErrNoRows {
// we shouldn't reach here, but if we do, it probably happened from the test
log.Warn("Migrating accounts: no accounts found")
return nil
}
if err != nil { if err != nil {
log.Error("Migrating accounts: failed to query accounts", "err", err.Error()) log.Error("Migrating accounts: failed to query accounts", "err", err.Error())
return err return err
@ -115,9 +120,22 @@ func fixMissingKeyUIDForAccounts(sqlTx *sql.Tx) error {
return err return err
} }
} }
_, err = sqlTx.Exec(`UPDATE accounts SET key_uid = ? WHERE type = '' OR type = 'generated'`, CurrentAppDBKeyUID)
var walletRootAddress e_types.Address
err = sqlTx.QueryRow(`SELECT wallet_root_address FROM settings WHERE synthetic_id='id'`).Scan(&walletRootAddress)
if err == sql.ErrNoRows {
// we shouldn't reach here, but if we do, it probably happened from the test
log.Warn("Migrating accounts: no wallet_root_address found in settings")
return nil
}
if err != nil { if err != nil {
log.Error("Migrating accounts: failed to update key_uid", "err", err.Error()) log.Error("Migrating accounts: failed to get wallet_root_address", "err", err.Error())
return err
}
_, err = sqlTx.Exec(`UPDATE accounts SET key_uid = ?, derived_from = ? WHERE type = '' OR type = 'generated'`, CurrentAppDBKeyUID, walletRootAddress.Hex())
if err != nil {
log.Error("Migrating accounts: failed to update key_uid/derived_from", "err", err.Error())
return err
} }
return nil return nil
} }

View File

@ -8,9 +8,10 @@ import (
big "math/big" big "math/big"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
common "github.com/ethereum/go-ethereum/common" common "github.com/ethereum/go-ethereum/common"
types "github.com/ethereum/go-ethereum/core/types" types "github.com/ethereum/go-ethereum/core/types"
gomock "github.com/golang/mock/gomock"
account "github.com/status-im/status-go/account" account "github.com/status-im/status-go/account"
types0 "github.com/status-im/status-go/eth-node/types" types0 "github.com/status-im/status-go/eth-node/types"
params "github.com/status-im/status-go/params" params "github.com/status-im/status-go/params"

View File

@ -8,9 +8,10 @@ import (
big "math/big" big "math/big"
reflect "reflect" reflect "reflect"
gomock "github.com/golang/mock/gomock"
common "github.com/ethereum/go-ethereum/common" common "github.com/ethereum/go-ethereum/common"
types "github.com/ethereum/go-ethereum/core/types" types "github.com/ethereum/go-ethereum/core/types"
gomock "github.com/golang/mock/gomock"
account "github.com/status-im/status-go/account" account "github.com/status-im/status-go/account"
types0 "github.com/status-im/status-go/eth-node/types" types0 "github.com/status-im/status-go/eth-node/types"
params "github.com/status-im/status-go/params" params "github.com/status-im/status-go/params"