feat(sled): Use the new store cipher to encrypt our keys and values

This commit is contained in:
Damir Jelić
2022-03-10 10:08:34 +01:00
parent 54e555f295
commit 75de41bb2e
2 changed files with 313 additions and 81 deletions

View File

@@ -27,6 +27,7 @@ futures-util = { version = "0.3.15", default-features = false }
matrix-sdk-base = { path = "../matrix-sdk-base", features = ["store_key"] }
matrix-sdk-common = { path = "../matrix-sdk-common" }
matrix-sdk-crypto = { path = "../matrix-sdk-crypto", optional = true }
matrix-sdk-store-encryption = { path = "../matrix-sdk-store-encryption" }
async-stream = "0.3.2"
serde = "1"
serde_json = "1.0.64"

View File

@@ -41,6 +41,7 @@ use matrix_sdk_crypto::{
},
GossipRequest, LocalTrust, ReadOnlyAccount, ReadOnlyDevice, ReadOnlyUserIdentities, SecretInfo,
};
use matrix_sdk_store_encryption::StoreCipher;
use serde::{Deserialize, Serialize};
pub use sled::Error;
use sled::{
@@ -51,12 +52,19 @@ use tracing::debug;
use super::OpenStoreError;
/// This needs to be 32 bytes long since AES-GCM requires it, otherwise we will
/// panic once we try to pickle a Signing object.
#[cfg(feature = "backups_v1")]
const DEFAULT_PICKLE: &str = "DEFAULT_PICKLE_PASSPHRASE_123456";
const DATABASE_VERSION: u8 = 3;
// Table names that are used to derive a separate key for each tree. This ensure
// that user ids encoded for different trees won't end up as the same byte
// sequence. This prevents corelation attacks on our tree metadata.
const DEVICE_TABLE_NAME: &str = "crypto-store-devices";
const IDENTITIES_TABLE_NAME: &str = "crypto-store-identities";
const SESSIONS_TABLE_NAME: &str = "crypto-store-sessions";
const INBOUND_GROUP_TABLE_NAME: &str = "crypto-store-inbound-group-sessions";
const OUTBOUND_GROUP_TABLE_NAME: &str = "crypto-store-outbound-group-sessions";
const SECRET_REQUEST_BY_INFO_TABLE: &str = "crypto-store-secret-request-by-info";
const TRACKED_USERS_TABLE: &str = "crypto-store-secret-tracked-users";
trait EncodeKey {
const SEPARATOR: u8 = 0xff;
fn encode(&self) -> Vec<u8>;
@@ -123,6 +131,133 @@ impl EncodeKey for ReadOnlyDevice {
}
}
impl EncodeSecureKey for (&UserId, &DeviceId) {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let user_id = store_cipher.hash_key(table_name, self.0.as_bytes());
let device_id = store_cipher.hash_key(table_name, self.1.as_bytes());
(user_id, device_id).encode()
}
}
impl EncodeSecureKey for SecretInfo {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
match self {
SecretInfo::KeyRequest(k) => k.encode_secure(table_name, store_cipher),
SecretInfo::SecretRequest(s) => s.encode_secure(table_name, store_cipher),
}
}
}
impl EncodeSecureKey for SecretName {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let name = store_cipher.hash_key(table_name, self.as_ref().as_bytes());
[name.as_slice(), &[Self::SEPARATOR]].concat()
}
}
impl EncodeSecureKey for RequestedKeyInfo {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let room_id = store_cipher.hash_key(table_name, self.room_id.as_bytes());
let sender_key = store_cipher.hash_key(table_name, self.sender_key.as_bytes());
let algorithm = store_cipher.hash_key(table_name, self.algorithm.as_ref().as_bytes());
let session_id = store_cipher.hash_key(table_name, self.session_id.as_bytes());
[
room_id.as_slice(),
&[Self::SEPARATOR],
sender_key.as_slice(),
&[Self::SEPARATOR],
algorithm.as_slice(),
&[Self::SEPARATOR],
session_id.as_slice(),
&[Self::SEPARATOR],
]
.concat()
}
}
impl EncodeSecureKey for UserId {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let user_id = store_cipher.hash_key(table_name, self.as_bytes());
[user_id.as_slice(), &[0xff]].concat()
}
}
impl EncodeSecureKey for ReadOnlyDevice {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
(self.user_id(), self.device_id()).encode_secure(table_name, store_cipher)
}
}
impl EncodeKey for Session {
fn encode(&self) -> Vec<u8> {
let sender_key = self.sender_key();
let session_id = self.session_id();
[sender_key.as_bytes(), &[Self::SEPARATOR], session_id.as_bytes(), &[Self::SEPARATOR]]
.concat()
}
}
impl EncodeSecureKey for str {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let key = store_cipher.hash_key(table_name, self.as_bytes());
[key.as_slice(), &[Self::SEPARATOR]].concat()
}
}
impl EncodeSecureKey for OutboundGroupSession {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
self.room_id().encode_secure(table_name, store_cipher)
}
}
impl EncodeSecureKey for RoomId {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let room_id = store_cipher.hash_key(table_name, self.as_bytes());
[room_id.as_slice(), &[Self::SEPARATOR]].concat()
}
}
impl EncodeSecureKey for InboundGroupSession {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
(self.room_id(), self.sender_key(), self.session_id())
.encode_secure(table_name, store_cipher)
}
}
impl EncodeSecureKey for (&RoomId, &str, &str) {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let first = store_cipher.hash_key(table_name, self.0.as_bytes());
let second = store_cipher.hash_key(table_name, self.1.as_bytes());
let third = store_cipher.hash_key(table_name, self.2.as_bytes());
[
first.as_slice(),
&[Self::SEPARATOR],
second.as_slice(),
&[Self::SEPARATOR],
third.as_slice(),
&[Self::SEPARATOR],
]
.concat()
}
}
impl EncodeSecureKey for Session {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8> {
let sender_key = store_cipher.hash_key(table_name, self.sender_key().as_bytes());
let session_id = store_cipher.hash_key(table_name, self.session_id().as_bytes());
[sender_key.as_slice(), &[Self::SEPARATOR], session_id.as_slice(), &[Self::SEPARATOR]]
.concat()
}
}
impl EncodeKey for RoomId {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
@@ -141,13 +276,37 @@ impl EncodeKey for str {
}
}
impl<const N: usize> EncodeKey for ([u8; N], [u8; N]) {
fn encode(&self) -> Vec<u8> {
[self.0.as_slice(), &[Self::SEPARATOR], self.1.as_slice(), &[Self::SEPARATOR]].concat()
}
}
impl EncodeKey for (&str, &str) {
fn encode(&self) -> Vec<u8> {
[self.0.as_bytes(), &[Self::SEPARATOR], self.1.as_bytes(), &[Self::SEPARATOR]].concat()
}
}
impl EncodeKey for (&str, &str, &str) {
impl EncodeKey for (&UserId, &DeviceId) {
fn encode(&self) -> Vec<u8> {
(self.0.as_str(), self.1.as_str()).encode()
}
}
impl EncodeKey for InboundGroupSession {
fn encode(&self) -> Vec<u8> {
(self.room_id(), self.sender_key(), self.session_id()).encode()
}
}
impl EncodeKey for OutboundGroupSession {
fn encode(&self) -> Vec<u8> {
self.room_id().encode()
}
}
impl EncodeKey for (&RoomId, &str, &str) {
fn encode(&self) -> Vec<u8> {
[
self.0.as_bytes(),
@@ -161,6 +320,10 @@ impl EncodeKey for (&str, &str, &str) {
}
}
trait EncodeSecureKey {
fn encode_secure(&self, table_name: &str, store_cipher: &StoreCipher) -> Vec<u8>;
}
#[derive(Clone, Debug)]
pub struct AccountInfo {
user_id: Arc<UserId>,
@@ -168,12 +331,19 @@ pub struct AccountInfo {
identity_keys: Arc<IdentityKeys>,
}
#[derive(Debug, Serialize, Deserialize)]
struct TrackedUser {
user_id: Box<UserId>,
dirty: bool,
}
/// A [sled] based cryptostore.
///
/// [sled]: https://github.com/spacejam/sled#readme
#[derive(Clone)]
pub struct SledStore {
account_info: Arc<RwLock<Option<AccountInfo>>>,
store_cipher: Arc<Option<StoreCipher>>,
path: Option<PathBuf>,
inner: Db,
@@ -236,16 +406,44 @@ impl SledStore {
self.account_info.read().unwrap().clone()
}
fn serialize_value(&self, event: &impl Serialize) -> Result<Vec<u8>, CryptoStoreError> {
if let Some(key) = &*self.store_cipher {
key.encrypt_value(event).map_err(|e| CryptoStoreError::Backend(anyhow!(e)))
} else {
Ok(serde_json::to_vec(event)?)
}
}
fn deserialize_value<T: for<'b> Deserialize<'b>>(
&self,
event: &[u8],
) -> Result<T, CryptoStoreError> {
if let Some(key) = &*self.store_cipher {
key.decrypt_value(event).map_err(|e| CryptoStoreError::Backend(anyhow!(e)))
} else {
Ok(serde_json::from_slice(event)?)
}
}
fn encode_key<T: EncodeSecureKey + EncodeKey + ?Sized>(
&self,
table_name: &str,
key: &T,
) -> Vec<u8> {
if let Some(store_cipher) = &*self.store_cipher {
key.encode_secure(table_name, store_cipher).to_vec()
} else {
key.encode()
}
}
async fn reset_backup_state(&self) -> Result<()> {
let mut pickles: Vec<(IVec, PickledInboundGroupSession)> = self
.inbound_group_sessions
.iter()
.map(|p| {
let item = p.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
Ok((
item.0,
serde_json::from_slice(&item.1).map_err(CryptoStoreError::Serialization)?,
))
Ok((item.0, self.deserialize_value(&item.1)?))
})
.collect::<Result<_>>()?;
@@ -253,12 +451,13 @@ impl SledStore {
pickle.backed_up = false;
}
let ret: Result<(), TransactionError<serde_json::Error>> =
let ret: Result<(), TransactionError<CryptoStoreError>> =
self.inbound_group_sessions.transaction(|inbound_sessions| {
for (key, pickle) in &pickles {
inbound_sessions.insert(
key,
serde_json::to_vec(&pickle).map_err(ConflictableTransactionError::Abort)?,
self.serialize_value(pickle)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
@@ -381,10 +580,29 @@ impl SledStore {
Ok(())
}
fn get_or_create_store_cipher(passphrase: &str, database: &Db) -> Result<StoreCipher> {
let key = if let Some(key) = database
.get("store_cipher".encode())
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
{
StoreCipher::import(passphrase, &key).map_err(|_| CryptoStoreError::UnpicklingError)?
} else {
let key = StoreCipher::new().map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
let encrypted =
key.export(passphrase).map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
database
.insert("store_cipher".encode(), encrypted)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
key
};
Ok(key)
}
fn open_helper(
db: Db,
path: Option<PathBuf>,
_passphrase: Option<&str>,
passphrase: Option<&str>,
) -> Result<Self, OpenStoreError> {
let account = db.open_tree("account")?;
let private_identity = db.open_tree("private_identity")?;
@@ -406,10 +624,18 @@ impl SledStore {
let session_cache = SessionStore::new();
let store_cipher = if let Some(passphrase) = passphrase {
Some(Self::get_or_create_store_cipher(passphrase, &db)?)
} else {
None
}
.into();
let database = Self {
account_info: RwLock::new(None).into(),
path,
inner: db,
store_cipher,
account,
private_identity,
sessions,
@@ -434,14 +660,13 @@ impl SledStore {
async fn load_tracked_users(&self) -> Result<()> {
for value in &self.tracked_users {
let (user, dirty) = value.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
let user = UserId::parse(String::from_utf8_lossy(&user).to_string())?;
let dirty = dirty.get(0).map(|d| *d == 1).unwrap_or(true);
let (_, user) = value.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
let user: TrackedUser = self.deserialize_value(&user)?;
self.tracked_users_cache.insert(user.to_owned());
self.tracked_users_cache.insert(user.user_id.to_owned());
if dirty {
self.users_for_key_query_cache.insert(user);
if user.dirty {
self.users_for_key_query_cache.insert(user.user_id);
}
}
@@ -455,9 +680,9 @@ impl SledStore {
let account_info = self.get_account_info().ok_or(CryptoStoreError::AccountUnset)?;
self.outbound_group_sessions
.get(room_id.encode())
.get(self.encode_key(OUTBOUND_GROUP_TABLE_NAME, room_id))
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|p| serde_json::from_slice(&p).map_err(CryptoStoreError::Serialization))
.map(|p| self.deserialize_value(&p))
.transpose()?
.map(|p| {
Ok(OutboundGroupSession::from_pickle(
@@ -482,11 +707,8 @@ impl SledStore {
let mut session_changes = HashMap::new();
for session in changes.sessions {
let sender_key = session.sender_key();
let session_id = session.session_id();
let pickle = session.pickle().await;
let key = (sender_key, session_id).encode();
let key = self.encode_key(SESSIONS_TABLE_NAME, &session);
self.session_cache.add(session).await;
session_changes.insert(key, pickle);
@@ -495,10 +717,7 @@ impl SledStore {
let mut inbound_session_changes = HashMap::new();
for session in changes.inbound_group_sessions {
let room_id = session.room_id();
let sender_key = session.sender_key();
let session_id = session.session_id();
let key = (room_id.as_str(), sender_key, session_id).encode();
let key = self.encode_key(INBOUND_GROUP_TABLE_NAME, &session);
let pickle = session.pickle().await;
inbound_session_changes.insert(key, pickle);
@@ -507,10 +726,10 @@ impl SledStore {
let mut outbound_session_changes = HashMap::new();
for session in changes.outbound_group_sessions {
let room_id = session.room_id();
let key = self.encode_key(OUTBOUND_GROUP_TABLE_NAME, &session);
let pickle = session.pickle().await;
outbound_session_changes.insert(room_id.to_owned(), pickle);
outbound_session_changes.insert(key, pickle);
}
let identity_changes = changes.identities;
@@ -518,7 +737,7 @@ impl SledStore {
let key_requests = changes.key_requests;
let backup_version = changes.backup_version;
let ret: Result<(), TransactionError<serde_json::Error>> = (
let ret: Result<(), TransactionError<CryptoStoreError>> = (
&self.account,
&self.private_identity,
&self.devices,
@@ -548,47 +767,49 @@ impl SledStore {
if let Some(a) = &account_pickle {
account.insert(
"account".encode(),
serde_json::to_vec(a).map_err(ConflictableTransactionError::Abort)?,
self.serialize_value(a).map_err(ConflictableTransactionError::Abort)?,
)?;
}
if let Some(i) = &private_identity_pickle {
private_identity.insert(
"identity".encode(),
serde_json::to_vec(&i).map_err(ConflictableTransactionError::Abort)?,
self.serialize_value(&i)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
if let Some(r) = &recovery_key_pickle {
account.insert(
"recovery_key_v1".encode(),
serde_json::to_vec(r).map_err(ConflictableTransactionError::Abort)?,
self.serialize_value(r).map_err(ConflictableTransactionError::Abort)?,
)?;
}
if let Some(b) = &backup_version {
account.insert(
"backup_version_v1".encode(),
serde_json::to_vec(b).map_err(ConflictableTransactionError::Abort)?,
self.serialize_value(b).map_err(ConflictableTransactionError::Abort)?,
)?;
}
for device in device_changes.new.iter().chain(&device_changes.changed) {
let key = device.encode();
let device = serde_json::to_vec(&device)
let key = self.encode_key(DEVICE_TABLE_NAME, device);
let device = self
.serialize_value(&device)
.map_err(ConflictableTransactionError::Abort)?;
devices.insert(key, device)?;
}
for device in &device_changes.deleted {
let key = device.encode();
let key = self.encode_key(DEVICE_TABLE_NAME, device);
devices.remove(key)?;
}
for identity in identity_changes.changed.iter().chain(&identity_changes.new) {
identities.insert(
identity.user_id().encode(),
serde_json::to_vec(&identity)
self.encode_key(IDENTITIES_TABLE_NAME, identity.user_id()),
self.serialize_value(&identity)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
@@ -596,7 +817,7 @@ impl SledStore {
for (key, session) in &session_changes {
sessions.insert(
key.as_slice(),
serde_json::to_vec(&session)
self.serialize_value(&session)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
@@ -604,30 +825,33 @@ impl SledStore {
for (key, session) in &inbound_session_changes {
inbound_sessions.insert(
key.as_slice(),
serde_json::to_vec(&session)
self.serialize_value(&session)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
for (key, session) in &outbound_session_changes {
outbound_sessions.insert(
key.encode(),
serde_json::to_vec(&session)
key.as_slice(),
self.serialize_value(&session)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
for hash in &olm_hashes {
hashes.insert(
serde_json::to_vec(&hash)
serde_json::to_vec(hash)
.map_err(CryptoStoreError::Serialization)
.map_err(ConflictableTransactionError::Abort)?,
&[0],
)?;
}
for key_request in &key_requests {
secret_requests_by_info
.insert(key_request.info.encode(), key_request.request_id.encode())?;
secret_requests_by_info.insert(
self.encode_key(SECRET_REQUEST_BY_INFO_TABLE, &key_request.info),
key_request.request_id.encode(),
)?;
let key_request_id = key_request.request_id.encode();
@@ -635,14 +859,14 @@ impl SledStore {
unsent_secret_requests.remove(key_request_id.clone())?;
outgoing_secret_requests.insert(
key_request_id,
serde_json::to_vec(&key_request)
self.serialize_value(&key_request)
.map_err(ConflictableTransactionError::Abort)?,
)?;
} else {
outgoing_secret_requests.remove(key_request_id.clone())?;
unsent_secret_requests.insert(
key_request_id,
serde_json::to_vec(&key_request)
self.serialize_value(&key_request)
.map_err(ConflictableTransactionError::Abort)?,
)?;
}
@@ -653,7 +877,7 @@ impl SledStore {
);
ret.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
self.inner.flush_async().await.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
self.inner.flush().map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
Ok(())
}
@@ -663,14 +887,14 @@ impl SledStore {
.outgoing_secret_requests
.get(id)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|r| serde_json::from_slice(&r))
.map(|r| self.deserialize_value(&r))
.transpose()?;
let request = if request.is_none() {
self.unsent_secret_requests
.get(id)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|r| serde_json::from_slice(&r))
.map(|r| self.deserialize_value(&r))
.transpose()?
} else {
request
@@ -688,7 +912,7 @@ impl CryptoStore for SledStore {
.get("account".encode())
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
{
let pickle = serde_json::from_slice(&pickle)?;
let pickle = self.deserialize_value(&pickle)?;
self.load_tracked_users().await?;
let account = ReadOnlyAccount::from_pickle(pickle)?;
@@ -727,7 +951,7 @@ impl CryptoStore for SledStore {
.get("identity".encode())
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
{
let pickle = serde_json::from_slice(&i)?;
let pickle = self.deserialize_value(&i)?;
Ok(Some(
PrivateCrossSigningIdentity::from_pickle(pickle)
.await
@@ -748,10 +972,9 @@ impl CryptoStore for SledStore {
if self.session_cache.get(sender_key).is_none() {
let sessions: Result<Vec<Session>> = self
.sessions
.scan_prefix(sender_key.encode())
.scan_prefix(self.encode_key(SESSIONS_TABLE_NAME, sender_key))
.map(|s| {
serde_json::from_slice(&s.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
.map_err(CryptoStoreError::Serialization)
self.deserialize_value(&s.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
})
.map(|p| {
Ok(Session::from_pickle(
@@ -775,12 +998,12 @@ impl CryptoStore for SledStore {
sender_key: &str,
session_id: &str,
) -> Result<Option<InboundGroupSession>> {
let key = (room_id.as_str(), sender_key, session_id).encode();
let key = self.encode_key(INBOUND_GROUP_TABLE_NAME, &(room_id, sender_key, session_id));
let pickle = self
.inbound_group_sessions
.get(&key)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|p| serde_json::from_slice(&p));
.map(|p| self.deserialize_value(&p));
if let Some(pickle) = pickle {
Ok(Some(InboundGroupSession::from_pickle(pickle?)?))
@@ -794,8 +1017,7 @@ impl CryptoStore for SledStore {
.inbound_group_sessions
.iter()
.map(|p| {
serde_json::from_slice(&p.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
.map_err(CryptoStoreError::Serialization)
self.deserialize_value(&p.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
})
.collect();
@@ -808,7 +1030,7 @@ impl CryptoStore for SledStore {
.iter()
.map(|p| {
let item = p.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
serde_json::from_slice(&item.1).map_err(CryptoStoreError::Serialization)
self.deserialize_value(&item.1)
})
.collect::<Result<_>>()?;
@@ -827,7 +1049,7 @@ impl CryptoStore for SledStore {
.iter()
.map(|p| {
let item = p.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
serde_json::from_slice(&item.1).map_err(CryptoStoreError::from)
self.deserialize_value(&item.1)
})
.filter_map(|p: Result<PickledInboundGroupSession, CryptoStoreError>| match p {
Ok(p) => {
@@ -882,8 +1104,13 @@ impl CryptoStore for SledStore {
self.users_for_key_query_cache.remove(user);
}
let user = TrackedUser { user_id: user.to_owned(), dirty };
self.tracked_users
.insert(user.as_str(), &[dirty as u8])
.insert(
self.encode_key(TRACKED_USERS_TABLE, user.user_id.as_str()),
self.serialize_value(&user)?,
)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
Ok(already_added)
@@ -894,12 +1121,13 @@ impl CryptoStore for SledStore {
user_id: &UserId,
device_id: &DeviceId,
) -> Result<Option<ReadOnlyDevice>> {
let key = (user_id.as_str(), device_id.as_str()).encode();
let key = self.encode_key(DEVICE_TABLE_NAME, &(user_id, device_id));
Ok(self
.devices
.get(key)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|d| serde_json::from_slice(&d))
.map(|d| self.deserialize_value(&d))
.transpose()?)
}
@@ -907,11 +1135,11 @@ impl CryptoStore for SledStore {
&self,
user_id: &UserId,
) -> Result<HashMap<Box<DeviceId>, ReadOnlyDevice>> {
let key = self.encode_key(DEVICE_TABLE_NAME, user_id);
self.devices
.scan_prefix(user_id.encode())
.scan_prefix(key)
.map(|d| {
serde_json::from_slice(&d.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
.map_err(CryptoStoreError::Serialization)
self.deserialize_value(&d.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
})
.map(|d| {
let d: ReadOnlyDevice = d?;
@@ -921,11 +1149,13 @@ impl CryptoStore for SledStore {
}
async fn get_user_identity(&self, user_id: &UserId) -> Result<Option<ReadOnlyUserIdentities>> {
let key = self.encode_key(IDENTITIES_TABLE_NAME, user_id);
Ok(self
.identities
.get(user_id.encode())
.get(key)
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|i| serde_json::from_slice(&i))
.map(|i| self.deserialize_value(&i))
.transpose()?)
}
@@ -954,7 +1184,7 @@ impl CryptoStore for SledStore {
) -> Result<Option<GossipRequest>> {
let id = self
.secret_requests_by_info
.get(key_info.encode())
.get(self.encode_key(SECRET_REQUEST_BY_INFO_TABLE, key_info))
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?;
if let Some(id) = id {
@@ -969,8 +1199,7 @@ impl CryptoStore for SledStore {
.unsent_secret_requests
.iter()
.map(|i| {
serde_json::from_slice(&i.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
.map_err(CryptoStoreError::from)
self.deserialize_value(&i.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?.1)
})
.collect();
@@ -978,7 +1207,7 @@ impl CryptoStore for SledStore {
}
async fn delete_outgoing_secret_requests(&self, request_id: &TransactionId) -> Result<()> {
let ret: Result<(), TransactionError<serde_json::Error>> = (
let ret: Result<(), TransactionError<CryptoStoreError>> = (
&self.outgoing_secret_requests,
&self.unsent_secret_requests,
&self.secret_requests_by_info,
@@ -987,22 +1216,24 @@ impl CryptoStore for SledStore {
|(outgoing_key_requests, unsent_key_requests, key_requests_by_info)| {
let sent_request: Option<GossipRequest> = outgoing_key_requests
.remove(request_id.encode())?
.map(|r| serde_json::from_slice(&r))
.map(|r| self.deserialize_value(&r))
.transpose()
.map_err(ConflictableTransactionError::Abort)?;
let unsent_request: Option<GossipRequest> = unsent_key_requests
.remove(request_id.encode())?
.map(|r| serde_json::from_slice(&r))
.map(|r| self.deserialize_value(&r))
.transpose()
.map_err(ConflictableTransactionError::Abort)?;
if let Some(request) = sent_request {
key_requests_by_info.remove(request.info.encode())?;
key_requests_by_info
.remove(self.encode_key(SECRET_REQUEST_BY_INFO_TABLE, &request.info))?;
}
if let Some(request) = unsent_request {
key_requests_by_info.remove(request.info.encode())?;
key_requests_by_info
.remove(self.encode_key(SECRET_REQUEST_BY_INFO_TABLE, &request.info))?;
}
Ok(())
@@ -1021,14 +1252,14 @@ impl CryptoStore for SledStore {
.account
.get("backup_version_v1".encode())
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|v| serde_json::from_slice(&v))
.map(|v| self.deserialize_value(&v))
.transpose()?;
let recovery_key = {
self.account
.get("recovery_key_v1".encode())
.map_err(|e| CryptoStoreError::Backend(anyhow!(e)))?
.map(|p| serde_json::from_slice(&p))
.map(|p| self.deserialize_value(&p))
.transpose()?
};