conflux/command/
helpers.rs1use cfxkey::Password;
22use rpassword::read_password;
23use std::{
24 fs::File,
25 io::{self, BufRead, BufReader, Write},
26};
27
28const PASSWORD_STDIN_ERROR: &str =
29 "Unable to ask for password on non-interactive terminal.";
30
31pub fn flush_stdout() {
33 io::stdout().flush().expect("stdout is flushable; qed");
34}
35
36pub fn password_prompt() -> Result<Password, String> {
38 println!("Please note that password is NOT RECOVERABLE.");
39 print!("Type password: ");
40 flush_stdout();
41
42 let password = read_password()
43 .map_err(|_| PASSWORD_STDIN_ERROR.to_owned())?
44 .into();
45
46 print!("Repeat password: ");
47 flush_stdout();
48
49 let password_repeat = read_password()
50 .map_err(|_| PASSWORD_STDIN_ERROR.to_owned())?
51 .into();
52
53 if password != password_repeat {
54 return Err("Passwords do not match!".into());
55 }
56
57 Ok(password)
58}
59
60pub fn input_password() -> Result<Password, String> {
61 print!("Type password: ");
62 flush_stdout();
63
64 let password = read_password()
65 .map_err(|_| PASSWORD_STDIN_ERROR.to_owned())?
66 .into();
67
68 Ok(password)
69}
70
71pub fn password_from_file(path: String) -> Result<Password, String> {
73 let passwords = passwords_from_files(&[path])?;
74 passwords
76 .get(0)
77 .map(Password::clone)
78 .ok_or_else(|| "Password file seems to be empty.".to_owned())
79}
80
81pub fn passwords_from_files(files: &[String]) -> Result<Vec<Password>, String> {
83 let passwords = files.iter().map(|filename| {
84 let file = File::open(filename).map_err(|_| format!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename))?;
85 let reader = BufReader::new(&file);
86 let lines = reader.lines()
87 .filter_map(|l| l.ok())
88 .map(|pwd| pwd.trim().to_owned().into())
89 .collect::<Vec<Password>>();
90 Ok(lines)
91 }).collect::<Result<Vec<Vec<Password>>, String>>();
92 Ok(passwords?.into_iter().flatten().collect())
93}