1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.

// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Parity.  If not, see <http://www.gnu.org/licenses/>.

use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use std::cmp::Ordering;
use ethkey::{Address, Message, Signature, Secret, Password, Public};
use Error;
use json::{Uuid, OpaqueKeyFile};
use ethereum_types::H256;
use OpaqueSecret;

/// Key directory reference
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum SecretVaultRef {
	/// Reference to key in root directory
	Root,
	/// Referenc to key in specific vault
	Vault(String),
}

/// Stored account reference
#[derive(Debug, Clone, PartialEq, Eq, Ord)]
pub struct StoreAccountRef {
	/// Account address
	pub address: Address,
	/// Vault reference
	pub vault: SecretVaultRef,
}

impl PartialOrd for StoreAccountRef {
	fn partial_cmp(&self, other: &StoreAccountRef) -> Option<Ordering> {
		Some(self.address.cmp(&other.address).then_with(|| self.vault.cmp(&other.vault)))
	}
}

impl ::std::borrow::Borrow<Address> for StoreAccountRef {
	fn borrow(&self) -> &Address {
		&self.address
	}
}

/// Simple Secret Store API
pub trait SimpleSecretStore: Send + Sync {
	/// Inserts new accounts to the store (or vault) with given password.
	fn insert_account(&self, vault: SecretVaultRef, secret: Secret, password: &Password) -> Result<StoreAccountRef, Error>;
	/// Inserts new derived account to the store (or vault) with given password.
	fn insert_derived(&self, vault: SecretVaultRef, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result<StoreAccountRef, Error>;
	/// Changes accounts password.
	fn change_password(&self, account: &StoreAccountRef, old_password: &Password, new_password: &Password) -> Result<(), Error>;
	/// Exports key details for account.
	fn export_account(&self, account: &StoreAccountRef, password: &Password) -> Result<OpaqueKeyFile, Error>;
	/// Entirely removes account from the store and underlying storage.
	fn remove_account(&self, account: &StoreAccountRef, password: &Password) -> Result<(), Error>;
	/// Generates new derived account.
	fn generate_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation) -> Result<Address, Error>;
	/// Sign a message with given account.
	fn sign(&self, account: &StoreAccountRef, password: &Password, message: &Message) -> Result<Signature, Error>;
	/// Sign a message with derived account.
	fn sign_derived(&self, account_ref: &StoreAccountRef, password: &Password, derivation: Derivation, message: &Message) -> Result<Signature, Error>;
	/// Decrypt a messages with given account.
	fn decrypt(&self, account: &StoreAccountRef, password: &Password, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error>;
	/// Agree on shared key.
	fn agree(&self, account: &StoreAccountRef, password: &Password, other: &Public) -> Result<Secret, Error>;

	/// Returns all accounts in this secret store.
	fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error>;
	/// Get reference to some account with given address.
	/// This method could be removed if we will guarantee that there is max(1) account for given address.
	fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error>;

	/// Create new vault with given password
	fn create_vault(&self, name: &str, password: &Password) -> Result<(), Error>;
	/// Open vault with given password
	fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error>;
	/// Close vault
	fn close_vault(&self, name: &str) -> Result<(), Error>;
	/// List all vaults
	fn list_vaults(&self) -> Result<Vec<String>, Error>;
	/// List all currently opened vaults
	fn list_opened_vaults(&self) -> Result<Vec<String>, Error>;
	/// Change vault password
	fn change_vault_password(&self, name: &str, new_password: &Password) -> Result<(), Error>;
	/// Cnage account' vault
	fn change_account_vault(&self, vault: SecretVaultRef, account: StoreAccountRef) -> Result<StoreAccountRef, Error>;
	/// Get vault metadata string.
	fn get_vault_meta(&self, name: &str) -> Result<String, Error>;
	/// Set vault metadata string.
	fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error>;
}

/// Secret Store API
pub trait SecretStore: SimpleSecretStore {

	/// Returns a raw opaque Secret that can be later used to sign a message.
	fn raw_secret(&self, account: &StoreAccountRef, password: &Password) -> Result<OpaqueSecret, Error>;

	/// Signs a message with raw secret.
	fn sign_with_secret(&self, secret: &OpaqueSecret, message: &Message) -> Result<Signature, Error> {
		Ok(::ethkey::sign(&secret.0, message)?)
	}

	/// Imports presale wallet
	fn import_presale(&self, vault: SecretVaultRef, json: &[u8], password: &Password) -> Result<StoreAccountRef, Error>;
	/// Imports existing JSON wallet
	fn import_wallet(&self, vault: SecretVaultRef, json: &[u8], password: &Password, gen_id: bool) -> Result<StoreAccountRef, Error>;
	/// Copies account between stores and vaults.
	fn copy_account(&self, new_store: &SimpleSecretStore, new_vault: SecretVaultRef, account: &StoreAccountRef, password: &Password, new_password: &Password) -> Result<(), Error>;
	/// Checks if password matches given account.
	fn test_password(&self, account: &StoreAccountRef, password: &Password) -> Result<bool, Error>;

	/// Returns a public key for given account.
	fn public(&self, account: &StoreAccountRef, password: &Password) -> Result<Public, Error>;

	/// Returns uuid of an account.
	fn uuid(&self, account: &StoreAccountRef) -> Result<Uuid, Error>;
	/// Returns account's name.
	fn name(&self, account: &StoreAccountRef) -> Result<String, Error>;
	/// Returns account's metadata.
	fn meta(&self, account: &StoreAccountRef) -> Result<String, Error>;

	/// Modifies account metadata.
	fn set_name(&self, account: &StoreAccountRef, name: String) -> Result<(), Error>;
	/// Modifies account name.
	fn set_meta(&self, account: &StoreAccountRef, meta: String) -> Result<(), Error>;

	/// Returns local path of the store.
	fn local_path(&self) -> PathBuf;
	/// Lists all found geth accounts.
	fn list_geth_accounts(&self, testnet: bool) -> Vec<Address>;
	/// Imports geth accounts to the store/vault.
	fn import_geth_accounts(&self, vault: SecretVaultRef, desired: Vec<Address>, testnet: bool) -> Result<Vec<StoreAccountRef>, Error>;
}

impl StoreAccountRef {
	/// Create reference to root account with given address
	pub fn root(address: Address) -> Self {
		StoreAccountRef::new(SecretVaultRef::Root, address)
	}

	/// Create reference to vault account with given address
	pub fn vault(vault_name: &str, address: Address) -> Self {
		StoreAccountRef::new(SecretVaultRef::Vault(vault_name.to_owned()), address)
	}

	/// Create new account reference
	pub fn new(vault_ref: SecretVaultRef, address: Address) -> Self {
		StoreAccountRef {
			vault: vault_ref,
			address: address,
		}
	}
}

impl Hash for StoreAccountRef {
	fn hash<H: Hasher>(&self, state: &mut H) {
		self.address.hash(state);
	}
}

/// Node in hierarchical derivation.
pub struct IndexDerivation {
	/// Node is soft (allows proof of parent from parent node).
	pub soft: bool,
	/// Index sequence of the node.
	pub index: u32,
}

/// Derivation scheme for keys
pub enum Derivation {
	/// Hierarchical derivation
	Hierarchical(Vec<IndexDerivation>),
	/// Hash derivation, soft.
	SoftHash(H256),
	/// Hash derivation, hard.
	HardHash(H256),
}