cfxstore/
import.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
17use std::{collections::HashSet, fs, path::Path};
18
19use crate::{
20    accounts_dir::{
21        DiskKeyFileManager, KeyDirectory, KeyFileManager, RootDiskDirectory,
22    },
23    Error,
24};
25use cfxkey::Address;
26
27/// Import an account from a file.
28pub fn import_account(
29    path: &Path, dst: &dyn KeyDirectory,
30) -> Result<Address, Error> {
31    let key_manager = DiskKeyFileManager::default();
32    let existing_accounts = dst
33        .load()?
34        .into_iter()
35        .map(|a| a.address)
36        .collect::<HashSet<_>>();
37    let filename = path
38        .file_name()
39        .and_then(|n| n.to_str())
40        .map(|f| f.to_owned());
41    let account = fs::File::open(path)
42        .map_err(Into::into)
43        .and_then(|file| key_manager.read(filename, file))?;
44
45    let address = account.address;
46    if !existing_accounts.contains(&address) {
47        dst.insert(account)?;
48    }
49    Ok(address)
50}
51
52/// Import all accounts from one directory to the other.
53pub fn import_accounts(
54    src: &dyn KeyDirectory, dst: &dyn KeyDirectory,
55) -> Result<Vec<Address>, Error> {
56    let accounts = src.load()?;
57    let existing_accounts = dst
58        .load()?
59        .into_iter()
60        .map(|a| a.address)
61        .collect::<HashSet<_>>();
62
63    accounts
64        .into_iter()
65        .filter(|a| !existing_accounts.contains(&a.address))
66        .map(|a| {
67            let address = a.address;
68            dst.insert(a)?;
69            Ok(address)
70        })
71        .collect()
72}
73
74/// Provide a `HashSet` of all accounts available for import from the Geth
75/// keystore.
76pub fn read_geth_accounts(testnet: bool) -> Vec<Address> {
77    RootDiskDirectory::at(dir::geth(testnet))
78        .load()
79        .map(|d| d.into_iter().map(|a| a.address).collect())
80        .unwrap_or_else(|_| Vec::new())
81}
82
83/// Import specific `desired` accounts from the Geth keystore into `dst`.
84pub fn import_geth_accounts(
85    dst: &dyn KeyDirectory, desired: HashSet<Address>, testnet: bool,
86) -> Result<Vec<Address>, Error> {
87    let src = RootDiskDirectory::at(dir::geth(testnet));
88    let accounts = src.load()?;
89    let existing_accounts = dst
90        .load()?
91        .into_iter()
92        .map(|a| a.address)
93        .collect::<HashSet<_>>();
94
95    accounts
96        .into_iter()
97        .filter(|a| !existing_accounts.contains(&a.address))
98        .filter(|a| desired.contains(&a.address))
99        .map(|a| {
100            let address = a.address;
101            dst.insert(a)?;
102            Ok(address)
103        })
104        .collect()
105}