Add type for passwords. (#8920)

* Add type for passwords.

* Fix test.

* Simplify `Drop` impls of `Password` and `Memzero`.

* Spaces to tabs.

* Custom `Drop` impl for `Password`.
This commit is contained in:
Toralf Wittner
2018-06-22 15:09:15 +02:00
committed by David
parent c473ab97c7
commit 41348dead4
61 changed files with 550 additions and 457 deletions

View File

@@ -85,7 +85,7 @@ fn secret_store(dir: Box<RootDiskDirectory>, iterations: Option<u32>) -> Result<
}
fn new(n: NewAccount) -> Result<String, String> {
let password: String = match n.password_file {
let password = match n.password_file {
Some(file) => password_from_file(file)?,
None => password_prompt()?,
};

View File

@@ -30,6 +30,7 @@ use upgrade::{upgrade, upgrade_data_paths};
use sync::{validate_node_url, self};
use db::migrate;
use path;
use ethkey::Password;
pub fn to_duration(s: &str) -> Result<Duration, String> {
to_seconds(s).map(Duration::from_secs)
@@ -277,7 +278,7 @@ pub fn execute_upgrades(
}
/// Prompts user asking for password.
pub fn password_prompt() -> Result<String, String> {
pub fn password_prompt() -> Result<Password, String> {
use rpassword::read_password;
const STDIN_ERROR: &'static str = "Unable to ask for password on non-interactive terminal.";
@@ -285,12 +286,12 @@ pub fn password_prompt() -> Result<String, String> {
print!("Type password: ");
flush_stdout();
let password = read_password().map_err(|_| STDIN_ERROR.to_owned())?;
let password = read_password().map_err(|_| STDIN_ERROR.to_owned())?.into();
print!("Repeat password: ");
flush_stdout();
let password_repeat = read_password().map_err(|_| STDIN_ERROR.to_owned())?;
let password_repeat = read_password().map_err(|_| STDIN_ERROR.to_owned())?.into();
if password != password_repeat {
return Err("Passwords do not match!".into());
@@ -300,24 +301,24 @@ pub fn password_prompt() -> Result<String, String> {
}
/// Read a password from password file.
pub fn password_from_file(path: String) -> Result<String, String> {
pub fn password_from_file(path: String) -> Result<Password, String> {
let passwords = passwords_from_files(&[path])?;
// use only first password from the file
passwords.get(0).map(String::to_owned)
passwords.get(0).map(Password::clone)
.ok_or_else(|| "Password file seems to be empty.".to_owned())
}
/// Reads passwords from files. Treats each line as a separate password.
pub fn passwords_from_files(files: &[String]) -> Result<Vec<String>, String> {
pub fn passwords_from_files(files: &[String]) -> Result<Vec<Password>, String> {
let passwords = files.iter().map(|filename| {
let file = File::open(filename).map_err(|_| format!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename))?;
let reader = BufReader::new(&file);
let lines = reader.lines()
.filter_map(|l| l.ok())
.map(|pwd| pwd.trim().to_owned())
.collect::<Vec<String>>();
.map(|pwd| pwd.trim().to_owned().into())
.collect::<Vec<Password>>();
Ok(lines)
}).collect::<Result<Vec<Vec<String>>, String>>();
}).collect::<Result<Vec<Vec<Password>>, String>>();
Ok(passwords?.into_iter().flat_map(|x| x).collect())
}
@@ -330,6 +331,7 @@ mod tests {
use ethereum_types::U256;
use ethcore::client::{Mode, BlockId};
use ethcore::miner::PendingSet;
use ethkey::Password;
use super::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_address, to_addresses, to_price, geth_ipc_path, to_bootnodes, password_from_file};
#[test]
@@ -435,7 +437,7 @@ ignored
but the first password is trimmed
"#).unwrap();
assert_eq!(&password_from_file(path.to_str().unwrap().into()).unwrap(), "password with trailing whitespace");
assert_eq!(password_from_file(path.to_str().unwrap().into()).unwrap(), Password::from("password with trailing whitespace"));
}
#[test]

View File

@@ -30,7 +30,7 @@ pub struct ImportWallet {
}
pub fn execute(cmd: ImportWallet) -> Result<String, String> {
let password: String = match cmd.password_file {
let password = match cmd.password_file {
Some(file) => password_from_file(file)?,
None => password_prompt()?,
};

View File

@@ -63,6 +63,7 @@ use rpc_apis;
use secretstore;
use signer;
use db;
use ethkey::Password;
// how often to take periodic snapshots.
const SNAPSHOT_PERIOD: u64 = 5000;
@@ -1002,7 +1003,7 @@ fn print_running_environment(spec_name: &String, dirs: &Directories, db_dirs: &D
info!("Path to dapps {}", Colour::White.bold().paint(dapps_conf.dapps_path.to_string_lossy().into_owned()));
}
fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[String]) -> Result<AccountProvider, String> {
fn prepare_account_provider(spec: &SpecType, dirs: &Directories, data_dir: &str, cfg: AccountsConfig, passwords: &[Password]) -> Result<AccountProvider, String> {
use ethcore::ethstore::EthStore;
use ethcore::ethstore::accounts_dir::RootDiskDirectory;
@@ -1058,7 +1059,7 @@ fn insert_dev_account(account_provider: &AccountProvider) {
let secret: ethkey::Secret = "4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7".into();
let dev_account = ethkey::KeyPair::from_secret(secret.clone()).expect("Valid secret produces valid key;qed");
if !account_provider.has_account(dev_account.address()) {
match account_provider.insert_account(secret, "") {
match account_provider.insert_account(secret, &Password::from(String::new())) {
Err(e) => warn!("Unable to add development account: {}", e),
Ok(address) => {
let _ = account_provider.set_account_name(address.clone(), "Development Account".into());

View File

@@ -95,7 +95,7 @@ pub struct Dependencies<'a> {
/// Account provider.
pub account_provider: Arc<AccountProvider>,
/// Passed accounts passwords.
pub accounts_passwords: &'a [String],
pub accounts_passwords: &'a [Password],
}
#[cfg(not(feature = "secretstore"))]
@@ -209,6 +209,7 @@ mod server {
}
pub use self::server::KeyServer;
use ethkey::Password;
impl Default for Configuration {
fn default() -> Self {