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