From b129ffe0dbcb285c6a6b6a63cfe99920fd83a822 Mon Sep 17 00:00:00 2001 From: Abdulrahim Al Methiab <31316147+abdulmth@users.noreply.github.com> Date: Wed, 9 Mar 2022 22:50:00 +0100 Subject: [PATCH] Update Stronghold (#691) * start handling stronghold errors * project compiles with new stronghold version * fix tests * fix io error mapping * improvements * remove unnecessary empty check * remove `records.rs` * remove `get_strict` * remove `StrongholdMutexPoisoned` error by using `parking_lot:Mutex` * remove unnecessary empty check * fix format issue * Revert "remove `records.rs`" This reverts commit fe8c90a8f221627168d076921b9f5260b31feb5b. * use `IotaStrongholdResult` for records.rs --- identity-account/Cargo.toml | 5 +- identity-account/src/error.rs | 20 +-- identity-account/src/storage/stronghold.rs | 109 +++++++------ identity-account/src/stronghold/context.rs | 139 +++++++--------- identity-account/src/stronghold/error.rs | 38 +++++ identity-account/src/stronghold/hint.rs | 9 +- identity-account/src/stronghold/mod.rs | 4 +- identity-account/src/stronghold/records.rs | 35 ++-- identity-account/src/stronghold/result.rs | 47 ------ identity-account/src/stronghold/snapshot.rs | 18 +-- identity-account/src/stronghold/status.rs | 2 +- identity-account/src/stronghold/store.rs | 46 ++---- identity-account/src/stronghold/tests.rs | 70 ++++---- identity-account/src/stronghold/vault.rs | 168 ++++---------------- identity-account/src/utils/fs.rs | 4 +- 15 files changed, 285 insertions(+), 429 deletions(-) create mode 100644 identity-account/src/stronghold/error.rs delete mode 100644 identity-account/src/stronghold/result.rs diff --git a/identity-account/Cargo.toml b/identity-account/Cargo.toml index c49e81e832..f5e6b9245c 100644 --- a/identity-account/Cargo.toml +++ b/identity-account/Cargo.toml @@ -22,6 +22,7 @@ identity-iota = { version = "=0.5.0-dev.4", path = "../identity-iota", default-f itoa = { version = "0.4" } log = { version = "0.4", default-features = false } once_cell = { version = "1.7", default-features = false, features = ["std"] } +parking_lot = { version = "0.12" } paste = { version = "1.0" } serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } slog = { version = "2.7" } @@ -36,12 +37,12 @@ features = ["blake2b", "ed25519", "hmac", "pbkdf", "sha", "slip10", "std"] [dependencies.iota_stronghold] git = "https://github.com/iotaledger/stronghold.rs" -rev = "aea8a9dc8c3fa12e5444c5b4bb3303876e4c1a2f" +rev = "969df405661ba4977f2cf30e9909cef7e30cefa2" optional = true [dependencies.stronghold_engine] git = "https://github.com/iotaledger/stronghold.rs" -rev = "aea8a9dc8c3fa12e5444c5b4bb3303876e4c1a2f" +rev = "969df405661ba4977f2cf30e9909cef7e30cefa2" optional = true [dev-dependencies] diff --git a/identity-account/src/error.rs b/identity-account/src/error.rs index fdcb5ac9af..455a9a4ee5 100644 --- a/identity-account/src/error.rs +++ b/identity-account/src/error.rs @@ -3,6 +3,8 @@ //! Errors that may occur when working with Identity Accounts. +use crate::stronghold::StrongholdError; + /// Alias for a `Result` with the error type [`Error`]. pub type Result = ::core::result::Result; @@ -27,25 +29,9 @@ pub enum Error { /// Caused by attempting to perform an invalid IO operation. #[error(transparent)] IoError(#[from] std::io::Error), - /// Caused by errors from the [iota_stronghold] crate. #[cfg(feature = "stronghold")] #[error(transparent)] - StrongholdError(#[from] iota_stronghold::Error), - /// Caused by errors from an invalid Stronghold procedure. - #[error("Stronghold error: {0}")] - StrongholdResult(String), - /// Caused by attempting to parse an invalid Stronghold resource index. - #[error("Stronghold resource index malformed")] - InvalidResourceIndex, - /// Caused by attempting to access a Stronghold snapshot without a password. - #[error("Stronghold snapshot password not found")] - StrongholdPasswordNotSet, - /// Caused by receiving an unexpected return value from a Stronghold procedure. - #[error("Stronghold procedure returned unexpected type")] - StrongholdProcedureFailure, - /// Caused by an internal panic in the Stronghold runtime. - #[error("Stronghold mutex poisoned: {0}")] - StrongholdMutexPoisoned(&'static str), + StrongholdError(#[from] StrongholdError), /// Caused by attempting to read a poisoned shared resource. #[error("Shared resource poisoned: read")] SharedReadPoisoned, diff --git a/identity-account/src/storage/stronghold.rs b/identity-account/src/storage/stronghold.rs index ef821b2e6c..1d8f58e151 100644 --- a/identity-account/src/storage/stronghold.rs +++ b/identity-account/src/storage/stronghold.rs @@ -1,7 +1,6 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::slip10::Chain; use futures::executor; use identity_core::convert::FromJson; @@ -11,8 +10,12 @@ use identity_core::crypto::PublicKey; use identity_did::did::DID; use identity_did::verification::MethodType; use identity_iota::did::IotaDID; +use iota_stronghold::procedures::Chain; +use iota_stronghold::procedures::Ed25519Sign; +use iota_stronghold::procedures::Slip10Derive; +use iota_stronghold::procedures::Slip10DeriveInput; +use iota_stronghold::procedures::Slip10Generate; use iota_stronghold::Location; -use iota_stronghold::SLIP10DeriveInput; use std::convert::TryFrom; use std::io; use std::path::Path; @@ -79,11 +82,13 @@ impl Stronghold { #[async_trait::async_trait] impl Storage for Stronghold { async fn set_password(&self, password: EncryptionKey) -> Result<()> { - self.snapshot.set_password(password).await + self.snapshot.set_password(password).await?; + Ok(()) } async fn flush_changes(&self) -> Result<()> { - self.snapshot.save().await + self.snapshot.save().await?; + Ok(()) } async fn key_new(&self, did: &IotaDID, location: &KeyLocation) -> Result { @@ -147,23 +152,21 @@ impl Storage for Stronghold { async fn key_exists(&self, did: &IotaDID, location: &KeyLocation) -> Result { let vault: Vault<'_> = self.vault(did); - match location.method() { + Ok(match location.method() { MethodType::Ed25519VerificationKey2018 => vault.exists(location_skey(location)).await, MethodType::MerkleKeyCollection2021 => todo!("[Stronghold::key_exists] Handle MerkleKeyCollection2021"), - } + }?) } async fn chain_state(&self, did: &IotaDID) -> Result> { // Load the chain-specific store let store: Store<'_> = self.store(&fmt_did(did)); + let data: Option> = store.get(location_chain_state()).await?; - let data: Vec = store.get(location_chain_state()).await?; - - if data.is_empty() { - return Ok(None); + match data { + None => return Ok(None), + Some(data) => Ok(Some(ChainState::from_json_slice(&data)?)), } - - Ok(Some(ChainState::from_json_slice(&data)?)) } async fn set_chain_state(&self, did: &IotaDID, chain_state: &ChainState) -> Result<()> { @@ -182,15 +185,12 @@ impl Storage for Stronghold { let store: Store<'_> = self.store(&fmt_did(did)); // Read the state from the stronghold snapshot - let data: Vec = store.get(location_state()).await?; + let data: Option> = store.get(location_state()).await?; - // No state data found - if data.is_empty() { - return Ok(None); + match data { + None => return Ok(None), + Some(data) => Ok(Some(IdentityState::from_json_slice(&data)?)), } - - // Deserialize and return - Ok(Some(IdentityState::from_json_slice(&data)?)) } async fn set_state(&self, did: &IotaDID, state: &IdentityState) -> Result<()> { @@ -216,23 +216,24 @@ impl Storage for Stronghold { let bytes = store.get(location_published_generation()).await?; - if bytes.is_empty() { - return Ok(None); + match bytes { + None => return Ok(None), + Some(bytes) => { + let le_bytes: [u8; 4] = <[u8; 4]>::try_from(bytes.as_ref()).map_err(|_| { + io::Error::new( + io::ErrorKind::InvalidData, + format!( + "expected to read 4 bytes as the published generation, found {} instead", + bytes.len() + ), + ) + })?; + + let gen = Generation::from_u32(u32::from_le_bytes(le_bytes)); + + Ok(Some(gen)) + } } - - let le_bytes: [u8; 4] = <[u8; 4]>::try_from(bytes.as_ref()).map_err(|_| { - io::Error::new( - io::ErrorKind::InvalidData, - format!( - "expected to read 4 bytes as the published generation, found {} instead", - bytes.len() - ), - ) - })?; - - let gen = Generation::from_u32(u32::from_le_bytes(le_bytes)); - - Ok(Some(gen)) } async fn set_published_generation(&self, did: &IotaDID, index: Generation) -> Result<()> { @@ -256,32 +257,44 @@ impl Drop for Stronghold { async fn generate_ed25519(vault: &Vault<'_>, location: &KeyLocation) -> Result { // Generate a SLIP10 seed as the private key - vault - .slip10_generate(location_seed(location), default_hint(), None) - .await?; + let procedure: Slip10Generate = Slip10Generate { + output: location_seed(location), + hint: default_hint(), + size_bytes: None, + }; + vault.execute(procedure).await?; let chain: Chain = Chain::from_u32_hardened(vec![0, 0, 0]); - let seed: SLIP10DeriveInput = SLIP10DeriveInput::Seed(location_seed(location)); + let seed: Slip10DeriveInput = Slip10DeriveInput::Seed(location_seed(location)); // Use the SLIP10 seed to derive a child key - vault - .slip10_derive(chain, seed, location_skey(location), default_hint()) - .await?; + let procedure: Slip10Derive = Slip10Derive { + chain, + input: seed, + output: location_skey(location), + hint: default_hint(), + }; + vault.execute(procedure).await?; // Retrieve the public key of the derived child key retrieve_ed25519(vault, location).await } async fn retrieve_ed25519(vault: &Vault<'_>, location: &KeyLocation) -> Result { - vault - .ed25519_public_key(location_skey(location)) - .await - .map(|public| public.to_vec().into()) + let procedure: iota_stronghold::procedures::PublicKey = iota_stronghold::procedures::PublicKey { + ty: iota_stronghold::procedures::KeyType::Ed25519, + private_key: location_skey(location), + }; + Ok(vault.execute(procedure).await.map(|public| public.to_vec().into())?) } async fn sign_ed25519(vault: &Vault<'_>, payload: Vec, location: &KeyLocation) -> Result { let public_key: PublicKey = retrieve_ed25519(vault, location).await?; - let signature: [u8; 64] = vault.ed25519_sign(payload, location_skey(location)).await?; + let procedure: Ed25519Sign = Ed25519Sign { + private_key: location_skey(location), + msg: payload, + }; + let signature: [u8; 64] = vault.execute(procedure).await?; Ok(Signature::new(public_key, signature.into())) } diff --git a/identity-account/src/stronghold/context.rs b/identity-account/src/stronghold/context.rs index 114270928a..7457c6f9bb 100644 --- a/identity-account/src/stronghold/context.rs +++ b/identity-account/src/stronghold/context.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use actix::System; @@ -6,14 +6,15 @@ use core::ops::Deref; use core::ops::DerefMut; use hashbrown::HashMap; use hashbrown::HashSet; +use iota_stronghold::ReadError; use iota_stronghold::Stronghold; use iota_stronghold::StrongholdFlags; use once_cell::sync::Lazy; +use parking_lot::Mutex; +use parking_lot::MutexGuard; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; -use std::sync::Mutex; -use std::sync::MutexGuard; use std::thread; use std::time::Duration; use std::time::Instant; @@ -21,10 +22,10 @@ use tokio::sync::Mutex as AsyncMutex; use tokio::sync::MutexGuard as AsyncMutexGuard; use zeroize::Zeroize; -use crate::error::Error; -use crate::error::PleaseDontMakeYourOwnResult; use crate::error::Result; +use crate::stronghold::error::IotaStrongholdResult; use crate::stronghold::SnapshotStatus; +use crate::stronghold::StrongholdError; use crate::utils::fs; use crate::utils::EncryptionKey; @@ -35,9 +36,9 @@ pub struct Context { runtime: Runtime, } -async fn clear_expired_passwords() -> Result<()> { +async fn clear_expired_passwords() -> IotaStrongholdResult<()> { let this: &'static Context = Context::get().await?; - let interval: Duration = *this.runtime.password_clear()?; + let interval: Duration = *this.runtime.password_clear(); tokio::time::sleep(interval).await; @@ -47,7 +48,7 @@ async fn clear_expired_passwords() -> Result<()> { let cleared: Vec = this .runtime - .password_store()? + .password_store() .drain_filter(|_, (_, instant)| instant.elapsed() > interval) .map(|(path, _)| path) .collect(); @@ -105,10 +106,10 @@ static CONTEXT: Lazy> = Lazy::new(|| { }); impl Context { - pub(crate) async fn get() -> Result<&'static Self> { + pub(crate) async fn get() -> IotaStrongholdResult<&'static Self> { match CONTEXT.deref() { Ok(ctx) => Ok(ctx), - Err(err) => Err(Error::StrongholdResult(err.to_owned())), + Err(err) => Err(StrongholdError::StrongholdResult(err.to_owned())), } } @@ -116,7 +117,7 @@ impl Context { path: &Path, name: &[u8], flags: &[StrongholdFlags], - ) -> Result> { + ) -> IotaStrongholdResult> { let this: &Self = Self::get().await?; let mut database: _ = this.database.lock().await; @@ -126,30 +127,30 @@ impl Context { Ok(database) } - pub(crate) async fn on_change(listener: T) -> Result<()> + pub(crate) async fn on_change(listener: T) -> IotaStrongholdResult<()> where T: FnMut(&Path, &SnapshotStatus) + Send + 'static, { Self::get().await.and_then(|this| this.runtime.on_change(listener)) } - pub(crate) async fn set_password(path: &Path, password: Password) -> Result<()> { + pub(crate) async fn set_password(path: &Path, password: Password) -> IotaStrongholdResult<()> { Self::get() .await .and_then(|this| this.runtime.set_password(path, password)) } - pub(crate) async fn set_password_clear(interval: Duration) -> Result<()> { + pub(crate) async fn set_password_clear(interval: Duration) -> IotaStrongholdResult<()> { Self::get() .await .and_then(|this| this.runtime.set_password_clear(interval)) } - pub(crate) async fn snapshot_status(path: &Path) -> Result { + pub(crate) async fn snapshot_status(path: &Path) -> IotaStrongholdResult { Self::get().await.and_then(|this| this.runtime.snapshot_status(path)) } - pub(crate) async fn load(path: &Path, password: Password) -> Result<()> { + pub(crate) async fn load(path: &Path, password: Password) -> IotaStrongholdResult<()> { let this: &Self = Self::get().await?; let mut database: _ = this.database.lock().await; @@ -160,7 +161,7 @@ impl Context { Ok(()) } - pub(crate) async fn unload(path: &Path, persist: bool) -> Result<()> { + pub(crate) async fn unload(path: &Path, persist: bool) -> IotaStrongholdResult<()> { let this: &Self = Self::get().await?; let mut database: _ = this.database.lock().await; @@ -169,7 +170,7 @@ impl Context { Ok(()) } - pub(crate) async fn save(path: &Path) -> Result<()> { + pub(crate) async fn save(path: &Path) -> IotaStrongholdResult<()> { let this: &Self = Self::get().await?; let mut database: _ = this.database.lock().await; @@ -211,18 +212,17 @@ impl Database { snapshot: &Path, client: &[u8], flags: &[StrongholdFlags], - ) -> Result<()> { + ) -> IotaStrongholdResult<()> { runtime.set_password_access(snapshot)?; // Spawn a new actor or switch targets if this client was already spawned if self.clients_active.contains(client) { - self.stronghold.switch_actor_target(client.into()).await.to_result()?; + self.stronghold.switch_actor_target(client.into()).await?; } else { self .stronghold .spawn_stronghold_actor(client.into(), flags.to_vec()) - .await - .to_result()?; + .await?; self.clients_active.insert(client.into()); } @@ -232,11 +232,10 @@ impl Database { let mut password: Vec = runtime.password(snapshot)?.to_vec(); let location: Option = Some(snapshot.to_path_buf()); - let result: Result<()> = self + let result: Result<(), ReadError> = self .stronghold .read_snapshot(client.into(), None, &password, None, location) - .await - .to_result(); + .await?; password.zeroize(); @@ -249,7 +248,7 @@ impl Database { Ok(()) } - async fn unload(&mut self, runtime: &Runtime, snapshot: &Path, persist: bool) -> Result<()> { + async fn unload(&mut self, runtime: &Runtime, snapshot: &Path, persist: bool) -> IotaStrongholdResult<()> { let active: bool = !self.clients_active.is_empty(); // Write the Stronghold state into a snapshot if requested @@ -260,18 +259,10 @@ impl Database { // Shutdown all loaded actors for client in self.clients_active.iter() { // Clear the actor cache - self - .stronghold - .kill_stronghold(client.clone(), false) - .await - .to_result()?; + self.stronghold.kill_stronghold(client.clone(), false).await?; // Kill the internal actor and client actor - self - .stronghold - .kill_stronghold(client.clone(), true) - .await - .to_result()?; + self.stronghold.kill_stronghold(client.clone(), true).await?; } if active { @@ -300,7 +291,7 @@ impl Database { ) } - async fn flush(&mut self, runtime: &Runtime, snapshot: &Path, persist: bool) -> Result<()> { + async fn flush(&mut self, runtime: &Runtime, snapshot: &Path, persist: bool) -> IotaStrongholdResult<()> { if self.current_snapshot_eq(snapshot) { self.unload(runtime, snapshot, persist).await?; } @@ -310,24 +301,21 @@ impl Database { Ok(()) } - async fn write(&mut self, runtime: &Runtime, snapshot: &Path) -> Result<()> { + async fn write(&mut self, runtime: &Runtime, snapshot: &Path) -> IotaStrongholdResult<()> { fs::ensure_directory(snapshot)?; let mut password: Vec = runtime.password(snapshot)?.to_vec(); let location: Option = Some(snapshot.to_path_buf()); - let result: Result<()> = self - .stronghold - .write_all_to_snapshot(&password, None, location) - .await - .to_result(); + let result = self.stronghold.write_all_to_snapshot(&password, None, location).await?; password.zeroize(); - result + result?; + Ok(()) } - async fn switch_snapshot(&mut self, runtime: &Runtime, snapshot: &Path) -> Result<()> { + async fn switch_snapshot(&mut self, runtime: &Runtime, snapshot: &Path) -> IotaStrongholdResult<()> { let previous: Option = if self.current_snapshot_neq(snapshot) { self.current_snapshot.replace(snapshot.to_path_buf()) } else { @@ -381,26 +369,26 @@ impl Runtime { } } - fn on_change(&self, listener: T) -> Result<()> + fn on_change(&self, listener: T) -> IotaStrongholdResult<()> where T: FnMut(&Path, &SnapshotStatus) + Send + 'static, { - self.event_listeners()?.push(Listener(Box::new(listener))); + self.event_listeners().push(Listener(Box::new(listener))); Ok(()) } - fn emit(&self, path: &Path, status: SnapshotStatus) -> Result<()> { - for listener in self.event_listeners()?.iter_mut() { + fn emit(&self, path: &Path, status: SnapshotStatus) -> IotaStrongholdResult<()> { + for listener in self.event_listeners().iter_mut() { (listener.0)(path, &status); } Ok(()) } - fn snapshot_status(&self, path: &Path) -> Result { - if let Some(elapsed) = self.password_elapsed(path)? { - let interval: Duration = *self.password_clear()?; + fn snapshot_status(&self, path: &Path) -> IotaStrongholdResult { + if let Some(elapsed) = self.password_elapsed(path) { + let interval: Duration = *self.password_clear(); let locked: bool = interval.as_millis() > 0 && elapsed >= interval; if locked { @@ -415,62 +403,51 @@ impl Runtime { } } - fn password(&self, path: &Path) -> Result { + fn password(&self, path: &Path) -> IotaStrongholdResult { self - .password_store()? + .password_store() .get(path) .map(|(password, _)| *password) - .ok_or(Error::StrongholdPasswordNotSet) + .ok_or(StrongholdError::StrongholdPasswordNotSet) } - fn password_elapsed(&self, path: &Path) -> Result> { - self - .password_store() - .map(|store| store.get(path).map(|(_, interval)| interval.elapsed())) + fn password_elapsed(&self, path: &Path) -> Option { + self.password_store().get(path).map(|(_, interval)| interval.elapsed()) } - fn set_password(&self, path: &Path, password: Password) -> Result<()> { + fn set_password(&self, path: &Path, password: Password) -> IotaStrongholdResult<()> { self - .password_store()? + .password_store() .insert(path.to_path_buf(), (password, Instant::now())); Ok(()) } - fn set_password_access(&self, path: &Path) -> Result<()> { - if let Some((_, ref mut time)) = self.password_store()?.get_mut(path) { + fn set_password_access(&self, path: &Path) -> IotaStrongholdResult<()> { + if let Some((_, ref mut time)) = self.password_store().get_mut(path) { *time = Instant::now(); } else { - return Err(Error::StrongholdPasswordNotSet); + return Err(StrongholdError::StrongholdPasswordNotSet); } Ok(()) } - fn set_password_clear(&self, interval: Duration) -> Result<()> { - *self.password_clear()? = interval; + fn set_password_clear(&self, interval: Duration) -> IotaStrongholdResult<()> { + *self.password_clear() = interval; Ok(()) } - fn event_listeners(&self) -> Result>> { - self - .event_listeners - .lock() - .map_err(|_| Error::StrongholdMutexPoisoned("listeners")) + fn event_listeners(&self) -> MutexGuard<'_, Vec> { + self.event_listeners.lock() } - fn password_store(&self) -> Result> { - self - .password_store - .lock() - .map_err(|_| Error::StrongholdMutexPoisoned("passwords")) + fn password_store(&self) -> MutexGuard<'_, PasswordMap> { + self.password_store.lock() } - fn password_clear(&self) -> Result> { - self - .password_clear - .lock() - .map_err(|_| Error::StrongholdMutexPoisoned("passwords")) + fn password_clear(&self) -> MutexGuard<'_, Duration> { + self.password_clear.lock() } } diff --git a/identity-account/src/stronghold/error.rs b/identity-account/src/stronghold/error.rs new file mode 100644 index 0000000000..bd9b5df1c7 --- /dev/null +++ b/identity-account/src/stronghold/error.rs @@ -0,0 +1,38 @@ +// Copyright 2020-2022 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +use iota_stronghold::procedures::ProcedureError; + +pub type IotaStrongholdResult = Result; + +/// Caused by errors from the [`iota_stronghold`] crate. +#[derive(Debug, thiserror::Error, strum::IntoStaticStr)] +pub enum StrongholdError { + #[error(transparent)] + StrongholdActorError(#[from] iota_stronghold::ActorError), + #[error(transparent)] + StrongholdWriteError(#[from] iota_stronghold::WriteError), + #[error(transparent)] + StrongholdReadError(#[from] iota_stronghold::ReadError), + #[error(transparent)] + StrongholdFatalEngineError(#[from] iota_stronghold::FatalEngineError), + #[error(transparent)] + StrongholdMailboxError(#[from] iota_stronghold::MailboxError), + /// Caused by attempting to perform an invalid IO operation. + #[error(transparent)] + IoError(#[from] std::io::Error), + /// Caused by receiving an unexpected return value from a Stronghold procedure. + #[error("Stronghold procedure returned unexpected type")] + StrongholdProcedureFailure(#[from] ProcedureError), + /// Caused by attempting to access a Stronghold snapshot without a password. + #[error("Stronghold snapshot password not found")] + StrongholdPasswordNotSet, + /// Caused by errors from an invalid Stronghold procedure. + #[error("Stronghold error: {0}")] + StrongholdResult(String), + #[error("Record Error")] + RecordError, + /// Caused by attempting to parse an invalid Stronghold resource index. + #[error("Stronghold resource index malformed")] + InvalidResourceIndex, +} diff --git a/identity-account/src/stronghold/hint.rs b/identity-account/src/stronghold/hint.rs index 63877fbef5..1dae0efe41 100644 --- a/identity-account/src/stronghold/hint.rs +++ b/identity-account/src/stronghold/hint.rs @@ -1,16 +1,13 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use iota_stronghold::Error; use iota_stronghold::RecordHint; -use crate::error::Result; - -pub fn hint(data: &T) -> Result +pub fn hint(data: &T) -> Option where T: AsRef<[u8]> + ?Sized, { - RecordHint::new(data.as_ref()).map_err(Error::from).map_err(Into::into) + RecordHint::new(data.as_ref()) } pub fn default_hint() -> RecordHint { diff --git a/identity-account/src/stronghold/mod.rs b/identity-account/src/stronghold/mod.rs index 71b3bc6cbe..ff8ef78225 100644 --- a/identity-account/src/stronghold/mod.rs +++ b/identity-account/src/stronghold/mod.rs @@ -2,18 +2,18 @@ // SPDX-License-Identifier: Apache-2.0 mod context; +mod error; mod hint; mod records; -mod result; mod snapshot; mod status; mod store; mod vault; pub use self::context::*; +pub use self::error::*; pub use self::hint::*; pub use self::records::*; -pub use self::result::*; pub use self::snapshot::*; pub use self::status::*; pub use self::store::*; diff --git a/identity-account/src/stronghold/records.rs b/identity-account/src/stronghold/records.rs index 8ca9aebfe5..bd06db0cf8 100644 --- a/identity-account/src/stronghold/records.rs +++ b/identity-account/src/stronghold/records.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use core::fmt::Debug; @@ -14,9 +14,9 @@ use iota_stronghold::Location; use iota_stronghold::StrongholdFlags; use std::path::Path; -use crate::error::Error; -use crate::error::Result; +use crate::stronghold::IotaStrongholdResult; use crate::stronghold::Store; +use crate::stronghold::StrongholdError; pub struct Records<'snapshot> { pub(crate) store: Store<'snapshot>, @@ -47,26 +47,31 @@ impl Records<'_> { self.store.flags() } - pub async fn index(&self) -> Result { - self.store.get(Locations::index()).await.and_then(RecordIndex::try_new) + pub async fn index(&self) -> IotaStrongholdResult { + self.store.get(Locations::index()).await?; + let record: Option> = self.store.get(Locations::index()).await?; + match record { + None => Err(StrongholdError::RecordError), + Some(record) => Ok(RecordIndex::try_new(record)?), + } } - pub async fn all(&self) -> Result>> { - self.index().await?.load_all(&self.store).await + pub async fn all(&self) -> IotaStrongholdResult>>> { + Ok(self.index().await?.load_all(&self.store).await?) } - pub async fn get(&self, record_id: &[u8]) -> Result> { + pub async fn get(&self, record_id: &[u8]) -> IotaStrongholdResult>> { let record_tag: RecordTag = RecordIndex::tag(record_id); let location: Location = Locations::record(&record_tag); - self.store.get(location).await + Ok(self.store.get(location).await?) } - pub async fn set(&self, record_id: &[u8], record: &[u8]) -> Result<()> { + pub async fn set(&self, record_id: &[u8], record: &[u8]) -> IotaStrongholdResult<()> { self.try_set(record_id, record, true).await.map(|_| ()) } - pub async fn try_set(&self, record_id: &[u8], record: &[u8], replace: bool) -> Result { + pub async fn try_set(&self, record_id: &[u8], record: &[u8], replace: bool) -> IotaStrongholdResult { let mut index: RecordIndex = self.index().await?; let record_tag: RecordTag = RecordIndex::tag(record_id); let inserted: bool = index.insert(&record_tag); @@ -89,7 +94,7 @@ impl Records<'_> { } } - pub async fn del(&self, record_id: &[u8]) -> Result<()> { + pub async fn del(&self, record_id: &[u8]) -> IotaStrongholdResult<()> { let mut index: RecordIndex = self.index().await?; let record_tag: RecordTag = RecordIndex::tag(record_id); @@ -130,9 +135,9 @@ pub struct RecordIndex(Vec); impl RecordIndex { const CHUNK: usize = 32; - pub(crate) fn try_new(data: Vec) -> Result { + pub(crate) fn try_new(data: Vec) -> IotaStrongholdResult { if data.len() % Self::CHUNK != 0 { - return Err(Error::InvalidResourceIndex); + return Err(StrongholdError::InvalidResourceIndex); } Ok(Self(data)) @@ -146,7 +151,7 @@ impl RecordIndex { self.iter().any(|chunk| chunk == tag) } - pub(crate) async fn load_all(&self, store: &Store<'_>) -> Result>> { + pub(crate) async fn load_all(&self, store: &Store<'_>) -> IotaStrongholdResult>>> { self .iter() .map(Locations::record) diff --git a/identity-account/src/stronghold/result.rs b/identity-account/src/stronghold/result.rs deleted file mode 100644 index e2e8f4c491..0000000000 --- a/identity-account/src/stronghold/result.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2020-2021 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -use crypto::keys::slip10::ChainCode; -use iota_stronghold::ProcResult; -use iota_stronghold::ResultMessage; - -use crate::error::Error; -use crate::error::PleaseDontMakeYourOwnResult; -use crate::error::Result; - -impl PleaseDontMakeYourOwnResult for ResultMessage { - #[allow(clippy::wrong_self_convention)] - fn to_result(self) -> Result { - match self { - Self::Ok(data) => Ok(data), - Self::Error(error) => Err(Error::StrongholdResult(error)), - } - } -} - -#[derive(Clone, Debug)] -pub enum ProcedureResult { - SLIP10Generate, - SLIP10Derive(ChainCode), - BIP39Recover, - BIP39Generate, - BIP39MnemonicSentence(String), - Ed25519PublicKey([u8; 32]), - Ed25519Sign([u8; 64]), -} - -impl PleaseDontMakeYourOwnResult for ProcResult { - #[allow(clippy::wrong_self_convention)] - fn to_result(self) -> Result { - match self { - ProcResult::SLIP10Generate(inner) => inner.to_result().map(|_| ProcedureResult::SLIP10Generate), - ProcResult::SLIP10Derive(inner) => inner.to_result().map(ProcedureResult::SLIP10Derive), - ProcResult::BIP39Recover(inner) => inner.to_result().map(|_| ProcedureResult::BIP39Recover), - ProcResult::BIP39Generate(inner) => inner.to_result().map(|_| ProcedureResult::BIP39Generate), - ProcResult::BIP39MnemonicSentence(inner) => inner.to_result().map(ProcedureResult::BIP39MnemonicSentence), - ProcResult::Ed25519PublicKey(inner) => inner.to_result().map(ProcedureResult::Ed25519PublicKey), - ProcResult::Ed25519Sign(inner) => inner.to_result().map(ProcedureResult::Ed25519Sign), - ProcResult::Error(inner) => Err(Error::StrongholdResult(inner)), - } - } -} diff --git a/identity-account/src/stronghold/snapshot.rs b/identity-account/src/stronghold/snapshot.rs index 452eadd6b3..858130b62e 100644 --- a/identity-account/src/stronghold/snapshot.rs +++ b/identity-account/src/stronghold/snapshot.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use iota_stronghold::StrongholdFlags; @@ -6,8 +6,8 @@ use std::path::Path; use std::path::PathBuf; use std::time::Duration; -use crate::error::Result; use crate::stronghold::Context; +use crate::stronghold::IotaStrongholdResult; use crate::stronghold::Password; use crate::stronghold::Records; use crate::stronghold::SnapshotStatus; @@ -20,11 +20,11 @@ pub struct Snapshot { } impl Snapshot { - pub async fn set_password_clear(interval: Duration) -> Result<()> { + pub async fn set_password_clear(interval: Duration) -> IotaStrongholdResult<()> { Context::set_password_clear(interval).await } - pub async fn on_change(listener: T) -> Result<()> + pub async fn on_change(listener: T) -> IotaStrongholdResult<()> where T: FnMut(&Path, &SnapshotStatus) + Send + 'static, { @@ -65,23 +65,23 @@ impl Snapshot { Records::new(&self.path, name, flags) } - pub async fn status(&self) -> Result { + pub async fn status(&self) -> IotaStrongholdResult { Context::snapshot_status(&self.path).await } - pub async fn set_password(&self, password: Password) -> Result<()> { + pub async fn set_password(&self, password: Password) -> IotaStrongholdResult<()> { Context::set_password(&self.path, password).await } - pub async fn load(&self, password: Password) -> Result<()> { + pub async fn load(&self, password: Password) -> IotaStrongholdResult<()> { Context::load(&self.path, password).await } - pub async fn unload(&self, persist: bool) -> Result<()> { + pub async fn unload(&self, persist: bool) -> IotaStrongholdResult<()> { Context::unload(&self.path, persist).await } - pub async fn save(&self) -> Result<()> { + pub async fn save(&self) -> IotaStrongholdResult<()> { Context::save(&self.path).await } } diff --git a/identity-account/src/stronghold/status.rs b/identity-account/src/stronghold/status.rs index 9d35e44068..aa1aacc0ba 100644 --- a/identity-account/src/stronghold/status.rs +++ b/identity-account/src/stronghold/status.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use std::time::Duration; diff --git a/identity-account/src/stronghold/store.rs b/identity-account/src/stronghold/store.rs index 0803ab5685..4eedeafa99 100644 --- a/identity-account/src/stronghold/store.rs +++ b/identity-account/src/stronghold/store.rs @@ -1,4 +1,4 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 use iota_stronghold::Location; @@ -6,13 +6,9 @@ use iota_stronghold::StrongholdFlags; use std::path::Path; use std::time::Duration; -use crate::error::Error; -use crate::error::PleaseDontMakeYourOwnResult; -use crate::error::Result; +use crate::stronghold::error::IotaStrongholdResult; use crate::stronghold::Context; -const STRONG_404: &str = "Unable to read from store"; - #[derive(Debug)] pub struct Store<'snapshot> { path: &'snapshot Path, @@ -51,50 +47,36 @@ impl Store<'_> { } /// Gets a record. - pub async fn get(&self, location: Location) -> Result> { - match self.get_strict(location).await { - Ok(data) => Ok(data), - Err(Error::StrongholdResult(message)) if message == STRONG_404 => Ok(Vec::new()), - Err(error) => Err(error), - } - } - - /// Gets a record. - pub async fn get_strict(&self, location: Location) -> Result> { + pub async fn get(&self, location: Location) -> IotaStrongholdResult>> { let scope: _ = Context::scope(self.path, &self.name, &self.flags).await?; - let (data, status): (Vec, _) = scope.read_from_store(location).await; - - status.to_result()?; - - Ok(data) + Ok(scope.read_from_store(location.vault_path().to_vec()).await?) } /// Adds a record. - pub async fn set(&self, location: Location, payload: T, ttl: Option) -> Result<()> + pub async fn set(&self, location: Location, payload: T, ttl: Option) -> IotaStrongholdResult<()> where T: Into>, { + let location = location.vault_path().to_vec(); Context::scope(self.path, &self.name, &self.flags) .await? .write_to_store(location, payload.into(), ttl) - .await - .to_result() + .await?; + Ok(()) } /// Removes a record. - pub async fn del(&self, location: Location) -> Result<()> { + pub async fn del(&self, location: Location) -> IotaStrongholdResult<()> { Context::scope(self.path, &self.name, &self.flags) .await? - .delete_from_store(location) - .await - .to_result() + .delete_from_store(location.vault_path().to_vec()) + .await?; + Ok(()) } /// Returns true if the specified location exists. - pub async fn exists(&self, location: Location) -> Result { + pub async fn exists(&self, location: Location) -> IotaStrongholdResult { let scope: _ = Context::scope(self.path, &self.name, &self.flags).await?; - let exists: bool = scope.record_exists(location).await; - - Ok(exists) + Ok(scope.record_exists(location).await?) } } diff --git a/identity-account/src/stronghold/tests.rs b/identity-account/src/stronghold/tests.rs index 279dca76fe..9ec8c8fb76 100644 --- a/identity-account/src/stronghold/tests.rs +++ b/identity-account/src/stronghold/tests.rs @@ -3,6 +3,7 @@ use core::iter; use futures::executor::block_on; +use iota_stronghold::procedures::KeyType; use iota_stronghold::Location; use rand::distributions::Alphanumeric; use rand::rngs::OsRng; @@ -15,11 +16,12 @@ use std::thread; use std::time::Duration; use std::time::Instant; -use crate::error::Error; use crate::stronghold::default_hint; +use crate::stronghold::IotaStrongholdResult; use crate::stronghold::Snapshot; use crate::stronghold::SnapshotStatus; use crate::stronghold::Store; +use crate::stronghold::StrongholdError; use crate::utils::derive_encryption_key; use crate::utils::EncryptionKey; use identity_core::crypto::KeyPair; @@ -74,10 +76,10 @@ rusty_fork_test! { thread::sleep(interval * 3); let store: Store<'_> = snapshot.store("", &[]); - let error: Error = store.get(location("expires")).await.unwrap_err(); + let error: StrongholdError = store.get(location("expires")).await.unwrap_err(); assert!( - matches!(error, Error::StrongholdPasswordNotSet), + matches!(error, StrongholdError::StrongholdPasswordNotSet), "unexpected error: {:?}", error ); @@ -129,21 +131,21 @@ rusty_fork_test! { } } - let mut result: Result, Error> = store.get(location("persists1")).await; + let mut result: IotaStrongholdResult>> = store.get(location("persists1")).await; // Test may have taken too long / been interrupted and cleared the password already, retry - if matches!(result, Err(Error::StrongholdPasswordNotSet)) && interval.checked_sub(instant.elapsed()).is_none() { + if matches!(result, Err(StrongholdError::StrongholdPasswordNotSet)) && interval.checked_sub(instant.elapsed()).is_none() { snapshot.set_password(Default::default()).await.unwrap(); result = store.get(location("persists1")).await; } - assert_eq!(result.unwrap(), b"STRONGHOLD1"); + assert_eq!(result.unwrap(), Some(b"STRONGHOLD1".to_vec())); // Wait for password to be cleared thread::sleep(interval * 2); - let error: Error = store.get(location("persists1")).await.unwrap_err(); + let error: StrongholdError = store.get(location("persists1")).await.unwrap_err(); assert!( - matches!(error, Error::StrongholdPasswordNotSet), + matches!(error, StrongholdError::StrongholdPasswordNotSet), "unexpected error: {:?}", error ); @@ -162,22 +164,22 @@ rusty_fork_test! { let store: Store<'_> = snapshot.store(b"store", &[]); - assert!(store.get(location("A")).await.unwrap().is_empty()); - assert!(store.get(location("B")).await.unwrap().is_empty()); - assert!(store.get(location("C")).await.unwrap().is_empty()); + assert!(store.get(location("A")).await.unwrap().is_none()); + assert!(store.get(location("B")).await.unwrap().is_none()); + assert!(store.get(location("C")).await.unwrap().is_none()); store.set(location("A"), b"foo".to_vec(), None).await.unwrap(); store.set(location("B"), b"bar".to_vec(), None).await.unwrap(); store.set(location("C"), b"baz".to_vec(), None).await.unwrap(); - assert_eq!(store.get(location("A")).await.unwrap(), b"foo".to_vec()); - assert_eq!(store.get(location("B")).await.unwrap(), b"bar".to_vec()); - assert_eq!(store.get(location("C")).await.unwrap(), b"baz".to_vec()); + assert_eq!(store.get(location("A")).await.unwrap(), Some(b"foo".to_vec())); + assert_eq!(store.get(location("B")).await.unwrap(), Some(b"bar".to_vec())); + assert_eq!(store.get(location("C")).await.unwrap(), Some(b"baz".to_vec())); store.del(location("A")).await.unwrap(); store.del(location("C")).await.unwrap(); - assert_eq!(store.get(location("B")).await.unwrap(), b"bar".to_vec()); + assert_eq!(store.get(location("B")).await.unwrap(), Some(b"bar".to_vec())); snapshot.unload(true).await.unwrap(); @@ -199,9 +201,9 @@ rusty_fork_test! { let stores: &[_] = &[&store1, &store2, &store3]; for store in stores { - assert!(store.get(location("A")).await.unwrap().is_empty()); - assert!(store.get(location("B")).await.unwrap().is_empty()); - assert!(store.get(location("C")).await.unwrap().is_empty()); + assert!(store.get(location("A")).await.unwrap().is_none()); + assert!(store.get(location("B")).await.unwrap().is_none()); + assert!(store.get(location("C")).await.unwrap().is_none()); } for store in stores { @@ -211,9 +213,9 @@ rusty_fork_test! { } for store in stores { - assert_eq!(store.get(location("A")).await.unwrap(), b"foo".to_vec()); - assert_eq!(store.get(location("B")).await.unwrap(), b"bar".to_vec()); - assert_eq!(store.get(location("C")).await.unwrap(), b"baz".to_vec()); + assert_eq!(store.get(location("A")).await.unwrap(), Some(b"foo".to_vec())); + assert_eq!(store.get(location("B")).await.unwrap(), Some(b"bar".to_vec())); + assert_eq!(store.get(location("C")).await.unwrap(), Some(b"baz".to_vec())); } for store in stores { @@ -222,7 +224,7 @@ rusty_fork_test! { } for store in stores { - assert_eq!(store.get(location("B")).await.unwrap(), b"bar".to_vec()); + assert_eq!(store.get(location("B")).await.unwrap(), Some(b"bar".to_vec())); } snapshot1.unload(true).await.unwrap(); @@ -245,17 +247,17 @@ rusty_fork_test! { let snapshot: Snapshot = open_snapshot(&filename, password).await; let store: Store<'_> = snapshot.store(b"persistence", &[]); - assert!(store.get(location("A")).await.unwrap().is_empty()); - assert!(store.get(location("B")).await.unwrap().is_empty()); - assert!(store.get(location("C")).await.unwrap().is_empty()); + assert!(store.get(location("A")).await.unwrap().is_none()); + assert!(store.get(location("B")).await.unwrap().is_none()); + assert!(store.get(location("C")).await.unwrap().is_none()); store.set(location("A"), b"foo".to_vec(), None).await.unwrap(); store.set(location("B"), b"bar".to_vec(), None).await.unwrap(); store.set(location("C"), b"baz".to_vec(), None).await.unwrap(); - assert_eq!(store.get(location("A")).await.unwrap(), b"foo".to_vec()); - assert_eq!(store.get(location("B")).await.unwrap(), b"bar".to_vec()); - assert_eq!(store.get(location("C")).await.unwrap(), b"baz".to_vec()); + assert_eq!(store.get(location("A")).await.unwrap(), Some(b"foo".to_vec())); + assert_eq!(store.get(location("B")).await.unwrap(), Some( b"bar".to_vec())); + assert_eq!(store.get(location("C")).await.unwrap(), Some(b"baz".to_vec())); snapshot.unload(true).await.unwrap(); } @@ -264,9 +266,9 @@ rusty_fork_test! { let snapshot: Snapshot = load_snapshot(&filename, password).await; let store: Store<'_> = snapshot.store(b"persistence", &[]); - assert_eq!(store.get(location("A")).await.unwrap(), b"foo".to_vec()); - assert_eq!(store.get(location("B")).await.unwrap(), b"bar".to_vec()); - assert_eq!(store.get(location("C")).await.unwrap(), b"baz".to_vec()); + assert_eq!(store.get(location("A")).await.unwrap(), Some(b"foo".to_vec())); + assert_eq!(store.get(location("B")).await.unwrap(), Some(b"bar".to_vec())); + assert_eq!(store.get(location("C")).await.unwrap(), Some(b"baz".to_vec())); fs::remove_file(store.path()).unwrap(); } @@ -297,7 +299,11 @@ rusty_fork_test! { let vault = snapshot.vault(b"persistence", &[]); assert!(vault.exists(location("A")).await.unwrap()); - let pubkey = vault.ed25519_public_key(location("A")).await.unwrap(); + let procedure = iota_stronghold::procedures::PublicKey{ + private_key: location("A"), + ty: KeyType::Ed25519 + }; + let pubkey = vault.execute(procedure).await.unwrap(); assert_eq!(pubkey, keypair.public().as_ref()); diff --git a/identity-account/src/stronghold/vault.rs b/identity-account/src/stronghold/vault.rs index d35533f249..b2d49d6592 100644 --- a/identity-account/src/stronghold/vault.rs +++ b/identity-account/src/stronghold/vault.rs @@ -1,22 +1,17 @@ -// Copyright 2020-2021 IOTA Stiftung +// Copyright 2020-2022 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -use crypto::keys::slip10::Chain; -use crypto::keys::slip10::ChainCode; use engine::vault::RecordId; +use iota_stronghold::procedures::Procedure; +use iota_stronghold::procedures::StrongholdProcedure; use iota_stronghold::Location; -use iota_stronghold::Procedure; use iota_stronghold::RecordHint; -use iota_stronghold::SLIP10DeriveInput; use iota_stronghold::StrongholdFlags; use iota_stronghold::VaultFlags; use std::path::Path; -use crate::error::Error; -use crate::error::PleaseDontMakeYourOwnResult; -use crate::error::Result; use crate::stronghold::Context; -use crate::stronghold::ProcedureResult; +use crate::stronghold::IotaStrongholdResult; pub type Record = (RecordId, RecordHint); @@ -58,161 +53,66 @@ impl Vault<'_> { } /// Inserts a record. - pub async fn insert(&self, location: Location, payload: T, hint: RecordHint, flags: &[VaultFlags]) -> Result<()> + pub async fn insert( + &self, + location: Location, + payload: T, + hint: RecordHint, + flags: &[VaultFlags], + ) -> IotaStrongholdResult<()> where T: Into>, { Context::scope(self.path, &self.name, &self.flags) .await? .write_to_vault(location, payload.into(), hint, flags.to_vec()) - .await - .to_result() + .await??; + Ok(()) } /// Deletes a record. - pub async fn delete(&self, location: Location, gc: bool) -> Result<()> { + pub async fn delete(&self, location: Location, gc: bool) -> IotaStrongholdResult<()> { Context::scope(self.path, &self.name, &self.flags) .await? .delete_data(location, gc) - .await - .to_result() + .await??; + Ok(()) } /// Returns true if the specified location exists. - pub async fn exists(&self, location: Location) -> Result { + pub async fn exists(&self, location: Location) -> IotaStrongholdResult { let scope: _ = Context::scope(self.path, &self.name, &self.flags).await?; - let exists: bool = scope.vault_exists(location).await; - - Ok(exists) + Ok(scope.vault_exists(location.vault_path()).await?) } /// Runs the Stronghold garbage collector. - pub async fn garbage_collect(&self, vault: &[u8]) -> Result<()> { - Context::scope(self.path, &self.name, &self.flags) - .await? - .garbage_collect(vault.to_vec()) - .await - .to_result() + pub async fn garbage_collect(&self, vault: &[u8]) -> IotaStrongholdResult { + Ok( + Context::scope(self.path, &self.name, &self.flags) + .await? + .garbage_collect(vault.to_vec()) + .await?, + ) } /// Executes a runtime [`procedure`][`Procedure`]. - pub async fn execute(&self, procedure: Procedure) -> Result { - Context::scope(self.path, &self.name, &self.flags) + pub async fn execute

(&self, procedure: P) -> IotaStrongholdResult + where + P: Procedure + Into, + { + let result:

::Output = Context::scope(self.path, &self.name, &self.flags) .await? .runtime_exec(procedure) - .await - .to_result() + .await??; + Ok(result) } /// Returns a list of available records and hints. - pub async fn records(&self, vault: &T) -> Result> + pub async fn records(&self, vault: &T) -> IotaStrongholdResult> where T: AsRef<[u8]> + ?Sized, { let scope: _ = Context::scope(self.path, &self.name, &self.flags).await?; - let (data, status): (Vec, _) = scope.list_hints_and_ids(vault.as_ref()).await; - - status.to_result()?; - - Ok(data) - } - - pub async fn slip10_generate(&self, output: Location, hint: RecordHint, bytes: Option) -> Result<()> { - let procedure: Procedure = Procedure::SLIP10Generate { - output, - hint, - size_bytes: bytes, - }; - - match self.execute(procedure).await? { - ProcedureResult::SLIP10Generate => Ok(()), - _ => Err(Error::StrongholdProcedureFailure), - } - } - - pub async fn slip10_derive( - &self, - chain: Chain, - input: SLIP10DeriveInput, - output: Location, - hint: RecordHint, - ) -> Result { - let procedure: Procedure = Procedure::SLIP10Derive { - chain, - input, - output, - hint, - }; - - match self.execute(procedure).await? { - ProcedureResult::SLIP10Derive(chaincode) => Ok(chaincode), - _ => Err(Error::StrongholdProcedureFailure), - } - } - - pub async fn bip39_recover

( - &self, - mnemonic: String, - output: Location, - passphrase: P, - hint: RecordHint, - ) -> Result<()> - where - P: Into>, - { - let procedure: Procedure = Procedure::BIP39Recover { - mnemonic, - passphrase: passphrase.into(), - output, - hint, - }; - - match self.execute(procedure).await? { - ProcedureResult::BIP39Recover => Ok(()), - _ => Err(Error::StrongholdProcedureFailure), - } - } - - pub async fn bip39_generate

(&self, output: Location, passphrase: P, hint: RecordHint) -> Result<()> - where - P: Into>, - { - let procedure: Procedure = Procedure::BIP39Generate { - passphrase: passphrase.into(), - output, - hint, - }; - - match self.execute(procedure).await? { - ProcedureResult::BIP39Generate => Ok(()), - _ => Err(Error::StrongholdProcedureFailure), - } - } - - pub async fn bip39_mnemonic_sentence(&self, seed: Location) -> Result { - let procedure: Procedure = Procedure::BIP39MnemonicSentence { seed }; - - match self.execute(procedure).await? { - ProcedureResult::BIP39MnemonicSentence(mnemonic) => Ok(mnemonic), - _ => Err(Error::StrongholdProcedureFailure), - } - } - - pub async fn ed25519_public_key(&self, private_key: Location) -> Result<[u8; 32]> { - let procedure: Procedure = Procedure::Ed25519PublicKey { private_key }; - - match self.execute(procedure).await? { - ProcedureResult::Ed25519PublicKey(public_key) => Ok(public_key), - _ => Err(Error::StrongholdProcedureFailure), - } - } - - pub async fn ed25519_sign(&self, msg: Vec, private_key: Location) -> Result<[u8; 64]> { - let procedure: Procedure = Procedure::Ed25519Sign { private_key, msg }; - - match self.execute(procedure).await? { - ProcedureResult::Ed25519Sign(signature) => Ok(signature), - _ => Err(Error::StrongholdProcedureFailure), - } + Ok(scope.list_hints_and_ids(vault.as_ref()).await?) } } diff --git a/identity-account/src/utils/fs.rs b/identity-account/src/utils/fs.rs index a8693140b2..4940a72101 100644 --- a/identity-account/src/utils/fs.rs +++ b/identity-account/src/utils/fs.rs @@ -4,9 +4,7 @@ use std::fs; use std::path::Path; -use crate::error::Result; - -pub fn ensure_directory

(path: &P) -> Result<()> +pub fn ensure_directory

(path: &P) -> Result<(), std::io::Error> where P: AsRef + ?Sized, {