Acconuts-V2: Allow importing from any valid keystore, regardless of name (#6992)

* Allow importing from any file

* Fix log

* Add test

* Fix test
This commit is contained in:
Ivan Martinez 2020-08-13 15:45:56 -04:00 committed by GitHub
parent 4de0b9fe69
commit 6ed0539723
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 8 deletions

View File

@ -130,22 +130,21 @@ func ImportAccounts(cliCtx *cli.Context) error {
if len(files) == 0 { if len(files) == 0 {
return fmt.Errorf("directory %s has no files, cannot import from it", keysDir) return fmt.Errorf("directory %s has no files, cannot import from it", keysDir)
} }
keystoreFileNames := make([]string, 0) filesInDir := make([]string, 0)
for i := 0; i < len(files); i++ { for i := 0; i < len(files); i++ {
if files[i].IsDir() { if files[i].IsDir() {
continue continue
} }
if !strings.HasPrefix(files[i].Name(), "keystore") { filesInDir = append(filesInDir, files[i].Name())
continue
}
keystoreFileNames = append(keystoreFileNames, files[i].Name())
} }
// Sort the imported keystores by derivation path if they // Sort the imported keystores by derivation path if they
// specify this value in their filename. // specify this value in their filename.
sort.Sort(byDerivationPath(keystoreFileNames)) sort.Sort(byDerivationPath(filesInDir))
for _, name := range keystoreFileNames { for _, name := range filesInDir {
keystore, err := readKeystoreFile(ctx, filepath.Join(keysDir, name)) keystore, err := readKeystoreFile(ctx, filepath.Join(keysDir, name))
if err != nil { if err != nil && strings.Contains(err.Error(), "could not decode keystore json") {
continue
} else if err != nil {
return errors.Wrapf(err, "could not import keystore at path: %s", name) return errors.Wrapf(err, "could not import keystore at path: %s", name)
} }
keystoresImported = append(keystoresImported, keystore) keystoresImported = append(keystoresImported, keystore)
@ -228,6 +227,9 @@ func readKeystoreFile(ctx context.Context, keystoreFilePath string) (*v2keymanag
if err := json.Unmarshal(keystoreBytes, keystoreFile); err != nil { if err := json.Unmarshal(keystoreBytes, keystoreFile); err != nil {
return nil, errors.Wrap(err, "could not decode keystore json") return nil, errors.Wrap(err, "could not decode keystore json")
} }
if keystoreFile.Pubkey == "" {
return nil, errors.New("could not decode keystore json")
}
return keystoreFile, nil return keystoreFile, nil
} }

View File

@ -80,6 +80,60 @@ func TestImport_Noninteractive(t *testing.T) {
assert.Equal(t, 2, len(keys)) assert.Equal(t, 2, len(keys))
} }
func TestImport_Noninteractive_RandomName(t *testing.T) {
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
randPath, err := rand.Int(rand.Reader, big.NewInt(1000000))
require.NoError(t, err, "Could not generate random file path")
keysDir := filepath.Join(testutil.TempDir(), fmt.Sprintf("/%d", randPath), "keysDir")
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
t.Cleanup(func() {
require.NoError(t, os.RemoveAll(keysDir), "Failed to remove directory")
})
cliCtx := setupWalletCtx(t, &testWalletConfig{
walletDir: walletDir,
passwordsDir: passwordsDir,
keysDir: keysDir,
keymanagerKind: v2keymanager.Direct,
walletPasswordFile: passwordFilePath,
accountPasswordFile: passwordFilePath,
})
wallet, err := NewWallet(cliCtx, v2keymanager.Direct)
require.NoError(t, err)
require.NoError(t, wallet.SaveWallet())
ctx := context.Background()
encodedCfg, err := direct.MarshalConfigFile(ctx, direct.DefaultConfig())
require.NoError(t, err)
require.NoError(t, wallet.WriteKeymanagerConfigToDisk(ctx, encodedCfg))
keymanager, err := direct.NewKeymanager(
cliCtx,
wallet,
direct.DefaultConfig(),
)
require.NoError(t, err)
// Make sure there are no accounts at the start.
accounts, err := keymanager.ValidatingAccountNames()
require.NoError(t, err)
assert.Equal(t, len(accounts), 0)
// Create 2 keys.
createRandomNameKeystore(t, keysDir)
time.Sleep(time.Second)
createRandomNameKeystore(t, keysDir)
require.NoError(t, ImportAccounts(cliCtx))
wallet, err = OpenWallet(cliCtx)
require.NoError(t, err)
km, err := wallet.InitializeKeymanager(cliCtx, true)
require.NoError(t, err)
keys, err := km.FetchValidatingPublicKeys(ctx)
require.NoError(t, err)
assert.Equal(t, 2, len(keys))
}
func TestImport_Noninteractive_Filepath(t *testing.T) { func TestImport_Noninteractive_Filepath(t *testing.T) {
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t) walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
randPath, err := rand.Int(rand.Reader, big.NewInt(1000000)) randPath, err := rand.Int(rand.Reader, big.NewInt(1000000))
@ -272,3 +326,28 @@ func createKeystore(t *testing.T, path string) (*v2keymanager.Keystore, string)
require.NoError(t, ioutil.WriteFile(fullPath, encoded, os.ModePerm)) require.NoError(t, ioutil.WriteFile(fullPath, encoded, os.ModePerm))
return keystoreFile, fullPath return keystoreFile, fullPath
} }
// Returns the fullPath to the newly created keystore file.
func createRandomNameKeystore(t *testing.T, path string) (*v2keymanager.Keystore, string) {
validatingKey := bls.RandKey()
encryptor := keystorev4.New()
cryptoFields, err := encryptor.Encrypt(validatingKey.Marshal(), password)
require.NoError(t, err)
id, err := uuid.NewRandom()
require.NoError(t, err)
keystoreFile := &v2keymanager.Keystore{
Crypto: cryptoFields,
ID: id.String(),
Pubkey: fmt.Sprintf("%x", validatingKey.PublicKey().Marshal()),
Version: encryptor.Version(),
Name: encryptor.Name(),
}
encoded, err := json.MarshalIndent(keystoreFile, "", "\t")
require.NoError(t, err)
// Write the encoded keystore to disk with the timestamp appended
random, err := rand.Int(rand.Reader, big.NewInt(1000000))
require.NoError(t, err)
fullPath := filepath.Join(path, fmt.Sprintf("test-%d-keystore", random.Int64()))
require.NoError(t, ioutil.WriteFile(fullPath, encoded, os.ModePerm))
return keystoreFile, fullPath
}