mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-20 19:11:09 +03:00
API Lifecycle Implementation, Part 2 (#217)
* additon of 'get_mnemonic' API function * rustfmt * added 'change_password' api function * rustfmt * add 'delete_wallet' function' * rustfmt
This commit is contained in:
parent
41c0058e84
commit
78e30aa779
10 changed files with 430 additions and 14 deletions
124
api/src/owner.rs
124
api/src/owner.rs
|
@ -1565,6 +1565,130 @@ where
|
||||||
let lc = w_lock.lc_provider()?;
|
let lc = w_lock.lc_provider()?;
|
||||||
lc.close_wallet(name)
|
lc.close_wallet(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the BIP39 mnemonic for the given wallet. This function will decrypt
|
||||||
|
/// the wallet's seed file with the given password, and thus does not need the
|
||||||
|
/// wallet to be open.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `name`: Reserved for future use, use `None` for the time being.
|
||||||
|
/// * `password`: The password used to encrypt the seed file.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * Ok(BIP-39 mneminc) if successful
|
||||||
|
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
||||||
|
/// ```
|
||||||
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
|
///
|
||||||
|
/// use grin_core::global::ChainTypes;
|
||||||
|
///
|
||||||
|
/// // Set up as above
|
||||||
|
/// # let api_owner = Owner::new(wallet.clone());
|
||||||
|
///
|
||||||
|
/// let pw = ZeroingString::from("my_password");
|
||||||
|
/// let res = api_owner.get_mnemonic(None, pw);
|
||||||
|
///
|
||||||
|
/// if let Ok(mne) = res {
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn get_mnemonic(
|
||||||
|
&self,
|
||||||
|
name: Option<&str>,
|
||||||
|
password: ZeroingString,
|
||||||
|
) -> Result<ZeroingString, Error> {
|
||||||
|
let mut w_lock = self.wallet_inst.lock();
|
||||||
|
let lc = w_lock.lc_provider()?;
|
||||||
|
lc.get_mnemonic(name, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changes a wallet's password, meaning the old seed file is decrypted with the old password,
|
||||||
|
/// and a new seed file is created with the same mnemonic and encrypted with the new password.
|
||||||
|
///
|
||||||
|
/// This function temporarily backs up the old seed file until a test-decryption of the new
|
||||||
|
/// file is confirmed to contain the same seed as the original seed file, at which point the
|
||||||
|
/// backup is deleted. If this operation fails for an unknown reason, the backup file will still
|
||||||
|
/// exist in the wallet's data directory encrypted with the old password.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `name`: Reserved for future use, use `None` for the time being.
|
||||||
|
/// * `old`: The password used to encrypt the existing seed file (i.e. old password)
|
||||||
|
/// * `new`: The password to be used to encrypt the new seed file
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * Ok(()) if successful
|
||||||
|
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
||||||
|
/// ```
|
||||||
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
|
///
|
||||||
|
/// use grin_core::global::ChainTypes;
|
||||||
|
///
|
||||||
|
/// // Set up as above
|
||||||
|
/// # let api_owner = Owner::new(wallet.clone());
|
||||||
|
///
|
||||||
|
/// let old = ZeroingString::from("my_password");
|
||||||
|
/// let new = ZeroingString::from("new_password");
|
||||||
|
/// let res = api_owner.change_password(None, old, new);
|
||||||
|
///
|
||||||
|
/// if let Ok(mne) = res {
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
pub fn change_password(
|
||||||
|
&self,
|
||||||
|
name: Option<&str>,
|
||||||
|
old: ZeroingString,
|
||||||
|
new: ZeroingString,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut w_lock = self.wallet_inst.lock();
|
||||||
|
let lc = w_lock.lc_provider()?;
|
||||||
|
lc.change_password(name, old, new)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Deletes a wallet, removing the config file, seed file and all data files.
|
||||||
|
/// Obviously, use with extreme caution and plenty of user warning
|
||||||
|
///
|
||||||
|
/// Highly recommended that the wallet be explicitly closed first via the `close_wallet`
|
||||||
|
/// function.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `name`: Reserved for future use, use `None` for the time being.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * Ok if successful
|
||||||
|
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
||||||
|
/// ```
|
||||||
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
|
///
|
||||||
|
/// use grin_core::global::ChainTypes;
|
||||||
|
///
|
||||||
|
/// // Set up as above
|
||||||
|
/// # let api_owner = Owner::new(wallet.clone());
|
||||||
|
///
|
||||||
|
/// let res = api_owner.delete_wallet(None);
|
||||||
|
///
|
||||||
|
/// if let Ok(_) = res {
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
pub fn delete_wallet(&self, name: Option<&str>) -> Result<(), Error> {
|
||||||
|
let mut w_lock = self.wallet_inst.lock();
|
||||||
|
let lc = w_lock.lc_provider()?;
|
||||||
|
lc.delete_wallet(name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -1587,6 +1587,102 @@ pub trait OwnerRpcS {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn close_wallet(&self, name: Option<String>) -> Result<(), ErrorKind>;
|
fn close_wallet(&self, name: Option<String>) -> Result<(), ErrorKind>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Networked version of [Owner::get_mnemonic](struct.Owner.html#method.get_mnemonic).
|
||||||
|
```
|
||||||
|
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
|
||||||
|
# r#"
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "get_mnemonic",
|
||||||
|
"params": {
|
||||||
|
"name": null,
|
||||||
|
"password": ""
|
||||||
|
},
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
# "#
|
||||||
|
# ,
|
||||||
|
# r#"
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": {
|
||||||
|
"Ok": "fat twenty mean degree forget shell check candy immense awful flame next during february bulb bike sun wink theory day kiwi embrace peace lunch"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# "#
|
||||||
|
# , true, 0, false, false, false);
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
|
||||||
|
fn get_mnemonic(&self, name: Option<String>, password: String) -> Result<String, ErrorKind>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Networked version of [Owner::change_password](struct.Owner.html#method.change_password).
|
||||||
|
```
|
||||||
|
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
|
||||||
|
# r#"
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "change_password",
|
||||||
|
"params": {
|
||||||
|
"name": null,
|
||||||
|
"old": "",
|
||||||
|
"new": "new_password"
|
||||||
|
},
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
# "#
|
||||||
|
# ,
|
||||||
|
# r#"
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": {
|
||||||
|
"Ok": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# "#
|
||||||
|
# , true, 0, false, false, false);
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
fn change_password(
|
||||||
|
&self,
|
||||||
|
name: Option<String>,
|
||||||
|
old: String,
|
||||||
|
new: String,
|
||||||
|
) -> Result<(), ErrorKind>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Networked version of [Owner::delete_wallet](struct.Owner.html#method.delete_wallet).
|
||||||
|
```
|
||||||
|
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
|
||||||
|
# r#"
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "delete_wallet",
|
||||||
|
"params": {
|
||||||
|
"name": null
|
||||||
|
},
|
||||||
|
"id": 1
|
||||||
|
}
|
||||||
|
# "#
|
||||||
|
# ,
|
||||||
|
# r#"
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"result": {
|
||||||
|
"Ok": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# "#
|
||||||
|
# , true, 0, false, false, false);
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
fn delete_wallet(&self, name: Option<String>) -> Result<(), ErrorKind>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, L, C, K> OwnerRpcS for Owner<'a, L, C, K>
|
impl<'a, L, C, K> OwnerRpcS for Owner<'a, L, C, K>
|
||||||
|
@ -1843,4 +1939,27 @@ where
|
||||||
let n = name.as_ref().map(|s| s.as_str());
|
let n = name.as_ref().map(|s| s.as_str());
|
||||||
Owner::close_wallet(self, n).map_err(|e| e.kind())
|
Owner::close_wallet(self, n).map_err(|e| e.kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_mnemonic(&self, name: Option<String>, password: String) -> Result<String, ErrorKind> {
|
||||||
|
let n = name.as_ref().map(|s| s.as_str());
|
||||||
|
let res =
|
||||||
|
Owner::get_mnemonic(self, n, ZeroingString::from(password)).map_err(|e| e.kind())?;
|
||||||
|
Ok(format!("{}", &*res))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn change_password(
|
||||||
|
&self,
|
||||||
|
name: Option<String>,
|
||||||
|
old: String,
|
||||||
|
new: String,
|
||||||
|
) -> Result<(), ErrorKind> {
|
||||||
|
let n = name.as_ref().map(|s| s.as_str());
|
||||||
|
Owner::change_password(self, n, ZeroingString::from(old), ZeroingString::from(new))
|
||||||
|
.map_err(|e| e.kind())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete_wallet(&self, name: Option<String>) -> Result<(), ErrorKind> {
|
||||||
|
let n = name.as_ref().map(|s| s.as_str());
|
||||||
|
Owner::delete_wallet(self, n).map_err(|e| e.kind())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -202,8 +202,9 @@ where
|
||||||
}
|
}
|
||||||
Ok(d) => d,
|
Ok(d) => d,
|
||||||
};
|
};
|
||||||
let wallet_seed = WalletSeed::from_file(&data_dir_name, password)
|
let wallet_seed = WalletSeed::from_file(&data_dir_name, password).context(
|
||||||
.context(ErrorKind::Lifecycle("Error opening wallet".into()))?;
|
ErrorKind::Lifecycle("Error opening wallet (is password correct?)".into()),
|
||||||
|
)?;
|
||||||
let keychain = wallet_seed
|
let keychain = wallet_seed
|
||||||
.derive_keychain(global::is_floonet())
|
.derive_keychain(global::is_floonet())
|
||||||
.context(ErrorKind::Lifecycle("Error deriving keychain".into()))?;
|
.context(ErrorKind::Lifecycle("Error deriving keychain".into()))?;
|
||||||
|
@ -270,12 +271,69 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn change_password(&self, _old: String, _new: String) -> Result<(), Error> {
|
fn change_password(
|
||||||
unimplemented!()
|
&self,
|
||||||
|
_name: Option<&str>,
|
||||||
|
old: ZeroingString,
|
||||||
|
new: ZeroingString,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let mut data_dir_name = PathBuf::from(self.data_dir.clone());
|
||||||
|
data_dir_name.push(GRIN_WALLET_DIR);
|
||||||
|
let data_dir_name = data_dir_name.to_str().unwrap();
|
||||||
|
// get seed for later check
|
||||||
|
|
||||||
|
let orig_wallet_seed = WalletSeed::from_file(&data_dir_name, old).context(
|
||||||
|
ErrorKind::Lifecycle("Error opening wallet seed file".into()),
|
||||||
|
)?;
|
||||||
|
let orig_mnemonic = orig_wallet_seed
|
||||||
|
.to_mnemonic()
|
||||||
|
.context(ErrorKind::Lifecycle("Error recovering mnemonic".into()))?;
|
||||||
|
|
||||||
|
// Back up existing seed, and keep track of filename as we're deleting it
|
||||||
|
// once the password change is confirmed
|
||||||
|
let backup_name = WalletSeed::backup_seed(data_dir_name).context(ErrorKind::Lifecycle(
|
||||||
|
"Error temporarily backing up existing seed".into(),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Delete seed file
|
||||||
|
WalletSeed::delete_seed_file(data_dir_name).context(ErrorKind::Lifecycle(
|
||||||
|
"Unable to delete seed file for password change".into(),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
// Init a new file
|
||||||
|
let _ = WalletSeed::init_file(
|
||||||
|
data_dir_name,
|
||||||
|
0,
|
||||||
|
Some(ZeroingString::from(orig_mnemonic)),
|
||||||
|
new.clone(),
|
||||||
|
);
|
||||||
|
info!("Wallet seed file created");
|
||||||
|
|
||||||
|
let new_wallet_seed = WalletSeed::from_file(&data_dir_name, new).context(
|
||||||
|
ErrorKind::Lifecycle("Error opening wallet seed file".into()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if orig_wallet_seed != new_wallet_seed {
|
||||||
|
let msg = format!(
|
||||||
|
"New and Old wallet seeds are not equal on password change, not removing backups."
|
||||||
|
);
|
||||||
|
return Err(ErrorKind::Lifecycle(msg).into());
|
||||||
|
}
|
||||||
|
// Removin
|
||||||
|
info!("Password change confirmed, removing old seed file.");
|
||||||
|
fs::remove_file(backup_name).context(ErrorKind::IO)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_wallet(&self, _name: Option<String>, _password: String) -> Result<(), Error> {
|
fn delete_wallet(&self, _name: Option<&str>) -> Result<(), Error> {
|
||||||
unimplemented!()
|
let data_dir_name = PathBuf::from(self.data_dir.clone());
|
||||||
|
warn!(
|
||||||
|
"Removing all wallet data from: {}",
|
||||||
|
data_dir_name.to_str().unwrap()
|
||||||
|
);
|
||||||
|
fs::remove_dir_all(data_dir_name).context(ErrorKind::IO)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wallet_inst(&mut self) -> Result<&mut Box<dyn WalletBackend<'a, C, K> + 'a>, Error> {
|
fn wallet_inst(&mut self) -> Result<&mut Box<dyn WalletBackend<'a, C, K> + 'a>, Error> {
|
||||||
|
|
|
@ -94,7 +94,7 @@ impl WalletSeed {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn backup_seed(data_file_dir: &str) -> Result<(), Error> {
|
pub fn backup_seed(data_file_dir: &str) -> Result<String, Error> {
|
||||||
let seed_file_name = &format!("{}{}{}", data_file_dir, MAIN_SEPARATOR, SEED_FILE,);
|
let seed_file_name = &format!("{}{}{}", data_file_dir, MAIN_SEPARATOR, SEED_FILE,);
|
||||||
|
|
||||||
let mut path = Path::new(seed_file_name).to_path_buf();
|
let mut path = Path::new(seed_file_name).to_path_buf();
|
||||||
|
@ -114,7 +114,7 @@ impl WalletSeed {
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
warn!("{} backed up as {}", seed_file_name, backup_seed_file_name);
|
warn!("{} backed up as {}", seed_file_name, backup_seed_file_name);
|
||||||
Ok(())
|
Ok(backup_seed_file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recover_from_phrase(
|
pub fn recover_from_phrase(
|
||||||
|
@ -180,7 +180,6 @@ impl WalletSeed {
|
||||||
data_file_dir: &str,
|
data_file_dir: &str,
|
||||||
password: util::ZeroingString,
|
password: util::ZeroingString,
|
||||||
) -> Result<WalletSeed, Error> {
|
) -> Result<WalletSeed, Error> {
|
||||||
// TODO: Is this desirable any more?
|
|
||||||
// create directory if it doesn't exist
|
// create directory if it doesn't exist
|
||||||
fs::create_dir_all(data_file_dir).context(ErrorKind::IO)?;
|
fs::create_dir_all(data_file_dir).context(ErrorKind::IO)?;
|
||||||
|
|
||||||
|
@ -205,6 +204,15 @@ impl WalletSeed {
|
||||||
Err(ErrorKind::WalletSeedDoesntExist)?
|
Err(ErrorKind::WalletSeedDoesntExist)?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn delete_seed_file(data_file_dir: &str) -> Result<(), Error> {
|
||||||
|
let seed_file_path = &format!("{}{}{}", data_file_dir, MAIN_SEPARATOR, SEED_FILE,);
|
||||||
|
if Path::new(seed_file_path).exists() {
|
||||||
|
debug!("Deleting wallet seed file at: {}", seed_file_path);
|
||||||
|
fs::remove_file(seed_file_path).context(ErrorKind::IO)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encrypted wallet seed, for storing on disk and decrypting
|
/// Encrypted wallet seed, for storing on disk and decrypting
|
||||||
|
|
|
@ -112,10 +112,15 @@ where
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// changes password
|
/// changes password
|
||||||
fn change_password(&self, old: String, new: String) -> Result<(), Error>;
|
fn change_password(
|
||||||
|
&self,
|
||||||
|
name: Option<&str>,
|
||||||
|
old: ZeroingString,
|
||||||
|
new: ZeroingString,
|
||||||
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
/// deletes wallet
|
/// deletes wallet
|
||||||
fn delete_wallet(&self, name: Option<String>, password: String) -> Result<(), Error>;
|
fn delete_wallet(&self, name: Option<&str>) -> Result<(), Error>;
|
||||||
|
|
||||||
/// return wallet instance
|
/// return wallet instance
|
||||||
fn wallet_inst(&mut self) -> Result<&mut Box<dyn WalletBackend<'a, C, K> + 'a>, Error>;
|
fn wallet_inst(&mut self) -> Result<&mut Box<dyn WalletBackend<'a, C, K> + 'a>, Error>;
|
||||||
|
|
|
@ -405,8 +405,8 @@ where
|
||||||
let value: OUT = v;
|
let value: OUT = v;
|
||||||
Ok(Ok(value))
|
Ok(Ok(value))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(_) => {
|
||||||
println!("Error deserializing: {:?}", e);
|
//println!("Error deserializing: {:?}", e);
|
||||||
let value: OUT = serde_json::from_value(json!("Null")).unwrap();
|
let value: OUT = serde_json::from_value(json!("Null")).unwrap();
|
||||||
Ok(Ok(value))
|
Ok(Ok(value))
|
||||||
}
|
}
|
||||||
|
|
10
tests/data/v3_reqs/change_password.req.json
Normal file
10
tests/data/v3_reqs/change_password.req.json
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "change_password",
|
||||||
|
"params": {
|
||||||
|
"name": null,
|
||||||
|
"old": "passwoid",
|
||||||
|
"new": "password"
|
||||||
|
},
|
||||||
|
"id": 1
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
"params": {
|
"params": {
|
||||||
"name": null,
|
"name": null,
|
||||||
"mnemonic": null,
|
"mnemonic": null,
|
||||||
"mnemonic_length": 0,
|
"mnemonic_length": 32,
|
||||||
"password": "passwoid"
|
"password": "passwoid"
|
||||||
},
|
},
|
||||||
"id": 1
|
"id": 1
|
||||||
|
|
8
tests/data/v3_reqs/delete_wallet.req.json
Normal file
8
tests/data/v3_reqs/delete_wallet.req.json
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"method": "delete_wallet",
|
||||||
|
"params": {
|
||||||
|
"name": null
|
||||||
|
},
|
||||||
|
"id": 1
|
||||||
|
}
|
|
@ -367,7 +367,91 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> {
|
||||||
println!("RES 16: {:?}", res);
|
println!("RES 16: {:?}", res);
|
||||||
assert!(res.is_ok());
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
//17) Change the password
|
||||||
|
let req = include_str!("data/v3_reqs/close_wallet.req.json");
|
||||||
|
let res =
|
||||||
|
send_request_enc::<String>(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?;
|
||||||
|
println!("RES 17: {:?}", res);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
let req = include_str!("data/v3_reqs/change_password.req.json");
|
||||||
|
let res =
|
||||||
|
send_request_enc::<String>(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?;
|
||||||
|
println!("RES 17a: {:?}", res);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
// 18) trying to open with old password should fail
|
||||||
|
let req = include_str!("data/v3_reqs/open_wallet.req.json");
|
||||||
|
let res =
|
||||||
|
send_request_enc::<String>(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?;
|
||||||
|
println!("RES 18: {:?}", res);
|
||||||
|
assert!(res.is_err());
|
||||||
|
|
||||||
|
// 19) Open with new password
|
||||||
|
let req = serde_json::json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "open_wallet",
|
||||||
|
"params": {
|
||||||
|
"name": null,
|
||||||
|
"password": "password"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let res = send_request_enc::<String>(
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
"http://127.0.0.1:43420/v3/owner",
|
||||||
|
&req.to_string(),
|
||||||
|
&shared_key,
|
||||||
|
)?;
|
||||||
|
println!("RES 19: {:?}", res);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let token = res.unwrap();
|
||||||
|
|
||||||
|
// 20) Send a request with new token with changed password, ensure balances are still there and
|
||||||
|
// therefore seed is the same
|
||||||
|
let req = serde_json::json!({
|
||||||
|
"jsonrpc": "2.0",
|
||||||
|
"id": 1,
|
||||||
|
"method": "retrieve_summary_info",
|
||||||
|
"params": {
|
||||||
|
"token": token,
|
||||||
|
"refresh_from_node": true,
|
||||||
|
"minimum_confirmations": 1
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let res = send_request_enc::<RetrieveSummaryInfoResp>(
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
"http://127.0.0.1:43420/v3/owner",
|
||||||
|
&req.to_string(),
|
||||||
|
&shared_key,
|
||||||
|
)?;
|
||||||
|
println!("RES 20: {:?}", res);
|
||||||
|
|
||||||
thread::sleep(Duration::from_millis(200));
|
thread::sleep(Duration::from_millis(200));
|
||||||
|
assert_eq!(res.unwrap().1.amount_awaiting_finalization, 6000000000);
|
||||||
|
|
||||||
|
// 21) Delete the wallet (close first)
|
||||||
|
let req = include_str!("data/v3_reqs/close_wallet.req.json");
|
||||||
|
let res =
|
||||||
|
send_request_enc::<String>(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?;
|
||||||
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
let req = include_str!("data/v3_reqs/delete_wallet.req.json");
|
||||||
|
let res =
|
||||||
|
send_request_enc::<String>(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?;
|
||||||
|
println!("RES 21: {:?}", res);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
|
||||||
|
// 22) Wallet should be gone
|
||||||
|
let req = include_str!("data/v3_reqs/open_wallet.req.json");
|
||||||
|
let res =
|
||||||
|
send_request_enc::<String>(1, 1, "http://127.0.0.1:43420/v3/owner", &req, &shared_key)?;
|
||||||
|
println!("RES 22: {:?}", res);
|
||||||
|
assert!(res.is_err());
|
||||||
|
|
||||||
clean_output_dir(test_dir);
|
clean_output_dir(test_dir);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
Loading…
Reference in a new issue