prysm-pulse/validator/accounts/accounts_backup_test.go
Raul Jordan 7449eba612
Refactor HD Wallets for Enhanced Security (#7821)
* begin hd wallet refactor

* further simplify the new derived keymanager

* make it almost a full wrapper around an imported keymanager

* fix up the EIP test

* deprecated derived

* fixing keymanager tests

* fix up derived tests

* refactor initialize keymanager

* simplify hd

* pass some tests

* pass accounts list test

* gaz

* regenerate protos without create account privilege

* enforce account recovery on wallet create

* allow accounts delete to work

* remove mentions of accounts create

* resolve comments and go mod

* fix up tests

* build fixes

* remove insecure warning

* revert

* fix proto file

* remove create account message

* gaz

* remove account create

* update web api protos

* fix up imports

* change func sig

* tidy

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
2020-11-16 22:26:04 +00:00

222 lines
7.6 KiB
Go

package accounts
import (
"archive/zip"
"encoding/hex"
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"testing"
"time"
"github.com/prysmaticlabs/prysm/shared/fileutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/validator/keymanager"
"github.com/prysmaticlabs/prysm/validator/keymanager/derived"
)
var (
testMnemonic = "tumble turn jewel sudden social great water general cabin jacket bounce dry flip monster advance problem social half flee inform century chicken hard reason"
)
func TestBackupAccounts_Noninteractive_Derived(t *testing.T) {
walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
//Specify the password locally to this file for convenience.
password := "Pa$sW0rD0__Fo0xPr"
require.NoError(t, ioutil.WriteFile(passwordFilePath, []byte(password), os.ModePerm))
// Write a directory where we will backup accounts to.
backupDir := filepath.Join(t.TempDir(), "backupDir")
require.NoError(t, os.MkdirAll(backupDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
// Write a password for the accounts we wish to backup to a file.
backupPasswordFile := filepath.Join(backupDir, "backuppass.txt")
err := ioutil.WriteFile(
backupPasswordFile,
[]byte("Passw0rdz4938%%"),
params.BeaconIoConfig().ReadWritePermissions,
)
require.NoError(t, err)
// We initialize a wallet with a derived keymanager.
cliCtx := setupWalletCtx(t, &testWalletConfig{
// Wallet configuration flags.
walletDir: walletDir,
keymanagerKind: keymanager.Derived,
walletPasswordFile: passwordFilePath,
// Flags required for BackupAccounts to work.
backupPasswordFile: backupPasswordFile,
backupDir: backupDir,
})
w, err := CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
WalletCfg: &wallet.Config{
WalletDir: walletDir,
KeymanagerKind: keymanager.Derived,
WalletPassword: password,
},
})
require.NoError(t, err)
km, err := w.InitializeKeymanager(cliCtx.Context)
require.NoError(t, err)
// Create 2 accounts
derivedKM, ok := km.(*derived.Keymanager)
require.Equal(t, true, ok)
err = derivedKM.RecoverAccountsFromMnemonic(cliCtx.Context, testMnemonic, "", 2)
require.NoError(t, err)
// Obtain the public keys of the accounts we created
pubkeys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
require.NoError(t, err)
var generatedPubKeys []string
for _, pubkey := range pubkeys {
encoded := make([]byte, hex.EncodedLen(len(pubkey)))
hex.Encode(encoded, pubkey[:])
generatedPubKeys = append(generatedPubKeys, string(encoded))
}
backupPublicKeys := strings.Join(generatedPubKeys, ",")
// Recreate a cliCtx with the addition of these backup keys to be later used by the backup process
cliCtx = setupWalletCtx(t, &testWalletConfig{
// Wallet configuration flags.
walletDir: walletDir,
keymanagerKind: keymanager.Derived,
walletPasswordFile: passwordFilePath,
// Flags required for BackupAccounts to work.
backupPublicKeys: backupPublicKeys,
backupPasswordFile: backupPasswordFile,
backupDir: backupDir,
})
// Next, we attempt to backup the accounts.
require.NoError(t, BackupAccountsCli(cliCtx))
// We check a backup.zip file was created at the output path.
zipFilePath := filepath.Join(backupDir, archiveFilename)
assert.DeepEqual(t, true, fileutil.FileExists(zipFilePath))
// We attempt to unzip the file and verify the keystores do match our accounts.
f, err := os.Open(zipFilePath)
require.NoError(t, err)
defer func() {
require.NoError(t, f.Close())
}()
fi, err := f.Stat()
require.NoError(t, err)
r, err := zip.NewReader(f, fi.Size())
require.NoError(t, err)
// We check we have 2 keystore files in the unzipped results.
require.DeepEqual(t, 2, len(r.File))
unzippedPublicKeys := make([]string, 2)
for i, unzipped := range r.File {
ff, err := unzipped.Open()
require.NoError(t, err)
encodedBytes, err := ioutil.ReadAll(ff)
require.NoError(t, err)
keystoreFile := &keymanager.Keystore{}
require.NoError(t, json.Unmarshal(encodedBytes, keystoreFile))
require.NoError(t, ff.Close())
unzippedPublicKeys[i] = keystoreFile.Pubkey
}
sort.Strings(unzippedPublicKeys)
sort.Strings(generatedPubKeys)
assert.DeepEqual(t, unzippedPublicKeys, generatedPubKeys)
}
func TestBackupAccounts_Noninteractive_Imported(t *testing.T) {
walletDir, _, passwordFilePath := setupWalletAndPasswordsDir(t)
// Write a directory where we will import keys from.
keysDir := filepath.Join(t.TempDir(), "keysDir")
require.NoError(t, os.MkdirAll(keysDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
// Write a directory where we will backup accounts to.
backupDir := filepath.Join(t.TempDir(), "backupDir")
require.NoError(t, os.MkdirAll(backupDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
// Create 2 keystore files in the keys directory we can then
// import from in our wallet.
k1, _ := createKeystore(t, keysDir)
time.Sleep(time.Second)
k2, _ := createKeystore(t, keysDir)
generatedPubKeys := []string{k1.Pubkey, k2.Pubkey}
backupPublicKeys := strings.Join(generatedPubKeys, ",")
// Write a password for the accounts we wish to backup to a file.
backupPasswordFile := filepath.Join(backupDir, "backuppass.txt")
err := ioutil.WriteFile(
backupPasswordFile,
[]byte("Passw0rdz4938%%"),
params.BeaconIoConfig().ReadWritePermissions,
)
require.NoError(t, err)
// We initialize a wallet with a imported keymanager.
cliCtx := setupWalletCtx(t, &testWalletConfig{
// Wallet configuration flags.
walletDir: walletDir,
keymanagerKind: keymanager.Imported,
walletPasswordFile: passwordFilePath,
accountPasswordFile: passwordFilePath,
// Flags required for ImportAccounts to work.
keysDir: keysDir,
// Flags required for BackupAccounts to work.
backupPublicKeys: backupPublicKeys,
backupPasswordFile: backupPasswordFile,
backupDir: backupDir,
})
_, err = CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
WalletCfg: &wallet.Config{
WalletDir: walletDir,
KeymanagerKind: keymanager.Imported,
WalletPassword: password,
},
})
require.NoError(t, err)
// We attempt to import accounts we wrote to the keys directory
// into our newly created wallet.
require.NoError(t, ImportAccountsCli(cliCtx))
// Next, we attempt to backup the accounts.
require.NoError(t, BackupAccountsCli(cliCtx))
// We check a backup.zip file was created at the output path.
zipFilePath := filepath.Join(backupDir, archiveFilename)
assert.DeepEqual(t, true, fileutil.FileExists(zipFilePath))
// We attempt to unzip the file and verify the keystores do match our accounts.
f, err := os.Open(zipFilePath)
require.NoError(t, err)
defer func() {
require.NoError(t, f.Close())
}()
fi, err := f.Stat()
require.NoError(t, err)
r, err := zip.NewReader(f, fi.Size())
require.NoError(t, err)
// We check we have 2 keystore files in the unzipped results.
require.DeepEqual(t, 2, len(r.File))
unzippedPublicKeys := make([]string, 2)
for i, unzipped := range r.File {
ff, err := unzipped.Open()
require.NoError(t, err)
encodedBytes, err := ioutil.ReadAll(ff)
require.NoError(t, err)
keystoreFile := &keymanager.Keystore{}
require.NoError(t, json.Unmarshal(encodedBytes, keystoreFile))
require.NoError(t, ff.Close())
unzippedPublicKeys[i] = keystoreFile.Pubkey
}
sort.Strings(unzippedPublicKeys)
sort.Strings(generatedPubKeys)
assert.DeepEqual(t, unzippedPublicKeys, generatedPubKeys)
}