base: Properly handle crypto related errors in the sled store
This commit is contained in:
parent
4a06c9e82d
commit
0a6b0e5804
3 changed files with 51 additions and 27 deletions
|
@ -25,8 +25,6 @@ use matrix_sdk_common::{
|
|||
locks::RwLock,
|
||||
};
|
||||
|
||||
use sled::transaction::TransactionError;
|
||||
|
||||
use crate::{
|
||||
deserialized_responses::{MemberEvent, StrippedMemberEvent},
|
||||
rooms::{RoomInfo, RoomType, StrippedRoom},
|
||||
|
@ -44,15 +42,12 @@ pub enum StoreError {
|
|||
Json(#[from] serde_json::Error),
|
||||
#[error(transparent)]
|
||||
Identifier(#[from] matrix_sdk_common::identifiers::Error),
|
||||
}
|
||||
|
||||
impl From<TransactionError<serde_json::Error>> for StoreError {
|
||||
fn from(e: TransactionError<serde_json::Error>) -> Self {
|
||||
match e {
|
||||
TransactionError::Abort(e) => Self::Json(e),
|
||||
TransactionError::Storage(e) => Self::Sled(e),
|
||||
}
|
||||
}
|
||||
#[error("The store failed to be unlocked")]
|
||||
StoreLocked,
|
||||
#[error("The store is not encrypted but was tried to be opened with a passphrase")]
|
||||
UnencryptedStore,
|
||||
#[error("Error encrypting or decrypting data from the store: {0}")]
|
||||
Encryption(String),
|
||||
}
|
||||
|
||||
/// A `StateStore` specific result type.
|
||||
|
|
|
@ -45,6 +45,35 @@ pub enum DatabaseType {
|
|||
Encrypted(store_key::EncryptedStoreKey),
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum SerializationError {
|
||||
#[error(transparent)]
|
||||
Json(#[from] serde_json::Error),
|
||||
#[error(transparent)]
|
||||
Encryption(#[from] store_key::Error),
|
||||
}
|
||||
|
||||
impl From<TransactionError<SerializationError>> for StoreError {
|
||||
fn from(e: TransactionError<SerializationError>) -> Self {
|
||||
match e {
|
||||
TransactionError::Abort(e) => e.into(),
|
||||
TransactionError::Storage(e) => StoreError::Sled(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SerializationError> for StoreError {
|
||||
fn from(e: SerializationError) -> Self {
|
||||
match e {
|
||||
SerializationError::Json(e) => StoreError::Json(e),
|
||||
SerializationError::Encryption(e) => match e {
|
||||
store_key::Error::Serialization(e) => StoreError::Json(e),
|
||||
store_key::Error::Encryption(e) => StoreError::Encryption(e),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SledStore {
|
||||
inner: Db,
|
||||
|
@ -119,10 +148,9 @@ impl SledStore {
|
|||
|
||||
let store_key = if let Some(key) = store_key {
|
||||
if let DatabaseType::Encrypted(k) = key {
|
||||
let key = StoreKey::import(passphrase, k).unwrap();
|
||||
key
|
||||
StoreKey::import(passphrase, k).map_err(|_| StoreError::StoreLocked)?
|
||||
} else {
|
||||
panic!("Trying to open an unencrypted store with a passphrase");
|
||||
return Err(StoreError::UnencryptedStore);
|
||||
}
|
||||
} else {
|
||||
let key = StoreKey::new();
|
||||
|
@ -144,24 +172,24 @@ impl SledStore {
|
|||
fn serialize_event(
|
||||
&self,
|
||||
event: &impl Serialize,
|
||||
) -> std::result::Result<Vec<u8>, serde_json::Error> {
|
||||
) -> std::result::Result<Vec<u8>, SerializationError> {
|
||||
if let Some(key) = &*self.store_key {
|
||||
let encrypted = key.encrypt(event).unwrap();
|
||||
serde_json::to_vec(&encrypted)
|
||||
let encrypted = key.encrypt(event)?;
|
||||
Ok(serde_json::to_vec(&encrypted)?)
|
||||
} else {
|
||||
serde_json::to_vec(event)
|
||||
Ok(serde_json::to_vec(event)?)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_event<T: for<'b> Deserialize<'b>>(
|
||||
&self,
|
||||
event: &[u8],
|
||||
) -> std::result::Result<T, serde_json::Error> {
|
||||
) -> std::result::Result<T, SerializationError> {
|
||||
if let Some(key) = &*self.store_key {
|
||||
let encrypted: EncryptedEvent = serde_json::from_slice(&event)?;
|
||||
Ok(key.decrypt(encrypted).unwrap())
|
||||
Ok(key.decrypt(encrypted)?)
|
||||
} else {
|
||||
serde_json::from_slice(event)
|
||||
Ok(serde_json::from_slice(event)?)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -189,7 +217,7 @@ impl SledStore {
|
|||
pub async fn save_changes(&self, changes: &StateChanges) -> Result<()> {
|
||||
let now = SystemTime::now();
|
||||
|
||||
let ret: std::result::Result<(), TransactionError<serde_json::Error>> = (
|
||||
let ret: std::result::Result<(), TransactionError<SerializationError>> = (
|
||||
&self.session,
|
||||
&self.account_data,
|
||||
&self.members,
|
||||
|
@ -440,7 +468,7 @@ impl SledStore {
|
|||
stream::iter(
|
||||
self.room_info
|
||||
.iter()
|
||||
.map(move |r| db.deserialize_event(&r?.1).map_err(StoreError::Json)),
|
||||
.map(move |r| db.deserialize_event(&r?.1).map_err(|e| e.into())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,8 +44,6 @@ pub enum Error {
|
|||
Serialization(#[from] serde_json::Error),
|
||||
#[error("Error encrypting or decrypting an event {0}")]
|
||||
Encryption(String),
|
||||
#[error("Unknown ciphertext version")]
|
||||
InvalidVersion,
|
||||
}
|
||||
|
||||
impl From<EncryptionError> for Error {
|
||||
|
@ -129,6 +127,7 @@ impl StoreKey {
|
|||
Default::default()
|
||||
}
|
||||
|
||||
/// Expand the given passphrase into a KEY_SIZE long key.
|
||||
fn expand_key(passphrase: &str, salt: &[u8], rounds: u32) -> Zeroizing<Vec<u8>> {
|
||||
let mut key = Zeroizing::from(vec![0u8; KEY_SIZE]);
|
||||
pbkdf2::<Hmac<Sha256>>(passphrase.as_bytes(), &salt, rounds, &mut *key);
|
||||
|
@ -172,7 +171,7 @@ impl StoreKey {
|
|||
|
||||
fn get_nonce() -> Vec<u8> {
|
||||
let mut nonce = vec![0u8; XNONCE_SIZE];
|
||||
getrandom(&mut nonce).expect("Can't generate nonce");
|
||||
getrandom(&mut nonce).expect("Can't get random nonce");
|
||||
nonce
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,9 @@ impl StoreKey {
|
|||
|
||||
pub fn decrypt<T: for<'b> Deserialize<'b>>(&self, event: EncryptedEvent) -> Result<T, Error> {
|
||||
if event.version != VERSION {
|
||||
return Err(Error::InvalidVersion);
|
||||
return Err(Error::Encryption(
|
||||
"Error decrypting: Unknown ciphertext version".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let cipher = XChaCha20Poly1305::new(self.key());
|
||||
|
|
Loading…
Reference in a new issue