conflux/command/
account.rs1use super::helpers::{password_from_file, password_prompt};
22use cfxstore::{
23 accounts_dir::RootDiskDirectory, import_account, import_accounts,
24};
25use clap;
26use client::accounts::{account_provider, keys_dir, keys_path};
27use std::path::PathBuf;
28
29#[derive(Debug, PartialEq)]
30pub enum AccountCmd {
31 New(NewAccount),
32 List(ListAccounts),
33 Import(ImportAccounts),
34}
35
36#[derive(Debug, PartialEq)]
37pub struct ListAccounts {
38 pub path: Option<String>,
39}
40
41impl ListAccounts {
42 pub fn new(_matches: &clap::ArgMatches) -> Self { Self { path: None } }
43}
44
45#[derive(Debug, PartialEq)]
46pub struct NewAccount {
47 pub iterations: u32,
48 pub path: Option<String>,
49 pub password_file: Option<String>,
50}
51
52impl NewAccount {
53 pub fn new(matches: &clap::ArgMatches) -> Self {
54 let iterations: u32 = matches
55 .get_one::<u32>("keys-iterations")
56 .unwrap_or(&0)
57 .to_owned();
58 let password_file =
59 matches.get_one::<String>("password").map(|s| s.to_string());
60 Self {
61 iterations,
62 path: None,
63 password_file,
64 }
65 }
66}
67
68#[derive(Debug, PartialEq)]
69pub struct ImportAccounts {
70 pub from: Vec<String>,
71 pub to: String,
72}
73
74impl ImportAccounts {
75 pub fn new(matches: &clap::ArgMatches) -> Self {
76 let from: Vec<_> = matches
77 .get_many::<String>("import-path")
78 .expect("CLI argument is required; qed")
79 .map(|s| s.to_string())
80 .collect();
81 Self {
82 from,
83 to: keys_path(),
84 }
85 }
86}
87
88pub fn execute(cmd: AccountCmd) -> Result<String, String> {
89 match cmd {
90 AccountCmd::New(new_cmd) => new(new_cmd),
91 AccountCmd::List(list_cmd) => list(list_cmd),
92 AccountCmd::Import(import_cmd) => import(import_cmd),
93 }
94}
95
96fn new(new_cmd: NewAccount) -> Result<String, String> {
97 let password = match new_cmd.password_file {
98 Some(file) => password_from_file(file)?,
99 None => password_prompt()?,
100 };
101
102 let acc_provider = account_provider(
103 new_cmd.path,
104 Some(new_cmd.iterations), None, )?;
107
108 let new_account = acc_provider
109 .new_account(&password)
110 .map_err(|e| format!("Could not create new account: {}", e))?;
111 Ok(format!("0x{:x}", new_account))
112}
113
114fn list(list_cmd: ListAccounts) -> Result<String, String> {
115 let acc_provider = account_provider(
116 list_cmd.path,
117 None, None, )?;
120
121 let accounts = acc_provider.accounts().map_err(|e| format!("{}", e))?;
122 let result = accounts
123 .into_iter()
124 .map(|a| format!("0x{:x}", a))
125 .collect::<Vec<String>>()
126 .join("\n");
127
128 Ok(result)
129}
130
131fn import(import_cmd: ImportAccounts) -> Result<String, String> {
132 let to = keys_dir(import_cmd.to)?;
133 let mut imported = 0;
134
135 for path in &import_cmd.from {
136 let path = PathBuf::from(path);
137 if path.is_dir() {
138 let from = RootDiskDirectory::at(&path);
139 imported += import_accounts(&from, &to)
140 .map_err(|e| {
141 format!("Importing accounts from {:?} failed: {}", path, e)
142 })?
143 .len();
144 } else if path.is_file() {
145 import_account(&path, &to).map_err(|e| {
146 format!("Importing account from {:?} failed: {}", path, e)
147 })?;
148 imported += 1;
149 }
150 }
151
152 Ok(format!("{} account(s) imported", imported))
153}