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}
107
108impl CryptoKeystoreError {
109    /// If the produced rusqlite error came from a constraint violation, then map it to our
110    /// AlreadyExists variant. Otherwise pass it through.
111    pub(crate) fn map_already_exists(table_name: &'static str) -> impl FnOnce(rusqlite::Error) -> Self {
112        move |err| {
113            if let rusqlite::Error::SqliteFailure(inner, _) = err
114                && let rusqlite::ErrorCode::ConstraintViolation = inner.code
115            {
116                Self::AlreadyExists(table_name)
117            } else {
118                err.into()
119            }
120        }
121    }
122
123    #[cfg(target_os = "unknown")]
124    pub(crate) fn relaxed_idb(
125        context: &'static str,
126    ) -> impl FnOnce(sqlite_wasm_vfs::relaxed_idb::RelaxedIdbError) -> Self {
127        move |error| Self::RelaxedIdbError { context, error }
128    }
129}
130
131#[cfg(target_os = "unknown")]
132#[allow(clippy::from_over_into)]
133impl Into<wasm_bindgen::JsValue> for CryptoKeystoreError {
134    fn into(self) -> wasm_bindgen::JsValue {
135        wasm_bindgen::JsValue::from_str(&self.to_string())
136    }
137}
138
139#[cfg(target_os = "unknown")]
140impl From<serde_wasm_bindgen::Error> for CryptoKeystoreError {
141    fn from(jsv: serde_wasm_bindgen::Error) -> Self {
142        Self::SerdeWasmBindgenError(jsv.to_string())
143    }
144}
145
146#[cfg(feature = "proteus-keystore")]
147impl proteus_traits::ProteusErrorCode for CryptoKeystoreError {
148    fn code(&self) -> proteus_traits::ProteusErrorKind {
149        use proteus_traits::ProteusErrorKind;
150        match self {
151            CryptoKeystoreError::KeyReprError(_) => ProteusErrorKind::DecodeError,
152            CryptoKeystoreError::TryFromSliceError(_) => ProteusErrorKind::DecodeError,
153            CryptoKeystoreError::LockPoisonError => ProteusErrorKind::OtherSystemError,
154            CryptoKeystoreError::BlobTooBig => ProteusErrorKind::IoError,
155            CryptoKeystoreError::KeyStoreValueTransformError(_) => ProteusErrorKind::DecodeError,
156            CryptoKeystoreError::IoError(_) => ProteusErrorKind::IoError,
157            CryptoKeystoreError::DbError(_) => ProteusErrorKind::IoError,
158            CryptoKeystoreError::DbMigrationError(_) => ProteusErrorKind::IoError,
159            CryptoKeystoreError::InvalidKeySize { .. } => ProteusErrorKind::InvalidArrayLen,
160            CryptoKeystoreError::ParseIntError(_) => ProteusErrorKind::DecodeError,
161            CryptoKeystoreError::HexDecodeError(_) => ProteusErrorKind::DecodeError,
162            CryptoKeystoreError::FromUtf8Error(_) => ProteusErrorKind::DecodeError,
163            _ => unreachable!(),
164        }
165    }
166}
167
168/// A specialized Result for the KeyStore functions
169pub type CryptoKeystoreResult<T> = Result<T, CryptoKeystoreError>;