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