Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a store transaction for Account #2660

Merged
merged 15 commits into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bindings/matrix-sdk-crypto-ffi/src/dehydrated_devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ pub enum DehydrationError {
MissingSigningKey(#[from] matrix_sdk_crypto::SignatureError),
#[error(transparent)]
Json(#[from] serde_json::Error),
#[error(transparent)]
Store(#[from] matrix_sdk_crypto::CryptoStoreError),
#[error("The pickle key has an invalid length, expected 32 bytes, got {0}")]
PickleKeyLength(usize),
}
Expand All @@ -30,6 +32,7 @@ impl From<matrix_sdk_crypto::dehydrated_devices::DehydrationError> for Dehydrati
matrix_sdk_crypto::dehydrated_devices::DehydrationError::MissingSigningKey(e) => {
Self::MissingSigningKey(e)
}
matrix_sdk_crypto::dehydrated_devices::DehydrationError::Store(e) => Self::Store(e),
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions bindings/matrix-sdk-crypto-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use matrix_sdk_common::deserialized_responses::ShieldState as RustShieldState;
use matrix_sdk_crypto::{
backups::SignatureState,
olm::{IdentityKeys, InboundGroupSession, Session},
store::{Changes, CryptoStore, RoomSettings as RustRoomSettings},
store::{Changes, CryptoStore, PendingChanges, RoomSettings as RustRoomSettings},
types::{EventEncryptionAlgorithm as RustEventEncryptionAlgorithm, SigningKey},
EncryptionSettings as RustEncryptionSettings, LocalTrust,
};
Expand Down Expand Up @@ -304,8 +304,9 @@ async fn migrate_data(
room_settings.insert(room_id, settings.into());
}

store.save_pending_changes(PendingChanges { account: Some(account) }).await?;

let changes = Changes {
account: Some(account),
private_identity: Some(cross_signing),
sessions,
inbound_group_sessions,
Expand Down
12 changes: 8 additions & 4 deletions bindings/matrix-sdk-crypto-ffi/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1389,9 +1389,13 @@ impl OlmMachine {

/// Sign the given message using our device key and if available cross
/// signing master key.
pub fn sign(&self, message: String) -> HashMap<String, HashMap<String, String>> {
self.runtime
.block_on(self.inner.sign(&message))
pub fn sign(
&self,
message: String,
) -> Result<HashMap<String, HashMap<String, String>>, CryptoStoreError> {
Ok(self
.runtime
.block_on(self.inner.sign(&message))?
.into_iter()
.map(|(k, v)| {
(
Expand All @@ -1409,7 +1413,7 @@ impl OlmMachine {
.collect(),
)
})
.collect()
.collect())
}

/// Check if the given backup has been verified by us or by another of our
Expand Down
20 changes: 10 additions & 10 deletions crates/matrix-sdk-crypto/src/backups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ use tokio::sync::RwLock;
use tracing::{debug, info, instrument, trace, warn};

use crate::{
olm::{Account, InboundGroupSession, SignedJsonObject},
olm::{InboundGroupSession, SignedJsonObject, StaticAccountData},
store::{BackupDecryptionKey, BackupKeys, Changes, RoomKeyCounts, Store},
types::{MegolmV1AuthData, RoomKeyBackupInfo, Signatures},
CryptoStoreError, Device, KeysBackupRequest, OutgoingRequest,
Expand All @@ -54,7 +54,7 @@ pub use keys::{DecodeError, DecryptionError, MegolmV1BackupKey};
/// using the [`BackupMachine::backup`] method.
#[derive(Debug, Clone)]
pub struct BackupMachine {
account: Account,
account: StaticAccountData,
store: Store,
backup_key: Arc<RwLock<Option<MegolmV1BackupKey>>>,
pending_backup: Arc<RwLock<Option<PendingBackup>>>,
Expand Down Expand Up @@ -146,7 +146,7 @@ impl BackupMachine {
const BACKUP_BATCH_SIZE: usize = 100;

pub(crate) fn new(
account: Account,
account: StaticAccountData,
store: Store,
backup_key: Option<MegolmV1BackupKey>,
) -> Self {
Expand All @@ -169,7 +169,7 @@ impl BackupMachine {
signatures: &Signatures,
auth_data: &str,
) -> SignatureState {
match self.account.static_data.has_signed_raw(signatures, auth_data) {
match self.account.has_signed_raw(signatures, auth_data) {
Ok(_) => SignatureState::ValidAndTrusted,
Err(e) => match e {
crate::SignatureError::NoSignatureFound => SignatureState::Missing,
Expand All @@ -185,7 +185,7 @@ impl BackupMachine {
signatures: &Signatures,
auth_data: &str,
) -> Result<SignatureState, CryptoStoreError> {
let user_id = &self.account.static_data.user_id;
let user_id = &self.account.user_id;
let identity = self.store.get_identity(user_id).await?;

let ret = if let Some(identity) = identity.and_then(|i| i.own()) {
Expand Down Expand Up @@ -238,12 +238,12 @@ impl BackupMachine {
) -> Result<BTreeMap<OwnedDeviceId, SignatureState>, CryptoStoreError> {
let mut result = BTreeMap::new();

if let Some(user_signatures) = signatures.get(&self.account.static_data.user_id) {
if let Some(user_signatures) = signatures.get(&self.account.user_id) {
for device_key_id in user_signatures.keys() {
if device_key_id.algorithm() == DeviceKeyAlgorithm::Ed25519 {
// No need to check our own device here, we're doing that using
// the check_own_device_signature().
if device_key_id.device_id() == self.account.static_data.device_id {
if device_key_id.device_id() == self.account.device_id {
continue;
}

Expand Down Expand Up @@ -648,7 +648,7 @@ mod tests {
}

#[async_test]
async fn verify_auth_data() -> Result<(), OlmError> {
async fn test_verify_auth_data() -> Result<(), OlmError> {
let machine = OlmMachine::new(alice_id(), alice_device_id()).await;
let backup_machine = machine.backup_machine();

Expand Down Expand Up @@ -676,7 +676,7 @@ mod tests {
assert!(!state.user_identity_signature.trusted());
assert!(!state.other_signatures.values().any(|s| s.trusted()));

let signatures = machine.sign(&serialized).await;
let signatures = machine.sign(&serialized).await?;

let backup_version = json!({
"algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
Expand All @@ -702,7 +702,7 @@ mod tests {
.await
.expect("Bootstrapping a new identity always works");

let signatures = machine.sign(&serialized).await;
let signatures = machine.sign(&serialized).await?;

let backup_version = json!({
"algorithm": "m.megolm_backup.v1.curve25519-aes-sha2",
Expand Down
36 changes: 29 additions & 7 deletions crates/matrix-sdk-crypto/src/dehydrated_devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use crate::{
olm::Account,
store::{CryptoStoreWrapper, MemoryStore, RoomKeyInfo, Store},
verification::VerificationMachine,
EncryptionSyncChanges, OlmError, OlmMachine, ReadOnlyAccount, SignatureError,
CryptoStoreError, EncryptionSyncChanges, OlmError, OlmMachine, ReadOnlyAccount, SignatureError,
};

/// Error type for device dehydration issues.
Expand All @@ -69,13 +69,19 @@ pub enum DehydrationError {
/// The dehydrated device could not be unpickled.
#[error(transparent)]
Pickle(#[from] LibolmPickleError),

/// The dehydrated device could not be signed by our user identity,
/// we're missing the self-signing key.
#[error("The self-signing key is missing, can't create a dehydrated device")]
MissingSigningKey(#[from] SignatureError),

/// We could not deserialize the dehydrated device data.
#[error(transparent)]
Json(#[from] serde_json::Error),

/// The store ran into an error.
#[error(transparent)]
Store(#[from] CryptoStoreError),
}

/// Struct collecting methods to create and rehydrate dehydrated devices.
Expand All @@ -98,9 +104,11 @@ impl DehydratedDevices {
user_identity.clone(),
store.clone(),
);
let store = Store::new(account.clone(), user_identity, store, verification_machine);

let account = Account { static_data: account.static_data().clone(), store };
let static_account = account.static_data().clone();
let store = Store::new(account, user_identity, store, verification_machine);

let account = Account { static_data: static_account, store };

DehydratedDevice { account }
}
Expand Down Expand Up @@ -234,7 +242,12 @@ impl RehydratedDevice {

// Let us first give the events to the rehydrated device, this will decrypt any
// encrypted to-device events and fetch out the room keys.
let (_, changes) = self.rehydrated.preprocess_sync_changes(sync_changes).await?;
let mut rehydrated_transaction = self.rehydrated.store().transaction().await?;

let (_, changes) = self
.rehydrated
.preprocess_sync_changes(&mut rehydrated_transaction, sync_changes)
.await?;

// Now take the room keys and persist them in our original `OlmMachine`.
let room_keys = &changes.inbound_group_sessions;
Expand All @@ -243,6 +256,8 @@ impl RehydratedDevice {
trace!(room_key_count = room_keys.len(), "Collected room keys from the rehydrated device");

self.original.store().save_inbound_group_sessions(room_keys).await?;

rehydrated_transaction.commit().await?;
self.rehydrated.store().save_changes(changes).await?;

Ok(updates)
Expand Down Expand Up @@ -302,8 +317,11 @@ impl DehydratedDevice {
initial_device_display_name: String,
pickle_key: &[u8; 32],
) -> Result<put_dehydrated_device::unstable::Request, DehydrationError> {
let account = self.account.store.account();
let mut transaction = self.account.store.transaction().await?;

let account = transaction.account().await?;
account.generate_fallback_key_helper().await;

let (device_keys, one_time_keys, fallback_keys) = account.keys_for_upload().await;

let mut device_keys = device_keys
Expand All @@ -324,6 +342,8 @@ impl DehydratedDevice {
let device_data = account.dehydrate(&pickle_key).await;
let initial_device_display_name = Some(initial_device_display_name);

transaction.commit().await?;

Ok(
assign!(put_dehydrated_device::unstable::Request::new(device_id, device_data, device_keys.to_raw()), {
one_time_keys, fallback_keys, initial_device_display_name
Expand Down Expand Up @@ -374,7 +394,9 @@ mod tests {
};

use crate::{
machine::tests::{create_session, get_prepared_machine, to_device_requests_to_content},
machine::tests::{
create_session, get_prepared_machine_test_helper, to_device_requests_to_content,
},
olm::OutboundGroupSession,
types::events::ToDeviceEvent,
utilities::json_convert,
Expand All @@ -388,7 +410,7 @@ mod tests {
}

async fn get_olm_machine() -> OlmMachine {
let (olm_machine, _) = get_prepared_machine(user_id(), false).await;
let (olm_machine, _) = get_prepared_machine_test_helper(user_id(), false).await;
olm_machine.bootstrap_cross_signing(false).await.unwrap();

olm_machine
Expand Down
4 changes: 4 additions & 0 deletions crates/matrix-sdk-crypto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ pub enum SignatureError {
/// The signed object couldn't be deserialized.
#[error(transparent)]
JsonError(#[from] CanonicalJsonError),

/// The store ran into an error.
#[error(transparent)]
StoreError(#[from] CryptoStoreError),
}

impl From<SerdeError> for SignatureError {
Expand Down
8 changes: 5 additions & 3 deletions crates/matrix-sdk-crypto/src/file_encryption/key_export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,9 @@ mod tests {
base64_decode, decrypt_helper, decrypt_room_key_export, encrypt_helper,
encrypt_room_key_export,
};
use crate::{error::OlmResult, machine::tests::get_prepared_machine, RoomKeyImportResult};
use crate::{
error::OlmResult, machine::tests::get_prepared_machine_test_helper, RoomKeyImportResult,
};

const PASSPHRASE: &str = "1234";

Expand Down Expand Up @@ -287,7 +289,7 @@ mod tests {
#[async_test]
async fn test_session_encrypt() {
let user_id = user_id!("@alice:localhost");
let (machine, _) = get_prepared_machine(user_id, false).await;
let (machine, _) = get_prepared_machine_test_helper(user_id, false).await;
let room_id = room_id!("!test:localhost");

machine.create_outbound_group_session_with_defaults(room_id).await.unwrap();
Expand All @@ -312,7 +314,7 @@ mod tests {
async fn test_importing_better_session() -> OlmResult<()> {
let user_id = user_id!("@alice:localhost");

let (machine, _) = get_prepared_machine(user_id, false).await;
let (machine, _) = get_prepared_machine_test_helper(user_id, false).await;
let room_id = room_id!("!test:localhost");
let session = machine.create_inbound_session(room_id).await?;

Expand Down
Loading