1use parking_lot::{Mutex, RwLock};
18use std::{
19 collections::{BTreeMap, HashMap},
20 path::PathBuf,
21 time::{Duration, Instant},
22};
23
24use crate::{
25 account::SafeAccount,
26 accounts_dir::{KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory},
27 import,
28 json::{self, OpaqueKeyFile, Uuid},
29 random::Random,
30 Derivation, Error, OpaqueSecret, SecretStore, SecretVaultRef,
31 SimpleSecretStore, StoreAccountRef,
32};
33use cfx_crypto::crypto::KEY_ITERATIONS;
34use cfxkey::{
35 self, Address, ExtendedKeyPair, KeyPair, Message, Password, Public, Secret,
36 Signature,
37};
38
39pub struct CfxStore {
41 store: CfxMultiStore,
42}
43
44impl CfxStore {
45 pub fn open(directory: Box<dyn KeyDirectory>) -> Result<Self, Error> {
47 Self::open_with_iterations(directory, KEY_ITERATIONS as u32)
48 }
49
50 pub fn open_with_iterations(
53 directory: Box<dyn KeyDirectory>, iterations: u32,
54 ) -> Result<Self, Error> {
55 Ok(CfxStore {
56 store: CfxMultiStore::open_with_iterations(directory, iterations)?,
57 })
58 }
59
60 pub fn set_refresh_time(&self, time: Duration) {
70 self.store.set_refresh_time(time)
71 }
72
73 fn get(&self, account: &StoreAccountRef) -> Result<SafeAccount, Error> {
74 let mut accounts = self.store.get_accounts(account)?.into_iter();
75 accounts.next().ok_or(Error::InvalidAccount)
76 }
77}
78
79impl SimpleSecretStore for CfxStore {
80 fn insert_account(
81 &self, vault: SecretVaultRef, secret: Secret, password: &Password,
82 ) -> Result<StoreAccountRef, Error> {
83 self.store.insert_account(vault, secret, password)
84 }
85
86 fn insert_derived(
87 &self, vault: SecretVaultRef, account_ref: &StoreAccountRef,
88 password: &Password, derivation: Derivation,
89 ) -> Result<StoreAccountRef, Error> {
90 self.store
91 .insert_derived(vault, account_ref, password, derivation)
92 }
93
94 fn generate_derived(
95 &self, account_ref: &StoreAccountRef, password: &Password,
96 derivation: Derivation,
97 ) -> Result<Address, Error> {
98 self.store
99 .generate_derived(account_ref, password, derivation)
100 }
101
102 fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error> {
103 self.store.account_ref(address)
104 }
105
106 fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error> {
107 self.store.accounts()
108 }
109
110 fn change_password(
111 &self, account: &StoreAccountRef, old_password: &Password,
112 new_password: &Password,
113 ) -> Result<(), Error> {
114 self.store
115 .change_password(account, old_password, new_password)
116 }
117
118 fn export_account(
119 &self, account: &StoreAccountRef, password: &Password,
120 ) -> Result<OpaqueKeyFile, Error> {
121 self.store.export_account(account, password)
122 }
123
124 fn remove_account(
125 &self, account: &StoreAccountRef, password: &Password,
126 ) -> Result<(), Error> {
127 self.store.remove_account(account, password)
128 }
129
130 fn sign(
131 &self, account: &StoreAccountRef, password: &Password,
132 message: &Message,
133 ) -> Result<Signature, Error> {
134 self.get(account)?.sign(password, message)
135 }
136
137 fn sign_derived(
138 &self, account_ref: &StoreAccountRef, password: &Password,
139 derivation: Derivation, message: &Message,
140 ) -> Result<Signature, Error> {
141 self.store
142 .sign_derived(account_ref, password, derivation, message)
143 }
144
145 fn agree(
146 &self, account: &StoreAccountRef, password: &Password, other: &Public,
147 ) -> Result<Secret, Error> {
148 self.store.agree(account, password, other)
149 }
150
151 fn decrypt(
152 &self, account: &StoreAccountRef, password: &Password,
153 shared_mac: &[u8], message: &[u8],
154 ) -> Result<Vec<u8>, Error> {
155 let account = self.get(account)?;
156 account.decrypt(password, shared_mac, message)
157 }
158
159 fn create_vault(
160 &self, name: &str, password: &Password,
161 ) -> Result<(), Error> {
162 self.store.create_vault(name, password)
163 }
164
165 fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
166 self.store.open_vault(name, password)
167 }
168
169 fn close_vault(&self, name: &str) -> Result<(), Error> {
170 self.store.close_vault(name)
171 }
172
173 fn list_vaults(&self) -> Result<Vec<String>, Error> {
174 self.store.list_vaults()
175 }
176
177 fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
178 self.store.list_opened_vaults()
179 }
180
181 fn change_vault_password(
182 &self, name: &str, new_password: &Password,
183 ) -> Result<(), Error> {
184 self.store.change_vault_password(name, new_password)
185 }
186
187 fn change_account_vault(
188 &self, vault: SecretVaultRef, account: StoreAccountRef,
189 ) -> Result<StoreAccountRef, Error> {
190 self.store.change_account_vault(vault, account)
191 }
192
193 fn get_vault_meta(&self, name: &str) -> Result<String, Error> {
194 self.store.get_vault_meta(name)
195 }
196
197 fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> {
198 self.store.set_vault_meta(name, meta)
199 }
200}
201
202impl SecretStore for CfxStore {
203 fn raw_secret(
204 &self, account: &StoreAccountRef, password: &Password,
205 ) -> Result<OpaqueSecret, Error> {
206 Ok(OpaqueSecret(self.get(account)?.crypto.secret(password)?))
207 }
208
209 fn import_wallet(
210 &self, vault: SecretVaultRef, json: &[u8], password: &Password,
211 gen_id: bool,
212 ) -> Result<StoreAccountRef, Error> {
213 let json_keyfile = json::KeyFile::load(json).map_err(|_| {
214 Error::InvalidKeyFile("Invalid JSON format".to_owned())
215 })?;
216 let mut safe_account =
217 SafeAccount::from_file(json_keyfile, None, &None)?;
218
219 if gen_id {
220 safe_account.id = Random::random();
221 }
222
223 let secret = safe_account
224 .crypto
225 .secret(password)
226 .map_err(|_| Error::InvalidPassword)?;
227 safe_account.address = KeyPair::from_secret(secret)?.address();
228 self.store.import(vault, safe_account)
229 }
230
231 fn test_password(
232 &self, account: &StoreAccountRef, password: &Password,
233 ) -> Result<bool, Error> {
234 let account = self.get(account)?;
235 Ok(account.check_password(password))
236 }
237
238 fn copy_account(
239 &self, new_store: &dyn SimpleSecretStore, new_vault: SecretVaultRef,
240 account: &StoreAccountRef, password: &Password,
241 new_password: &Password,
242 ) -> Result<(), Error> {
243 let account = self.get(account)?;
244 let secret = account.crypto.secret(password)?;
245 new_store.insert_account(new_vault, secret, new_password)?;
246 Ok(())
247 }
248
249 fn public(
250 &self, account: &StoreAccountRef, password: &Password,
251 ) -> Result<Public, Error> {
252 let account = self.get(account)?;
253 account.public(password)
254 }
255
256 fn uuid(&self, account: &StoreAccountRef) -> Result<Uuid, Error> {
257 let account = self.get(account)?;
258 Ok(account.id.into())
259 }
260
261 fn name(&self, account: &StoreAccountRef) -> Result<String, Error> {
262 let account = self.get(account)?;
263 Ok(account.name)
264 }
265
266 fn meta(&self, account: &StoreAccountRef) -> Result<String, Error> {
267 let account = self.get(account)?;
268 Ok(account.meta)
269 }
270
271 fn set_name(
272 &self, account_ref: &StoreAccountRef, name: String,
273 ) -> Result<(), Error> {
274 let old = self.get(account_ref)?;
275 let mut safe_account = old.clone();
276 safe_account.name = name;
277
278 self.store.update(account_ref, old, safe_account)
280 }
281
282 fn set_meta(
283 &self, account_ref: &StoreAccountRef, meta: String,
284 ) -> Result<(), Error> {
285 let old = self.get(account_ref)?;
286 let mut safe_account = old.clone();
287 safe_account.meta = meta;
288
289 self.store.update(account_ref, old, safe_account)
291 }
292
293 fn local_path(&self) -> PathBuf {
294 self.store.dir.path().cloned().unwrap_or_else(PathBuf::new)
295 }
296
297 fn list_geth_accounts(&self, testnet: bool) -> Vec<Address> {
298 import::read_geth_accounts(testnet)
299 }
300
301 fn import_geth_accounts(
302 &self, vault: SecretVaultRef, desired: Vec<Address>, testnet: bool,
303 ) -> Result<Vec<StoreAccountRef>, Error> {
304 let imported_addresses = match vault {
305 SecretVaultRef::Root => import::import_geth_accounts(
306 &*self.store.dir,
307 desired.into_iter().collect(),
308 testnet,
309 ),
310 SecretVaultRef::Vault(vault_name) => {
311 if let Some(vault) = self.store.vaults.lock().get(&vault_name) {
312 import::import_geth_accounts(
313 vault.as_key_directory(),
314 desired.into_iter().collect(),
315 testnet,
316 )
317 } else {
318 Err(Error::VaultNotFound)
319 }
320 }
321 };
322
323 imported_addresses
324 .map(|a| a.into_iter().map(StoreAccountRef::root).collect())
325 }
326}
327
328pub struct CfxMultiStore {
331 dir: Box<dyn KeyDirectory>,
332 iterations: u32,
333 cache: RwLock<BTreeMap<StoreAccountRef, Vec<SafeAccount>>>,
335 vaults: Mutex<HashMap<String, Box<dyn VaultKeyDirectory>>>,
336 timestamp: Mutex<Timestamp>,
337}
338
339struct Timestamp {
340 dir_hash: Option<u64>,
341 last_checked: Instant,
342 refresh_time: Duration,
343}
344
345impl CfxMultiStore {
346 pub fn open(directory: Box<dyn KeyDirectory>) -> Result<Self, Error> {
348 Self::open_with_iterations(directory, KEY_ITERATIONS as u32)
349 }
350
351 pub fn open_with_iterations(
354 directory: Box<dyn KeyDirectory>, iterations: u32,
355 ) -> Result<Self, Error> {
356 let store = CfxMultiStore {
357 dir: directory,
358 vaults: Mutex::new(HashMap::new()),
359 iterations,
360 cache: Default::default(),
361 timestamp: Mutex::new(Timestamp {
362 dir_hash: None,
363 last_checked: Instant::now(),
364 refresh_time: Duration::from_secs(u64::max_value()),
366 }),
367 };
368 store.reload_accounts()?;
369 Ok(store)
370 }
371
372 pub fn set_refresh_time(&self, time: Duration) {
382 self.timestamp.lock().refresh_time = time;
383 }
384
385 fn reload_if_changed(&self) -> Result<(), Error> {
386 let mut last_timestamp = self.timestamp.lock();
387 let now = Instant::now();
388
389 if now - last_timestamp.last_checked > last_timestamp.refresh_time {
390 let dir_hash = Some(self.dir.unique_repr()?);
391 last_timestamp.last_checked = now;
392
393 if last_timestamp.dir_hash == dir_hash {
394 return Ok(());
395 }
396
397 self.reload_accounts()?;
398 last_timestamp.dir_hash = dir_hash;
399 }
400
401 Ok(())
402 }
403
404 fn reload_accounts(&self) -> Result<(), Error> {
405 let mut cache = self.cache.write();
406
407 let mut new_accounts = BTreeMap::new();
408 for account in self.dir.load()? {
409 let account_ref = StoreAccountRef::root(account.address);
410 new_accounts
411 .entry(account_ref)
412 .or_insert_with(Vec::new)
413 .push(account);
414 }
415 for (vault_name, vault) in &*self.vaults.lock() {
416 for account in vault.load()? {
417 let account_ref =
418 StoreAccountRef::vault(vault_name, account.address);
419 new_accounts
420 .entry(account_ref)
421 .or_insert_with(Vec::new)
422 .push(account);
423 }
424 }
425
426 *cache = new_accounts;
427 Ok(())
428 }
429
430 fn get_accounts(
431 &self, account: &StoreAccountRef,
432 ) -> Result<Vec<SafeAccount>, Error> {
433 let from_cache = |account| {
434 let cache = self.cache.read();
435 if let Some(accounts) = cache.get(account) {
436 if !accounts.is_empty() {
437 return Some(accounts.clone());
438 }
439 }
440
441 None
442 };
443
444 match from_cache(account) {
445 Some(accounts) => Ok(accounts),
446 None => {
447 self.reload_if_changed()?;
448 from_cache(account).ok_or(Error::InvalidAccount)
449 }
450 }
451 }
452
453 fn get_matching(
454 &self, account: &StoreAccountRef, password: &Password,
455 ) -> Result<Vec<SafeAccount>, Error> {
456 let accounts = self.get_accounts(account)?;
457
458 Ok(accounts
459 .into_iter()
460 .filter(|acc| acc.check_password(password))
461 .collect())
462 }
463
464 fn import(
465 &self, vault: SecretVaultRef, account: SafeAccount,
466 ) -> Result<StoreAccountRef, Error> {
467 let account = match vault {
469 SecretVaultRef::Root => self.dir.insert(account)?,
470 SecretVaultRef::Vault(ref vault_name) => self
471 .vaults
472 .lock()
473 .get_mut(vault_name)
474 .ok_or(Error::VaultNotFound)?
475 .insert(account)?,
476 };
477
478 let account_ref = StoreAccountRef::new(vault, account.address.clone());
480 let mut cache = self.cache.write();
481 cache
482 .entry(account_ref.clone())
483 .or_insert_with(Vec::new)
484 .push(account);
485
486 Ok(account_ref)
487 }
488
489 fn update(
490 &self, account_ref: &StoreAccountRef, old: SafeAccount,
491 new: SafeAccount,
492 ) -> Result<(), Error> {
493 let account = match account_ref.vault {
495 SecretVaultRef::Root => self.dir.update(new)?,
496 SecretVaultRef::Vault(ref vault_name) => self
497 .vaults
498 .lock()
499 .get_mut(vault_name)
500 .ok_or(Error::VaultNotFound)?
501 .update(new)?,
502 };
503
504 let mut cache = self.cache.write();
506 let accounts =
507 cache.entry(account_ref.clone()).or_insert_with(Vec::new);
508 accounts.retain(|acc| acc != &old);
510 accounts.push(account);
512 Ok(())
513 }
514
515 fn remove_safe_account(
516 &self, account_ref: &StoreAccountRef, account: &SafeAccount,
517 ) -> Result<(), Error> {
518 match account_ref.vault {
520 SecretVaultRef::Root => self.dir.remove(&account)?,
521 SecretVaultRef::Vault(ref vault_name) => self
522 .vaults
523 .lock()
524 .get(vault_name)
525 .ok_or(Error::VaultNotFound)?
526 .remove(&account)?,
527 };
528
529 let mut cache = self.cache.write();
531 let is_empty = {
532 if let Some(accounts) = cache.get_mut(account_ref) {
533 if let Some(position) =
534 accounts.iter().position(|acc| acc == account)
535 {
536 accounts.remove(position);
537 }
538 accounts.is_empty()
539 } else {
540 false
541 }
542 };
543
544 if is_empty {
545 cache.remove(account_ref);
546 }
547
548 Ok(())
549 }
550
551 fn generate(
552 &self, secret: Secret, derivation: Derivation,
553 ) -> Result<ExtendedKeyPair, Error> {
554 let mut extended = ExtendedKeyPair::new(secret);
555 match derivation {
556 Derivation::Hierarchical(path) => {
557 for path_item in path {
558 extended = extended.derive(
559 if path_item.soft {
560 cfxkey::Derivation::Soft(path_item.index)
561 } else {
562 cfxkey::Derivation::Hard(path_item.index)
563 },
564 )?;
565 }
566 }
567 Derivation::SoftHash(h256) => {
568 extended = extended.derive(cfxkey::Derivation::Soft(h256))?;
569 }
570 Derivation::HardHash(h256) => {
571 extended = extended.derive(cfxkey::Derivation::Hard(h256))?;
572 }
573 }
574 Ok(extended)
575 }
576}
577
578impl SimpleSecretStore for CfxMultiStore {
579 fn insert_account(
580 &self, vault: SecretVaultRef, secret: Secret, password: &Password,
581 ) -> Result<StoreAccountRef, Error> {
582 let keypair =
583 KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed)?;
584 let id: [u8; 16] = Random::random();
585 let account = SafeAccount::create(
586 &keypair,
587 id,
588 password,
589 self.iterations,
590 "".to_owned(),
591 "{}".to_owned(),
592 )?;
593 self.import(vault, account)
594 }
595
596 fn insert_derived(
597 &self, vault: SecretVaultRef, account_ref: &StoreAccountRef,
598 password: &Password, derivation: Derivation,
599 ) -> Result<StoreAccountRef, Error> {
600 let accounts = self.get_matching(account_ref, password)?;
601 if let Some(account) = accounts.first() {
602 let extended =
603 self.generate(account.crypto.secret(password)?, derivation)?;
604 self.insert_account(
605 vault,
606 extended.secret().as_raw().clone(),
607 password,
608 )
609 } else {
610 Err(Error::InvalidPassword)
611 }
612 }
613
614 fn generate_derived(
615 &self, account_ref: &StoreAccountRef, password: &Password,
616 derivation: Derivation,
617 ) -> Result<Address, Error> {
618 let accounts = self.get_matching(&account_ref, password)?;
619 if let Some(account) = accounts.first() {
620 let extended =
621 self.generate(account.crypto.secret(password)?, derivation)?;
622 Ok(cfxkey::public_to_address(extended.public().public(), true))
623 } else {
624 Err(Error::InvalidPassword)
625 }
626 }
627
628 fn sign_derived(
629 &self, account_ref: &StoreAccountRef, password: &Password,
630 derivation: Derivation, message: &Message,
631 ) -> Result<Signature, Error> {
632 let accounts = self.get_matching(&account_ref, password)?;
633 if let Some(account) = accounts.first() {
634 let extended =
635 self.generate(account.crypto.secret(password)?, derivation)?;
636 let secret = extended.secret().as_raw();
637 Ok(cfxkey::sign(&secret, message)?)
638 } else {
639 Err(Error::InvalidPassword)
640 }
641 }
642
643 fn account_ref(&self, address: &Address) -> Result<StoreAccountRef, Error> {
644 let read_from_cache = |address: &Address| {
645 use std::collections::Bound;
646 let cache = self.cache.read();
647 let mut r = cache
648 .range((Bound::Included(*address), Bound::Included(*address)));
649 r.next().map(|(k, _)| k.clone())
650 };
651
652 match read_from_cache(address) {
653 Some(account) => Ok(account),
654 None => {
655 self.reload_if_changed()?;
656 read_from_cache(address).ok_or(Error::InvalidAccount)
657 }
658 }
659 }
660
661 fn accounts(&self) -> Result<Vec<StoreAccountRef>, Error> {
662 self.reload_if_changed()?;
663 Ok(self.cache.read().keys().cloned().collect())
664 }
665
666 fn remove_account(
667 &self, account_ref: &StoreAccountRef, password: &Password,
668 ) -> Result<(), Error> {
669 let accounts = self.get_matching(account_ref, password)?;
670
671 if let Some(account) = accounts.first() {
672 self.remove_safe_account(account_ref, &account)
673 } else {
674 Err(Error::InvalidPassword)
675 }
676 }
677
678 fn change_password(
679 &self, account_ref: &StoreAccountRef, old_password: &Password,
680 new_password: &Password,
681 ) -> Result<(), Error> {
682 let accounts = self.get_matching(account_ref, old_password)?;
683
684 if accounts.is_empty() {
685 return Err(Error::InvalidPassword);
686 }
687
688 for account in accounts {
689 let new_account = account.change_password(
691 old_password,
692 new_password,
693 self.iterations,
694 )?;
695 self.update(account_ref, account, new_account)?;
696 }
697
698 Ok(())
699 }
700
701 fn export_account(
702 &self, account_ref: &StoreAccountRef, password: &Password,
703 ) -> Result<OpaqueKeyFile, Error> {
704 self.get_matching(account_ref, password)?
705 .into_iter()
706 .nth(0)
707 .map(Into::into)
708 .ok_or(Error::InvalidPassword)
709 }
710
711 fn sign(
712 &self, account: &StoreAccountRef, password: &Password,
713 message: &Message,
714 ) -> Result<Signature, Error> {
715 let accounts = self.get_matching(account, password)?;
716 match accounts.first() {
717 Some(ref account) => account.sign(password, message),
718 None => Err(Error::InvalidPassword),
719 }
720 }
721
722 fn decrypt(
723 &self, account: &StoreAccountRef, password: &Password,
724 shared_mac: &[u8], message: &[u8],
725 ) -> Result<Vec<u8>, Error> {
726 let accounts = self.get_matching(account, password)?;
727 match accounts.first() {
728 Some(ref account) => account.decrypt(password, shared_mac, message),
729 None => Err(Error::InvalidPassword),
730 }
731 }
732
733 fn agree(
734 &self, account: &StoreAccountRef, password: &Password, other: &Public,
735 ) -> Result<Secret, Error> {
736 let accounts = self.get_matching(account, password)?;
737 match accounts.first() {
738 Some(ref account) => account.agree(password, other),
739 None => Err(Error::InvalidPassword),
740 }
741 }
742
743 fn create_vault(
744 &self, name: &str, password: &Password,
745 ) -> Result<(), Error> {
746 let is_vault_created = {
747 let mut vaults = self.vaults.lock();
749 if !vaults.contains_key(&name.to_owned()) {
750 let vault_provider = self
751 .dir
752 .as_vault_provider()
753 .ok_or(Error::VaultsAreNotSupported)?;
754 let vault = vault_provider
755 .create(name, VaultKey::new(password, self.iterations))?;
756 vaults.insert(name.to_owned(), vault);
757 true
758 } else {
759 false
760 }
761 };
762
763 if is_vault_created {
764 self.reload_accounts()?;
765 }
766
767 Ok(())
768 }
769
770 fn open_vault(&self, name: &str, password: &Password) -> Result<(), Error> {
771 let is_vault_opened = {
772 let mut vaults = self.vaults.lock();
774 if !vaults.contains_key(&name.to_owned()) {
775 let vault_provider = self
776 .dir
777 .as_vault_provider()
778 .ok_or(Error::VaultsAreNotSupported)?;
779 let vault = vault_provider
780 .open(name, VaultKey::new(password, self.iterations))?;
781 vaults.insert(name.to_owned(), vault);
782 true
783 } else {
784 false
785 }
786 };
787
788 if is_vault_opened {
789 self.reload_accounts()?;
790 }
791
792 Ok(())
793 }
794
795 fn close_vault(&self, name: &str) -> Result<(), Error> {
796 let is_vault_removed =
797 self.vaults.lock().remove(&name.to_owned()).is_some();
798 if is_vault_removed {
799 self.reload_accounts()?;
800 }
801 Ok(())
802 }
803
804 fn list_vaults(&self) -> Result<Vec<String>, Error> {
805 let vault_provider = self
806 .dir
807 .as_vault_provider()
808 .ok_or(Error::VaultsAreNotSupported)?;
809 vault_provider.list_vaults()
810 }
811
812 fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
813 Ok(self.vaults.lock().keys().cloned().collect())
814 }
815
816 fn change_vault_password(
817 &self, name: &str, new_password: &Password,
818 ) -> Result<(), Error> {
819 let old_key = self
820 .vaults
821 .lock()
822 .get(name)
823 .map(|v| v.key())
824 .ok_or(Error::VaultNotFound)?;
825 let vault_provider = self
826 .dir
827 .as_vault_provider()
828 .ok_or(Error::VaultsAreNotSupported)?;
829 let vault = vault_provider.open(name, old_key)?;
830 match vault.set_key(VaultKey::new(new_password, self.iterations)) {
831 Ok(_) => self
832 .close_vault(name)
833 .and_then(|_| self.open_vault(name, new_password)),
834 Err(SetKeyError::Fatal(err)) => {
835 let _ = self.close_vault(name);
836 Err(err)
837 }
838 Err(SetKeyError::NonFatalNew(err)) => {
839 let _ = self
840 .close_vault(name)
841 .and_then(|_| self.open_vault(name, new_password));
842 Err(err)
843 }
844 Err(SetKeyError::NonFatalOld(err)) => Err(err),
845 }
846 }
847
848 fn change_account_vault(
849 &self, vault: SecretVaultRef, account_ref: StoreAccountRef,
850 ) -> Result<StoreAccountRef, Error> {
851 if account_ref.vault == vault {
852 return Ok(account_ref);
853 }
854
855 let account = self
856 .get_accounts(&account_ref)?
857 .into_iter()
858 .nth(0)
859 .ok_or(Error::InvalidAccount)?;
860 let new_account_ref = self.import(vault, account.clone())?;
861 self.remove_safe_account(&account_ref, &account)?;
862 self.reload_accounts()?;
863 Ok(new_account_ref)
864 }
865
866 fn get_vault_meta(&self, name: &str) -> Result<String, Error> {
867 self.vaults
870 .lock()
871 .get(name)
872 .map(|v| v.meta())
873 .ok_or(Error::VaultNotFound)
874 .or_else(|_| {
875 let vault_provider = self
876 .dir
877 .as_vault_provider()
878 .ok_or(Error::VaultsAreNotSupported)?;
879 vault_provider.vault_meta(name)
880 })
881 }
882
883 fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> {
884 self.vaults
885 .lock()
886 .get(name)
887 .ok_or(Error::VaultNotFound)
888 .and_then(|v| v.set_meta(meta))
889 }
890}
891
892#[cfg(test)]
893mod tests {
894 use super::{CfxMultiStore, CfxStore};
895 use crate::{
896 accounts_dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory},
897 secret_store::{
898 Derivation, SecretStore, SecretVaultRef, SimpleSecretStore,
899 StoreAccountRef,
900 },
901 };
902 use cfx_types::H256;
903 use cfxkey::{Generator, KeyPair, Random};
904 use tempfile::{tempdir, TempDir};
905 fn keypair() -> KeyPair { Random.generate().unwrap() }
906
907 fn store() -> CfxStore {
908 CfxStore::open(Box::new(MemoryDirectory::default()))
909 .expect("MemoryDirectory always load successfuly; qed")
910 }
911
912 fn multi_store() -> CfxMultiStore {
913 CfxMultiStore::open(Box::new(MemoryDirectory::default()))
914 .expect("MemoryDirectory always load successfuly; qed")
915 }
916
917 struct RootDiskDirectoryGuard {
918 pub key_dir: Option<Box<dyn KeyDirectory>>,
919 _path: TempDir,
920 }
921
922 impl RootDiskDirectoryGuard {
923 pub fn new() -> Self {
924 let temp_path = tempdir().unwrap();
925 let disk_dir =
926 Box::new(RootDiskDirectory::create(temp_path.path()).unwrap());
927
928 RootDiskDirectoryGuard {
929 key_dir: Some(disk_dir),
930 _path: temp_path,
931 }
932 }
933 }
934
935 #[test]
936 fn should_insert_account_successfully() {
937 let store = store();
939 let keypair = keypair();
940
941 let passwd = "test".into();
943 let address = store
944 .insert_account(
945 SecretVaultRef::Root,
946 keypair.secret().clone(),
947 &passwd,
948 )
949 .unwrap();
950
951 assert_eq!(address, StoreAccountRef::root(keypair.address()));
953 assert!(store.get(&address).is_ok(), "Should contain account.");
954 assert_eq!(
955 store.accounts().unwrap().len(),
956 1,
957 "Should have one account."
958 );
959 }
960
961 #[test]
962 fn should_update_meta_and_name() {
963 let store = store();
965 let keypair = keypair();
966 let passwd = "test".into();
967 let address = store
968 .insert_account(
969 SecretVaultRef::Root,
970 keypair.secret().clone(),
971 &passwd,
972 )
973 .unwrap();
974 assert_eq!(&store.meta(&address).unwrap(), "{}");
975 assert_eq!(&store.name(&address).unwrap(), "");
976
977 store.set_meta(&address, "meta".into()).unwrap();
979 store.set_name(&address, "name".into()).unwrap();
980
981 assert_eq!(&store.meta(&address).unwrap(), "meta");
983 assert_eq!(&store.name(&address).unwrap(), "name");
984 assert_eq!(store.accounts().unwrap().len(), 1);
985 }
986
987 #[test]
988 fn should_remove_account() {
989 let store = store();
991 let passwd = "test".into();
992 let keypair = keypair();
993 let address = store
994 .insert_account(
995 SecretVaultRef::Root,
996 keypair.secret().clone(),
997 &passwd,
998 )
999 .unwrap();
1000
1001 store.remove_account(&address, &passwd).unwrap();
1003
1004 assert_eq!(
1006 store.accounts().unwrap().len(),
1007 0,
1008 "Should remove account."
1009 );
1010 }
1011
1012 #[test]
1013 fn should_return_true_if_password_is_correct() {
1014 let store = store();
1016 let passwd = "test".into();
1017 let keypair = keypair();
1018 let address = store
1019 .insert_account(
1020 SecretVaultRef::Root,
1021 keypair.secret().clone(),
1022 &passwd,
1023 )
1024 .unwrap();
1025
1026 let res1 = store.test_password(&address, &"x".into()).unwrap();
1028 let res2 = store.test_password(&address, &passwd).unwrap();
1029
1030 assert!(!res1, "First password should be invalid.");
1031 assert!(res2, "Second password should be correct.");
1032 }
1033
1034 #[test]
1035 fn multistore_should_be_able_to_have_the_same_account_twice() {
1036 let store = multi_store();
1038 let passwd1 = "test".into();
1039 let passwd2 = "xyz".into();
1040 let keypair = keypair();
1041 let address = store
1042 .insert_account(
1043 SecretVaultRef::Root,
1044 keypair.secret().clone(),
1045 &passwd1,
1046 )
1047 .unwrap();
1048 let address2 = store
1049 .insert_account(
1050 SecretVaultRef::Root,
1051 keypair.secret().clone(),
1052 &passwd2,
1053 )
1054 .unwrap();
1055 assert_eq!(address, address2);
1056
1057 assert!(
1059 store.remove_account(&address, &passwd1).is_ok(),
1060 "First password should work."
1061 );
1062 assert_eq!(store.accounts().unwrap().len(), 1);
1063
1064 assert!(
1065 store.remove_account(&address, &passwd2).is_ok(),
1066 "Second password should work too."
1067 );
1068 assert_eq!(store.accounts().unwrap().len(), 0);
1069 }
1070
1071 #[test]
1072 fn should_copy_account() {
1073 let store = store();
1075 let passwd1 = "test".into();
1076 let passwd2 = "xzy".into();
1077 let multi_store = multi_store();
1078 let keypair = keypair();
1079 let address = store
1080 .insert_account(
1081 SecretVaultRef::Root,
1082 keypair.secret().clone(),
1083 &passwd1,
1084 )
1085 .unwrap();
1086 assert_eq!(multi_store.accounts().unwrap().len(), 0);
1087
1088 store
1090 .copy_account(
1091 &multi_store,
1092 SecretVaultRef::Root,
1093 &address,
1094 &passwd1,
1095 &passwd2,
1096 )
1097 .unwrap();
1098
1099 assert!(
1101 store.test_password(&address, &passwd1).unwrap(),
1102 "First password should work for store."
1103 );
1104 assert!(
1105 multi_store
1106 .sign(&address, &passwd2, &Default::default())
1107 .is_ok(),
1108 "Second password should work for second store."
1109 );
1110 assert_eq!(multi_store.accounts().unwrap().len(), 1);
1111 }
1112
1113 #[test]
1114 fn should_create_and_open_vaults() {
1115 let mut dir = RootDiskDirectoryGuard::new();
1117 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1118 let name1 = "vault1";
1119 let password1 = "password1".into();
1120 let name2 = "vault2";
1121 let password2 = "password2".into();
1122 let keypair1 = keypair();
1123 let keypair2 = keypair();
1124 let keypair3 = keypair();
1125 let password3 = "password3".into();
1126
1127 store.create_vault(name1, &password1).unwrap();
1129 store.create_vault(name2, &password2).unwrap();
1130
1131 store
1135 .insert_account(
1136 SecretVaultRef::Vault(name1.to_owned()),
1137 keypair1.secret().clone(),
1138 &password1,
1139 )
1140 .unwrap();
1141 store
1142 .insert_account(
1143 SecretVaultRef::Vault(name2.to_owned()),
1144 keypair2.secret().clone(),
1145 &password2,
1146 )
1147 .unwrap();
1148 store
1149 .insert_account(
1150 SecretVaultRef::Root,
1151 keypair3.secret().clone(),
1152 &password3,
1153 )
1154 .unwrap();
1155 store
1156 .insert_account(
1157 SecretVaultRef::Vault("vault3".to_owned()),
1158 keypair1.secret().clone(),
1159 &password3,
1160 )
1161 .unwrap_err();
1162 let accounts = store.accounts().unwrap();
1163
1164 assert_eq!(accounts.len(), 3);
1166 assert!(accounts.iter().any(|a| a.vault == SecretVaultRef::Root));
1167 assert!(accounts
1168 .iter()
1169 .any(|a| a.vault == SecretVaultRef::Vault(name1.to_owned())));
1170 assert!(accounts
1171 .iter()
1172 .any(|a| a.vault == SecretVaultRef::Vault(name2.to_owned())));
1173
1174 store.close_vault(name1).unwrap();
1176 store.close_vault(name2).unwrap();
1177 store.close_vault("vault3").unwrap();
1178 let accounts = store.accounts().unwrap();
1179
1180 assert_eq!(accounts.len(), 1);
1182 assert!(accounts.iter().any(|a| a.vault == SecretVaultRef::Root));
1183
1184 store.open_vault(name1, &password2).unwrap_err();
1186 store.open_vault(name2, &password1).unwrap_err();
1187 store.open_vault(name1, &password1).unwrap();
1188 store.open_vault(name2, &password2).unwrap();
1189 let accounts = store.accounts().unwrap();
1190
1191 assert_eq!(accounts.len(), 3);
1194 assert!(accounts.iter().any(|a| a.vault == SecretVaultRef::Root));
1195 assert!(accounts
1196 .iter()
1197 .any(|a| a.vault == SecretVaultRef::Vault(name1.to_owned())));
1198 assert!(accounts
1199 .iter()
1200 .any(|a| a.vault == SecretVaultRef::Vault(name2.to_owned())));
1201 }
1202
1203 #[test]
1204 fn should_move_vault_acounts() {
1205 let mut dir = RootDiskDirectoryGuard::new();
1207 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1208 let name1 = "vault1";
1209 let password1 = "password1".into();
1210 let name2 = "vault2";
1211 let password2 = "password2".into();
1212 let password3 = "password3".into();
1213 let keypair1 = keypair();
1214 let keypair2 = keypair();
1215 let keypair3 = keypair();
1216
1217 store.create_vault(name1, &password1).unwrap();
1219 store.create_vault(name2, &password2).unwrap();
1220 let account1 = store
1221 .insert_account(
1222 SecretVaultRef::Vault(name1.to_owned()),
1223 keypair1.secret().clone(),
1224 &password1,
1225 )
1226 .unwrap();
1227 let account2 = store
1228 .insert_account(
1229 SecretVaultRef::Vault(name1.to_owned()),
1230 keypair2.secret().clone(),
1231 &password1,
1232 )
1233 .unwrap();
1234 let account3 = store
1235 .insert_account(
1236 SecretVaultRef::Root,
1237 keypair3.secret().clone(),
1238 &password3,
1239 )
1240 .unwrap();
1241
1242 let account1 = store
1244 .change_account_vault(SecretVaultRef::Root, account1)
1245 .unwrap();
1246 let account2 = store
1247 .change_account_vault(
1248 SecretVaultRef::Vault(name2.to_owned()),
1249 account2,
1250 )
1251 .unwrap();
1252 let account3 = store
1253 .change_account_vault(
1254 SecretVaultRef::Vault(name2.to_owned()),
1255 account3,
1256 )
1257 .unwrap();
1258 let accounts = store.accounts().unwrap();
1259 assert_eq!(accounts.len(), 3);
1260 assert!(accounts
1261 .iter()
1262 .any(|a| a == &StoreAccountRef::root(account1.address.clone())));
1263 assert!(accounts
1264 .iter()
1265 .any(|a| a
1266 == &StoreAccountRef::vault(name2, account2.address.clone())));
1267 assert!(accounts
1268 .iter()
1269 .any(|a| a
1270 == &StoreAccountRef::vault(name2, account3.address.clone())));
1271
1272 assert_eq!(
1274 store
1275 .meta(&StoreAccountRef::root(account1.address))
1276 .unwrap(),
1277 r#"{}"#
1278 );
1279 assert_eq!(
1280 store
1281 .meta(&StoreAccountRef::vault("vault2", account2.address))
1282 .unwrap(),
1283 r#"{"vault":"vault2"}"#
1284 );
1285 assert_eq!(
1286 store
1287 .meta(&StoreAccountRef::vault("vault2", account3.address))
1288 .unwrap(),
1289 r#"{"vault":"vault2"}"#
1290 );
1291 }
1292
1293 #[test]
1294 fn should_not_remove_account_when_moving_to_self() {
1295 let mut dir = RootDiskDirectoryGuard::new();
1297 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1298 let password1 = "password1".into();
1299 let keypair1 = keypair();
1300
1301 let account1 = store
1303 .insert_account(
1304 SecretVaultRef::Root,
1305 keypair1.secret().clone(),
1306 &password1,
1307 )
1308 .unwrap();
1309 store
1310 .change_account_vault(SecretVaultRef::Root, account1)
1311 .unwrap();
1312
1313 let accounts = store.accounts().unwrap();
1315 assert_eq!(accounts.len(), 1);
1316 }
1317
1318 #[test]
1319 fn should_remove_account_from_vault() {
1320 let mut dir = RootDiskDirectoryGuard::new();
1322 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1323 let name1 = "vault1";
1324 let password1 = "password1".into();
1325 let keypair1 = keypair();
1326
1327 store.create_vault(name1, &password1).unwrap();
1329 let account1 = store
1330 .insert_account(
1331 SecretVaultRef::Vault(name1.to_owned()),
1332 keypair1.secret().clone(),
1333 &password1,
1334 )
1335 .unwrap();
1336 assert_eq!(store.accounts().unwrap().len(), 1);
1337
1338 store.remove_account(&account1, &password1).unwrap();
1340 assert_eq!(store.accounts().unwrap().len(), 0);
1341 }
1342
1343 #[test]
1344 fn should_not_remove_account_from_vault_when_password_is_incorrect() {
1345 let mut dir = RootDiskDirectoryGuard::new();
1347 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1348 let name1 = "vault1";
1349 let password1 = "password1".into();
1350 let password2 = "password2".into();
1351 let keypair1 = keypair();
1352
1353 store.create_vault(name1, &password1).unwrap();
1355 let account1 = store
1356 .insert_account(
1357 SecretVaultRef::Vault(name1.to_owned()),
1358 keypair1.secret().clone(),
1359 &password1,
1360 )
1361 .unwrap();
1362 assert_eq!(store.accounts().unwrap().len(), 1);
1363
1364 store.remove_account(&account1, &password2).unwrap_err();
1366 assert_eq!(store.accounts().unwrap().len(), 1);
1367 }
1368
1369 #[test]
1370 fn should_change_vault_password() {
1371 let mut dir = RootDiskDirectoryGuard::new();
1373 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1374 let name = "vault";
1375 let password = "password".into();
1376 let keypair = keypair();
1377
1378 store.create_vault(name, &password).unwrap();
1380 store
1381 .insert_account(
1382 SecretVaultRef::Vault(name.to_owned()),
1383 keypair.secret().clone(),
1384 &password,
1385 )
1386 .unwrap();
1387
1388 assert_eq!(store.accounts().unwrap().len(), 1);
1390 let new_password = "new_password".into();
1391 store.change_vault_password(name, &new_password).unwrap();
1392 assert_eq!(store.accounts().unwrap().len(), 1);
1393
1394 store.close_vault(name).unwrap();
1396
1397 store.open_vault(name, &new_password).unwrap();
1399 assert_eq!(store.accounts().unwrap().len(), 1);
1400 }
1401
1402 #[test]
1403 fn should_have_different_passwords_for_vault_secret_and_meta() {
1404 let mut dir = RootDiskDirectoryGuard::new();
1406 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1407 let name = "vault";
1408 let password = "password".into();
1409 let secret_password = "sec_password".into();
1410 let keypair = keypair();
1411
1412 store.create_vault(name, &password).unwrap();
1414 let account_ref = store
1415 .insert_account(
1416 SecretVaultRef::Vault(name.to_owned()),
1417 keypair.secret().clone(),
1418 &secret_password,
1419 )
1420 .unwrap();
1421
1422 assert_eq!(store.accounts().unwrap().len(), 1);
1424 let new_secret_password = "new_sec_password".into();
1425 store
1426 .change_password(
1427 &account_ref,
1428 &secret_password,
1429 &new_secret_password,
1430 )
1431 .unwrap();
1432 assert_eq!(store.accounts().unwrap().len(), 1);
1433 }
1434
1435 #[test]
1436 fn should_list_opened_vaults() {
1437 let mut dir = RootDiskDirectoryGuard::new();
1439 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1440 let name1 = "vault1";
1441 let password1 = "password1".into();
1442 let name2 = "vault2";
1443 let password2 = "password2".into();
1444 let name3 = "vault3";
1445 let password3 = "password3".into();
1446
1447 store.create_vault(name1, &password1).unwrap();
1449 store.create_vault(name2, &password2).unwrap();
1450 store.create_vault(name3, &password3).unwrap();
1451 store.close_vault(name2).unwrap();
1452
1453 let opened_vaults = store.list_opened_vaults().unwrap();
1455 assert_eq!(opened_vaults.len(), 2);
1456 assert!(opened_vaults.iter().any(|v| *v == name1));
1457 assert!(opened_vaults.iter().any(|v| *v == name3));
1458 }
1459
1460 #[test]
1461 fn should_manage_vaults_meta() {
1462 let mut dir = RootDiskDirectoryGuard::new();
1464 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1465 let name1 = "vault1";
1466 let password1 = "password1".into();
1467
1468 store.create_vault(name1, &password1).unwrap();
1470
1471 assert_eq!(store.get_vault_meta(name1).unwrap(), "{}".to_owned());
1473 assert!(store.set_vault_meta(name1, "Hello, world!!!").is_ok());
1474 assert_eq!(
1475 store.get_vault_meta(name1).unwrap(),
1476 "Hello, world!!!".to_owned()
1477 );
1478
1479 store.close_vault(name1).unwrap();
1481 store.open_vault(name1, &password1).unwrap();
1482
1483 assert_eq!(
1485 store.get_vault_meta(name1).unwrap(),
1486 "Hello, world!!!".to_owned()
1487 );
1488
1489 store.close_vault(name1).unwrap();
1491
1492 assert_eq!(
1494 store.get_vault_meta(name1).unwrap(),
1495 "Hello, world!!!".to_owned()
1496 );
1497 assert!(store.get_vault_meta("vault2").is_err());
1498 }
1499
1500 #[test]
1501 fn should_store_derived_keys() {
1502 let store = store();
1504 let keypair = keypair();
1505 let address = store
1506 .insert_account(
1507 SecretVaultRef::Root,
1508 keypair.secret().clone(),
1509 &"test".into(),
1510 )
1511 .unwrap();
1512
1513 let derived = store
1515 .insert_derived(
1516 SecretVaultRef::Root,
1517 &address,
1518 &"test".into(),
1519 Derivation::HardHash(H256::zero()),
1520 )
1521 .unwrap();
1522
1523 let accounts = store.accounts().unwrap();
1525 assert_eq!(accounts.len(), 2);
1526
1527 assert!(
1529 store
1530 .sign(&derived, &"test".into(), &Default::default())
1531 .is_ok(),
1532 "Second password should work for second store."
1533 );
1534 }
1535
1536 #[test]
1537 fn should_save_meta_when_setting_before_password() {
1538 let mut dir = RootDiskDirectoryGuard::new();
1540 let store = CfxStore::open(dir.key_dir.take().unwrap()).unwrap();
1541 let name = "vault";
1542 let password = "password1".into();
1543 let new_password = "password2".into();
1544
1545 store.create_vault(name, &password).unwrap();
1547 store.set_vault_meta(name, "OldMeta").unwrap();
1548 store.change_vault_password(name, &new_password).unwrap();
1549
1550 assert_eq!(store.get_vault_meta(name).unwrap(), "OldMeta".to_owned());
1552 }
1553
1554 #[test]
1555 fn should_export_account() {
1556 let store = store();
1558 let keypair = keypair();
1559 let address = store
1560 .insert_account(
1561 SecretVaultRef::Root,
1562 keypair.secret().clone(),
1563 &"test".into(),
1564 )
1565 .unwrap();
1566
1567 let exported = store.export_account(&address, &"test".into());
1569
1570 assert!(
1572 exported.is_ok(),
1573 "Should export single account: {:?}",
1574 exported
1575 );
1576 }
1577}