cfxcore_accounts/
lib.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#![warn(missing_docs)]
18
19//! Account management.
20
21mod account_data;
22mod error;
23mod stores;
24
25use self::{
26    account_data::{AccountData, Unlock},
27    stores::AddressBook,
28};
29
30use std::{
31    collections::HashMap,
32    time::{Duration, Instant},
33};
34
35use cfxkey::{Address, Generator, Message, Password, Public, Random, Secret};
36use cfxstore::{
37    accounts_dir::MemoryDirectory, random_string, CfxMultiStore, CfxStore,
38    OpaqueSecret, SecretStore, SecretVaultRef, SimpleSecretStore,
39    StoreAccountRef,
40};
41use log::warn;
42use parking_lot::RwLock;
43
44pub use cfxkey::Signature;
45pub use cfxstore::{Derivation, Error, IndexDerivation, KeyFile};
46
47pub use self::{account_data::AccountMeta, error::SignError};
48
49type AccountToken = Password;
50
51/// Account management settings.
52#[derive(Debug, Default)]
53pub struct AccountProviderSettings {
54    /// Store raw account secret when unlocking the account permanently.
55    pub unlock_keep_secret: bool,
56    /// Disallowed accounts.
57    pub blacklisted_accounts: Vec<Address>,
58}
59
60/// Account management.
61/// Responsible for unlocking accounts.
62pub struct AccountProvider {
63    /// For performance reasons some methods can re-use unlocked secrets.
64    unlocked_secrets: RwLock<HashMap<StoreAccountRef, OpaqueSecret>>,
65    /// Unlocked account data.
66    unlocked: RwLock<HashMap<StoreAccountRef, AccountData>>,
67    /// Address book.
68    address_book: RwLock<AddressBook>,
69    /// Accounts on disk
70    sstore: Box<dyn SecretStore>,
71    /// Accounts unlocked with rolling tokens
72    transient_sstore: CfxMultiStore,
73    /// When unlocking account permanently we additionally keep a raw secret in
74    /// memory to increase the performance of transaction signing.
75    unlock_keep_secret: bool,
76    /// Disallowed accounts.
77    blacklisted_accounts: Vec<Address>,
78}
79
80fn transient_sstore() -> CfxMultiStore {
81    CfxMultiStore::open(Box::new(MemoryDirectory::default()))
82        .expect("MemoryDirectory load always succeeds; qed")
83}
84
85impl AccountProvider {
86    /// Creates new account provider.
87    pub fn new(
88        sstore: Box<dyn SecretStore>, settings: AccountProviderSettings,
89    ) -> Self {
90        if let Ok(accounts) = sstore.accounts() {
91            for account in accounts
92                .into_iter()
93                .filter(|a| settings.blacklisted_accounts.contains(&a.address))
94            {
95                warn!("Local Account {} has a blacklisted (known to be weak) address and will be ignored",
96					account.address);
97            }
98        }
99
100        // Remove blacklisted accounts from address book.
101        let mut address_book = AddressBook::new(&sstore.local_path());
102        for addr in &settings.blacklisted_accounts {
103            address_book.remove(*addr);
104        }
105
106        AccountProvider {
107            unlocked_secrets: RwLock::new(HashMap::new()),
108            unlocked: RwLock::new(HashMap::new()),
109            address_book: RwLock::new(address_book),
110            sstore,
111            transient_sstore: transient_sstore(),
112            unlock_keep_secret: settings.unlock_keep_secret,
113            blacklisted_accounts: settings.blacklisted_accounts,
114        }
115    }
116
117    /// Creates not disk backed provider.
118    pub fn transient_provider() -> Self {
119        AccountProvider {
120            unlocked_secrets: RwLock::new(HashMap::new()),
121            unlocked: RwLock::new(HashMap::new()),
122            address_book: RwLock::new(AddressBook::transient()),
123            sstore: Box::new(
124                CfxStore::open(Box::new(MemoryDirectory::default()))
125                    .expect("MemoryDirectory load always succeeds; qed"),
126            ),
127            transient_sstore: transient_sstore(),
128            unlock_keep_secret: false,
129            blacklisted_accounts: vec![],
130        }
131    }
132
133    /// Creates new random account.
134    pub fn new_account(&self, password: &Password) -> Result<Address, Error> {
135        self.new_account_and_public(password).map(|d| d.0)
136    }
137
138    /// Creates new random account and returns address and public key
139    pub fn new_account_and_public(
140        &self, password: &Password,
141    ) -> Result<(Address, Public), Error> {
142        let acc = Random
143            .generate()
144            .expect("secp context has generation capabilities; qed");
145        let public = acc.public().clone();
146        let secret = acc.secret().clone();
147        let account = self.sstore.insert_account(
148            SecretVaultRef::Root,
149            secret,
150            password,
151        )?;
152        Ok((account.address, public))
153    }
154
155    /// Inserts new account into underlying store.
156    /// Does not unlock account!
157    pub fn insert_account(
158        &self, secret: Secret, password: &Password,
159    ) -> Result<Address, Error> {
160        let account = self.sstore.insert_account(
161            SecretVaultRef::Root,
162            secret,
163            password,
164        )?;
165        if self.blacklisted_accounts.contains(&account.address) {
166            self.sstore.remove_account(&account, password)?;
167            return Err(Error::InvalidAccount);
168        }
169        Ok(account.address)
170    }
171
172    /// Generates new derived account based on the existing one
173    /// If password is not provided, account must be unlocked
174    /// New account will be created with the same password (if save: true)
175    pub fn derive_account(
176        &self, address: &Address, password: Option<Password>,
177        derivation: Derivation, save: bool,
178    ) -> Result<Address, SignError> {
179        let account = self.sstore.account_ref(&address)?;
180        let password = password
181            .map(Ok)
182            .unwrap_or_else(|| self.password(&account))?;
183        Ok(if save {
184            self.sstore
185                .insert_derived(
186                    SecretVaultRef::Root,
187                    &account,
188                    &password,
189                    derivation,
190                )?
191                .address
192        } else {
193            self.sstore
194                .generate_derived(&account, &password, derivation)?
195        })
196    }
197
198    /// Import a new wallet.
199    pub fn import_wallet(
200        &self, json: &[u8], password: &Password, gen_id: bool,
201    ) -> Result<Address, Error> {
202        let account = self.sstore.import_wallet(
203            SecretVaultRef::Root,
204            json,
205            password,
206            gen_id,
207        )?;
208        if self.blacklisted_accounts.contains(&account.address) {
209            self.sstore.remove_account(&account, password)?;
210            return Err(Error::InvalidAccount);
211        }
212        Ok(account.address)
213    }
214
215    /// Checks whether an account with a given address is present.
216    pub fn has_account(&self, address: Address) -> bool {
217        self.sstore.account_ref(&address).is_ok()
218            && !self.blacklisted_accounts.contains(&address)
219    }
220
221    /// Returns addresses of all accounts.
222    pub fn accounts(&self) -> Result<Vec<Address>, Error> {
223        let accounts = self.sstore.accounts()?;
224        Ok(accounts
225            .into_iter()
226            .map(|a| a.address)
227            .filter(|address| !self.blacklisted_accounts.contains(address))
228            .collect())
229    }
230
231    /// Returns the address of default account.
232    pub fn default_account(&self) -> Result<Address, Error> {
233        Ok(self.accounts()?.first().cloned().unwrap_or_default())
234    }
235
236    /// Returns each address along with metadata.
237    pub fn addresses_info(&self) -> HashMap<Address, AccountMeta> {
238        self.address_book.read().get()
239    }
240
241    /// Returns each address along with metadata.
242    pub fn set_address_name(&self, account: Address, name: String) {
243        self.address_book.write().set_name(account, name)
244    }
245
246    /// Returns each address along with metadata.
247    pub fn set_address_meta(&self, account: Address, meta: String) {
248        self.address_book.write().set_meta(account, meta)
249    }
250
251    /// Removes and address from the address book
252    pub fn remove_address(&self, addr: Address) {
253        self.address_book.write().remove(addr)
254    }
255
256    /// Returns each account along with name and meta.
257    pub fn accounts_info(
258        &self,
259    ) -> Result<HashMap<Address, AccountMeta>, Error> {
260        let r = self
261            .sstore
262            .accounts()?
263            .into_iter()
264            .filter(|a| !self.blacklisted_accounts.contains(&a.address))
265            .map(|a| {
266                (
267                    a.address.clone(),
268                    self.account_meta(a.address).ok().unwrap_or_default(),
269                )
270            })
271            .collect();
272        Ok(r)
273    }
274
275    /// Returns each account along with name and meta.
276    pub fn account_meta(&self, address: Address) -> Result<AccountMeta, Error> {
277        let account = self.sstore.account_ref(&address)?;
278        Ok(AccountMeta {
279            name: self.sstore.name(&account)?,
280            meta: self.sstore.meta(&account)?,
281            uuid: self.sstore.uuid(&account).ok().map(Into::into), /* allowed to not have a Uuid */
282        })
283    }
284
285    /// Returns account public key.
286    pub fn account_public(
287        &self, address: Address, password: &Password,
288    ) -> Result<Public, Error> {
289        self.sstore
290            .public(&self.sstore.account_ref(&address)?, password)
291    }
292
293    /// Returns each account along with name and meta.
294    pub fn set_account_name(
295        &self, address: Address, name: String,
296    ) -> Result<(), Error> {
297        self.sstore
298            .set_name(&self.sstore.account_ref(&address)?, name)?;
299        Ok(())
300    }
301
302    /// Returns each account along with name and meta.
303    pub fn set_account_meta(
304        &self, address: Address, meta: String,
305    ) -> Result<(), Error> {
306        self.sstore
307            .set_meta(&self.sstore.account_ref(&address)?, meta)?;
308        Ok(())
309    }
310
311    /// Returns `true` if the password for `account` is `password`. `false` if
312    /// not.
313    pub fn test_password(
314        &self, address: &Address, password: &Password,
315    ) -> Result<bool, Error> {
316        self.sstore
317            .test_password(&self.sstore.account_ref(&address)?, password)
318            .map_err(Into::into)
319    }
320
321    /// Permanently removes an account.
322    pub fn kill_account(
323        &self, address: &Address, password: &Password,
324    ) -> Result<(), Error> {
325        self.sstore
326            .remove_account(&self.sstore.account_ref(&address)?, &password)?;
327        Ok(())
328    }
329
330    /// Changes the password of `account` from `password` to `new_password`.
331    /// Fails if incorrect `password` given.
332    pub fn change_password(
333        &self, address: &Address, password: Password, new_password: Password,
334    ) -> Result<(), Error> {
335        self.sstore.change_password(
336            &self.sstore.account_ref(address)?,
337            &password,
338            &new_password,
339        )
340    }
341
342    /// Exports an account for given address.
343    pub fn export_account(
344        &self, address: &Address, password: Password,
345    ) -> Result<KeyFile, Error> {
346        self.sstore
347            .export_account(&self.sstore.account_ref(address)?, &password)
348    }
349
350    /// Helper method used for unlocking accounts.
351    fn unlock_account(
352        &self, address: Address, password: Password, unlock: Unlock,
353    ) -> Result<(), Error> {
354        let account = self.sstore.account_ref(&address)?;
355
356        // check if account is already unlocked permanently, if it is, do
357        // nothing
358        let mut unlocked = self.unlocked.write();
359        if let Some(data) = unlocked.get(&account) {
360            if let Unlock::Perm = data.unlock {
361                return Ok(());
362            }
363        }
364
365        if self.unlock_keep_secret && unlock == Unlock::Perm {
366            // verify password and get the secret
367            let secret = self.sstore.raw_secret(&account, &password)?;
368            self.unlocked_secrets
369                .write()
370                .insert(account.clone(), secret);
371        } else {
372            // verify password by signing dump message
373            // result may be discarded
374            let _ =
375                self.sstore.sign(&account, &password, &Default::default())?;
376        }
377
378        let data = AccountData { unlock, password };
379
380        unlocked.insert(account, data);
381        Ok(())
382    }
383
384    /// Lock an account
385    pub fn lock_account(&self, address: Address) -> Result<(), Error> {
386        let account = self.sstore.account_ref(&address)?;
387
388        let mut unlocked = self.unlocked.write();
389        if let Some(data) = unlocked.get(&account) {
390            if let Unlock::Perm = data.unlock {
391                self.unlocked_secrets.write().remove(&account);
392            }
393            unlocked.remove(&account);
394        }
395        Ok(())
396    }
397
398    fn password(
399        &self, account: &StoreAccountRef,
400    ) -> Result<Password, SignError> {
401        let mut unlocked = self.unlocked.write();
402        Self::password_with_unlocked(&mut unlocked, account)
403    }
404
405    fn password_with_unlocked(
406        unlocked: &mut HashMap<StoreAccountRef, AccountData>,
407        account: &StoreAccountRef,
408    ) -> Result<Password, SignError> {
409        let data = unlocked.get(account).ok_or(SignError::NotUnlocked)?.clone();
410        if let Unlock::OneTime = data.unlock {
411            unlocked
412                .remove(account)
413                .expect("data exists: so key must exist: qed");
414        }
415        if let Unlock::Timed(ref end) = data.unlock {
416            if Instant::now() > *end {
417                unlocked
418                    .remove(account)
419                    .expect("data exists: so key must exist: qed");
420                return Err(SignError::NotUnlocked);
421            }
422        }
423        Ok(data.password)
424    }
425
426    /// Unlocks account permanently.
427    pub fn unlock_account_permanently(
428        &self, account: Address, password: Password,
429    ) -> Result<(), Error> {
430        self.unlock_account(account, password, Unlock::Perm)
431    }
432
433    /// Unlocks account temporarily (for one signing).
434    pub fn unlock_account_temporarily(
435        &self, account: Address, password: Password,
436    ) -> Result<(), Error> {
437        self.unlock_account(account, password, Unlock::OneTime)
438    }
439
440    /// Unlocks account temporarily with a timeout.
441    pub fn unlock_account_timed(
442        &self, account: Address, password: Password, duration: Duration,
443    ) -> Result<(), Error> {
444        self.unlock_account(
445            account,
446            password,
447            Unlock::Timed(Instant::now() + duration),
448        )
449    }
450
451    /// Checks if given account is unlocked
452    pub fn is_unlocked(&self, address: &Address) -> bool {
453        let unlocked = self.unlocked.read();
454        let unlocked_secrets = self.unlocked_secrets.read();
455        self.sstore
456            .account_ref(address)
457            .map(|r| {
458                unlocked.get(&r).is_some() || unlocked_secrets.get(&r).is_some()
459            })
460            .unwrap_or(false)
461    }
462
463    /// Checks if given account is unlocked permanently
464    pub fn is_unlocked_permanently(&self, address: &Address) -> bool {
465        let unlocked = self.unlocked.read();
466        self.sstore
467            .account_ref(address)
468            .map(|r| {
469                unlocked
470                    .get(&r)
471                    .map_or(false, |account| account.unlock == Unlock::Perm)
472            })
473            .unwrap_or(false)
474    }
475
476    /// Signs the message. If password is not provided the account must be
477    /// unlocked.
478    pub fn sign(
479        &self, address: Address, password: Option<Password>, message: Message,
480    ) -> Result<Signature, SignError> {
481        let account = self.sstore.account_ref(&address)?;
482        // unlocked must be acquired before unlocked_secrets
483        let mut unlocked = self.unlocked.write();
484        match self.unlocked_secrets.read().get(&account) {
485            Some(secret) => {
486                Ok(self.sstore.sign_with_secret(&secret, &message)?)
487            }
488            None => {
489                let password = password.map(Ok).unwrap_or_else(|| {
490                    Self::password_with_unlocked(&mut unlocked, &account)
491                })?;
492                Ok(self.sstore.sign(&account, &password, &message)?)
493            }
494        }
495    }
496
497    /// Signs message using the derived secret. If password is not provided the
498    /// account must be unlocked.
499    pub fn sign_derived(
500        &self, address: &Address, password: Option<Password>,
501        derivation: Derivation, message: Message,
502    ) -> Result<Signature, SignError> {
503        let account = self.sstore.account_ref(address)?;
504        let password = password
505            .map(Ok)
506            .unwrap_or_else(|| self.password(&account))?;
507        Ok(self
508            .sstore
509            .sign_derived(&account, &password, derivation, &message)?)
510    }
511
512    /// Signs given message with supplied token. Returns a token to use in next
513    /// signing within this session.
514    pub fn sign_with_token(
515        &self, address: Address, token: AccountToken, message: Message,
516    ) -> Result<(Signature, AccountToken), SignError> {
517        let account = self.sstore.account_ref(&address)?;
518        let is_std_password = self.sstore.test_password(&account, &token)?;
519
520        let new_token = Password::from(random_string(16));
521        let signature = if is_std_password {
522            // Insert to transient store
523            self.sstore.copy_account(
524                &self.transient_sstore,
525                SecretVaultRef::Root,
526                &account,
527                &token,
528                &new_token,
529            )?;
530            // sign
531            self.sstore.sign(&account, &token, &message)?
532        } else {
533            // check transient store
534            self.transient_sstore
535                .change_password(&account, &token, &new_token)?;
536            // and sign
537            self.transient_sstore.sign(&account, &new_token, &message)?
538        };
539
540        Ok((signature, new_token))
541    }
542
543    /// Decrypts a message with given token. Returns a token to use in next
544    /// operation for this account.
545    pub fn decrypt_with_token(
546        &self, address: Address, token: AccountToken, shared_mac: &[u8],
547        message: &[u8],
548    ) -> Result<(Vec<u8>, AccountToken), SignError> {
549        let account = self.sstore.account_ref(&address)?;
550        let is_std_password = self.sstore.test_password(&account, &token)?;
551
552        let new_token = Password::from(random_string(16));
553        let message = if is_std_password {
554            // Insert to transient store
555            self.sstore.copy_account(
556                &self.transient_sstore,
557                SecretVaultRef::Root,
558                &account,
559                &token,
560                &new_token,
561            )?;
562            // decrypt
563            self.sstore.decrypt(&account, &token, shared_mac, message)?
564        } else {
565            // check transient store
566            self.transient_sstore
567                .change_password(&account, &token, &new_token)?;
568            // and decrypt
569            self.transient_sstore
570                .decrypt(&account, &token, shared_mac, message)?
571        };
572
573        Ok((message, new_token))
574    }
575
576    /// Decrypts a message. If password is not provided the account must be
577    /// unlocked.
578    pub fn decrypt(
579        &self, address: Address, password: Option<Password>, shared_mac: &[u8],
580        message: &[u8],
581    ) -> Result<Vec<u8>, SignError> {
582        let account = self.sstore.account_ref(&address)?;
583        let password = password
584            .map(Ok)
585            .unwrap_or_else(|| self.password(&account))?;
586        Ok(self
587            .sstore
588            .decrypt(&account, &password, shared_mac, message)?)
589    }
590
591    /// Agree on shared key.
592    pub fn agree(
593        &self, address: Address, password: Option<Password>,
594        other_public: &Public,
595    ) -> Result<Secret, SignError> {
596        let account = self.sstore.account_ref(&address)?;
597        let password = password
598            .map(Ok)
599            .unwrap_or_else(|| self.password(&account))?;
600        Ok(self.sstore.agree(&account, &password, other_public)?)
601    }
602
603    /// Returns the underlying `SecretStore` reference if one exists.
604    pub fn list_geth_accounts(&self, testnet: bool) -> Vec<Address> {
605        self.sstore
606            .list_geth_accounts(testnet)
607            .into_iter()
608            .map(|a| a)
609            .collect()
610    }
611
612    /// Returns the underlying `SecretStore` reference if one exists.
613    pub fn import_geth_accounts(
614        &self, desired: Vec<Address>, testnet: bool,
615    ) -> Result<Vec<Address>, Error> {
616        self.sstore
617            .import_geth_accounts(SecretVaultRef::Root, desired, testnet)
618            .map(|a| a.into_iter().map(|a| a.address).collect())
619            .map_err(Into::into)
620    }
621
622    /// Create new vault.
623    pub fn create_vault(
624        &self, name: &str, password: &Password,
625    ) -> Result<(), Error> {
626        self.sstore.create_vault(name, password).map_err(Into::into)
627    }
628
629    /// Open existing vault.
630    pub fn open_vault(
631        &self, name: &str, password: &Password,
632    ) -> Result<(), Error> {
633        self.sstore.open_vault(name, password).map_err(Into::into)
634    }
635
636    /// Close previously opened vault.
637    pub fn close_vault(&self, name: &str) -> Result<(), Error> {
638        self.sstore.close_vault(name).map_err(Into::into)
639    }
640
641    /// List all vaults
642    pub fn list_vaults(&self) -> Result<Vec<String>, Error> {
643        self.sstore.list_vaults().map_err(Into::into)
644    }
645
646    /// List all currently opened vaults
647    pub fn list_opened_vaults(&self) -> Result<Vec<String>, Error> {
648        self.sstore.list_opened_vaults().map_err(Into::into)
649    }
650
651    /// Change vault password.
652    pub fn change_vault_password(
653        &self, name: &str, new_password: &Password,
654    ) -> Result<(), Error> {
655        self.sstore
656            .change_vault_password(name, new_password)
657            .map_err(Into::into)
658    }
659
660    /// Change vault of the given address.
661    pub fn change_vault(
662        &self, address: Address, new_vault: &str,
663    ) -> Result<(), Error> {
664        let new_vault_ref = if new_vault.is_empty() {
665            SecretVaultRef::Root
666        } else {
667            SecretVaultRef::Vault(new_vault.to_owned())
668        };
669        let old_account_ref = self.sstore.account_ref(&address)?;
670        self.sstore
671            .change_account_vault(new_vault_ref, old_account_ref)
672            .map_err(Into::into)
673            .map(|_| ())
674    }
675
676    /// Get vault metadata string.
677    pub fn get_vault_meta(&self, name: &str) -> Result<String, Error> {
678        self.sstore.get_vault_meta(name).map_err(Into::into)
679    }
680
681    /// Set vault metadata string.
682    pub fn set_vault_meta(&self, name: &str, meta: &str) -> Result<(), Error> {
683        self.sstore.set_vault_meta(name, meta).map_err(Into::into)
684    }
685}
686
687#[cfg(test)]
688mod tests {
689    use super::{AccountProvider, Unlock};
690    use cfx_types::H256;
691    use cfxkey::{Address, Generator, Random};
692    use cfxstore::{Derivation, StoreAccountRef};
693    use std::time::{Duration, Instant};
694
695    #[test]
696    fn unlock_account_temp() {
697        let kp = Random.generate().unwrap();
698        let ap = AccountProvider::transient_provider();
699        assert!(ap
700            .insert_account(kp.secret().clone(), &"test".into())
701            .is_ok());
702        assert!(ap
703            .unlock_account_temporarily(kp.address(), "test1".into())
704            .is_err());
705        assert!(ap
706            .unlock_account_temporarily(kp.address(), "test".into())
707            .is_ok());
708        assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
709        assert!(ap.sign(kp.address(), None, Default::default()).is_err());
710    }
711
712    #[test]
713    fn derived_account_nosave() {
714        let kp = Random.generate().unwrap();
715        let ap = AccountProvider::transient_provider();
716        assert!(ap
717            .insert_account(kp.secret().clone(), &"base".into())
718            .is_ok());
719        assert!(ap
720            .unlock_account_permanently(kp.address(), "base".into())
721            .is_ok());
722
723        let derived_addr = ap
724            .derive_account(
725                &kp.address(),
726                None,
727                Derivation::SoftHash(H256::from_low_u64_be(999)),
728                false,
729            )
730            .expect("Derivation should not fail");
731
732        assert!(ap.unlock_account_permanently(derived_addr, "base".into()).is_err(),
733			"There should be an error because account is not supposed to be saved");
734    }
735
736    #[test]
737    fn derived_account_save() {
738        let kp = Random.generate().unwrap();
739        let ap = AccountProvider::transient_provider();
740        assert!(ap
741            .insert_account(kp.secret().clone(), &"base".into())
742            .is_ok());
743        assert!(ap
744            .unlock_account_permanently(kp.address(), "base".into())
745            .is_ok());
746
747        let derived_addr = ap
748            .derive_account(
749                &kp.address(),
750                None,
751                Derivation::SoftHash(H256::from_low_u64_be(999)),
752                true,
753            )
754            .expect("Derivation should not fail");
755
756        assert!(
757            ap.unlock_account_permanently(derived_addr, "base_wrong".into())
758                .is_err(),
759            "There should be an error because password is invalid"
760        );
761
762        assert!(
763            ap.unlock_account_permanently(derived_addr, "base".into())
764                .is_ok(),
765            "Should be ok because account is saved and password is valid"
766        );
767    }
768
769    #[test]
770    fn derived_account_sign() {
771        let kp = Random.generate().unwrap();
772        let ap = AccountProvider::transient_provider();
773        assert!(ap
774            .insert_account(kp.secret().clone(), &"base".into())
775            .is_ok());
776        assert!(ap
777            .unlock_account_permanently(kp.address(), "base".into())
778            .is_ok());
779
780        let derived_addr = ap
781            .derive_account(
782                &kp.address(),
783                None,
784                Derivation::SoftHash(H256::from_low_u64_be(1999)),
785                true,
786            )
787            .expect("Derivation should not fail");
788        ap.unlock_account_permanently(derived_addr, "base".into())
789            .expect(
790                "Should be ok because account is saved and password is valid",
791            );
792
793        let msg = Default::default();
794        let signed_msg1 = ap
795            .sign(derived_addr, None, msg)
796            .expect("Signing with existing unlocked account should not fail");
797        let signed_msg2 = ap.sign_derived(
798			&kp.address(),
799			None,
800			Derivation::SoftHash(H256::from_low_u64_be(1999)),
801			msg,
802		).expect("Derived signing with existing unlocked account should not fail");
803
804        assert_eq!(signed_msg1, signed_msg2, "Signed messages should match");
805    }
806
807    #[test]
808    fn unlock_account_perm() {
809        let kp = Random.generate().unwrap();
810        let ap = AccountProvider::transient_provider();
811        assert!(ap
812            .insert_account(kp.secret().clone(), &"test".into())
813            .is_ok());
814        assert!(ap
815            .unlock_account_permanently(kp.address(), "test1".into())
816            .is_err());
817        assert!(ap
818            .unlock_account_permanently(kp.address(), "test".into())
819            .is_ok());
820        assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
821        assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
822        assert!(ap
823            .unlock_account_temporarily(kp.address(), "test".into())
824            .is_ok());
825        assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
826        assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
827    }
828
829    #[test]
830    fn unlock_account_timer() {
831        let kp = Random.generate().unwrap();
832        let ap = AccountProvider::transient_provider();
833        assert!(ap
834            .insert_account(kp.secret().clone(), &"test".into())
835            .is_ok());
836        assert!(ap
837            .unlock_account_timed(
838                kp.address(),
839                "test1".into(),
840                Duration::from_secs(60)
841            )
842            .is_err());
843        assert!(ap
844            .unlock_account_timed(
845                kp.address(),
846                "test".into(),
847                Duration::from_secs(60)
848            )
849            .is_ok());
850        assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
851        ap.unlocked
852            .write()
853            .get_mut(&StoreAccountRef::root(kp.address()))
854            .unwrap()
855            .unlock = Unlock::Timed(Instant::now());
856        assert!(ap.sign(kp.address(), None, Default::default()).is_err());
857    }
858
859    #[test]
860    fn should_sign_and_return_token() {
861        // given
862        let kp = Random.generate().unwrap();
863        let ap = AccountProvider::transient_provider();
864        assert!(ap
865            .insert_account(kp.secret().clone(), &"test".into())
866            .is_ok());
867
868        // when
869        let (_signature, token) = ap
870            .sign_with_token(kp.address(), "test".into(), Default::default())
871            .unwrap();
872
873        // then
874        ap.sign_with_token(kp.address(), token.clone(), Default::default())
875            .expect("First usage of token should be correct.");
876        assert!(
877            ap.sign_with_token(kp.address(), token, Default::default())
878                .is_err(),
879            "Second usage of the same token should fail."
880        );
881    }
882
883    #[test]
884    fn should_not_return_blacklisted_account() {
885        // given
886        let mut ap = AccountProvider::transient_provider();
887        let acc = ap.new_account(&"test".into()).unwrap();
888        ap.blacklisted_accounts = vec![acc];
889
890        // then
891        assert_eq!(
892            ap.accounts_info()
893                .unwrap()
894                .keys()
895                .cloned()
896                .collect::<Vec<Address>>(),
897            vec![]
898        );
899        assert_eq!(ap.accounts().unwrap(), vec![]);
900    }
901}