Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: errors per module [WPB-14354] #791

Merged
merged 31 commits into from
Dec 20, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4d5244b
build(mls/client): byte literals exist so that humans do not have to …
coriolinus Nov 27, 2024
d548298
refactor!(mls): simplify `get_conversation` api
coriolinus Nov 27, 2024
807a9d1
refactor!(e2e_identity): module uses a module-specific error type
coriolinus Nov 27, 2024
c4a2b1c
refactor!(mls/client): client module uses a module-internal error type
coriolinus Nov 28, 2024
a782d53
refactor!(mls/conversation): conversation module uses a module-intern…
coriolinus Nov 29, 2024
2361365
refactor!(mls/credential): credential module uses a module-internal e…
coriolinus Nov 29, 2024
37730a7
refactor!(mls): mls root module uses a module-internal error type
coriolinus Nov 29, 2024
3aa7e84
refactor!(core-crypto): root module uses module-internal error type
coriolinus Dec 3, 2024
5d0541a
refactor!(errors): reexport each from module root
coriolinus Dec 4, 2024
b0dbc11
refactor(errors): extract `LeafError` to consolidate error leaves fro…
coriolinus Dec 4, 2024
7dd921f
refactor!(errors): centralize recursive error definitions to simplify
coriolinus Dec 4, 2024
a612ad8
refactor!(errors): centralize `KeystoreError`
coriolinus Dec 4, 2024
373ac0a
refactor(errors): better organize top-level errors
coriolinus Dec 5, 2024
4bd521a
fix(errors): make core-crypto compile again for `wasm32-unknown-unknown`
coriolinus Dec 5, 2024
1a083e3
refactor(errors): move `error::Error::ConversationNotFound` into `Lea…
coriolinus Dec 5, 2024
b9a9190
refactor(e2e_identity/errors): audit error type and simplify where po…
coriolinus Dec 5, 2024
cb7821c
refactor(mls/client/errors): audit error type and simplify where poss…
coriolinus Dec 5, 2024
17e4e89
refactor(mls/conversation/errors): audit error type and simplify wher…
coriolinus Dec 5, 2024
5b68c75
partial(errors): get some core-crypto test cases passing again
coriolinus Dec 6, 2024
65f672b
fix(errors): fix remaining failing test cases
coriolinus Dec 9, 2024
81dd49a
refactor(crypto-ffi): `core-crypto-ffi` builds given new errors
coriolinus Dec 12, 2024
7fdeeb4
fix: fix `check` ci action
coriolinus Dec 13, 2024
d0db260
fix: make leaf node validation tests pass
coriolinus Dec 13, 2024
15cbf13
build: reduce visibility of unreachable pub items
coriolinus Dec 13, 2024
e1d6dc5
fix: cause doctests to build/pass
coriolinus Dec 13, 2024
eab63e3
fix: ensure everything still builds in arbitray feature combinations
coriolinus Dec 13, 2024
4181deb
fix(kotlin): cause kotlin to build again
coriolinus Dec 13, 2024
a61739b
chore: rm legacy error type
coriolinus Dec 18, 2024
c84da0b
chore: typos and vocab fixes
coriolinus Dec 18, 2024
8cd3806
fixup: `innermost_source_matches` can handle dereferencing boxed errors
coriolinus Dec 18, 2024
e93cee6
chore: remove error variants already removed by `c5482e5`
coriolinus Dec 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions crypto/src/e2e_identity/enabled.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//! Utility for clients to get the current state of E2EI when the app resumes

use super::error::Result;
use super::error::{Error, Result};
use crate::context::CentralContext;
use crate::prelude::{Client, CryptoError, MlsCentral, MlsCredentialType};
use crate::mls;
use crate::prelude::{Client, MlsCentral, MlsCredentialType};
use openmls_traits::types::SignatureScheme;

impl CentralContext {
Expand All @@ -26,12 +27,15 @@ impl Client {
.find_most_recent_credential_bundle(signature_scheme, MlsCredentialType::X509)
.await;
match x509_result {
Err(CryptoError::CredentialNotFound(MlsCredentialType::X509)) => {
Err(mls::client::error::Error::CredentialNotFound(MlsCredentialType::X509)) => {
self.find_most_recent_credential_bundle(signature_scheme, MlsCredentialType::Basic)
.await?;
.await
.map_err(Error::mls_client(
"finding most recent basic credential bundle after searching for x509",
))?;
Ok(false)
}
Err(e) => Err(e.into()),
Err(e) => Err(Error::mls_client("finding most recent x509 credential bundle")(e)),
Ok(_) => Ok(true),
}
}
Expand Down
15 changes: 15 additions & 0 deletions crypto/src/e2e_identity/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ pub enum Error {
/// Serializing key package for TLS
#[error("Serializing key package for TLS")]
TlsSerializingKeyPackage(#[from] tls_codec::Error),
/// Something in the MLS client went wrong
#[error("{context}")]
MlsClient {
/// What was happening when the error was thrown
context: &'static str,
/// The inner error which was produced
#[source]
source: crate::mls::client::error::Error,
},
/// Compatibility wrapper
///
/// This should be removed before merging this branch, but it allows an easier migration path to module-specific errors.
Expand All @@ -88,3 +97,9 @@ impl From<crate::CryptoError> for Error {
Self::CryptoError(Box::new(value))
}
}

impl Error {
pub(crate) fn mls_client(context: &'static str) -> impl FnOnce(crate::mls::client::error::Error) -> Self {
move |source| Self::MlsClient { context, source }
}
}
6 changes: 4 additions & 2 deletions crypto/src/e2e_identity/rotate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,17 @@ impl CentralContext {
cs.signature_algorithm(),
cert_bundle,
)
.await?;
.await
.map_err(Error::mls_client("saving new x509 credential bundle"))?;

let commits = self.e2ei_update_all(client, &new_cb).await?;

let key_package_refs_to_remove = self.find_key_packages_to_remove(&new_cb).await?;

let new_key_packages = client
.generate_new_keypackages(&self.mls_provider().await?, cs, &new_cb, new_key_packages_count)
.await?;
.await
.map_err(Error::mls_client("generating new keypackages"))?;

Ok(MlsRotateBundle {
commits,
Expand Down
3 changes: 3 additions & 0 deletions crypto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ pub enum CryptoError {
/// Invalid Context. This context has been finished and can no longer be used.
#[error("This context has already been finished and can no longer be used.")]
InvalidContext,
/// Something happened in the MLS client code
#[error(transparent)]
MlsClient(#[from] crate::mls::client::error::Error),
}

impl From<MlsError> for CryptoError {
Expand Down
112 changes: 110 additions & 2 deletions crypto/src/mls/client/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,117 @@

pub type Result<T, E = Error> = core::result::Result<T, E>;

/// MLS errors
/// MLS client errors
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("Supplied User Id was not valid")]
#[error("Supplied user id was not valid")]
InvalidUserId,
#[error("X509 certificate bundle set was empty")]
NoX509CertificateBundle,
/// Tried to insert an already existing CredentialBundle
#[error("Tried to insert an already existing CredentialBundle")]
CredentialBundleConflict,
/// A MLS operation was requested but MLS hasn't been initialized on this instance
#[error("A MLS operation was requested but MLS hasn't been initialized on this instance")]
MlsNotInitialized,
/// A Credential was not found locally which is very likely an implementation error
#[error("A Credential of type {0:?} was not found locally which is very likely an implementation error")]
CredentialNotFound(crate::prelude::MlsCredentialType),
/// A key store operation failed
//
// This uses a `Box<dyn>` pattern because we do not directly import `keystore` from here right now,
// and it feels a bit silly to add the dependency only for this.
#[error("{context}")]
Keystore {
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
context: &'static str,
},
/// Serializing an item for tls
#[error("Serializing {item} for TLS")]
TlsSerialize {
item: &'static str,
#[source]
source: tls_codec::Error,
},
/// Deserializing an item for tls
#[error("Deserializing {item} for TLS")]
TlsDeserialize {
item: &'static str,
#[source]
source: tls_codec::Error,
},
/// Keypackage list was empty
#[error("Keypackage list was empty")]
EmptyKeypackageList,
/// Computing Keypackage Hashref
#[error("Computing keypackage hashref")]
ComputeKeypackageHashref(#[source] openmls::error::LibraryError),
/// The keystore has no knowledge of such client; this shouldn't happen as Client::init is failsafe (find-else-create)
#[error("The provided client signature has not been found in the keystore")]
ClientSignatureNotFound,
/// Client was unexpectedly ready.
///
/// This indicates an invalid calling pattern.
#[error("Client was unexpectedly ready")]
UnexpectedlyReady,
/// The keystore already has a stored identity. As such, we cannot create a new raw identity
#[error("The keystore already contains a stored identity. Cannot create a new one!")]
IdentityAlreadyPresent,
/// Generating random client id
#[error("Generating random client id")]
GenerateRandomClientId(#[source] mls_crypto_provider::MlsProviderError),
/// This error occurs when we cannot find any provisional keypair in the store, indicating that the `generate_raw_keypair` method hasn't been called.
#[error(
r#"The externally-generated client ID initialization cannot continue - there's no provisional keypair in-store!

Have you called `CoreCrypto::generate_raw_keypair` ?"#
)]
NoProvisionalIdentityFound,
/// This error occurs when during the MLS external client generation, we end up with more than one client identity in store.
///
/// This is usually not possible, unless there's some kind of concurrency issue
/// on the consumer (creating an ext-gen client AND a normal one at the same time for instance)
#[error(
"Somehow CoreCrypto holds more than one MLS identity. Something might've gone very wrong with this client!"
)]
TooManyIdentitiesPresent,
/// The supplied credential does not match the id or signature schemes provided.
#[error("The supplied credential does not match the id or signature schemes provided")]
WrongCredential,
/// Generating signature keypair
#[error("Generating signature keypair")]
GeneratingSignatureKeypair(#[source] openmls_traits::types::CryptoError),
/// Compatibility wrapper
///
/// This should be removed before merging this branch, but it allows an easier migration path to module-specific errors.
#[deprecated]
#[error(transparent)]
CryptoError(Box<crate::CryptoError>),
}

impl From<crate::CryptoError> for Error {
fn from(value: crate::CryptoError) -> Self {
Self::CryptoError(Box::new(value))
}
}

impl Error {
pub(crate) fn keystore<E>(context: &'static str) -> impl FnOnce(E) -> Self
where
E: 'static + std::error::Error + Send + Sync,
{
move |err| Self::Keystore {
context,
source: Box::new(err),
}
}

pub(crate) fn tls_serialize(item: &'static str) -> impl FnOnce(tls_codec::Error) -> Self {
move |source| Self::TlsSerialize { item, source }
}

pub(crate) fn tls_deserialize(item: &'static str) -> impl FnOnce(tls_codec::Error) -> Self {
move |source| Self::TlsDeserialize { item, source }
}
}
4 changes: 2 additions & 2 deletions crypto/src/mls/client/id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/.

use crate::CryptoError;
use super::error::Error;

/// A Client identifier
///
Expand Down Expand Up @@ -69,7 +69,7 @@ impl std::fmt::Display for ClientId {
}

impl std::str::FromStr for ClientId {
type Err = CryptoError;
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(
Expand Down
18 changes: 9 additions & 9 deletions crypto/src/mls/client/identifier.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::CredentialBundle;
use crate::{
prelude::CryptoError,
prelude::{CertificateBundle, Client, ClientId, CryptoResult},
use super::{
error::{Error, Result},
CredentialBundle,
};
use crate::prelude::{CertificateBundle, Client, ClientId};
use mls_crypto_provider::MlsCryptoProvider;
use openmls_traits::types::SignatureScheme;
use std::collections::{HashMap, HashSet};
Expand All @@ -20,14 +20,14 @@ pub enum ClientIdentifier {
impl ClientIdentifier {
/// Extract the unique [ClientId] from an identifier. Use with parsimony as, in case of a x509
/// certificate this leads to parsing the certificate
pub fn get_id(&self) -> CryptoResult<std::borrow::Cow<ClientId>> {
pub fn get_id(&self) -> Result<std::borrow::Cow<ClientId>> {
match self {
ClientIdentifier::Basic(id) => Ok(std::borrow::Cow::Borrowed(id)),
ClientIdentifier::X509(certs) => {
// since ClientId has uniqueness constraints, it is the same for all certificates.
// hence no need to compute it for every certificate then verify its uniqueness
// that's not a getter's job
let cert = certs.values().next().ok_or(CryptoError::ImplementationError)?;
let cert = certs.values().next().ok_or(Error::NoX509CertificateBundle)?;
let id = cert.get_client_id()?;
Ok(std::borrow::Cow::Owned(id))
}
Expand All @@ -40,11 +40,11 @@ impl ClientIdentifier {
self,
backend: &MlsCryptoProvider,
signature_schemes: HashSet<SignatureScheme>,
) -> CryptoResult<Vec<(SignatureScheme, ClientId, CredentialBundle)>> {
) -> Result<Vec<(SignatureScheme, ClientId, CredentialBundle)>> {
match self {
ClientIdentifier::Basic(id) => signature_schemes.iter().try_fold(
Vec::with_capacity(signature_schemes.len()),
|mut acc, &sc| -> CryptoResult<_> {
|mut acc, &sc| -> Result<_> {
let cb = Client::new_basic_credential_bundle(&id, sc, backend)?;
acc.push((sc, id.clone(), cb));
Ok(acc)
Expand All @@ -54,7 +54,7 @@ impl ClientIdentifier {
let cap = certs.len();
certs
.into_iter()
.try_fold(Vec::with_capacity(cap), |mut acc, (sc, cert)| -> CryptoResult<_> {
.try_fold(Vec::with_capacity(cap), |mut acc, (sc, cert)| -> Result<_> {
let id = cert.get_client_id()?;
let cb = Client::new_x509_credential_bundle(cert)?;
acc.push((sc, id, cb));
Expand Down
Loading