mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-16 20:49:05 -04:00
feat(sled): Use the new store cipher to encrypt our keys and values
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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()?
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user