tests: Added unit test for copying 'keypairs_accounts' table to the wallet db.
Added a unit test for changing app and wallet DBs passwords. Refactored geth_backend to simplify and allow wallet db password changing. Fixed opening database with wrong password.
This commit is contained in:
parent
2df9df10ab
commit
ea38b788b3
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/rpc"
|
"github.com/status-im/status-go/rpc"
|
||||||
"github.com/status-im/status-go/services/typeddata"
|
"github.com/status-im/status-go/services/typeddata"
|
||||||
|
"github.com/status-im/status-go/sqlite"
|
||||||
"github.com/status-im/status-go/t/helpers"
|
"github.com/status-im/status-go/t/helpers"
|
||||||
"github.com/status-im/status-go/t/utils"
|
"github.com/status-im/status-go/t/utils"
|
||||||
"github.com/status-im/status-go/transactions"
|
"github.com/status-im/status-go/transactions"
|
||||||
|
@ -1196,3 +1197,41 @@ func TestLoginAndMigrationsStillWorkWithExistingUsers(t *testing.T) {
|
||||||
login(t, conf)
|
login(t, conf)
|
||||||
login(t, conf) // Login twice to catch weird errors that only appear after logout
|
login(t, conf) // Login twice to catch weird errors that only appear after logout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestChangeDatabasePassword(t *testing.T) {
|
||||||
|
backend := NewGethStatusBackend()
|
||||||
|
backend.UpdateRootDataDir(t.TempDir())
|
||||||
|
|
||||||
|
account := multiaccounts.Account{
|
||||||
|
Name: "TestAccount",
|
||||||
|
Timestamp: 1,
|
||||||
|
KeyUID: "0x7c46c8f6f059ab72d524f2a6d356904db30bb0392636172ab3929a6bd2220f84",
|
||||||
|
KDFIterations: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
oldPassword := "password"
|
||||||
|
newPassword := "newPassword"
|
||||||
|
|
||||||
|
// Initialize accounts DB
|
||||||
|
err := backend.OpenAccounts()
|
||||||
|
require.NoError(t, err)
|
||||||
|
err = backend.SaveAccount(account)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Created DBs with old password
|
||||||
|
err = backend.ensureDBsOpened(account, oldPassword)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Change password
|
||||||
|
err = backend.ChangeDatabasePassword(account.KeyUID, oldPassword, newPassword)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Test that DBs can be opened with new password
|
||||||
|
appDb, err := sqlite.OpenDB(backend.getAppDBPath(account.KeyUID), newPassword, account.KDFIterations)
|
||||||
|
require.NoError(t, err)
|
||||||
|
appDb.Close()
|
||||||
|
|
||||||
|
walletDb, err := sqlite.OpenDB(backend.getWalletDBPath(account.KeyUID), newPassword, account.KDFIterations)
|
||||||
|
require.NoError(t, err)
|
||||||
|
walletDb.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/common/dbsetup"
|
||||||
"github.com/status-im/status-go/images"
|
"github.com/status-im/status-go/images"
|
||||||
"github.com/status-im/status-go/walletdatabase"
|
"github.com/status-im/status-go/walletdatabase"
|
||||||
|
|
||||||
|
@ -246,6 +247,7 @@ func (b *GethStatusBackend) DeleteMultiaccount(keyUID string, keyStoreDir string
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
appDbPath := b.getAppDBPath(keyUID)
|
||||||
dbFiles := []string{
|
dbFiles := []string{
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql", keyUID)),
|
filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql", keyUID)),
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql-shm", keyUID)),
|
filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql-shm", keyUID)),
|
||||||
|
@ -253,9 +255,9 @@ func (b *GethStatusBackend) DeleteMultiaccount(keyUID string, keyStoreDir string
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db", keyUID)),
|
filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db", keyUID)),
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db-shm", keyUID)),
|
filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db-shm", keyUID)),
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db-wal", keyUID)),
|
filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db-wal", keyUID)),
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db", keyUID)),
|
appDbPath,
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db-shm", keyUID)),
|
appDbPath + "-shm",
|
||||||
filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db-wal", keyUID)),
|
appDbPath + "-wal",
|
||||||
}
|
}
|
||||||
for _, path := range dbFiles {
|
for _, path := range dbFiles {
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
|
@ -301,7 +303,7 @@ func (b *GethStatusBackend) runDBFileMigrations(account multiaccounts.Account, p
|
||||||
// Migrate file path to fix issue https://github.com/status-im/status-go/issues/2027
|
// Migrate file path to fix issue https://github.com/status-im/status-go/issues/2027
|
||||||
unsupportedPath := filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql", account.KeyUID))
|
unsupportedPath := filepath.Join(b.rootDataDir, fmt.Sprintf("app-%x.sql", account.KeyUID))
|
||||||
v3Path := filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db", account.KeyUID))
|
v3Path := filepath.Join(b.rootDataDir, fmt.Sprintf("%s.db", account.KeyUID))
|
||||||
v4Path := filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db", account.KeyUID))
|
v4Path := b.getAppDBPath(account.KeyUID)
|
||||||
|
|
||||||
_, err := os.Stat(unsupportedPath)
|
_, err := os.Stat(unsupportedPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
@ -378,7 +380,7 @@ func (b *GethStatusBackend) ensureWalletDBOpened(account multiaccounts.Account,
|
||||||
return errors.New("root datadir wasn't provided")
|
return errors.New("root datadir wasn't provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
dbWalletPath := filepath.Join(b.rootDataDir, fmt.Sprintf("%s-wallet.db", account.KeyUID))
|
dbWalletPath := b.getWalletDBPath(account.KeyUID)
|
||||||
b.walletDB, err = walletdatabase.InitializeDB(dbWalletPath, password, account.KDFIterations)
|
b.walletDB, err = walletdatabase.InitializeDB(dbWalletPath, password, account.KDFIterations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.log.Error("failed to initialize wallet db", "err", err)
|
b.log.Error("failed to initialize wallet db", "err", err)
|
||||||
|
@ -798,7 +800,7 @@ func (b *GethStatusBackend) ExportUnencryptedDatabase(acc multiaccounts.Account,
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = appdatabase.DecryptDatabase(dbPath, directory, password, acc.KDFIterations)
|
err = dbsetup.DecryptDatabase(dbPath, directory, password, acc.KDFIterations)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.log.Error("failed to initialize db", "err", err)
|
b.log.Error("failed to initialize db", "err", err)
|
||||||
return err
|
return err
|
||||||
|
@ -816,9 +818,9 @@ func (b *GethStatusBackend) ImportUnencryptedDatabase(acc multiaccounts.Account,
|
||||||
return errors.New("root datadir wasn't provided")
|
return errors.New("root datadir wasn't provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
path := filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db", acc.KeyUID))
|
path := b.getAppDBPath(acc.KeyUID)
|
||||||
|
|
||||||
err := appdatabase.EncryptDatabase(databasePath, path, password, acc.KDFIterations, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
|
err := dbsetup.EncryptDatabase(databasePath, path, password, acc.KDFIterations, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.log.Error("failed to initialize db", "err", err)
|
b.log.Error("failed to initialize db", "err", err)
|
||||||
return err
|
return err
|
||||||
|
@ -845,29 +847,59 @@ func (b *GethStatusBackend) reEncryptKeyStoreDir(currentPassword string, newPass
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) ChangeDatabasePassword(keyUID string, password string, newPassword string) error {
|
func (b *GethStatusBackend) ChangeDatabasePassword(keyUID string, password string, newPassword string) error {
|
||||||
dbPath := filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db", keyUID))
|
|
||||||
|
|
||||||
account, err := b.multiaccountsDB.GetAccount(keyUID)
|
account, err := b.multiaccountsDB.GetAccount(keyUID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
file, err := os.CreateTemp("", "*-v4.db")
|
internalDbPath, err := dbsetup.GetDBFilename(b.appDB)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get database file name, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
isCurrentAccount := b.getAppDBPath(keyUID) == internalDbPath
|
||||||
|
restartNode := func() {
|
||||||
|
if isCurrentAccount {
|
||||||
|
if err != nil {
|
||||||
|
_ = b.startNodeWithAccount(*account, password, nil)
|
||||||
|
} else {
|
||||||
|
_ = b.startNodeWithAccount(*account, newPassword, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer restartNode()
|
||||||
|
|
||||||
|
logout := func() {
|
||||||
|
if isCurrentAccount {
|
||||||
|
_ = b.Logout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
noLogout := func() {}
|
||||||
|
|
||||||
|
err = b.changeWalletDBPassword(account, logout, password, newPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
newDBPath := file.Name()
|
// Already logged out
|
||||||
defer func() {
|
err = b.changeAppDBPassword(account, noLogout, password, newPassword)
|
||||||
_ = file.Close()
|
if err != nil {
|
||||||
_ = os.Remove(newDBPath)
|
return err
|
||||||
_ = os.Remove(newDBPath + "-wal")
|
}
|
||||||
_ = os.Remove(newDBPath + "-shm")
|
|
||||||
_ = os.Remove(newDBPath + "-journal")
|
|
||||||
}()
|
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) changeAppDBPassword(account *multiaccounts.Account, logout func(), password string, newPassword string) error {
|
||||||
|
tmpDbPath, cleanup, err := b.createTempDBFile("v4.db")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
dbPath := b.getAppDBPath(account.KeyUID)
|
||||||
// Exporting database to a temporary file with a new password
|
// Exporting database to a temporary file with a new password
|
||||||
err = appdatabase.ExportDB(dbPath, password, account.KDFIterations, newDBPath, newPassword, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
|
err = dbsetup.ExportDB(dbPath, password, account.KDFIterations, tmpDbPath, newPassword, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -879,34 +911,83 @@ func (b *GethStatusBackend) ChangeDatabasePassword(keyUID string, password strin
|
||||||
|
|
||||||
// Replacing the old database with the new one requires closing all connections to the database
|
// Replacing the old database with the new one requires closing all connections to the database
|
||||||
// This is done by stopping the node and restarting it with the new DB
|
// This is done by stopping the node and restarting it with the new DB
|
||||||
appDBPath, _ := appdatabase.GetDBFilename(b.appDB)
|
logout()
|
||||||
changeCurrentAccountPassword := appDBPath == dbPath
|
|
||||||
if changeCurrentAccountPassword {
|
|
||||||
_ = b.Logout()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replacing the old database files with the new ones, ignoring the wal and shm errors
|
// Replacing the old database files with the new ones, ignoring the wal and shm errors
|
||||||
err = os.Rename(newDBPath, dbPath)
|
replaceCleanup, err := replaceDBFile(dbPath, tmpDbPath)
|
||||||
|
if replaceCleanup != nil {
|
||||||
|
defer replaceCleanup()
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Restore the old account
|
// Restore the old account
|
||||||
_ = b.reEncryptKeyStoreDir(newPassword, password)
|
_ = b.reEncryptKeyStoreDir(newPassword, password)
|
||||||
if changeCurrentAccountPassword {
|
|
||||||
_ = b.startNodeWithAccount(*account, password, nil)
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = os.Remove(dbPath + "-wal")
|
|
||||||
_ = os.Remove(dbPath + "-shm")
|
|
||||||
_ = os.Rename(newDBPath+"-wal", dbPath+"-wal")
|
|
||||||
_ = os.Rename(newDBPath+"-shm", dbPath+"-shm")
|
|
||||||
|
|
||||||
if changeCurrentAccountPassword {
|
|
||||||
return b.startNodeWithAccount(*account, newPassword, nil)
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) changeWalletDBPassword(account *multiaccounts.Account, logout func(), password string, newPassword string) error {
|
||||||
|
tmpDbPath, cleanup, err := b.createTempDBFile("wallet.db")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
dbPath := b.getWalletDBPath(account.KeyUID)
|
||||||
|
// Exporting database to a temporary file with a new password
|
||||||
|
err = dbsetup.ExportDB(dbPath, password, account.KDFIterations, tmpDbPath, newPassword, signal.SendReEncryptionStarted, signal.SendReEncryptionFinished)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replacing the old database with the new one requires closing all connections to the database
|
||||||
|
// This is done by stopping the node and restarting it with the new DB
|
||||||
|
logout()
|
||||||
|
|
||||||
|
// Replacing the old database files with the new ones, ignoring the wal and shm errors
|
||||||
|
replaceCleanup, err := replaceDBFile(dbPath, tmpDbPath)
|
||||||
|
if replaceCleanup != nil {
|
||||||
|
defer replaceCleanup()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) createTempDBFile(pattern string) (tmpDbPath string, cleanup func(), err error) {
|
||||||
|
if len(b.rootDataDir) == 0 {
|
||||||
|
err = errors.New("root datadir wasn't provided")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file, err := os.CreateTemp(filepath.Dir(b.rootDataDir), "*-"+pattern)
|
||||||
|
tmpDbPath = file.Name()
|
||||||
|
cleanup = func() {
|
||||||
|
filePath := file.Name()
|
||||||
|
_ = file.Close()
|
||||||
|
_ = os.Remove(filePath)
|
||||||
|
_ = os.Remove(filePath + "-wal")
|
||||||
|
_ = os.Remove(filePath + "-shm")
|
||||||
|
_ = os.Remove(filePath + "-journal")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func replaceDBFile(dbPath string, newDBPath string) (cleanup func(), err error) {
|
||||||
|
err = os.Rename(newDBPath, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup = func() {
|
||||||
|
_ = os.Remove(dbPath + "-wal")
|
||||||
|
_ = os.Remove(dbPath + "-shm")
|
||||||
|
_ = os.Rename(newDBPath+"-wal", dbPath+"-wal")
|
||||||
|
_ = os.Rename(newDBPath+"-shm", dbPath+"-shm")
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Account, s settings.Settings, keycardUID string, password string, newPassword string) error {
|
func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Account, s settings.Settings, keycardUID string, 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 {
|
||||||
|
@ -996,7 +1077,7 @@ func (b *GethStatusBackend) ConvertToKeycardAccount(account multiaccounts.Accoun
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.closeAppDB()
|
err = b.closeDBs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1191,7 +1272,7 @@ func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPasswor
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.ensureDBsOpened(multiaccounts.Account{KeyUID: accountInfo.KeyUID, KDFIterations: kdfIterations}, newPassword)
|
err = b.ensureDBsOpened(multiaccounts.Account{KeyUID: accountInfo.KeyUID, KDFIterations: kdfIterations}, currPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1252,7 +1333,7 @@ func (b *GethStatusBackend) ConvertToRegularAccount(mnemonic string, currPasswor
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.closeAppDB()
|
err = b.closeDBs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1271,7 +1352,7 @@ func (b *GethStatusBackend) VerifyDatabasePassword(keyUID string, password strin
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = b.closeAppDB()
|
err = b.closeDBs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1937,14 +2018,12 @@ func (b *GethStatusBackend) Logout() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = b.closeAppDB()
|
err = b.closeDBs()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
b.AccountManager().Logout()
|
b.AccountManager().Logout()
|
||||||
b.appDB = nil
|
|
||||||
b.walletDB = nil
|
|
||||||
b.account = nil
|
b.account = nil
|
||||||
|
|
||||||
if b.statusNode != nil {
|
if b.statusNode != nil {
|
||||||
|
@ -1973,6 +2052,14 @@ func (b *GethStatusBackend) cleanupServices() error {
|
||||||
return b.statusNode.Cleanup()
|
return b.statusNode.Cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) closeDBs() error {
|
||||||
|
err := b.closeWalletDB()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return b.closeAppDB()
|
||||||
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) closeAppDB() error {
|
func (b *GethStatusBackend) closeAppDB() error {
|
||||||
if b.appDB != nil {
|
if b.appDB != nil {
|
||||||
err := b.appDB.Close()
|
err := b.appDB.Close()
|
||||||
|
@ -1985,6 +2072,17 @@ func (b *GethStatusBackend) closeAppDB() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) closeWalletDB() error {
|
||||||
|
if b.walletDB != nil {
|
||||||
|
err := b.walletDB.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b.walletDB = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SelectAccount selects current wallet and chat accounts, by verifying that each address has corresponding account which can be decrypted
|
// SelectAccount selects current wallet and chat accounts, by verifying that each address has corresponding account which can be decrypted
|
||||||
// using provided password. Once verification is done, the decrypted chat key is injected into Whisper (as a single identity,
|
// using provided password. Once verification is done, the decrypted chat key is injected into Whisper (as a single identity,
|
||||||
// all previous identities are removed).
|
// all previous identities are removed).
|
||||||
|
@ -2157,3 +2255,11 @@ func (b *GethStatusBackend) SwitchFleet(fleet string, conf *params.NodeConfig) e
|
||||||
func (b *GethStatusBackend) SetLocalPairing(value bool) {
|
func (b *GethStatusBackend) SetLocalPairing(value bool) {
|
||||||
b.localPairing = value
|
b.localPairing = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) getAppDBPath(keyUID string) string {
|
||||||
|
return filepath.Join(b.rootDataDir, fmt.Sprintf("%s-v4.db", keyUID))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *GethStatusBackend) getWalletDBPath(keyUID string) string {
|
||||||
|
return filepath.Join(b.rootDataDir, fmt.Sprintf("%s-wallet.db", keyUID))
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ package appdatabase
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -77,59 +76,6 @@ func InitializeDB(path, password string, kdfIterationsNumber int) (*sql.DB, erro
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptDatabase creates an unencrypted copy of the database and copies it
|
|
||||||
// over to the given directory
|
|
||||||
func DecryptDatabase(oldPath, newPath, password string, kdfIterationsNumber int) error {
|
|
||||||
return sqlite.DecryptDB(oldPath, newPath, password, kdfIterationsNumber)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EncryptDatabase creates an encrypted copy of the database and copies it to the
|
|
||||||
// user path
|
|
||||||
func EncryptDatabase(oldPath, newPath, password string, kdfIterationsNumber int, onStart func(), onEnd func()) error {
|
|
||||||
return sqlite.EncryptDB(oldPath, newPath, password, kdfIterationsNumber, onStart, onEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ExportDB(path string, password string, kdfIterationsNumber int, newDbPAth string, newPassword string, onStart func(), onEnd func()) error {
|
|
||||||
return sqlite.ExportDB(path, password, kdfIterationsNumber, newDbPAth, newPassword, onStart, onEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChangeDatabasePassword(path string, password string, kdfIterationsNumber int, newPassword string, onStart func(), onEnd func()) error {
|
|
||||||
return sqlite.ChangeEncryptionKey(path, password, kdfIterationsNumber, newPassword, onStart, onEnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDBFilename takes an instance of sql.DB and returns the filename of the "main" database
|
|
||||||
func GetDBFilename(db *sql.DB) (string, error) {
|
|
||||||
if db == nil {
|
|
||||||
logger := log.New()
|
|
||||||
logger.Warn("GetDBFilename was passed a nil pointer sql.DB")
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var i, category, filename string
|
|
||||||
rows, err := db.Query("PRAGMA database_list;")
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer rows.Close()
|
|
||||||
for rows.Next() {
|
|
||||||
err = rows.Scan(&i, &category, &filename)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// The "main" database is the one we care about
|
|
||||||
if category == "main" {
|
|
||||||
return filename, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := rows.Err(); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errors.New("no main database found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func migrateEnsUsernames(sqlTx *sql.Tx) error {
|
func migrateEnsUsernames(sqlTx *sql.Tx) error {
|
||||||
|
|
||||||
// 1. Check if ens_usernames table already exist
|
// 1. Check if ens_usernames table already exist
|
||||||
|
|
|
@ -16,6 +16,7 @@ import (
|
||||||
|
|
||||||
"github.com/status-im/status-go/appdatabase/migrations"
|
"github.com/status-im/status-go/appdatabase/migrations"
|
||||||
migrationsprevnodecfg "github.com/status-im/status-go/appdatabase/migrationsprevnodecfg"
|
migrationsprevnodecfg "github.com/status-im/status-go/appdatabase/migrationsprevnodecfg"
|
||||||
|
"github.com/status-im/status-go/common/dbsetup"
|
||||||
"github.com/status-im/status-go/nodecfg"
|
"github.com/status-im/status-go/nodecfg"
|
||||||
"github.com/status-im/status-go/services/wallet/bigint"
|
"github.com/status-im/status-go/services/wallet/bigint"
|
||||||
w_common "github.com/status-im/status-go/services/wallet/common"
|
w_common "github.com/status-im/status-go/services/wallet/common"
|
||||||
|
@ -31,7 +32,7 @@ func Test_GetDBFilename(t *testing.T) {
|
||||||
require.NoError(t, stop())
|
require.NoError(t, stop())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fn, err := GetDBFilename(db)
|
fn, err := dbsetup.GetDBFilename(db)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.True(t, len(fn) > 0)
|
require.True(t, len(fn) > 0)
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@ func Test_GetDBFilename(t *testing.T) {
|
||||||
require.NoError(t, mdb.Close())
|
require.NoError(t, mdb.Close())
|
||||||
}()
|
}()
|
||||||
|
|
||||||
fn, err = GetDBFilename(mdb)
|
fn, err = dbsetup.GetDBFilename(mdb)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "", fn)
|
require.Equal(t, "", fn)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,66 @@
|
||||||
package dbsetup
|
package dbsetup
|
||||||
|
|
||||||
import "database/sql"
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/status-im/status-go/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
type DatabaseInitializer interface {
|
type DatabaseInitializer interface {
|
||||||
Initialize(path, password string, kdfIterationsNumber int) (*sql.DB, error)
|
Initialize(path, password string, kdfIterationsNumber int) (*sql.DB, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecryptDatabase creates an unencrypted copy of the database and copies it
|
||||||
|
// over to the given directory
|
||||||
|
func DecryptDatabase(oldPath, newPath, password string, kdfIterationsNumber int) error {
|
||||||
|
return sqlite.DecryptDB(oldPath, newPath, password, kdfIterationsNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncryptDatabase creates an encrypted copy of the database and copies it to the
|
||||||
|
// user path
|
||||||
|
func EncryptDatabase(oldPath, newPath, password string, kdfIterationsNumber int, onStart func(), onEnd func()) error {
|
||||||
|
return sqlite.EncryptDB(oldPath, newPath, password, kdfIterationsNumber, onStart, onEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExportDB(path string, password string, kdfIterationsNumber int, newDbPath string, newPassword string, onStart func(), onEnd func()) error {
|
||||||
|
return sqlite.ExportDB(path, password, kdfIterationsNumber, newDbPath, newPassword, onStart, onEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ChangeDatabasePassword(path string, password string, kdfIterationsNumber int, newPassword string, onStart func(), onEnd func()) error {
|
||||||
|
return sqlite.ChangeEncryptionKey(path, password, kdfIterationsNumber, newPassword, onStart, onEnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDBFilename takes an instance of sql.DB and returns the filename of the "main" database
|
||||||
|
func GetDBFilename(db *sql.DB) (string, error) {
|
||||||
|
if db == nil {
|
||||||
|
logger := log.New()
|
||||||
|
logger.Warn("GetDBFilename was passed a nil pointer sql.DB")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var i, category, filename string
|
||||||
|
rows, err := db.Query("PRAGMA database_list;")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer rows.Close()
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(&i, &category, &filename)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "main" database is the one we care about
|
||||||
|
if category == "main" {
|
||||||
|
return filename, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("no main database found")
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/status-im/status-go/appdatabase"
|
"github.com/status-im/status-go/common/dbsetup"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/multiaccounts/errors"
|
"github.com/status-im/status-go/multiaccounts/errors"
|
||||||
"github.com/status-im/status-go/nodecfg"
|
"github.com/status-im/status-go/nodecfg"
|
||||||
|
@ -32,7 +32,7 @@ type Database struct {
|
||||||
|
|
||||||
// MakeNewDB ensures that a singleton instance of Database is returned per sqlite db file
|
// MakeNewDB ensures that a singleton instance of Database is returned per sqlite db file
|
||||||
func MakeNewDB(db *sql.DB) (*Database, error) {
|
func MakeNewDB(db *sql.DB) (*Database, error) {
|
||||||
filename, err := appdatabase.GetDBFilename(db)
|
filename, err := dbsetup.GetDBFilename(db)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -633,9 +633,11 @@ func (b *StatusNode) Cleanup() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := b.ensSrvc.Stop()
|
if b.ensSrvc != nil {
|
||||||
if err != nil {
|
err := b.ensSrvc.Stop()
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -304,7 +304,7 @@ const (
|
||||||
? AS includeAllNetworks
|
? AS includeAllNetworks
|
||||||
),
|
),
|
||||||
filter_addresses(address) AS (
|
filter_addresses(address) AS (
|
||||||
SELECT HEX(address) FROM keypairs_accounts WHERE (SELECT filterAllAddresses FROM filter_conditions) != 0
|
SELECT HEX(address) FROM %s WHERE (SELECT filterAllAddresses FROM filter_conditions) != 0
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT * FROM (VALUES %s) WHERE (SELECT filterAllAddresses FROM filter_conditions) = 0
|
SELECT * FROM (VALUES %s) WHERE (SELECT filterAllAddresses FROM filter_conditions) = 0
|
||||||
),
|
),
|
||||||
|
@ -666,7 +666,7 @@ func getActivityEntries(ctx context.Context, deps FilterDependencies, addresses
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
queryString := fmt.Sprintf(queryFormatString, involvedAddresses, toAddresses, assetsTokenCodes, assetsERC20, networks,
|
queryString := fmt.Sprintf(queryFormatString, keypairAccountsTable, involvedAddresses, toAddresses, assetsTokenCodes, assetsERC20, networks,
|
||||||
joinedMTTypes)
|
joinedMTTypes)
|
||||||
|
|
||||||
rows, err := deps.db.QueryContext(ctx, queryString,
|
rows, err := deps.db.QueryContext(ctx, queryString,
|
||||||
|
|
|
@ -3,6 +3,7 @@ package activity
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -1272,3 +1273,59 @@ func BenchmarkGetActivityEntries(bArg *testing.B) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUpdateWalletKeypairsAccountsTable(t *testing.T) {
|
||||||
|
// initialize
|
||||||
|
appDb, err := helpers.SetupTestMemorySQLDB(appdatabase.DbInitializer{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
walletDb, err := helpers.SetupTestMemorySQLDB(walletdatabase.DbInitializer{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
accountsAppDb, err := accounts.NewDB(appDb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
accountsWalletDb, err := accounts.NewDB(walletDb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check initially empty
|
||||||
|
addressesApp, err := accountsAppDb.GetWalletAddresses()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Empty(t, addressesApp)
|
||||||
|
addressesWallet, err := accountsWalletDb.GetWalletAddresses()
|
||||||
|
require.Error(t, err) // no such table error
|
||||||
|
require.Empty(t, addressesWallet)
|
||||||
|
|
||||||
|
// Insert 2 addresses in app db, but only 1 is a wallet
|
||||||
|
addresses := []types.Address{{0x01}, {0x02}, {0x03}}
|
||||||
|
accounts := []*accounts.Account{
|
||||||
|
{Address: addresses[0], Chat: true, Wallet: true},
|
||||||
|
{Address: addresses[1], Wallet: true},
|
||||||
|
{Address: addresses[2]},
|
||||||
|
}
|
||||||
|
err = accountsAppDb.SaveOrUpdateAccounts(accounts, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check only 2 wallet accs is returned in app db
|
||||||
|
addressesApp, err = accountsAppDb.GetWalletAddresses()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, addressesApp, 2)
|
||||||
|
|
||||||
|
// update wallet DB
|
||||||
|
err = updateKeypairsAccountsTable(accountsAppDb, walletDb)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Check only 2 wallet acc is returned in wallet db
|
||||||
|
var count int
|
||||||
|
err = walletDb.QueryRow(fmt.Sprintf("SELECT count(address) FROM %s", keypairAccountsTable)).Scan(&count)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, count, 2)
|
||||||
|
|
||||||
|
// Compare addresses between app and wallet db
|
||||||
|
rows, err := walletDb.Query(fmt.Sprintf("SELECT address FROM %s", keypairAccountsTable))
|
||||||
|
require.NoError(t, err)
|
||||||
|
for rows.Next() {
|
||||||
|
var address types.Address
|
||||||
|
err = rows.Scan(&address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Contains(t, addresses, address)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
}
|
||||||
|
|
|
@ -200,7 +200,7 @@ func openDB(path string, key string, kdfIterationsNumber int, cipherPageSize int
|
||||||
|
|
||||||
// readers do not block writers and faster i/o operations
|
// readers do not block writers and faster i/o operations
|
||||||
if _, err := conn.Exec("PRAGMA journal_mode=WAL", []driver.Value{}); err != nil && path != InMemoryPath {
|
if _, err := conn.Exec("PRAGMA journal_mode=WAL", []driver.Value{}); err != nil && path != InMemoryPath {
|
||||||
return errors.New("failed to set `journal_mode` pragma")
|
return fmt.Errorf("failed to set `journal_mode` pragma: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// workaround to mitigate the issue of "database is locked" errors during concurrent write operations
|
// workaround to mitigate the issue of "database is locked" errors during concurrent write operations
|
||||||
|
|
Loading…
Reference in New Issue