Merge branch 'master' into sfedgecase
This commit is contained in:
commit
fc9ceb9131
@ -205,6 +205,13 @@ impl AccountProvider {
|
|||||||
self.unlock_account(account, password, Unlock::Temp)
|
self.unlock_account(account, password, Unlock::Temp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if given account is unlocked
|
||||||
|
pub fn is_unlocked<A>(&self, account: A) -> bool where Address: From<A> {
|
||||||
|
let account = Address::from(account).into();
|
||||||
|
let unlocked = self.unlocked.read().unwrap();
|
||||||
|
unlocked.get(&account).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
/// Signs the message. Account must be unlocked.
|
/// Signs the message. Account must be unlocked.
|
||||||
pub fn sign<A, M>(&self, account: A, message: M) -> Result<H520, Error> where Address: From<A>, Message: From<M> {
|
pub fn sign<A, M>(&self, account: A, message: M) -> Result<H520, Error> where Address: From<A>, Message: From<M> {
|
||||||
let account = Address::from(account).into();
|
let account = Address::from(account).into();
|
||||||
|
@ -20,6 +20,7 @@ Usage:
|
|||||||
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
|
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
|
||||||
ethstore list [--dir DIR]
|
ethstore list [--dir DIR]
|
||||||
ethstore import [--src DIR] [--dir DIR]
|
ethstore import [--src DIR] [--dir DIR]
|
||||||
|
ethstore import-wallet <path> <password> [--dir DIR]
|
||||||
ethstore remove <address> <password> [--dir DIR]
|
ethstore remove <address> <password> [--dir DIR]
|
||||||
ethstore sign <address> <password> <message> [--dir DIR]
|
ethstore sign <address> <password> <message> [--dir DIR]
|
||||||
ethstore [-h | --help]
|
ethstore [-h | --help]
|
||||||
@ -38,6 +39,7 @@ Commands:
|
|||||||
change-pwd Change account password.
|
change-pwd Change account password.
|
||||||
list List accounts.
|
list List accounts.
|
||||||
import Import accounts from src.
|
import Import accounts from src.
|
||||||
|
import-wallet Import presale wallet.
|
||||||
remove Remove account.
|
remove Remove account.
|
||||||
sign Sign message.
|
sign Sign message.
|
||||||
```
|
```
|
||||||
@ -48,11 +50,11 @@ Commands:
|
|||||||
*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, any string
|
- `<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
|
||||||
|
|
||||||
```
|
```
|
||||||
ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 "this is sparta"
|
ethstore insert 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5 password.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -75,12 +77,12 @@ ethstore insert `ethkey generate random -s` "this is sparta"
|
|||||||
*Change account password.*
|
*Change account password.*
|
||||||
|
|
||||||
- `<address>` - ethereum address, 20 bytes long
|
- `<address>` - ethereum address, 20 bytes long
|
||||||
- `<old-pwd>` - old account password, any string
|
- `<old-pwd>` - old account password, file path
|
||||||
- `<new-pwd>` - new account password, any string
|
- `<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
|
||||||
|
|
||||||
```
|
```
|
||||||
ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e "this is sparta" "hello world"
|
ethstore change-pwd a8fa5dd30a87bb9e3288d604eb74949c515ab66e old_pwd.txt new_pwd.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -112,6 +114,10 @@ ethstore list
|
|||||||
- `[--src DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: geth
|
- `[--src DIR]` - secret store directory, It may be either parity, parity-test, geth, geth-test or a path. default: geth
|
||||||
- `[--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
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore import
|
||||||
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
0: e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
|
0: e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
|
||||||
1: 6edddfc6349aff20bc6467ccf276c5b52487f7a8
|
1: 6edddfc6349aff20bc6467ccf276c5b52487f7a8
|
||||||
@ -119,15 +125,32 @@ ethstore list
|
|||||||
|
|
||||||
--
|
--
|
||||||
|
|
||||||
|
#### `import-wallet <path> <password> [--dir DIR]`
|
||||||
|
*Import account from presale wallet.*
|
||||||
|
|
||||||
|
- `<path>` - presale wallet 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
|
||||||
|
|
||||||
|
```
|
||||||
|
ethstore import-wallet ethwallet.json password.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
|
||||||
|
```
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
#### `remove <address> <password> [--dir DIR]`
|
#### `remove <address> <password> [--dir DIR]`
|
||||||
*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, any string
|
- `<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
|
||||||
|
|
||||||
```
|
```
|
||||||
ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e "hello world"
|
ethstore remove a8fa5dd30a87bb9e3288d604eb74949c515ab66e password.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
@ -140,12 +163,12 @@ true
|
|||||||
*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, any string
|
- `<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
|
||||||
|
|
||||||
```
|
```
|
||||||
ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 "this is sparta" 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5
|
ethstore sign 24edfff680d536a5f6fe862d36df6f8f6f40f115 password.txt 7d29fab185a33e2cd955812397354c472d2b84615b645aa135ff539f6b0d70d5
|
||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -18,13 +18,14 @@ extern crate rustc_serialize;
|
|||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
extern crate ethstore;
|
extern crate ethstore;
|
||||||
|
|
||||||
use std::{env, process};
|
use std::{env, process, fs};
|
||||||
|
use std::io::Read;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use ethstore::ethkey::{Secret, Address, Message};
|
use ethstore::ethkey::{Secret, Address, Message};
|
||||||
use ethstore::dir::{KeyDirectory, ParityDirectory, DiskDirectory, GethDirectory, DirectoryType};
|
use ethstore::dir::{KeyDirectory, ParityDirectory, DiskDirectory, GethDirectory, DirectoryType};
|
||||||
use ethstore::{EthStore, SecretStore, import_accounts, Error};
|
use ethstore::{EthStore, SecretStore, import_accounts, Error, PresaleWallet};
|
||||||
|
|
||||||
pub const USAGE: &'static str = r#"
|
pub const USAGE: &'static str = r#"
|
||||||
Ethereum key management.
|
Ethereum key management.
|
||||||
@ -35,6 +36,7 @@ Usage:
|
|||||||
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
|
ethstore change-pwd <address> <old-pwd> <new-pwd> [--dir DIR]
|
||||||
ethstore list [--dir DIR]
|
ethstore list [--dir DIR]
|
||||||
ethstore import [--src DIR] [--dir DIR]
|
ethstore import [--src DIR] [--dir DIR]
|
||||||
|
ethstore import-wallet <path> <password> [--dir DIR]
|
||||||
ethstore remove <address> <password> [--dir DIR]
|
ethstore remove <address> <password> [--dir DIR]
|
||||||
ethstore sign <address> <password> <message> [--dir DIR]
|
ethstore sign <address> <password> <message> [--dir DIR]
|
||||||
ethstore [-h | --help]
|
ethstore [-h | --help]
|
||||||
@ -53,6 +55,7 @@ Commands:
|
|||||||
change-pwd Change password.
|
change-pwd Change password.
|
||||||
list List accounts.
|
list List accounts.
|
||||||
import Import accounts from src.
|
import Import accounts from src.
|
||||||
|
import-wallet Import presale wallet.
|
||||||
remove Remove account.
|
remove Remove account.
|
||||||
sign Sign message.
|
sign Sign message.
|
||||||
"#;
|
"#;
|
||||||
@ -63,6 +66,7 @@ struct Args {
|
|||||||
cmd_change_pwd: bool,
|
cmd_change_pwd: bool,
|
||||||
cmd_list: bool,
|
cmd_list: bool,
|
||||||
cmd_import: bool,
|
cmd_import: bool,
|
||||||
|
cmd_import_wallet: bool,
|
||||||
cmd_remove: bool,
|
cmd_remove: bool,
|
||||||
cmd_sign: bool,
|
cmd_sign: bool,
|
||||||
arg_secret: String,
|
arg_secret: String,
|
||||||
@ -71,6 +75,7 @@ struct Args {
|
|||||||
arg_new_pwd: String,
|
arg_new_pwd: String,
|
||||||
arg_address: String,
|
arg_address: String,
|
||||||
arg_message: String,
|
arg_message: String,
|
||||||
|
arg_path: String,
|
||||||
flag_src: String,
|
flag_src: String,
|
||||||
flag_dir: String,
|
flag_dir: String,
|
||||||
}
|
}
|
||||||
@ -105,6 +110,15 @@ fn format_accounts(accounts: &[Address]) -> String {
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_password(path: &str) -> Result<String, Error> {
|
||||||
|
let mut file = try!(fs::File::open(path));
|
||||||
|
let mut password = String::new();
|
||||||
|
try!(file.read_to_string(&mut password));
|
||||||
|
// drop EOF
|
||||||
|
let _ = password.pop();
|
||||||
|
Ok(password)
|
||||||
|
}
|
||||||
|
|
||||||
fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item=S>, S: AsRef<str> {
|
||||||
let args: Args = Docopt::new(USAGE)
|
let args: Args = Docopt::new(USAGE)
|
||||||
.and_then(|d| d.argv(command).decode())
|
.and_then(|d| d.argv(command).decode())
|
||||||
@ -114,11 +128,14 @@ 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 = try!(Secret::from_str(&args.arg_secret));
|
let secret = try!(Secret::from_str(&args.arg_secret));
|
||||||
let address = try!(store.insert_account(secret, &args.arg_password));
|
let password = try!(load_password(&args.arg_password));
|
||||||
|
let address = try!(store.insert_account(secret, &password));
|
||||||
Ok(format!("{}", address))
|
Ok(format!("{}", address))
|
||||||
} else if args.cmd_change_pwd {
|
} else if args.cmd_change_pwd {
|
||||||
let address = try!(Address::from_str(&args.arg_address));
|
let address = try!(Address::from_str(&args.arg_address));
|
||||||
let ok = store.change_password(&address, &args.arg_old_pwd, &args.arg_new_pwd).is_ok();
|
let old_pwd = try!(load_password(&args.arg_old_pwd));
|
||||||
|
let new_pwd = try!(load_password(&args.arg_new_pwd));
|
||||||
|
let ok = store.change_password(&address, &old_pwd, &new_pwd).is_ok();
|
||||||
Ok(format!("{}", ok))
|
Ok(format!("{}", ok))
|
||||||
} else if args.cmd_list {
|
} else if args.cmd_list {
|
||||||
let accounts = store.accounts();
|
let accounts = store.accounts();
|
||||||
@ -128,14 +145,22 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
|
|||||||
let dst = try!(key_dir(&args.flag_dir));
|
let dst = try!(key_dir(&args.flag_dir));
|
||||||
let accounts = try!(import_accounts(src.deref(), dst.deref()));
|
let accounts = try!(import_accounts(src.deref(), dst.deref()));
|
||||||
Ok(format_accounts(&accounts))
|
Ok(format_accounts(&accounts))
|
||||||
|
} else if args.cmd_import_wallet {
|
||||||
|
let wallet = try!(PresaleWallet::open(&args.arg_path));
|
||||||
|
let password = try!(load_password(&args.arg_password));
|
||||||
|
let kp = try!(wallet.decrypt(&password));
|
||||||
|
let address = try!(store.insert_account(kp.secret().clone(), &password));
|
||||||
|
Ok(format!("{}", address))
|
||||||
} else if args.cmd_remove {
|
} else if args.cmd_remove {
|
||||||
let address = try!(Address::from_str(&args.arg_address));
|
let address = try!(Address::from_str(&args.arg_address));
|
||||||
let ok = store.remove_account(&address, &args.arg_password).is_ok();
|
let password = try!(load_password(&args.arg_password));
|
||||||
|
let ok = store.remove_account(&address, &password).is_ok();
|
||||||
Ok(format!("{}", ok))
|
Ok(format!("{}", ok))
|
||||||
} else if args.cmd_sign {
|
} else if args.cmd_sign {
|
||||||
let address = try!(Address::from_str(&args.arg_address));
|
let address = try!(Address::from_str(&args.arg_address));
|
||||||
let message = try!(Message::from_str(&args.arg_message));
|
let message = try!(Message::from_str(&args.arg_message));
|
||||||
let signature = try!(store.sign(&address, &args.arg_password, &message));
|
let password = try!(load_password(&args.arg_password));
|
||||||
|
let signature = try!(store.sign(&address, &password, &message));
|
||||||
Ok(format!("{}", signature))
|
Ok(format!("{}", signature))
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
|
@ -67,7 +67,7 @@ impl Keccak256<[u8; 32]> for [u8] {
|
|||||||
pub mod aes {
|
pub mod aes {
|
||||||
use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding};
|
use rcrypto::blockmodes::{CtrMode, CbcDecryptor, PkcsPadding};
|
||||||
use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor};
|
use rcrypto::aessafe::{AesSafe128Encryptor, AesSafe128Decryptor};
|
||||||
use rcrypto::symmetriccipher::{Encryptor, Decryptor};
|
use rcrypto::symmetriccipher::{Encryptor, Decryptor, SymmetricCipherError};
|
||||||
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer};
|
use rcrypto::buffer::{RefReadBuffer, RefWriteBuffer};
|
||||||
|
|
||||||
/// Encrypt a message
|
/// Encrypt a message
|
||||||
@ -83,9 +83,10 @@ pub mod aes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decrypt a message using cbc mode
|
/// Decrypt a message using cbc mode
|
||||||
pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) {
|
pub fn decrypt_cbc(k: &[u8], iv: &[u8], encrypted: &[u8], dest: &mut [u8]) -> Result<(), SymmetricCipherError> {
|
||||||
let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec());
|
let mut encryptor = CbcDecryptor::new(AesSafe128Decryptor::new(k), PkcsPadding, iv.to_vec());
|
||||||
encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true).expect("Invalid length or padding");
|
try!(encryptor.decrypt(&mut RefReadBuffer::new(encrypted), &mut RefWriteBuffer::new(dest), true));
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ impl PresaleWallet {
|
|||||||
pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key);
|
pbkdf2(&mut h_mac, password.as_bytes(), 2000, &mut derived_key);
|
||||||
|
|
||||||
let mut key = [0u8; 64];
|
let mut key = [0u8; 64];
|
||||||
crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key);
|
try!(crypto::aes::decrypt_cbc(&derived_key, &self.iv, &self.ciphertext, &mut key).map_err(|_| Error::InvalidPassword));
|
||||||
|
|
||||||
let secret = Secret::from(key.keccak256());
|
let secret = Secret::from(key.keccak256());
|
||||||
if let Ok(kp) = KeyPair::from_secret(secret) {
|
if let Ok(kp) = KeyPair::from_secret(secret) {
|
||||||
@ -58,7 +58,6 @@ impl PresaleWallet {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ethkey::Address;
|
|
||||||
use super::PresaleWallet;
|
use super::PresaleWallet;
|
||||||
use json;
|
use json;
|
||||||
|
|
||||||
@ -74,7 +73,7 @@ mod tests {
|
|||||||
|
|
||||||
let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap();
|
let wallet = json::PresaleWallet::load(json.as_bytes()).unwrap();
|
||||||
let wallet = PresaleWallet::from(wallet);
|
let wallet = PresaleWallet::from(wallet);
|
||||||
let kp = wallet.decrypt("123").unwrap();
|
assert!(wallet.decrypt("123").is_ok());
|
||||||
assert_eq!(kp.address(), Address::from(wallet.address));
|
assert!(wallet.decrypt("124").is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ Usage:
|
|||||||
parity daemon <pid-file> [options]
|
parity daemon <pid-file> [options]
|
||||||
parity account (new | list ) [options]
|
parity account (new | list ) [options]
|
||||||
parity account import <path>... [options]
|
parity account import <path>... [options]
|
||||||
|
parity wallet import <path> --password FILE [options]
|
||||||
parity import [ <file> ] [options]
|
parity import [ <file> ] [options]
|
||||||
parity export [ <file> ] [options]
|
parity export [ <file> ] [options]
|
||||||
parity signer new-token [options]
|
parity signer new-token [options]
|
||||||
@ -115,7 +116,7 @@ API and Console Options:
|
|||||||
--dapps-path PATH Specify directory where dapps should be installed.
|
--dapps-path PATH Specify directory where dapps should be installed.
|
||||||
[default: $HOME/.parity/dapps]
|
[default: $HOME/.parity/dapps]
|
||||||
|
|
||||||
--signer Enable Trusted Signer WebSocket endpoint used by
|
--signer-off Disable Trusted Signer WebSocket endpoint used by
|
||||||
Signer UIs.
|
Signer UIs.
|
||||||
--signer-port PORT Specify the port of Trusted Signer server
|
--signer-port PORT Specify the port of Trusted Signer server
|
||||||
[default: 8180].
|
[default: 8180].
|
||||||
@ -223,6 +224,7 @@ Miscellaneous Options:
|
|||||||
pub struct Args {
|
pub struct Args {
|
||||||
pub cmd_daemon: bool,
|
pub cmd_daemon: bool,
|
||||||
pub cmd_account: bool,
|
pub cmd_account: bool,
|
||||||
|
pub cmd_wallet: bool,
|
||||||
pub cmd_new: bool,
|
pub cmd_new: bool,
|
||||||
pub cmd_list: bool,
|
pub cmd_list: bool,
|
||||||
pub cmd_export: bool,
|
pub cmd_export: bool,
|
||||||
@ -272,7 +274,7 @@ pub struct Args {
|
|||||||
pub flag_dapps_user: Option<String>,
|
pub flag_dapps_user: Option<String>,
|
||||||
pub flag_dapps_pass: Option<String>,
|
pub flag_dapps_pass: Option<String>,
|
||||||
pub flag_dapps_path: String,
|
pub flag_dapps_path: String,
|
||||||
pub flag_signer: bool,
|
pub flag_signer_off: bool,
|
||||||
pub flag_signer_port: u16,
|
pub flag_signer_port: u16,
|
||||||
pub flag_signer_path: String,
|
pub flag_signer_path: String,
|
||||||
pub flag_no_token: bool,
|
pub flag_no_token: bool,
|
||||||
|
@ -432,10 +432,10 @@ impl Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn signer_port(&self) -> Option<u16> {
|
pub fn signer_port(&self) -> Option<u16> {
|
||||||
if self.args.flag_signer {
|
if self.args.flag_signer_off {
|
||||||
Some(self.args.flag_signer_port)
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.args.flag_signer_port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,11 @@ fn execute(conf: Configuration) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if conf.args.cmd_wallet {
|
||||||
|
execute_wallet_cli(conf);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if conf.args.cmd_export {
|
if conf.args.cmd_export {
|
||||||
execute_export(conf);
|
execute_export(conf);
|
||||||
return;
|
return;
|
||||||
@ -187,12 +192,18 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
|
|||||||
let sync_config = conf.sync_config(&spec);
|
let sync_config = conf.sync_config(&spec);
|
||||||
|
|
||||||
// Create and display a new token for UIs.
|
// Create and display a new token for UIs.
|
||||||
if conf.args.flag_signer && !conf.args.flag_no_token {
|
if !conf.args.flag_signer_off && !conf.args.flag_no_token {
|
||||||
new_token(conf.directories().signer).unwrap_or_else(|e| {
|
new_token(conf.directories().signer).unwrap_or_else(|e| {
|
||||||
die!("Error generating token: {:?}", e)
|
die!("Error generating token: {:?}", e)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Display warning about using unlock with signer
|
||||||
|
if conf.args.flag_signer && conf.args.flag_unlock.is_some() {
|
||||||
|
warn!("Using Trusted Signer and --unlock is not recommended!");
|
||||||
|
warn!("NOTE that Signer will not ask you to confirm transactions from unlocked account.");
|
||||||
|
}
|
||||||
|
|
||||||
// Secret Store
|
// Secret Store
|
||||||
let account_service = Arc::new(conf.account_service());
|
let account_service = Arc::new(conf.account_service());
|
||||||
|
|
||||||
@ -534,6 +545,30 @@ fn execute_account_cli(conf: Configuration) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn execute_wallet_cli(conf: Configuration) {
|
||||||
|
use ethcore::ethstore::{PresaleWallet, SecretStore, EthStore};
|
||||||
|
use ethcore::ethstore::dir::DiskDirectory;
|
||||||
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
|
||||||
|
let wallet_path = conf.args.arg_path.first().unwrap();
|
||||||
|
let filename = conf.args.flag_password.first().unwrap();
|
||||||
|
let mut file = File::open(filename).unwrap_or_else(|_| die!("{} Unable to read password file.", filename));
|
||||||
|
let mut file_content = String::new();
|
||||||
|
file.read_to_string(&mut file_content).unwrap_or_else(|_| die!("{} Unable to read password file.", filename));
|
||||||
|
|
||||||
|
let dir = Box::new(DiskDirectory::create(conf.keys_path()).unwrap());
|
||||||
|
let iterations = conf.keys_iterations();
|
||||||
|
let store = AccountProvider::new(Box::new(EthStore::open_with_iterations(dir, iterations).unwrap()));
|
||||||
|
|
||||||
|
// remove eof
|
||||||
|
let pass = &file_content[..file_content.len() - 1];
|
||||||
|
let wallet = PresaleWallet::open(wallet_path).unwrap_or_else(|_| die!("Unable to open presale wallet."));
|
||||||
|
let kp = wallet.decrypt(pass).unwrap_or_else(|_| die!("Invalid password"));
|
||||||
|
let address = store.insert_account(kp.secret().clone(), pass).unwrap();
|
||||||
|
|
||||||
|
println!("Imported account: {}", address);
|
||||||
|
}
|
||||||
|
|
||||||
fn wait_for_exit(
|
fn wait_for_exit(
|
||||||
panic_handler: Arc<PanicHandler>,
|
panic_handler: Arc<PanicHandler>,
|
||||||
_rpc_server: Option<RpcServer>,
|
_rpc_server: Option<RpcServer>,
|
||||||
|
@ -150,7 +150,7 @@ pub fn setup_rpc<T: Extendable>(server: T, deps: Arc<Dependencies>, apis: ApiSet
|
|||||||
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
|
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
|
||||||
|
|
||||||
if deps.signer_port.is_some() {
|
if deps.signer_port.is_some() {
|
||||||
server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue, &deps.client, &deps.miner).to_delegate());
|
server.add_delegate(EthSigningQueueClient::new(&deps.signer_queue, &deps.client, &deps.miner, &deps.secret_store).to_delegate());
|
||||||
} else {
|
} else {
|
||||||
server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
|
server.add_delegate(EthSigningUnsafeClient::new(&deps.client, &deps.secret_store, &deps.miner).to_delegate());
|
||||||
}
|
}
|
||||||
|
@ -43,15 +43,17 @@ fn fill_optional_fields<C, M>(request: &mut TransactionRequest, client: &C, mine
|
|||||||
/// Implementation of functions that require signing when no trusted signer is used.
|
/// Implementation of functions that require signing when no trusted signer is used.
|
||||||
pub struct EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
pub struct EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||||
queue: Weak<ConfirmationsQueue>,
|
queue: Weak<ConfirmationsQueue>,
|
||||||
|
accounts: Weak<AccountProvider>,
|
||||||
client: Weak<C>,
|
client: Weak<C>,
|
||||||
miner: Weak<M>,
|
miner: Weak<M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, M> EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
impl<C, M> EthSigningQueueClient<C, M> where C: MiningBlockChainClient, M: MinerService {
|
||||||
/// Creates a new signing queue client given shared signing queue.
|
/// Creates a new signing queue client given shared signing queue.
|
||||||
pub fn new(queue: &Arc<ConfirmationsQueue>, client: &Arc<C>, miner: &Arc<M>) -> Self {
|
pub fn new(queue: &Arc<ConfirmationsQueue>, client: &Arc<C>, miner: &Arc<M>, accounts: &Arc<AccountProvider>) -> Self {
|
||||||
EthSigningQueueClient {
|
EthSigningQueueClient {
|
||||||
queue: Arc::downgrade(queue),
|
queue: Arc::downgrade(queue),
|
||||||
|
accounts: Arc::downgrade(accounts),
|
||||||
client: Arc::downgrade(client),
|
client: Arc::downgrade(client),
|
||||||
miner: Arc::downgrade(miner),
|
miner: Arc::downgrade(miner),
|
||||||
}
|
}
|
||||||
@ -71,9 +73,18 @@ impl<C, M> EthSigning for EthSigningQueueClient<C, M>
|
|||||||
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
|
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
|
||||||
from_params::<(TransactionRequest, )>(params)
|
from_params::<(TransactionRequest, )>(params)
|
||||||
.and_then(|(mut request, )| {
|
.and_then(|(mut request, )| {
|
||||||
let queue = take_weak!(self.queue);
|
let accounts = take_weak!(self.accounts);
|
||||||
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
|
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
|
||||||
|
|
||||||
|
if accounts.is_unlocked(request.from) {
|
||||||
|
let sender = request.from;
|
||||||
|
return match sign_and_dispatch(&*client, &*miner, request, &*accounts, sender) {
|
||||||
|
Ok(hash) => to_value(&hash),
|
||||||
|
_ => to_value(&H256::zero()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let queue = take_weak!(self.queue);
|
||||||
fill_optional_fields(&mut request, &*client, &*miner);
|
fill_optional_fields(&mut request, &*client, &*miner);
|
||||||
let id = queue.add_request(request);
|
let id = queue.add_request(request);
|
||||||
let result = id.wait_with_timeout();
|
let result = id.wait_with_timeout();
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
use v1::impls::EthSigningQueueClient;
|
use v1::impls::EthSigningQueueClient;
|
||||||
@ -21,12 +22,16 @@ use v1::traits::EthSigning;
|
|||||||
use v1::helpers::{ConfirmationsQueue, SigningQueue};
|
use v1::helpers::{ConfirmationsQueue, SigningQueue};
|
||||||
use v1::tests::helpers::TestMinerService;
|
use v1::tests::helpers::TestMinerService;
|
||||||
use util::{Address, FixedHash};
|
use util::{Address, FixedHash};
|
||||||
|
use util::numbers::{Uint, U256};
|
||||||
|
use ethcore::account_provider::AccountProvider;
|
||||||
use ethcore::client::TestBlockChainClient;
|
use ethcore::client::TestBlockChainClient;
|
||||||
|
use ethcore::transaction::{Transaction, Action};
|
||||||
|
|
||||||
struct EthSigningTester {
|
struct EthSigningTester {
|
||||||
pub queue: Arc<ConfirmationsQueue>,
|
pub queue: Arc<ConfirmationsQueue>,
|
||||||
pub client: Arc<TestBlockChainClient>,
|
pub client: Arc<TestBlockChainClient>,
|
||||||
pub miner: Arc<TestMinerService>,
|
pub miner: Arc<TestMinerService>,
|
||||||
|
pub accounts: Arc<AccountProvider>,
|
||||||
pub io: IoHandler,
|
pub io: IoHandler,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,13 +40,15 @@ impl Default for EthSigningTester {
|
|||||||
let queue = Arc::new(ConfirmationsQueue::default());
|
let queue = Arc::new(ConfirmationsQueue::default());
|
||||||
let client = Arc::new(TestBlockChainClient::default());
|
let client = Arc::new(TestBlockChainClient::default());
|
||||||
let miner = Arc::new(TestMinerService::default());
|
let miner = Arc::new(TestMinerService::default());
|
||||||
|
let accounts = Arc::new(AccountProvider::transient_provider());
|
||||||
let io = IoHandler::new();
|
let io = IoHandler::new();
|
||||||
io.add_delegate(EthSigningQueueClient::new(&queue, &client, &miner).to_delegate());
|
io.add_delegate(EthSigningQueueClient::new(&queue, &client, &miner, &accounts).to_delegate());
|
||||||
|
|
||||||
EthSigningTester {
|
EthSigningTester {
|
||||||
queue: queue,
|
queue: queue,
|
||||||
client: client,
|
client: client,
|
||||||
miner: miner,
|
miner: miner,
|
||||||
|
accounts: accounts,
|
||||||
io: io,
|
io: io,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,5 +85,41 @@ fn should_add_transaction_to_queue() {
|
|||||||
// then
|
// then
|
||||||
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
|
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
|
||||||
assert_eq!(tester.queue.requests().len(), 1);
|
assert_eq!(tester.queue.requests().len(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn should_dispatch_transaction_if_account_is_unlocked() {
|
||||||
|
// given
|
||||||
|
let tester = eth_signing();
|
||||||
|
let acc = tester.accounts.new_account("test").unwrap();
|
||||||
|
tester.accounts.unlock_account_permanently(acc, "test".into()).unwrap();
|
||||||
|
|
||||||
|
let t = Transaction {
|
||||||
|
nonce: U256::zero(),
|
||||||
|
gas_price: U256::from(0x9184e72a000u64),
|
||||||
|
gas: U256::from(0x76c0),
|
||||||
|
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
|
||||||
|
value: U256::from(0x9184e72au64),
|
||||||
|
data: vec![]
|
||||||
|
};
|
||||||
|
let signature = tester.accounts.sign(acc, t.hash()).unwrap();
|
||||||
|
let t = t.with_signature(signature);
|
||||||
|
|
||||||
|
// when
|
||||||
|
let request = r#"{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "eth_sendTransaction",
|
||||||
|
"params": [{
|
||||||
|
"from": ""#.to_owned() + format!("0x{:?}", acc).as_ref() + r#"",
|
||||||
|
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
|
||||||
|
"gas": "0x76c0",
|
||||||
|
"gasPrice": "0x9184e72a000",
|
||||||
|
"value": "0x9184e72a"
|
||||||
|
}],
|
||||||
|
"id": 1
|
||||||
|
}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
|
||||||
|
|
||||||
|
// then
|
||||||
|
assert_eq!(tester.io.handle_request(&request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,6 @@ impl Server {
|
|||||||
let config = {
|
let config = {
|
||||||
let mut config = ws::Settings::default();
|
let mut config = ws::Settings::default();
|
||||||
// It's also used for handling min-sysui requests (browser can make many of them in paralel)
|
// It's also used for handling min-sysui requests (browser can make many of them in paralel)
|
||||||
config.max_connections = 15;
|
|
||||||
config.method_strict = true;
|
config.method_strict = true;
|
||||||
// Was shutting down server when suspending on linux:
|
// Was shutting down server when suspending on linux:
|
||||||
config.shutdown_on_interrupt = false;
|
config.shutdown_on_interrupt = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user