Added vaults support to ethstore-cli (#4532)

* added vaults support to ethstore-cli

* improved error message
This commit is contained in:
Svyatoslav Nikolsky 2017-02-16 19:42:01 +03:00 committed by Gav Wood
parent aa83603af8
commit 00c843afea
2 changed files with 263 additions and 42 deletions

View File

@ -16,13 +16,19 @@ Ethereum key management.
Copyright 2016, 2017 Parity Technologies (UK) Ltd Copyright 2016, 2017 Parity Technologies (UK) Ltd
Usage: Usage:
ethstore insert <secret> <password> [--dir DIR] ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore list [--dir DIR] ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore import [--src DIR] [--dir DIR] ethstore import [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR] ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore remove <address> <password> [--dir DIR] ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore sign <address> <password> <message> [--dir DIR] ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore list-vaults [--dir DIR]
ethstore create-vault <vault> <password> [--dir DIR]
ethstore change-vault-pwd <vault> <old-pwd> <new-pwd> [--dir DIR]
ethstore move-to-vault <address> <vault> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore move-from-vault <address> <vault> <password> [--dir DIR]
ethstore [-h | --help] ethstore [-h | --help]
Options: Options:
@ -30,6 +36,10 @@ Options:
--dir DIR Specify the secret store directory. It may be either --dir DIR Specify the secret store directory. It may be either
parity, parity-test, geth, geth-test parity, parity-test, geth, geth-test
or a path [default: parity]. or a path [default: parity].
--vault VAULT Specify vault to use in this operation.
--vault-pwd VAULTPWD Specify vault password to use in this operation. Please note
that this option is required when vault option is set.
Otherwise it is ignored.
--src DIR Specify import source. It may be either --src DIR Specify import source. It may be either
parity, parity-test, get, geth-test parity, parity-test, get, geth-test
or a path [default: geth]. or a path [default: geth].
@ -42,16 +52,24 @@ Commands:
import-wallet Import presale wallet. import-wallet Import presale wallet.
remove Remove account. remove Remove account.
sign Sign message. sign Sign message.
public Displays public key for an address.
list-vaults List vaults.
create-vault Create new vault.
change-vault-pwd Change vault password.
move-to-vault Move account to vault from another vault/root directory.
move-from-vault Move account to root directory from given vault or root.
``` ```
### Examples ### Examples
#### `insert <secret> <password> [--dir DIR]` #### `insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Encrypt secret with a password and save it in secret store.* *Encrypt secret with a password and save it in secret store.*
- `<secret>` - ethereum secret, 32 bytes long - `<secret>` - ethereum secret, 32 bytes long
- `<password>` - account password, file path - `<password>` - account password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
``` ```
ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 password.txt ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 password.txt
@ -73,13 +91,15 @@ ethstore insert `ethkey generate random -s` "this is sparta"
-- --
#### `change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]` #### `change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Change account password.* *Change account password.*
- `<address>` - ethereum address, 20 bytes long - `<address>` - ethereum address, 20 bytes long
- `<old-pwd>` - old account password, file path - `<old-pwd>` - old account password, file path
- `<new-pwd>` - new account password, file path - `<new-pwd>` - new account password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
``` ```
ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e old_pwd.txt new_pwd.txt ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e old_pwd.txt new_pwd.txt
@ -91,10 +111,12 @@ true
-- --
#### `list [--dir DIR]` #### `list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*List secret store accounts.* *List secret store accounts.*
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
``` ```
ethstore list ethstore list
@ -125,12 +147,14 @@ ethstore import
-- --
#### `import-wallet <path> <password> [--dir DIR]` #### `import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Import account from presale wallet.* *Import account from presale wallet.*
- `<path>` - presale wallet path - `<path>` - presale wallet path
- `<password>` - account password, file path - `<password>` - account password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
``` ```
ethstore import-wallet ethwallet.json password.txt ethstore import-wallet ethwallet.json password.txt
@ -142,12 +166,14 @@ e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
-- --
#### `remove <address> <password> [--dir DIR]` #### `remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Remove account from secret store.* *Remove account from secret store.*
- `<address>` - ethereum address, 20 bytes long - `<address>` - ethereum address, 20 bytes long
- `<password>` - account password, file path - `<password>` - account password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
``` ```
ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e password.txt ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e password.txt
@ -159,13 +185,15 @@ true
-- --
#### `sign <address> <password> <message> [--dir DIR]` #### `sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Sign message with account's secret.* *Sign message with account's secret.*
- `<address>` - ethereum address, 20 bytes long - `<address>` - ethereum address, 20 bytes long
- `<password>` - account password, file path - `<password>` - account password, file path
- `<message>` - message to sign, 32 bytes long - `<message>` - message to sign, 32 bytes long
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity - `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
``` ```
ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 password.txt 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 password.txt 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5
@ -177,6 +205,119 @@ c6649f9555232d90ff716d7e552a744c5af771574425a74860e12f763479eb1b708c1f3a7dc0a0a7
-- --
#### `public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Displays public key for an address.*
- `<address>` - ethereum address, 20 bytes long
- `<password>` - account password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - vault to use in this operation
- `[--vault-pwd VAULTPWD]` - vault password to use in this operation, file path
```
ethstore public 00e63fdb87ceb815ec96ae185b8f7381a0b4a5ea account_password.txt --vault vault_name --vault-pwd vault_password.txt
```
```
0x84161d8c05a996a534efbec50f24485cfcc07458efaef749a1b22156d7836c903eeb39bf2df74676e702eacc4cfdde069e5fd86692b5ef6ef81ba906e9e77d82
```
--
#### `list-vaults [--dir DIR]`
*List vaults.*
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
```
ethstore list-vaults
```
```
vault1
vault2
vault3
```
--
#### `create-vault <vault> <password> [--dir DIR]`
*Create new vault.*
- `<vault>` - name of new vault. This can only contain letters, digits, whitespaces, dashes and underscores
- `<password>` - vault password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
```
ethstore create-vault vault3 vault3_password.txt
```
```
OK
```
--
#### `change-vault-pwd <vault> <old-pwd> <new-pwd> [--dir DIR]`
*Change vault password.*
- `<vault>` - name of existing vault
- `<old-pwd>` - old vault password, file path
- `<new-pwd>` - new vault password, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
```
ethstore change-vault-pwd vault3 vault3_password.txt new_vault3_password.txt
```
```
OK
```
--
#### `move-to-vault <address> <vault> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
*Move account to vault from another vault/root directory.*
- `<address>` - ethereum address, 20 bytes long
- `<vault>` - name of existing vault to move account to
- `<password>` - password of existing `<vault>` to move account to, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
- `[--vault VAULT]` - current vault of the `<address>` argument, if set
- `[--vault-pwd VAULTPWD]` - password for the current vault of the `<address>` argument, if any. file path
```
ethstore move-to-vault 00e63fdb87ceb815ec96ae185b8f7381a0b4a5ea vault3 vault3_password.txt
ethstore move-to-vault 00e63fdb87ceb815ec96ae185b8f7381a0b4a5ea vault1 vault1_password.txt --vault vault3 --vault-pwd vault3_password.txt
```
```
OK
OK
```
--
#### `move-from-vault <address> <vault> <password> [--dir DIR]`
*Move account to root directory from given vault.*
- `<address>` - ethereum address, 20 bytes long
- `<vault>` - name of existing vault to move account to
- `<password>` - password of existing `<vault>` to move account to, file path
- `[--dir DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: parity
```
ethstore move-from-vault 00e63fdb87ceb815ec96ae185b8f7381a0b4a5ea vault1 vault1_password.txt
```
```
OK
```
--
# Ethcore toolchain # Ethcore toolchain
*this project is a part of the ethcore toolchain* *this project is a part of the ethcore toolchain*

View File

@ -31,14 +31,19 @@ Ethereum key management.
Copyright 2016, 2017 Parity Technologies (UK) Ltd Copyright 2016, 2017 Parity Technologies (UK) Ltd
Usage: Usage:
ethstore insert <secret> <password> [--dir DIR] ethstore insert <secret> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore list [--dir DIR] ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore import [--src DIR] [--dir DIR] ethstore import [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR] ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore remove <address> <password> [--dir DIR] ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore sign <address> <password> <message> [--dir DIR] ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore public <address> <password> ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore list-vaults [--dir DIR]
ethstore create-vault <vault> <password> [--dir DIR]
ethstore change-vault-pwd <vault> <old-pwd> <new-pwd> [--dir DIR]
ethstore move-to-vault <address> <vault> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore move-from-vault <address> <vault> <password> [--dir DIR]
ethstore [-h | --help] ethstore [-h | --help]
Options: Options:
@ -46,6 +51,10 @@ Options:
--dir DIR Specify the secret store directory. It may be either --dir DIR Specify the secret store directory. It may be either
parity, parity-test, geth, geth-test parity, parity-test, geth, geth-test
or a path [default: parity]. or a path [default: parity].
--vault VAULT Specify vault to use in this operation.
--vault-pwd VAULTPWD Specify vault password to use in this operation. Please note
that this option is required when vault option is set.
Otherwise it is ignored.
--src DIR Specify import source. It may be either --src DIR Specify import source. It may be either
parity, parity-test, get, geth-test parity, parity-test, get, geth-test
or a path [default: geth]. or a path [default: geth].
@ -59,6 +68,11 @@ Commands:
remove Remove account. remove Remove account.
sign Sign message. sign Sign message.
public Displays public key for an address. public Displays public key for an address.
list-vaults List vaults.
create-vault Create new vault.
change-vault-pwd Change vault password.
move-to-vault Move account to vault from another vault/root directory.
move-from-vault Move account to root directory from given vault.
"#; "#;
#[derive(Debug, RustcDecodable)] #[derive(Debug, RustcDecodable)]
@ -71,6 +85,11 @@ struct Args {
cmd_remove: bool, cmd_remove: bool,
cmd_sign: bool, cmd_sign: bool,
cmd_public: bool, cmd_public: bool,
cmd_list_vaults: bool,
cmd_create_vault: bool,
cmd_change_vault_pwd: bool,
cmd_move_to_vault: bool,
cmd_move_from_vault: bool,
arg_secret: String, arg_secret: String,
arg_password: String, arg_password: String,
arg_old_pwd: String, arg_old_pwd: String,
@ -78,8 +97,11 @@ struct Args {
arg_address: String, arg_address: String,
arg_message: String, arg_message: String,
arg_path: String, arg_path: String,
arg_vault: String,
flag_src: String, flag_src: String,
flag_dir: String, flag_dir: String,
flag_vault: String,
flag_vault_pwd: String,
} }
fn main() { fn main() {
@ -104,6 +126,23 @@ fn key_dir(location: &str) -> Result<Box<KeyDirectory>, Error> {
Ok(dir) Ok(dir)
} }
fn open_args_vault(store: &EthStore, args: &Args) -> Result<SecretVaultRef, Error> {
if args.flag_vault.is_empty() {
return Ok(SecretVaultRef::Root);
}
let vault_pwd = load_password(&args.flag_vault_pwd)?;
store.open_vault(&args.flag_vault, &vault_pwd)?;
Ok(SecretVaultRef::Vault(args.flag_vault.clone()))
}
fn open_args_vault_account(store: &EthStore, address: Address, args: &Args) -> Result<StoreAccountRef, Error> {
match open_args_vault(store, args)? {
SecretVaultRef::Root => Ok(StoreAccountRef::root(address)),
SecretVaultRef::Vault(name) => Ok(StoreAccountRef::vault(&name, address)),
}
}
fn format_accounts(accounts: &[Address]) -> String { fn format_accounts(accounts: &[Address]) -> String {
accounts.iter() accounts.iter()
.enumerate() .enumerate()
@ -112,10 +151,14 @@ fn format_accounts(accounts: &[Address]) -> String {
.join("\n") .join("\n")
} }
fn format_vaults(vaults: &[String]) -> String {
vaults.join("\n")
}
fn load_password(path: &str) -> Result<String, Error> { fn load_password(path: &str) -> Result<String, Error> {
let mut file = fs::File::open(path)?; let mut file = fs::File::open(path).map_err(|e| Error::Custom(format!("Error opening password file {}: {}", path, e)))?;
let mut password = String::new(); let mut password = String::new();
file.read_to_string(&mut password)?; file.read_to_string(&mut password).map_err(|e| Error::Custom(format!("Error reading password file {}: {}", path, e)))?;
// drop EOF // drop EOF
let _ = password.pop(); let _ = password.pop();
Ok(password) Ok(password)
@ -131,17 +174,24 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
return if args.cmd_insert { return if args.cmd_insert {
let secret = args.arg_secret.parse().map_err(|_| Error::InvalidSecret)?; let secret = args.arg_secret.parse().map_err(|_| Error::InvalidSecret)?;
let password = load_password(&args.arg_password)?; let password = load_password(&args.arg_password)?;
let address = store.insert_account(SecretVaultRef::Root, secret, &password)?; let vault_ref = open_args_vault(&store, &args)?;
let address = store.insert_account(vault_ref, secret, &password)?;
Ok(format!("0x{:?}", address)) Ok(format!("0x{:?}", address))
} else if args.cmd_change_pwd { } else if args.cmd_change_pwd {
let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?; let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?;
let old_pwd = load_password(&args.arg_old_pwd)?; let old_pwd = load_password(&args.arg_old_pwd)?;
let new_pwd = load_password(&args.arg_new_pwd)?; let new_pwd = load_password(&args.arg_new_pwd)?;
let ok = store.change_password(&StoreAccountRef::root(address), &old_pwd, &new_pwd).is_ok(); let account_ref = open_args_vault_account(&store, address, &args)?;
let ok = store.change_password(&account_ref, &old_pwd, &new_pwd).is_ok();
Ok(format!("{}", ok)) Ok(format!("{}", ok))
} else if args.cmd_list { } else if args.cmd_list {
let vault_ref = open_args_vault(&store, &args)?;
let accounts = store.accounts()?; let accounts = store.accounts()?;
let accounts: Vec<_> = accounts.into_iter().map(|a| a.address).collect(); let accounts: Vec<_> = accounts
.into_iter()
.filter(|a| &a.vault == &vault_ref)
.map(|a| a.address)
.collect();
Ok(format_accounts(&accounts)) Ok(format_accounts(&accounts))
} else if args.cmd_import { } else if args.cmd_import {
let src = key_dir(&args.flag_src)?; let src = key_dir(&args.flag_src)?;
@ -152,24 +202,54 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
let wallet = PresaleWallet::open(&args.arg_path)?; let wallet = PresaleWallet::open(&args.arg_path)?;
let password = load_password(&args.arg_password)?; let password = load_password(&args.arg_password)?;
let kp = wallet.decrypt(&password)?; let kp = wallet.decrypt(&password)?;
let address = store.insert_account(SecretVaultRef::Root, kp.secret().clone(), &password)?; let vault_ref = open_args_vault(&store, &args)?;
let address = store.insert_account(vault_ref, kp.secret().clone(), &password)?;
Ok(format!("0x{:?}", address)) Ok(format!("0x{:?}", address))
} else if args.cmd_remove { } else if args.cmd_remove {
let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?; let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?; let password = load_password(&args.arg_password)?;
let ok = store.remove_account(&StoreAccountRef::root(address), &password).is_ok(); let account_ref = open_args_vault_account(&store, address, &args)?;
let ok = store.remove_account(&account_ref, &password).is_ok();
Ok(format!("{}", ok)) Ok(format!("{}", ok))
} else if args.cmd_sign { } else if args.cmd_sign {
let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?; let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?;
let message = args.arg_message.parse().map_err(|_| Error::InvalidMessage)?; let message = args.arg_message.parse().map_err(|_| Error::InvalidMessage)?;
let password = load_password(&args.arg_password)?; let password = load_password(&args.arg_password)?;
let signature = store.sign(&StoreAccountRef::root(address), &password, &message)?; let account_ref = open_args_vault_account(&store, address, &args)?;
let signature = store.sign(&account_ref, &password, &message)?;
Ok(format!("0x{:?}", signature)) Ok(format!("0x{:?}", signature))
} else if args.cmd_public { } else if args.cmd_public {
let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?; let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?; let password = load_password(&args.arg_password)?;
let public = store.public(&StoreAccountRef::root(address), &password)?; let account_ref = open_args_vault_account(&store, address, &args)?;
let public = store.public(&account_ref, &password)?;
Ok(format!("0x{:?}", public)) Ok(format!("0x{:?}", public))
} else if args.cmd_list_vaults {
let vaults = store.list_vaults()?;
Ok(format_vaults(&vaults))
} else if args.cmd_create_vault {
let password = load_password(&args.arg_password)?;
store.create_vault(&args.arg_vault, &password)?;
Ok("OK".to_owned())
} else if args.cmd_change_vault_pwd {
let old_pwd = load_password(&args.arg_old_pwd)?;
let new_pwd = load_password(&args.arg_new_pwd)?;
store.open_vault(&args.arg_vault, &old_pwd)?;
store.change_vault_password(&args.arg_vault, &new_pwd)?;
Ok("OK".to_owned())
} else if args.cmd_move_to_vault {
let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?;
let account_ref = open_args_vault_account(&store, address, &args)?;
store.open_vault(&args.arg_vault, &password)?;
store.change_account_vault(SecretVaultRef::Vault(args.arg_vault), account_ref)?;
Ok("OK".to_owned())
} else if args.cmd_move_from_vault {
let address = args.arg_address.parse().map_err(|_| Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?;
store.open_vault(&args.arg_vault, &password)?;
store.change_account_vault(SecretVaultRef::Root, StoreAccountRef::vault(&args.arg_vault, address))?;
Ok("OK".to_owned())
} else { } else {
Ok(format!("{}", USAGE)) Ok(format!("{}", USAGE))
} }