core_crypto/error/
mod.rs

1// Wire
2// Copyright (C) 2022 Wire Swiss GmbH
3
4// This program 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// This program 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 this program. If not, see http://www.gnu.org/licenses/.
16
17mod cryptobox_migration;
18mod keystore;
19mod leaf;
20mod mls;
21mod proteus;
22mod recursive;
23mod wrapper;
24
25pub use cryptobox_migration::{CryptoboxMigrationError, CryptoboxMigrationErrorKind};
26pub use keystore::KeystoreError;
27pub use leaf::LeafError;
28pub use mls::{MlsError, MlsErrorKind};
29pub use proteus::{ProteusError, ProteusErrorKind};
30pub use recursive::{RecursiveError, ToRecursiveError};
31pub(crate) use wrapper::WrappedContextualError;
32
33/// A module-specific [Result][core::result::Result] type with a default error variant.
34pub type Result<T, E = Error> = core::result::Result<T, E>;
35
36/// Errors produced by the root module group
37#[derive(Debug, thiserror::Error)]
38pub enum Error {
39    /// Invalid Context. This context has been finished and can no longer be used.
40    #[error("This context has already been finished and can no longer be used.")]
41    InvalidContext,
42    /// The proteus client has been called but has not been initialized yet
43    #[error("Proteus client hasn't been initialized")]
44    ProteusNotInitialized,
45    /// Mls Transport Callbacks were not provided
46    #[error("The mls transport callbacks needed for CoreCrypto to operate were not set")]
47    MlsTransportNotProvided,
48    /// Any error that occurs during mls transport.
49    #[error("Error during mls transport: {0}")]
50    ErrorDuringMlsTransport(String),
51    /// This item requires a feature that the core-crypto library was built without
52    #[error("This item requires a feature that the core-crypto library was built without: {0}")]
53    FeatureDisabled(&'static str),
54    /// A key store operation failed
55    #[error(transparent)]
56    Keystore(#[from] KeystoreError),
57    /// An external MLS operation failed
58    #[error(transparent)]
59    Mls(#[from] MlsError),
60    /// A Proteus operation failed
61    #[error(transparent)]
62    Proteus(#[from] ProteusError),
63    /// A cryptobox migration operation failed
64    #[error(transparent)]
65    CryptoboxMigration(#[from] CryptoboxMigrationError),
66    /// A crate-internal operation failed
67    #[error(transparent)]
68    Recursive(#[from] RecursiveError),
69}
70
71/// Produce the error message from the innermost wrapped error.
72///
73/// We produce arbitrarily nested errors which are very helpful
74/// at capturing relevant context, and very bad at surfacing the
75/// root error cause in a default `.to_string()` call.
76///
77/// This trait, automatically implemented for all standard errors,
78/// rectifies this problem.
79pub trait InnermostErrorMessage {
80    /// Produce the error message from the innermost wrapped error.
81    fn innermost_error_message(&self) -> String;
82}
83
84impl<E: std::error::Error> InnermostErrorMessage for E {
85    fn innermost_error_message(&self) -> String {
86        let mut err: &dyn std::error::Error = self;
87        while let Some(source) = err.source() {
88            err = source;
89        }
90        err.to_string()
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn can_unpack_wrapped_error() {
100        let inner = Error::InvalidContext;
101        let outer = RecursiveError::root("wrapping the inner for test purposes")(inner);
102        let message = outer.innermost_error_message();
103        assert_eq!(message, Error::InvalidContext.to_string());
104    }
105}