Skip to main content

core_crypto_keystore/
error.rs

1/// Error type to represent various errors that can happen in the KeyStore
2#[derive(Debug, thiserror::Error)]
3pub enum CryptoKeystoreError {
4    #[error("The given key doesn't contain valid utf-8")]
5    KeyReprError(#[from] std::str::Utf8Error),
6    #[error("A transaction must be in progress to perform this operation.")]
7    MutatingOperationWithoutTransaction,
8    #[error("cannot open a new transaction as there exists another transaction currently in progress")]
9    TransactionInProgress,
10    #[error("the transaction was unexpectedly rolled back by sqlite")]
11    UnexpectedRollback,
12    #[error(transparent)]
13    TryFromSliceError(#[from] std::array::TryFromSliceError),
14    #[error("One of the Keystore locks has been poisoned")]
15    LockPoisonError,
16    #[error("The keystore has run out of keypackage bundles!")]
17    OutOfKeyPackageBundles,
18    #[error("Incorrect API usage: {0}")]
19    IncorrectApiUsage(&'static str),
20    #[error("The credential tied to this signature keypair is different from the provided one")]
21    SignatureKeyPairDoesNotBelongToCredential,
22    #[error("The uniqueness constraint has been violated for {0}")]
23    AlreadyExists(&'static str),
24    #[error("The provided buffer is too big to be persisted in the store")]
25    BlobTooBig,
26    #[error("This database connection has been closed")]
27    Closed,
28    #[error(transparent)]
29    KeyStoreValueTransformError(#[from] postcard::Error),
30    #[error(transparent)]
31    IoError(#[from] std::io::Error),
32    #[cfg(not(target_os = "unknown"))]
33    #[error(transparent)]
34    TimeError(#[from] std::time::SystemTimeError),
35    #[error("aead::Error: {0}")]
36    AesGcmError(&'static str),
37    #[cfg(target_os = "unknown")]
38    #[error("{0}")]
39    SerdeWasmBindgenError(String),
40    #[error(transparent)]
41    DbError(#[from] rusqlite::Error),
42    #[error(transparent)]
43    DbMigrationError(#[from] Box<refinery::Error>),
44    #[cfg(test)]
45    #[error(transparent)]
46    MlsKeyPackageIdError(#[from] openmls::prelude::KeyPackageIdError),
47    #[cfg(test)]
48    #[error(transparent)]
49    MlsExtensionError(#[from] openmls::prelude::ExtensionError),
50    #[error("Invalid database key size, expected {expected}, got {actual}")]
51    InvalidDbKeySize { expected: usize, actual: usize },
52    #[cfg(feature = "proteus-keystore")]
53    #[error("Invalid key [{key}] size, expected {expected}, got {actual}")]
54    InvalidKeySize {
55        expected: usize,
56        actual: usize,
57        key: &'static str,
58    },
59    #[cfg(feature = "proteus-keystore")]
60    #[error(transparent)]
61    ParseIntError(#[from] std::num::ParseIntError),
62    #[cfg(feature = "proteus-keystore")]
63    #[error("Could not find a free prekey id")]
64    NoFreePrekeyId,
65    #[error("{0}")]
66    MlsKeyStoreError(String),
67    #[error(transparent)]
68    HexDecodeError(#[from] hex::FromHexError),
69    #[error(transparent)]
70    FromUtf8Error(#[from] std::string::FromUtf8Error),
71    #[cfg(target_os = "ios")]
72    #[error(transparent)]
73    HexSaltDecodeError(hex::FromHexError),
74    #[cfg(target_os = "ios")]
75    #[error(transparent)]
76    SecurityFrameworkError(#[from] security_framework::base::Error),
77    #[error("Not implemented (and probably never will)")]
78    NotImplemented,
79    #[error("Failed getting current timestamp")]
80    TimestampError,
81    #[error("Could not find {0} in keystore with value {1}")]
82    NotFound(&'static str, String),
83    #[error(transparent)]
84    SerdeJsonError(#[from] serde_json::Error),
85    #[cfg(target_os = "unknown")]
86    #[error(transparent)]
87    IdbError(#[from] idb::Error),
88    #[cfg(target_os = "unknown")]
89    #[error("Migration from version {0} is not supported")]
90    MigrationNotSupported(u32),
91    #[error("The migration failed: {0}")]
92    MigrationFailed(String),
93    #[cfg(target_os = "unknown")]
94    #[error("{context}")]
95    RelaxedIdbError {
96        context: &'static str,
97        #[source]
98        error: sqlite_wasm_vfs::relaxed_idb::RelaxedIdbError,
99    },
100}
101
102impl CryptoKeystoreError {
103    /// If the produced rusqlite error came from a constraint violation, then map it to our
104    /// AlreadyExists variant. Otherwise pass it through.
105    pub(crate) fn map_already_exists(table_name: &'static str) -> impl FnOnce(rusqlite::Error) -> Self {
106        move |err| {
107            if let rusqlite::Error::SqliteFailure(inner, _) = err
108                && let rusqlite::ErrorCode::ConstraintViolation = inner.code
109            {
110                Self::AlreadyExists(table_name)
111            } else {
112                err.into()
113            }
114        }
115    }
116
117    #[cfg(target_os = "unknown")]
118    pub(crate) fn relaxed_idb(
119        context: &'static str,
120    ) -> impl FnOnce(sqlite_wasm_vfs::relaxed_idb::RelaxedIdbError) -> Self {
121        move |error| Self::RelaxedIdbError { context, error }
122    }
123}
124
125#[cfg(target_os = "unknown")]
126#[allow(clippy::from_over_into)]
127impl Into<wasm_bindgen::JsValue> for CryptoKeystoreError {
128    fn into(self) -> wasm_bindgen::JsValue {
129        wasm_bindgen::JsValue::from_str(&self.to_string())
130    }
131}
132
133#[cfg(target_os = "unknown")]
134impl From<serde_wasm_bindgen::Error> for CryptoKeystoreError {
135    fn from(jsv: serde_wasm_bindgen::Error) -> Self {
136        Self::SerdeWasmBindgenError(jsv.to_string())
137    }
138}
139
140#[cfg(feature = "proteus-keystore")]
141impl proteus_traits::ProteusErrorCode for CryptoKeystoreError {
142    fn code(&self) -> proteus_traits::ProteusErrorKind {
143        use proteus_traits::ProteusErrorKind;
144        match self {
145            CryptoKeystoreError::KeyReprError(_) => ProteusErrorKind::DecodeError,
146            CryptoKeystoreError::TryFromSliceError(_) => ProteusErrorKind::DecodeError,
147            CryptoKeystoreError::LockPoisonError => ProteusErrorKind::OtherSystemError,
148            CryptoKeystoreError::BlobTooBig => ProteusErrorKind::IoError,
149            CryptoKeystoreError::KeyStoreValueTransformError(_) => ProteusErrorKind::DecodeError,
150            CryptoKeystoreError::IoError(_) => ProteusErrorKind::IoError,
151            CryptoKeystoreError::DbError(_) => ProteusErrorKind::IoError,
152            CryptoKeystoreError::DbMigrationError(_) => ProteusErrorKind::IoError,
153            CryptoKeystoreError::InvalidKeySize { .. } => ProteusErrorKind::InvalidArrayLen,
154            CryptoKeystoreError::ParseIntError(_) => ProteusErrorKind::DecodeError,
155            CryptoKeystoreError::HexDecodeError(_) => ProteusErrorKind::DecodeError,
156            CryptoKeystoreError::FromUtf8Error(_) => ProteusErrorKind::DecodeError,
157            _ => unreachable!(),
158        }
159    }
160}
161
162/// A specialized Result for the KeyStore functions
163pub type CryptoKeystoreResult<T> = Result<T, CryptoKeystoreError>;