diff --git a/parity/main.rs b/parity/main.rs index 5d95085c5..e9833fd38 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -508,13 +508,13 @@ impl Configuration { .collect::>() .into_iter() }).collect::>(); - + let account_service = AccountService::new(); for d in &self.args.flag_unlock { let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| { die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d) }); - if passwords.iter().find(|p| account_service.unlock_account(&a, p).is_ok()).is_none() { + if passwords.iter().find(|p| account_service.unlock_account_no_expire(&a, p).is_ok()).is_none() { die!("No password given to unlock account {}. Pass the password using `--password`.", a); } } diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 78540bdb0..f98efd4be 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -75,7 +75,8 @@ pub struct SecretStore { struct AccountUnlock { secret: H256, - expires: DateTime, + /// expiration datetime (None - never) + expires: Option>, } /// Basic account management trait @@ -148,6 +149,11 @@ impl AccountService { pub fn tick(&self) { self.secret_store.write().unwrap().collect_garbage(); } + + /// Unlocks account for use (no expiration of unlock) + pub fn unlock_account_no_expire(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + self.secret_store.write().unwrap().unlock_account_with_expiration(account, pass, None) + } } @@ -226,14 +232,23 @@ impl SecretStore { /// Unlocks account for use pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + self.unlock_account_with_expiration(account, pass, Some(UTC::now() + Duration::minutes(20))) + } + + /// Unlocks account for use (no expiration of unlock) + pub fn unlock_account_no_expire(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + self.unlock_account_with_expiration(account, pass, None) + } + + fn unlock_account_with_expiration(&self, account: &Address, pass: &str, expiration: Option>) -> Result<(), EncryptedHashMapError> { let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); let secret = try!(self.get(&secret_id, pass)); { let mut write_lock = self.unlocks.write().unwrap(); let mut unlock = write_lock.entry(*account) - .or_insert_with(|| AccountUnlock { secret: secret, expires: UTC::now() }); + .or_insert_with(|| AccountUnlock { secret: secret, expires: Some(UTC::now()) }); unlock.secret = secret; - unlock.expires = UTC::now() + Duration::minutes(20); + unlock.expires = expiration; } Ok(()) } @@ -277,7 +292,7 @@ impl SecretStore { self.directory.collect_garbage(); let utc = UTC::now(); let expired_addresses = garbage_lock.iter() - .filter(|&(_, unlock)| unlock.expires < utc) + .filter(|&(_, unlock)| match unlock.expires { Some(ref expire_val) => expire_val < &utc, _ => false }) .map(|(address, _)| address.clone()).collect::>(); for expired in expired_addresses { garbage_lock.remove(&expired); } @@ -629,7 +644,7 @@ mod tests { let ss_rw = svc.secret_store.write().unwrap(); let mut ua_rw = ss_rw.unlocks.write().unwrap(); let entry = ua_rw.entry(address); - if let Entry::Occupied(mut occupied) = entry { occupied.get_mut().expires = UTC::now() - Duration::minutes(1); } + if let Entry::Occupied(mut occupied) = entry { occupied.get_mut().expires = Some(UTC::now() - Duration::minutes(1)) } } svc.tick();