conflux/command/
account.rs

1// Copyright 2015-2019 Parity Technologies (UK) Ltd.
2// This file is part of Parity Ethereum.
3
4// Parity Ethereum is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity Ethereum is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity Ethereum.  If not, see <http://www.gnu.org/licenses/>.
16
17// Copyright 2019 Conflux Foundation. All rights reserved.
18// Conflux is free software and distributed under GNU General Public License.
19// See http://www.gnu.org/licenses/
20
21use 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), /* sstore_iterations */
105        None,                     /* refresh_time */
106    )?;
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, /* sstore_iterations */
118        None, /* refresh_time */
119    )?;
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}