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