Merge remote-tracking branch 'upstream/main' into ben-wasm-store

This commit is contained in:
Benjamin Kampmann
2022-02-02 12:16:49 +01:00
55 changed files with 1206 additions and 458 deletions

View File

@@ -29,4 +29,8 @@ thiserror = "1.0.25"
[dependencies.ruma-identifiers]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
[dependencies.ruma-serde]
git = "https://github.com/ruma/ruma/"
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"

View File

@@ -22,6 +22,7 @@ use byteorder::{BigEndian, ReadBytesExt};
use image::{DynamicImage, GenericImage, GenericImageView, ImageBuffer, Luma};
use qrcode::QrCode;
use ruma_identifiers::EventId;
use ruma_serde::Base64;
#[cfg(feature = "decode_image")]
use crate::utils::decode_qr;
@@ -312,7 +313,7 @@ impl QrVerificationData {
let first_key = base_64_encode(&first_key);
let second_key = base_64_encode(&second_key);
let flow_id = String::from_utf8(flow_id)?;
let shared_secret = base_64_encode(&shared_secret);
let shared_secret = Base64::new(shared_secret);
match mode {
VerificationData::QR_MODE => {
@@ -360,7 +361,7 @@ impl QrVerificationData {
}
/// Get the secret of this `QrVerificationData`.
pub fn secret(&self) -> &str {
pub fn secret(&self) -> &Base64 {
match self {
QrVerificationData::Verification(v) => &v.shared_secret,
QrVerificationData::SelfVerification(v) => &v.shared_secret,
@@ -378,7 +379,7 @@ pub struct VerificationData {
event_id: Box<EventId>,
first_master_key: String,
second_master_key: String,
shared_secret: String,
shared_secret: Base64,
}
impl VerificationData {
@@ -401,7 +402,7 @@ impl VerificationData {
event_id: Box<EventId>,
first_key: String,
second_key: String,
shared_secret: String,
shared_secret: Base64,
) -> Self {
Self { event_id, first_master_key: first_key, second_master_key: second_key, shared_secret }
}
@@ -477,7 +478,7 @@ pub struct SelfVerificationData {
transaction_id: String,
master_key: String,
device_key: String,
shared_secret: String,
shared_secret: Base64,
}
impl SelfVerificationData {
@@ -504,7 +505,7 @@ impl SelfVerificationData {
transaction_id: String,
master_key: String,
device_key: String,
shared_secret: String,
shared_secret: Base64,
) -> Self {
Self { transaction_id, master_key, device_key, shared_secret }
}
@@ -580,7 +581,7 @@ pub struct SelfVerificationNoMasterKey {
transaction_id: String,
device_key: String,
master_key: String,
shared_secret: String,
shared_secret: Base64,
}
impl SelfVerificationNoMasterKey {
@@ -607,7 +608,7 @@ impl SelfVerificationNoMasterKey {
transaction_id: String,
device_key: String,
master_key: String,
shared_secret: String,
shared_secret: Base64,
) -> Self {
Self { transaction_id, device_key, master_key, shared_secret }
}

View File

@@ -18,6 +18,7 @@ use base64::{decode_config, encode_config, STANDARD_NO_PAD};
#[cfg(feature = "decode_image")]
use image::{GenericImage, GenericImageView, Luma};
use qrcode::{bits::Bits, EcLevel, QrCode, Version};
use ruma_serde::Base64;
#[cfg(feature = "decode_image")]
use crate::error::DecodingError;
@@ -41,14 +42,13 @@ pub(crate) fn to_bytes(
flow_id: &str,
first_key: &str,
second_key: &str,
shared_secret: &str,
shared_secret: &Base64,
) -> Result<Vec<u8>, EncodingError> {
let flow_id_len: u16 = flow_id.len().try_into()?;
let flow_id_len = flow_id_len.to_be_bytes();
let first_key = base64_decode(first_key)?;
let second_key = base64_decode(second_key)?;
let shared_secret = base64_decode(shared_secret)?;
let data = [
HEADER,
@@ -58,7 +58,7 @@ pub(crate) fn to_bytes(
flow_id.as_bytes(),
&first_key,
&second_key,
&shared_secret,
shared_secret.as_bytes(),
]
.concat();
@@ -70,7 +70,7 @@ pub(crate) fn to_qr_code(
flow_id: &str,
first_key: &str,
second_key: &str,
shared_secret: &str,
shared_secret: &Base64,
) -> Result<QrCode, EncodingError> {
let data = to_bytes(mode, flow_id, first_key, second_key, shared_secret)?;

View File

@@ -38,7 +38,7 @@ warp = { version = "0.3.1", optional = true, default-features = false }
[dependencies.ruma]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
features = ["client-api-c", "appservice-api-s", "unstable-pre-spec"]
[dev-dependencies]

View File

@@ -36,13 +36,8 @@ async fn appservice(registration: Option<Registration>) -> Result<AppService> {
let client_config =
ClientConfig::default().request_config(RequestConfig::default().disable_retry());
Ok(AppService::new_with_config(
homeserver_url.as_ref(),
server_name,
registration,
client_config,
)
.await?)
AppService::new_with_config(homeserver_url.as_ref(), server_name, registration, client_config)
.await
}
#[async_test]

View File

@@ -61,7 +61,7 @@ wasm-bindgen = { version = "0.2.74", features = ["serde-serialize"], optional =
[dependencies.ruma]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
features = ["client-api-c", "unstable-pre-spec"]
[dev-dependencies]

View File

@@ -25,6 +25,8 @@ use std::{
sync::Arc,
};
#[cfg(feature = "encryption")]
use matrix_sdk_common::locks::Mutex;
use matrix_sdk_common::{
deserialized_responses::{
AmbiguityChanges, JoinedRoom, LeftRoom, MemberEvent, MembersResponse, Rooms,
@@ -35,8 +37,6 @@ use matrix_sdk_common::{
util::milli_seconds_since_unix_epoch,
};
#[cfg(feature = "encryption")]
use matrix_sdk_common::{locks::Mutex, uuid::Uuid};
#[cfg(feature = "encryption")]
use matrix_sdk_crypto::{
store::{CryptoStore, CryptoStoreError},
Device, EncryptionSettings, IncomingResponse, MegolmError, OlmError, OlmMachine,
@@ -49,7 +49,7 @@ use ruma::{
room::{encrypted::RoomEncryptedEventContent, history_visibility::HistoryVisibility},
AnySyncMessageEvent, MessageEventContent,
},
DeviceId,
DeviceId, TransactionId,
};
use ruma::{
api::client::r0::{self as api, push::get_notifications::Notification},
@@ -1115,7 +1115,7 @@ impl BaseClient {
#[cfg(feature = "encryption")]
pub async fn mark_request_as_sent<'a>(
&self,
request_id: &Uuid,
request_id: &TransactionId,
response: impl Into<IncomingResponse<'a>>,
) -> Result<()> {
let olm = self.olm.lock().await;
@@ -1133,7 +1133,7 @@ impl BaseClient {
pub async fn get_missing_sessions(
&self,
users: impl Iterator<Item = &UserId>,
) -> Result<Option<(Uuid, KeysClaimRequest)>> {
) -> Result<Option<(Box<TransactionId>, KeysClaimRequest)>> {
let olm = self.olm.lock().await;
match &*olm {

View File

@@ -4,29 +4,36 @@ macro_rules! statestore_integration_tests {
($($name:ident)*) => {
$(
mod $name {
use matrix_sdk_test::async_test;
use matrix_sdk_test::{async_test, test_json};
use ruma::{
api::client::r0::media::get_content_thumbnail::Method,
event_id,
device_id, event_id,
events::{
presence::PresenceEvent, EventContent,
room::{
member::{MembershipState, RoomMemberEventContent},
power_levels::RoomPowerLevelsEventContent,
},
AnyEphemeralRoomEventContent, AnySyncEphemeralRoomEvent, AnyStrippedStateEvent,
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
AnySyncStateEvent, EventType, Unsigned,
},
mxc_uri,
receipt::ReceiptType,
room_id,
serde::Raw,
uint, user_id, MilliSecondsSinceUnixEpoch, UserId, EventId,
uint, user_id, MilliSecondsSinceUnixEpoch, UserId, EventId, RoomId,
};
use serde_json::json;
use serde_json::{json, Value as JsonValue};
use std::collections::{BTreeMap, BTreeSet};
use crate::{
deserialized_responses::MemberEvent,
RoomType, Session,
deserialized_responses::{MemberEvent, StrippedMemberEvent},
media::{MediaFormat, MediaRequest, MediaThumbnailSize, MediaType},
store::{
Store,
StateStore,
Result,
StateChanges
@@ -39,6 +46,155 @@ macro_rules! statestore_integration_tests {
fn user_id() -> &'static UserId {
user_id!("@example:localhost")
}
pub(crate) fn invited_user_id() -> &'static UserId {
user_id!("@invited:localhost")
}
pub(crate) fn room_id() -> &'static RoomId {
room_id!("!test:localhost")
}
pub(crate) fn stripped_room_id() -> &'static RoomId {
room_id!("!stripped:localhost")
}
pub(crate) fn first_receipt_event_id() -> &'static EventId {
event_id!("$example")
}
/// Populate the given `StateStore`.
pub(crate) async fn populated_store(inner: Box<dyn StateStore>) -> Result<Store> {
let mut changes = StateChanges::default();
let store = Store::new(inner);
let user_id = user_id();
let invited_user_id = invited_user_id();
let room_id = room_id();
let stripped_room_id = stripped_room_id();
let device_id = device_id!("device");
let session = Session {
access_token: "token".to_string(),
user_id: user_id.to_owned(),
device_id: device_id.to_owned(),
};
store.restore_session(session).await.unwrap();
changes.sync_token = Some("t392-516_47314_0_7_1_1_1_11444_1".to_string());
let presence_json: &JsonValue = &test_json::PRESENCE;
let presence_raw =
serde_json::from_value::<Raw<PresenceEvent>>(presence_json.clone()).unwrap();
let presence_event = presence_raw.deserialize().unwrap();
changes.add_presence_event(presence_event, presence_raw);
let pushrules_json: &JsonValue = &test_json::PUSH_RULES;
let pushrules_raw =
serde_json::from_value::<Raw<AnyGlobalAccountDataEvent>>(pushrules_json.clone())
.unwrap();
let pushrules_event = pushrules_raw.deserialize().unwrap();
changes.add_account_data(pushrules_event, pushrules_raw);
let mut room = store.get_or_create_room(room_id, RoomType::Joined).await.clone_info();
room.mark_as_left();
let tag_json: &JsonValue = &test_json::TAG;
let tag_raw =
serde_json::from_value::<Raw<AnyRoomAccountDataEvent>>(tag_json.clone()).unwrap();
let tag_event = tag_raw.deserialize().unwrap();
changes.add_room_account_data(room_id, tag_event, tag_raw);
let name_json: &JsonValue = &test_json::NAME;
let name_raw = serde_json::from_value::<Raw<AnySyncStateEvent>>(name_json.clone()).unwrap();
let name_event = name_raw.deserialize().unwrap();
room.handle_state_event(&name_event.content());
changes.add_state_event(room_id, name_event, name_raw);
let topic_json: &JsonValue = &test_json::TOPIC;
let topic_raw =
serde_json::from_value::<Raw<AnySyncStateEvent>>(topic_json.clone()).unwrap();
let topic_event = topic_raw.deserialize().unwrap();
room.handle_state_event(&topic_event.content());
changes.add_state_event(room_id, topic_event, topic_raw);
let mut room_ambiguity_map = BTreeMap::new();
let mut room_profiles = BTreeMap::new();
let mut room_members = BTreeMap::new();
let member_json: &JsonValue = &test_json::MEMBER;
let member_event = serde_json::from_value::<MemberEvent>(member_json.clone()).unwrap();
let member_event_content = member_event.content.clone();
room_ambiguity_map.insert(
member_event_content.displayname.clone().unwrap(),
BTreeSet::from([user_id.to_owned()]),
);
room_profiles.insert(user_id.to_owned(), member_event.content.clone());
room_members.insert(user_id.to_owned(), member_event);
let member_state_raw =
serde_json::from_value::<Raw<AnySyncStateEvent>>(member_json.clone()).unwrap();
let member_state_event = member_state_raw.deserialize().unwrap();
changes.add_state_event(room_id, member_state_event, member_state_raw);
let invited_member_json: &JsonValue = &test_json::MEMBER_INVITE;
let invited_member_event =
serde_json::from_value::<MemberEvent>(invited_member_json.clone()).unwrap();
room_ambiguity_map
.entry(member_event_content.displayname.clone().unwrap())
.or_default()
.insert(invited_user_id.to_owned());
room_profiles.insert(invited_user_id.to_owned(), invited_member_event.content.clone());
room_members.insert(invited_user_id.to_owned(), invited_member_event);
let invited_member_state_raw =
serde_json::from_value::<Raw<AnySyncStateEvent>>(invited_member_json.clone()).unwrap();
let invited_member_state_event = invited_member_state_raw.deserialize().unwrap();
changes.add_state_event(room_id, invited_member_state_event, invited_member_state_raw);
let receipt_json: &JsonValue = &test_json::READ_RECEIPT;
let receipt_event =
serde_json::from_value::<AnySyncEphemeralRoomEvent>(receipt_json.clone()).unwrap();
let receipt_content = match receipt_event.content() {
AnyEphemeralRoomEventContent::Receipt(content) => content,
_ => panic!(),
};
changes.add_receipts(room_id, receipt_content);
changes.ambiguity_maps.insert(room_id.to_owned(), room_ambiguity_map);
changes.profiles.insert(room_id.to_owned(), room_profiles);
changes.members.insert(room_id.to_owned(), room_members);
changes.add_room(room);
let mut stripped_room =
store.get_or_create_stripped_room(stripped_room_id).await.clone_info();
let stripped_name_json: &JsonValue = &test_json::NAME_STRIPPED;
let stripped_name_raw =
serde_json::from_value::<Raw<AnyStrippedStateEvent>>(stripped_name_json.clone())
.unwrap();
let stripped_name_event = stripped_name_raw.deserialize().unwrap();
stripped_room.handle_state_event(&stripped_name_event.content());
changes.stripped_state.insert(
stripped_room_id.to_owned(),
BTreeMap::from([(
stripped_name_event.content().event_type().to_owned(),
BTreeMap::from([(
stripped_name_event.state_key().to_owned(),
stripped_name_raw.clone(),
)]),
)]),
);
changes.invited_room_info.insert(stripped_room_id.to_owned(), stripped_room.clone());
changes.add_stripped_room(stripped_room);
let stripped_member_json: &JsonValue = &test_json::MEMBER_STRIPPED;
let stripped_member_event =
serde_json::from_value::<StrippedMemberEvent>(stripped_member_json.clone()).unwrap();
changes.add_stripped_member(stripped_room_id, stripped_member_event);
store.save_changes(&changes).await?;
Ok(store)
}
fn power_level_event() -> Raw<AnySyncStateEvent> {
let content = RoomPowerLevelsEventContent::default();
@@ -265,6 +421,53 @@ macro_rules! statestore_integration_tests {
Ok(())
}
#[async_test]
async fn test_room_removal() -> Result<()> {
let room_id = room_id();
let user_id = user_id();
let inner_store = get_store().await?;
let stripped_room_id = stripped_room_id();
let store = populated_store(Box::new(inner_store)).await?;
// We assume the store was correctly populated like the test above.
store.remove_room(room_id).await?;
assert_eq!(store.get_room_infos().await?.len(), 1);
assert_eq!(store.get_stripped_room_infos().await?.len(), 1);
assert!(store.get_state_event(room_id, EventType::RoomName, "").await?.is_none());
assert_eq!(store.get_state_events(room_id, EventType::RoomTopic).await?.len(), 0);
assert!(store.get_profile(room_id, user_id).await?.is_none());
assert!(store.get_member_event(room_id, user_id).await?.is_none());
assert_eq!(store.get_user_ids(room_id).await?.len(), 0);
assert_eq!(store.get_invited_user_ids(room_id).await?.len(), 0);
assert_eq!(store.get_joined_user_ids(room_id).await?.len(), 0);
assert_eq!(store.get_users_with_display_name(room_id, "example").await?.len(), 0);
assert!(store
.get_room_account_data_event(room_id, EventType::Tag)
.await?
.is_none());
assert!(store
.get_user_room_receipt_event(room_id, ReceiptType::Read, user_id)
.await?
.is_none());
assert_eq!(
store
.get_event_room_receipt_events(room_id, ReceiptType::Read, first_receipt_event_id())
.await?
.len(),
0
);
store.remove_room(stripped_room_id).await?;
assert_eq!(store.get_room_infos().await?.len(), 0);
assert_eq!(store.get_stripped_room_infos().await?.len(), 0);
Ok(())
}
}
)*
}

View File

@@ -440,6 +440,24 @@ impl MemoryStore {
Ok(())
}
async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
self.members.remove(room_id);
self.profiles.remove(room_id);
self.display_names.remove(room_id);
self.joined_user_ids.remove(room_id);
self.invited_user_ids.remove(room_id);
self.room_info.remove(room_id);
self.room_state.remove(room_id);
self.room_account_data.remove(room_id);
self.stripped_room_info.remove(room_id);
self.stripped_room_state.remove(room_id);
self.stripped_members.remove(room_id);
self.room_user_receipts.remove(room_id);
self.room_event_receipts.remove(room_id);
Ok(())
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@@ -586,6 +604,10 @@ impl StateStore for MemoryStore {
async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()> {
self.remove_media_content_for_uri(uri).await
}
async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
self.remove_room(room_id).await
}
}
#[cfg(test)]

View File

@@ -347,6 +347,13 @@ pub trait StateStore: AsyncTraitDeps {
///
/// * `uri` - The `MxcUri` of the media files.
async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()>;
/// Removes a room and all elements associated from the state store.
///
/// # Arguments
///
/// * `room_id` - The `RoomId` of the room to delete.
async fn remove_room(&self, room_id: &RoomId) -> Result<()>;
}
/// A state store wrapper for the SDK.
@@ -628,4 +635,4 @@ impl StateChanges {
pub fn add_receipts(&mut self, room_id: &RoomId, event: ReceiptEventContent) {
self.receipts.insert(room_id.to_owned(), event);
}
}
}

View File

@@ -91,19 +91,37 @@ trait EncodeKey {
fn encode(&self) -> Vec<u8>;
}
impl EncodeKey for &UserId {
impl<T: EncodeKey> EncodeKey for &T {
fn encode(&self) -> Vec<u8> {
T::encode(self)
}
}
impl<T: EncodeKey> EncodeKey for Box<T> {
fn encode(&self) -> Vec<u8> {
T::encode(self)
}
}
impl EncodeKey for UserId {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
impl EncodeKey for &RoomId {
impl EncodeKey for RoomId {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
impl EncodeKey for &str {
impl EncodeKey for String {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
impl EncodeKey for str {
fn encode(&self) -> Vec<u8> {
[self.as_bytes(), &[ENCODE_SEPARATOR]].concat()
}
@@ -423,7 +441,7 @@ impl SledStore {
for (event_type, event) in &changes.account_data {
account_data.insert(
event_type.as_str().encode(),
event_type.encode(),
self.serialize_event(&event)
.map_err(ConflictableTransactionError::Abort)?,
)?;
@@ -454,7 +472,7 @@ impl SledStore {
for (room_id, room_info) in &changes.room_infos {
rooms.insert(
(&**room_id).encode(),
room_id.encode(),
self.serialize_event(room_info)
.map_err(ConflictableTransactionError::Abort)?,
)?;
@@ -462,7 +480,7 @@ impl SledStore {
for (sender, event) in &changes.presence {
presence.insert(
(&**sender).encode(),
sender.encode(),
self.serialize_event(&event)
.map_err(ConflictableTransactionError::Abort)?,
)?;
@@ -470,7 +488,7 @@ impl SledStore {
for (room_id, info) in &changes.invited_room_info {
striped_rooms.insert(
(&**room_id).encode(),
room_id.encode(),
self.serialize_event(&info)
.map_err(ConflictableTransactionError::Abort)?,
)?;
@@ -844,6 +862,121 @@ impl SledStore {
Ok(self.media.apply_batch(batch)?)
}
async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
let room_key = room_id.encode();
let mut members_batch = sled::Batch::default();
for key in self.members.scan_prefix(room_key.as_slice()).keys() {
members_batch.remove(key?)
}
let mut profiles_batch = sled::Batch::default();
for key in self.profiles.scan_prefix(room_key.as_slice()).keys() {
profiles_batch.remove(key?)
}
let mut display_names_batch = sled::Batch::default();
for key in self.display_names.scan_prefix(room_key.as_slice()).keys() {
display_names_batch.remove(key?)
}
let mut joined_user_ids_batch = sled::Batch::default();
for key in self.joined_user_ids.scan_prefix(room_key.as_slice()).keys() {
joined_user_ids_batch.remove(key?)
}
let mut invited_user_ids_batch = sled::Batch::default();
for key in self.invited_user_ids.scan_prefix(room_key.as_slice()).keys() {
invited_user_ids_batch.remove(key?)
}
let mut room_state_batch = sled::Batch::default();
for key in self.room_state.scan_prefix(room_key.as_slice()).keys() {
room_state_batch.remove(key?)
}
let mut room_account_data_batch = sled::Batch::default();
for key in self.room_account_data.scan_prefix(room_key.as_slice()).keys() {
room_account_data_batch.remove(key?)
}
let mut stripped_members_batch = sled::Batch::default();
for key in self.stripped_members.scan_prefix(room_key.as_slice()).keys() {
stripped_members_batch.remove(key?)
}
let mut stripped_room_state_batch = sled::Batch::default();
for key in self.stripped_room_state.scan_prefix(room_key.as_slice()).keys() {
stripped_room_state_batch.remove(key?)
}
let mut room_user_receipts_batch = sled::Batch::default();
for key in self.room_user_receipts.scan_prefix(room_key.as_slice()).keys() {
room_user_receipts_batch.remove(key?)
}
let mut room_event_receipts_batch = sled::Batch::default();
for key in self.room_event_receipts.scan_prefix(room_key.as_slice()).keys() {
room_event_receipts_batch.remove(key?)
}
let ret: Result<(), TransactionError<SerializationError>> = (
&self.members,
&self.profiles,
&self.display_names,
&self.joined_user_ids,
&self.invited_user_ids,
&self.room_info,
&self.room_state,
&self.room_account_data,
&self.stripped_room_info,
&self.stripped_members,
&self.stripped_room_state,
&self.room_user_receipts,
&self.room_event_receipts,
)
.transaction(
|(
members,
profiles,
display_names,
joined,
invited,
rooms,
state,
room_account_data,
stripped_rooms,
stripped_members,
stripped_state,
room_user_receipts,
room_event_receipts,
)| {
rooms.remove(room_key.as_slice())?;
stripped_rooms.remove(room_key.as_slice())?;
members.apply_batch(&members_batch)?;
profiles.apply_batch(&profiles_batch)?;
display_names.apply_batch(&display_names_batch)?;
joined.apply_batch(&joined_user_ids_batch)?;
invited.apply_batch(&invited_user_ids_batch)?;
state.apply_batch(&room_state_batch)?;
room_account_data.apply_batch(&room_account_data_batch)?;
stripped_members.apply_batch(&stripped_members_batch)?;
stripped_state.apply_batch(&stripped_room_state_batch)?;
room_user_receipts.apply_batch(&room_user_receipts_batch)?;
room_event_receipts.apply_batch(&room_event_receipts_batch)?;
Ok(())
},
);
ret?;
self.inner.flush_async().await?;
Ok(())
}
}
#[async_trait]
@@ -985,6 +1118,10 @@ impl StateStore for SledStore {
async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()> {
self.remove_media_content_for_uri(uri).await
}
async fn remove_room(&self, room_id: &RoomId) -> Result<()> {
self.remove_room(room_id).await
}
}
#[cfg(test)]

View File

@@ -21,7 +21,7 @@ serde = "1.0.126"
[dependencies.ruma]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
features = ["client-api-c"]
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]

View File

@@ -10,7 +10,6 @@
pub use async_trait::async_trait;
pub use instant;
pub use uuid;
pub mod deserialized_responses;
pub mod executor;

View File

@@ -52,8 +52,8 @@ indexed_db_futures = { version = "0.2.0", optional = true }
wasm-bindgen = { version = "0.2.74", features = ["serde-serialize"], optional = true }
[dependencies.ruma]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
features = ["client-api-c", "unstable-pre-spec"]
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
features = ["client-api-c", "rand", "unstable-pre-spec"]
[dev-dependencies]
futures = { version = "0.3.15", default-features = false, features = ["executor"] }

View File

@@ -1,7 +1,6 @@
use std::{ops::Deref, sync::Arc};
use std::ops::Deref;
use criterion::*;
use matrix_sdk_common::uuid::Uuid;
use matrix_sdk_crypto::{EncryptionSettings, OlmMachine};
use matrix_sdk_test::response_from_file;
use ruma::{
@@ -12,7 +11,7 @@ use ruma::{
},
IncomingResponse,
},
device_id, room_id, user_id, DeviceId, UserId,
device_id, room_id, user_id, DeviceId, TransactionId, UserId,
};
use serde_json::Value;
use tokio::runtime::Builder;
@@ -51,7 +50,7 @@ pub fn keys_query(c: &mut Criterion) {
let runtime = Builder::new_multi_thread().build().expect("Can't create runtime");
let machine = OlmMachine::new(alice_id(), alice_device_id());
let response = keys_query_response();
let uuid = Uuid::new_v4();
let txn_id = TransactionId::new();
let count = response.device_keys.values().fold(0, |acc, d| acc + d.len())
+ response.master_keys.len()
@@ -65,7 +64,7 @@ pub fn keys_query(c: &mut Criterion) {
group.bench_with_input(BenchmarkId::new("memory store", &name), &response, |b, response| {
b.to_async(&runtime)
.iter(|| async { machine.mark_request_as_sent(&uuid, response).await.unwrap() })
.iter(|| async { machine.mark_request_as_sent(&txn_id, response).await.unwrap() })
});
let dir = tempfile::tempdir().unwrap();
@@ -80,17 +79,17 @@ pub fn keys_query(c: &mut Criterion) {
group.bench_with_input(BenchmarkId::new("sled store", &name), &response, |b, response| {
b.to_async(&runtime)
.iter(|| async { machine.mark_request_as_sent(&uuid, response).await.unwrap() })
.iter(|| async { machine.mark_request_as_sent(&txn_id, response).await.unwrap() })
});
group.finish()
}
pub fn keys_claiming(c: &mut Criterion) {
let runtime = Arc::new(Builder::new_multi_thread().build().expect("Can't create runtime"));
let runtime = Builder::new_multi_thread().build().expect("Can't create runtime");
let keys_query_response = keys_query_response();
let uuid = Uuid::new_v4();
let txn_id = TransactionId::new();
let response = keys_claim_response();
@@ -106,12 +105,12 @@ pub fn keys_claiming(c: &mut Criterion) {
|| {
let machine = OlmMachine::new(alice_id(), alice_device_id());
runtime
.block_on(machine.mark_request_as_sent(&uuid, &keys_query_response))
.block_on(machine.mark_request_as_sent(&txn_id, &keys_query_response))
.unwrap();
(machine, runtime.clone())
(machine, &runtime, &txn_id)
},
move |(machine, runtime)| {
runtime.block_on(machine.mark_request_as_sent(&uuid, response)).unwrap()
move |(machine, runtime, txn_id)| {
runtime.block_on(machine.mark_request_as_sent(txn_id, response)).unwrap()
},
BatchSize::SmallInput,
)
@@ -130,12 +129,12 @@ pub fn keys_claiming(c: &mut Criterion) {
))
.unwrap();
runtime
.block_on(machine.mark_request_as_sent(&uuid, &keys_query_response))
.block_on(machine.mark_request_as_sent(&txn_id, &keys_query_response))
.unwrap();
(machine, runtime.clone())
(machine, &runtime, &txn_id)
},
move |(machine, runtime)| {
runtime.block_on(machine.mark_request_as_sent(&uuid, response)).unwrap()
move |(machine, runtime, txn_id)| {
runtime.block_on(machine.mark_request_as_sent(txn_id, response)).unwrap()
},
BatchSize::SmallInput,
)
@@ -148,7 +147,7 @@ pub fn room_key_sharing(c: &mut Criterion) {
let runtime = Builder::new_multi_thread().build().expect("Can't create runtime");
let keys_query_response = keys_query_response();
let uuid = Uuid::new_v4();
let txn_id = TransactionId::new();
let response = keys_claim_response();
let room_id = room_id!("!test:localhost");
@@ -158,8 +157,8 @@ pub fn room_key_sharing(c: &mut Criterion) {
let count = response.one_time_keys.values().fold(0, |acc, d| acc + d.len());
let machine = OlmMachine::new(alice_id(), alice_device_id());
runtime.block_on(machine.mark_request_as_sent(&uuid, &keys_query_response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&uuid, &response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &keys_query_response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
let mut group = c.benchmark_group("Room key sharing");
group.throughput(Throughput::Elements(count as u64));
@@ -195,8 +194,8 @@ pub fn room_key_sharing(c: &mut Criterion) {
None,
))
.unwrap();
runtime.block_on(machine.mark_request_as_sent(&uuid, &keys_query_response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&uuid, &response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &keys_query_response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
group.bench_function(BenchmarkId::new("sled store", &name), |b| {
b.to_async(&runtime).iter(|| async {
@@ -227,7 +226,7 @@ pub fn devices_missing_sessions_collecting(c: &mut Criterion) {
let machine = OlmMachine::new(alice_id(), alice_device_id());
let response = huge_keys_query_response();
let uuid = Uuid::new_v4();
let txn_id = TransactionId::new();
let users: Vec<Box<UserId>> = response.device_keys.keys().cloned().collect();
let count = response.device_keys.values().fold(0, |acc, d| acc + d.len());
@@ -237,7 +236,7 @@ pub fn devices_missing_sessions_collecting(c: &mut Criterion) {
let name = format!("{} devices", count);
runtime.block_on(machine.mark_request_as_sent(&uuid, &response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
group.bench_function(BenchmarkId::new("memory store", &name), |b| {
b.to_async(&runtime).iter_with_large_drop(|| async {
@@ -255,7 +254,7 @@ pub fn devices_missing_sessions_collecting(c: &mut Criterion) {
))
.unwrap();
runtime.block_on(machine.mark_request_as_sent(&uuid, &response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
group.bench_function(BenchmarkId::new("sled store", &name), |b| {
b.to_async(&runtime).iter(|| async {

View File

@@ -28,10 +28,10 @@ use std::{
sync::Arc,
};
use matrix_sdk_common::{locks::RwLock, uuid::Uuid};
use matrix_sdk_common::locks::RwLock;
use ruma::{
api::client::r0::backup::RoomKeyBackup, serde::Raw, DeviceKeyAlgorithm, DeviceKeyId, RoomId,
UserId,
TransactionId, UserId,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
@@ -64,7 +64,7 @@ pub struct BackupMachine {
#[derive(Debug, Clone)]
struct PendingBackup {
request_id: Uuid,
request_id: &TransactionId,
request: KeysBackupRequest,
sessions: BTreeMap<Box<RoomId>, BTreeMap<String, BTreeSet<String>>>,
}
@@ -259,7 +259,7 @@ impl BackupMachine {
pub(crate) async fn mark_request_as_sent(
&self,
request_id: Uuid,
request_id: &TransactionId,
) -> Result<(), CryptoStoreError> {
let mut request = self.pending_backup.write().await;
@@ -325,7 +325,7 @@ impl BackupMachine {
);
let request = PendingBackup {
request_id: Uuid::new_v4(),
request_id: TransactionId::new(),
request: KeysBackupRequest { version, rooms: backup },
sessions: session_record,
};

View File

@@ -23,14 +23,15 @@ use aes::{
};
use base64::DecodeError;
use getrandom::getrandom;
use ruma::events::room::{EncryptedFile, JsonWebKey, JsonWebKeyInit};
use ruma::{
events::room::{EncryptedFile, JsonWebKey, JsonWebKeyInit},
serde::Base64,
};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use thiserror::Error;
use zeroize::Zeroizing;
use crate::utilities::{decode, decode_url_safe, encode, encode_url_safe};
const IV_SIZE: usize = 16;
const KEY_SIZE: usize = 32;
const VERSION: &str = "v2";
@@ -131,9 +132,10 @@ impl<'a, R: Read + 'a> AttachmentDecryptor<'a, R> {
return Err(DecryptorError::UnknownVersion);
}
let hash = decode(info.hashes.get("sha256").ok_or(DecryptorError::MissingHash)?)?;
let key = Zeroizing::from(decode_url_safe(info.web_key.k)?);
let iv = decode(info.iv)?;
let hash =
info.hashes.get("sha256").ok_or(DecryptorError::MissingHash)?.as_bytes().to_owned();
let key = Zeroizing::from(info.web_key.k.into_inner());
let iv = info.iv.into_inner();
let iv = GenericArray::from_exact_iter(iv).ok_or(DecryptorError::KeyNonceLength)?;
let sha = Sha256::default();
@@ -149,8 +151,8 @@ pub struct AttachmentEncryptor<'a, R: Read + 'a> {
finished: bool,
inner: &'a mut R,
web_key: JsonWebKey,
iv: String,
hashes: BTreeMap<String, String>,
iv: Base64,
hashes: BTreeMap<String, Base64>,
aes: Aes256Ctr,
sha: Sha256,
}
@@ -170,7 +172,9 @@ impl<'a, R: Read + 'a> Read for AttachmentEncryptor<'a, R> {
if read_bytes == 0 {
let hash = self.sha.finalize_reset();
self.hashes.entry("sha256".to_owned()).or_insert_with(|| encode(hash));
self.hashes
.entry("sha256".to_owned())
.or_insert_with(|| Base64::new(hash.as_slice().to_owned()));
Ok(0)
} else {
self.aes.apply_keystream(&mut buf[0..read_bytes]);
@@ -223,10 +227,10 @@ impl<'a, R: Read + 'a> AttachmentEncryptor<'a, R> {
kty: "oct".to_owned(),
key_ops: vec!["encrypt".to_owned(), "decrypt".to_owned()],
alg: "A256CTR".to_owned(),
k: encode_url_safe(&*key),
k: Base64::new((*key).to_vec()),
ext: true,
});
let encoded_iv = encode(&*iv);
let encoded_iv = Base64::new((*iv).to_vec());
let iv = GenericArray::from_slice(&*iv);
let key = GenericArray::from_slice(&*key);
@@ -247,7 +251,9 @@ impl<'a, R: Read + 'a> AttachmentEncryptor<'a, R> {
/// Consume the encryptor and get the encryption key.
pub fn finish(mut self) -> MediaEncryptionInfo {
let hash = self.sha.finalize();
self.hashes.entry("sha256".to_owned()).or_insert_with(|| encode(hash));
self.hashes
.entry("sha256".to_owned())
.or_insert_with(|| Base64::new(hash.as_slice().to_owned()));
MediaEncryptionInfo {
version: VERSION.to_string(),
@@ -268,9 +274,9 @@ pub struct MediaEncryptionInfo {
/// The web key that was used to encrypt the file.
pub web_key: JsonWebKey,
/// The initialization vector that was used to encrypt the file.
pub iv: String,
pub iv: Base64,
/// The hashes that can be used to check the validity of the file.
pub hashes: BTreeMap<String, String>,
pub hashes: BTreeMap<String, Base64>,
}
impl From<EncryptedFile> for MediaEncryptionInfo {

View File

@@ -23,7 +23,6 @@
use std::{collections::BTreeMap, sync::Arc};
use dashmap::{mapref::entry::Entry, DashMap, DashSet};
use matrix_sdk_common::uuid::Uuid;
use ruma::{
api::client::r0::keys::claim_keys::Request as KeysClaimRequest,
events::{
@@ -40,7 +39,7 @@ use ruma::{
},
AnyToDeviceEvent, AnyToDeviceEventContent,
},
DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, TransactionId, UserId,
};
use tracing::{debug, info, trace, warn};
@@ -60,7 +59,7 @@ pub(crate) struct GossipMachine {
device_id: Arc<DeviceId>,
store: Store,
outbound_group_sessions: GroupSessionCache,
outgoing_requests: Arc<DashMap<Uuid, OutgoingRequest>>,
outgoing_requests: Arc<DashMap<Box<TransactionId>, OutgoingRequest>>,
incoming_key_requests: Arc<DashMap<RequestInfo, RequestEvent>>,
wait_queue: WaitQueue,
users_for_key_claim: Arc<DashMap<Box<UserId>, DashSet<Box<DeviceId>>>>,
@@ -133,7 +132,7 @@ impl GossipMachine {
if !users_for_key_claim.is_empty() {
let key_claim_request = KeysClaimRequest::new(users_for_key_claim);
key_requests.push(OutgoingRequest {
request_id: Uuid::new_v4(),
request_id: TransactionId::new(),
request: Arc::new(key_claim_request.into()),
});
}
@@ -439,9 +438,11 @@ impl GossipMachine {
AnyToDeviceEventContent::RoomEncrypted(content),
);
let request =
OutgoingRequest { request_id: request.txn_id, request: Arc::new(request.into()) };
self.outgoing_requests.insert(request.request_id, request);
let request = OutgoingRequest {
request_id: request.txn_id.clone(),
request: Arc::new(request.into()),
};
self.outgoing_requests.insert(request.request_id.clone(), request);
Ok(used_session)
}
@@ -461,9 +462,11 @@ impl GossipMachine {
AnyToDeviceEventContent::RoomEncrypted(content),
);
let request =
OutgoingRequest { request_id: request.txn_id, request: Arc::new(request.into()) };
self.outgoing_requests.insert(request.request_id, request);
let request = OutgoingRequest {
request_id: request.txn_id.clone(),
request: Arc::new(request.into()),
};
self.outgoing_requests.insert(request.request_id.clone(), request);
Ok(used_session)
}
@@ -633,7 +636,7 @@ impl GossipMachine {
) -> Result<OutgoingRequest, CryptoStoreError> {
let request = GossipRequest {
request_recipient: self.user_id().to_owned(),
request_id: Uuid::new_v4(),
request_id: TransactionId::new(),
info: key_info,
sent_out: false,
};
@@ -707,11 +710,14 @@ impl GossipMachine {
/// Delete the given outgoing key info.
async fn delete_key_info(&self, info: &GossipRequest) -> Result<(), CryptoStoreError> {
self.store.delete_outgoing_secret_requests(info.request_id).await
self.store.delete_outgoing_secret_requests(&info.request_id).await
}
/// Mark the outgoing request as sent.
pub async fn mark_outgoing_request_as_sent(&self, id: Uuid) -> Result<(), CryptoStoreError> {
pub async fn mark_outgoing_request_as_sent(
&self,
id: &TransactionId,
) -> Result<(), CryptoStoreError> {
let info = self.store.get_outgoing_secret_requests(id).await?;
if let Some(mut info) = info {
@@ -725,7 +731,7 @@ impl GossipMachine {
self.save_outgoing_key_info(info).await?;
}
self.outgoing_requests.remove(&id);
self.outgoing_requests.remove(id);
Ok(())
}
@@ -747,7 +753,7 @@ impl GossipMachine {
self.delete_key_info(&key_info).await?;
let request = key_info.to_cancellation(self.device_id());
self.outgoing_requests.insert(request.request_id, request);
self.outgoing_requests.insert(request.request_id.clone(), request);
Ok(())
}
@@ -763,12 +769,7 @@ impl GossipMachine {
"Received a m.secret.send event"
);
let request_id = if let Ok(r) = Uuid::parse_str(&event.content.request_id) {
r
} else {
warn!("Received a m.secret.send event but the request ID is invalid");
return Ok(None);
};
let request_id = <&TransactionId>::from(event.content.request_id.as_str());
let secret = std::mem::take(&mut event.content.secret);
@@ -1066,7 +1067,7 @@ mod test {
assert!(cancel.is_none());
machine.mark_outgoing_request_as_sent(request.request_id).await.unwrap();
machine.mark_outgoing_request_as_sent(&request.request_id).await.unwrap();
let (cancel, _) = machine
.request_key(session.room_id(), &session.sender_key, session.session_id())
@@ -1116,7 +1117,7 @@ mod test {
let request = requests.get(0).unwrap();
machine.mark_outgoing_request_as_sent(request.request_id).await.unwrap();
machine.mark_outgoing_request_as_sent(&request.request_id).await.unwrap();
assert!(machine.outgoing_to_device_requests().await.unwrap().is_empty());
}
@@ -1145,7 +1146,7 @@ mod test {
let requests = machine.outgoing_to_device_requests().await.unwrap();
let request = requests.get(0).unwrap();
let id = request.request_id;
let id = &request.request_id;
machine.mark_outgoing_request_as_sent(id).await.unwrap();
@@ -1178,9 +1179,9 @@ mod test {
// Get the cancel request.
let request = machine.outgoing_requests.iter().next().unwrap();
let id = request.request_id;
let id = request.request_id.clone();
drop(request);
machine.mark_outgoing_request_as_sent(id).await.unwrap();
machine.mark_outgoing_request_as_sent(&id).await.unwrap();
machine
.create_outgoing_key_request(
@@ -1194,7 +1195,7 @@ mod test {
let requests = machine.outgoing_to_device_requests().await.unwrap();
let request = &requests[0];
machine.mark_outgoing_request_as_sent(request.request_id).await.unwrap();
machine.mark_outgoing_request_as_sent(&request.request_id).await.unwrap();
let export = session.export_at_index(15).await;
@@ -1391,7 +1392,7 @@ mod test {
// Get the request and convert it into a event.
let requests = alice_machine.outgoing_to_device_requests().await.unwrap();
let request = &requests[0];
let id = request.request_id;
let id = &request.request_id;
let content = request
.request
.to_device()
@@ -1420,7 +1421,7 @@ mod test {
let requests = bob_machine.outgoing_to_device_requests().await.unwrap();
let request = &requests[0];
let id = request.request_id;
let id = &request.request_id;
let content = request
.request
.to_device()
@@ -1494,7 +1495,7 @@ mod test {
content: ToDeviceSecretRequestEventContent::new(
RequestAction::Request(SecretName::CrossSigningMasterKey),
bob_account.device_id().to_owned(),
"request_id".to_owned(),
"request_id".into(),
),
};
@@ -1523,7 +1524,7 @@ mod test {
content: ToDeviceSecretRequestEventContent::new(
RequestAction::Request(SecretName::CrossSigningMasterKey),
second_account.device_id().into(),
"request_id".to_owned(),
"request_id".into(),
),
};
@@ -1595,7 +1596,7 @@ mod test {
// Get the request and convert it into a event.
let requests = alice_machine.outgoing_to_device_requests().await.unwrap();
let request = &requests[0];
let id = request.request_id;
let id = &request.request_id;
let content = request
.request
.to_device()
@@ -1644,7 +1645,7 @@ mod test {
let request = &requests[0];
let id = request.request_id;
let id = &request.request_id;
let content = request
.request
.to_device()

View File

@@ -18,7 +18,6 @@ use std::sync::Arc;
use dashmap::{DashMap, DashSet};
pub(crate) use machine::GossipMachine;
use matrix_sdk_common::uuid::Uuid;
use ruma::{
events::{
room_key_request::{
@@ -32,7 +31,7 @@ use ruma::{
AnyToDeviceEventContent,
},
to_device::DeviceIdOrAllDevices,
DeviceId, UserId,
DeviceId, TransactionId, UserId,
};
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -69,7 +68,7 @@ pub struct GossipRequest {
/// The user we requested the secret from
pub request_recipient: Box<UserId>,
/// The unique id of the secret request.
pub request_id: Uuid,
pub request_id: Box<TransactionId>,
/// The info of the requested secret.
pub info: SecretInfo,
/// Has the request been sent out.
@@ -120,7 +119,7 @@ impl GossipRequest {
pub(crate) fn from_secret_name(own_user_id: Box<UserId>, secret_name: SecretName) -> Self {
Self {
request_recipient: own_user_id,
request_id: Uuid::new_v4(),
request_id: TransactionId::new(),
info: secret_name.into(),
sent_out: false,
}
@@ -140,14 +139,14 @@ impl GossipRequest {
Action::Request,
Some(r.clone()),
own_device_id.to_owned(),
self.request_id.to_string(),
self.request_id.clone(),
))
}
SecretInfo::SecretRequest(s) => {
AnyToDeviceEventContent::SecretRequest(SecretRequestEventContent::new(
RequestAction::Request(s.clone()),
own_device_id.to_owned(),
self.request_id.to_string(),
self.request_id.clone(),
))
}
};
@@ -156,10 +155,10 @@ impl GossipRequest {
&self.request_recipient,
DeviceIdOrAllDevices::AllDevices,
content,
self.request_id,
self.request_id.clone(),
);
OutgoingRequest { request_id: request.txn_id, request: Arc::new(request.into()) }
OutgoingRequest { request_id: request.txn_id.clone(), request: Arc::new(request.into()) }
}
fn to_cancellation(&self, own_device_id: &DeviceId) -> OutgoingRequest {
@@ -169,14 +168,14 @@ impl GossipRequest {
Action::CancelRequest,
None,
own_device_id.to_owned(),
self.request_id.to_string(),
self.request_id.clone(),
))
}
SecretInfo::SecretRequest(_) => {
AnyToDeviceEventContent::SecretRequest(SecretRequestEventContent::new(
RequestAction::RequestCancellation,
own_device_id.to_owned(),
self.request_id.to_string(),
self.request_id.clone(),
))
}
};
@@ -187,7 +186,7 @@ impl GossipRequest {
content,
);
OutgoingRequest { request_id: request.txn_id, request: Arc::new(request.into()) }
OutgoingRequest { request_id: request.txn_id.clone(), request: Arc::new(request.into()) }
}
}
@@ -251,7 +250,7 @@ impl RequestEvent {
}
}
fn request_id(&self) -> &str {
fn request_id(&self) -> &TransactionId {
match self {
RequestEvent::KeyShare(e) => &e.content.request_id,
RequestEvent::Secret(e) => &e.content.request_id,
@@ -263,11 +262,15 @@ impl RequestEvent {
struct RequestInfo {
sender: Box<UserId>,
requesting_device_id: Box<DeviceId>,
request_id: String,
request_id: Box<TransactionId>,
}
impl RequestInfo {
fn new(sender: Box<UserId>, requesting_device_id: Box<DeviceId>, request_id: String) -> Self {
fn new(
sender: Box<UserId>,
requesting_device_id: Box<DeviceId>,
request_id: Box<TransactionId>,
) -> Self {
Self { sender, requesting_device_id, request_id }
}
}
@@ -278,7 +281,7 @@ impl RequestInfo {
struct WaitQueue {
requests_waiting_for_session: Arc<DashMap<RequestInfo, RequestEvent>>,
#[allow(clippy::type_complexity)]
requests_ids_waiting: Arc<DashMap<(Box<UserId>, Box<DeviceId>), DashSet<String>>>,
requests_ids_waiting: Arc<DashMap<(Box<UserId>, Box<DeviceId>), DashSet<Box<TransactionId>>>>,
}
impl WaitQueue {

View File

@@ -24,7 +24,6 @@ use dashmap::DashMap;
use matrix_sdk_common::{
deserialized_responses::{AlgorithmInfo, EncryptionInfo, RoomEvent, VerificationState},
locks::Mutex,
uuid::Uuid,
};
use ruma::{
api::client::r0::{
@@ -47,7 +46,8 @@ use ruma::{
AnyRoomEvent, AnyToDeviceEvent, MessageEventContent,
},
serde::Raw,
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId,
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, TransactionId,
UInt, UserId,
};
use serde_json::{value::to_raw_value, Value};
use tracing::{debug, error, info, trace, warn};
@@ -322,21 +322,17 @@ impl OlmMachine {
pub async fn outgoing_requests(&self) -> StoreResult<Vec<OutgoingRequest>> {
let mut requests = Vec::new();
if let Some(r) = self
.keys_for_upload()
.await
.map(|r| OutgoingRequest { request_id: Uuid::new_v4(), request: Arc::new(r.into()) })
{
if let Some(r) = self.keys_for_upload().await.map(|r| OutgoingRequest {
request_id: TransactionId::new(),
request: Arc::new(r.into()),
}) {
self.account.save().await?;
requests.push(r);
}
for request in
self.identity_manager.users_for_key_query().await.into_iter().map(|r| OutgoingRequest {
request_id: Uuid::new_v4(),
request: Arc::new(r.into()),
})
{
for request in self.identity_manager.users_for_key_query().await.into_iter().map(|r| {
OutgoingRequest { request_id: TransactionId::new(), request: Arc::new(r.into()) }
}) {
requests.push(request);
}
@@ -357,7 +353,7 @@ impl OlmMachine {
/// outgoing request was sent out.
pub async fn mark_request_as_sent<'a>(
&self,
request_id: &Uuid,
request_id: &TransactionId,
response: impl Into<IncomingResponse<'a>>,
) -> OlmResult<()> {
match response.into() {
@@ -522,7 +518,7 @@ impl OlmMachine {
pub async fn get_missing_sessions(
&self,
users: impl Iterator<Item = &UserId>,
) -> StoreResult<Option<(Uuid, KeysClaimRequest)>> {
) -> StoreResult<Option<(Box<TransactionId>, KeysClaimRequest)>> {
self.session_manager.get_missing_sessions(users).await
}
@@ -835,9 +831,9 @@ impl OlmMachine {
}
/// Mark an outgoing to-device requests as sent.
async fn mark_to_device_request_as_sent(&self, request_id: &Uuid) -> StoreResult<()> {
async fn mark_to_device_request_as_sent(&self, request_id: &TransactionId) -> StoreResult<()> {
self.verification_machine.mark_request_as_sent(request_id);
self.key_request_machine.mark_outgoing_request_as_sent(*request_id).await?;
self.key_request_machine.mark_outgoing_request_as_sent(request_id).await?;
self.group_session_manager.mark_request_as_sent(request_id).await?;
self.session_manager.mark_outgoing_request_as_sent(request_id);
@@ -1679,9 +1675,9 @@ pub(crate) mod test {
let mut bob_keys = BTreeMap::new();
let one_time_key = one_time_keys.iter().next().unwrap();
let (device_key_id, one_time_key) = one_time_keys.iter().next().unwrap();
let mut keys = BTreeMap::new();
keys.insert(one_time_key.0.clone(), one_time_key.1.clone());
keys.insert(device_key_id.clone(), one_time_key.clone());
bob_keys.insert(bob.device_id().into(), keys);
let mut one_time_keys = BTreeMap::new();
@@ -1911,9 +1907,9 @@ pub(crate) mod test {
let mut bob_keys = BTreeMap::new();
let one_time_key = one_time_keys.iter().next().unwrap();
let (device_key_id, one_time_key) = one_time_keys.iter().next().unwrap();
let mut keys = BTreeMap::new();
keys.insert(one_time_key.0.clone(), one_time_key.1.clone());
keys.insert(device_key_id.clone(), one_time_key.clone());
bob_keys.insert(bob_machine.device_id().into(), keys);
let mut one_time_keys = BTreeMap::new();

View File

@@ -39,7 +39,7 @@ use ruma::{
},
AnyToDeviceEvent, OlmV1Keys,
},
serde::{CanonicalJsonValue, Raw},
serde::{Base64, CanonicalJsonValue, Raw},
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UInt, UserId,
};
use serde::{Deserialize, Serialize};
@@ -625,7 +625,7 @@ impl ReadOnlyAccount {
let max_keys = self.max_one_time_keys().await;
let max_on_server = (max_keys as u64) / 2;
if count >= (max_on_server) {
if count >= max_on_server {
return Err(());
}
@@ -862,11 +862,11 @@ impl ReadOnlyAccount {
pub(crate) async fn signed_one_time_keys_helper(
&self,
) -> Result<BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>, ()> {
) -> BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>> {
let one_time_keys = self.one_time_keys().await;
let mut one_time_key_map = BTreeMap::new();
for (key_id, key) in one_time_keys.curve25519().iter() {
for (key_id, key) in one_time_keys.curve25519() {
let key_json = json!({
"key": key,
});
@@ -883,7 +883,10 @@ impl ReadOnlyAccount {
let mut signatures = BTreeMap::new();
signatures.insert((*self.user_id).to_owned(), signature_map);
let signed_key = SignedKey::new(key.to_owned(), signatures);
let signed_key = SignedKey::new(
Base64::parse(key).expect("Couldn't base64-decode one-time key"),
signatures,
);
one_time_key_map.insert(
DeviceKeyId::from_parts(
@@ -897,7 +900,7 @@ impl ReadOnlyAccount {
);
}
Ok(one_time_key_map)
one_time_key_map
}
/// Generate, sign and prepare one-time keys to be uploaded.
@@ -907,7 +910,7 @@ impl ReadOnlyAccount {
&self,
) -> Result<BTreeMap<Box<DeviceKeyId>, Raw<OneTimeKey>>, ()> {
let _ = self.generate_one_time_keys().await?;
self.signed_one_time_keys_helper().await
Ok(self.signed_one_time_keys_helper().await)
}
/// Create a new session with another account given a one-time key.
@@ -929,7 +932,7 @@ impl ReadOnlyAccount {
.inner
.lock()
.await
.create_outbound_session(their_identity_key, &their_one_time_key.key)?;
.create_outbound_session(their_identity_key, &their_one_time_key.key.encode())?;
let now = Instant::now();
let session_id = session.session_id();
@@ -1173,7 +1176,7 @@ mod test {
use std::{collections::BTreeSet, ops::Deref};
use matrix_sdk_test::async_test;
use ruma::{device_id, identifiers::DeviceId, user_id, DeviceKeyId, UserId};
use ruma::{device_id, user_id, DeviceId, DeviceKeyId, UserId};
use super::ReadOnlyAccount;
use crate::error::OlmResult as Result;

View File

@@ -24,7 +24,7 @@ use std::{
};
use dashmap::DashMap;
use matrix_sdk_common::{instant::Instant, locks::Mutex, uuid::Uuid};
use matrix_sdk_common::{instant::Instant, locks::Mutex};
pub use olm_rs::{
account::IdentityKeys,
session::{OlmMessage, PreKeyMessage},
@@ -45,7 +45,7 @@ use ruma::{
room_key::ToDeviceRoomKeyEventContent,
AnyToDeviceEventContent,
},
DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, TransactionId, UserId,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
@@ -130,7 +130,8 @@ pub struct OutboundGroupSession {
settings: Arc<EncryptionSettings>,
#[allow(clippy::type_complexity)]
pub(crate) shared_with_set: Arc<DashMap<Box<UserId>, DashMap<Box<DeviceId>, ShareInfo>>>,
to_share_with_set: Arc<DashMap<Uuid, (Arc<ToDeviceRequest>, ShareInfoSet)>>,
#[allow(clippy::type_complexity)]
to_share_with_set: Arc<DashMap<Box<TransactionId>, (Arc<ToDeviceRequest>, ShareInfoSet)>>,
}
/// A a map of userid/device it to a `ShareInfo`.
@@ -191,7 +192,7 @@ impl OutboundGroupSession {
pub(crate) fn add_request(
&self,
request_id: Uuid,
request_id: Box<TransactionId>,
request: Arc<ToDeviceRequest>,
share_infos: ShareInfoSet,
) {
@@ -212,7 +213,7 @@ impl OutboundGroupSession {
///
/// This removes the request from the queue and marks the set of
/// users/devices that received the session.
pub fn mark_request_as_sent(&self, request_id: &Uuid) {
pub fn mark_request_as_sent(&self, request_id: &TransactionId) {
if let Some((_, (_, r))) = self.to_share_with_set.remove(request_id) {
let recipients: BTreeMap<&UserId, BTreeSet<&DeviceId>> =
r.iter().map(|(u, d)| (&**u, d.keys().map(|d| d.as_ref()).collect())).collect();
@@ -456,8 +457,8 @@ impl OutboundGroupSession {
}
/// Get the list of request ids this session is waiting for to be sent out.
pub(crate) fn pending_request_ids(&self) -> Vec<Uuid> {
self.to_share_with_set.iter().map(|e| *e.key()).collect()
pub(crate) fn pending_request_ids(&self) -> Vec<Box<TransactionId>> {
self.to_share_with_set.iter().map(|e| e.key().clone()).collect()
}
/// Restore a Session from a previously pickled string.
@@ -541,7 +542,7 @@ impl OutboundGroupSession {
requests: self
.to_share_with_set
.iter()
.map(|r| (*r.key(), r.value().clone()))
.map(|r| (r.key().clone(), r.value().clone()))
.collect(),
}
}
@@ -592,7 +593,7 @@ pub struct PickledOutboundGroupSession {
/// The set of users the session has been already shared with.
pub shared_with_set: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceId>, ShareInfo>>,
/// Requests that need to be sent out to share the session.
pub requests: BTreeMap<Uuid, (Arc<ToDeviceRequest>, ShareInfoSet)>,
pub requests: BTreeMap<Box<TransactionId>, (Arc<ToDeviceRequest>, ShareInfoSet)>,
}
#[cfg(test)]

View File

@@ -74,7 +74,9 @@ pub(crate) mod test {
room::message::{Relation, Replacement, RoomMessageEventContent},
AnyMessageEvent, AnyRoomEvent, AnySyncMessageEvent, AnySyncRoomEvent,
},
room_id, user_id, DeviceId, UserId,
room_id,
serde::Base64,
user_id, DeviceId, UserId,
};
use serde_json::json;
@@ -102,7 +104,7 @@ pub(crate) mod test {
bob.generate_one_time_keys_helper(1).await;
let one_time_key =
bob.one_time_keys().await.curve25519().iter().next().unwrap().1.to_owned();
Base64::parse(bob.one_time_keys().await.curve25519().values().next().unwrap()).unwrap();
let one_time_key = SignedKey::new(one_time_key, BTreeMap::new());
let sender_key = bob.identity_keys().curve25519().to_owned();
let session =
@@ -162,7 +164,8 @@ pub(crate) mod test {
let one_time_keys = alice.one_time_keys().await;
alice.mark_keys_as_published().await;
let one_time_key = one_time_keys.curve25519().iter().next().unwrap().1.to_owned();
let one_time_key =
Base64::parse(one_time_keys.curve25519().values().next().unwrap()).unwrap();
let one_time_key = SignedKey::new(one_time_key, BTreeMap::new());

View File

@@ -14,7 +14,6 @@
use std::{collections::BTreeMap, iter, sync::Arc, time::Duration};
use matrix_sdk_common::uuid::Uuid;
use ruma::{
api::client::r0::{
backup::{add_backup_keys::Response as KeysBackupResponse, RoomKeyBackup},
@@ -34,13 +33,12 @@ use ruma::{
events::{AnyMessageEventContent, AnyToDeviceEventContent, EventContent, EventType},
serde::Raw,
to_device::DeviceIdOrAllDevices,
DeviceId, RoomId, UserId,
DeviceId, RoomId, TransactionId, UserId,
};
use serde::{Deserialize, Serialize};
/// Customized version of
/// `ruma_client_api::r0::to_device::send_event_to_device::Request`,
/// using a UUID for the transaction ID.
/// `ruma_client_api::r0::to_device::send_event_to_device::Request`
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct ToDeviceRequest {
/// Type of event being sent to each device.
@@ -48,7 +46,7 @@ pub struct ToDeviceRequest {
/// A request identifier unique to the access token used to send the
/// request.
pub txn_id: Uuid,
pub txn_id: Box<TransactionId>,
/// A map of users to devices to a content for a message event to be
/// sent to the user's device. Individual message events can be sent
@@ -77,14 +75,14 @@ impl ToDeviceRequest {
recipient_device: impl Into<DeviceIdOrAllDevices>,
content: AnyToDeviceEventContent,
) -> Self {
Self::new_with_id(recipient, recipient_device, content, Uuid::new_v4())
Self::new_with_id(recipient, recipient_device, content, TransactionId::new())
}
pub(crate) fn new_for_recipients(
recipient: &UserId,
recipient_devices: Vec<Box<DeviceId>>,
content: AnyToDeviceEventContent,
txn_id: Uuid,
txn_id: Box<TransactionId>,
) -> Self {
if recipient_devices.is_empty() {
Self::new(recipient, DeviceIdOrAllDevices::AllDevices, content)
@@ -108,7 +106,7 @@ impl ToDeviceRequest {
recipient: &UserId,
recipient_device: impl Into<DeviceIdOrAllDevices>,
content: AnyToDeviceEventContent,
txn_id: Uuid,
txn_id: Box<TransactionId>,
) -> Self {
let event_type = EventType::from(content.event_type());
let raw_content = Raw::new(&content).expect("Failed to serialize to-device event");
@@ -119,11 +117,6 @@ impl ToDeviceRequest {
ToDeviceRequest { event_type, txn_id, messages }
}
/// Gets the transaction ID as a string.
pub fn txn_id_string(&self) -> String {
self.txn_id.to_string()
}
/// Get the number of unique messages this request contains.
///
/// *Note*: A single message may be sent to multiple devices, so this may or
@@ -257,13 +250,13 @@ impl From<SignatureUploadRequest> for OutgoingRequests {
impl From<OutgoingVerificationRequest> for OutgoingRequest {
fn from(r: OutgoingVerificationRequest) -> Self {
Self { request_id: r.request_id(), request: Arc::new(r.into()) }
Self { request_id: r.request_id().to_owned(), request: Arc::new(r.into()) }
}
}
impl From<SignatureUploadRequest> for OutgoingRequest {
fn from(r: SignatureUploadRequest) -> Self {
Self { request_id: Uuid::new_v4(), request: Arc::new(r.into()) }
Self { request_id: TransactionId::new(), request: Arc::new(r.into()) }
}
}
@@ -340,14 +333,14 @@ impl<'a> From<&'a SignatureUploadResponse> for IncomingResponse<'a> {
pub struct OutgoingRequest {
/// The unique id of a request, needs to be passed when receiving a
/// response.
pub(crate) request_id: Uuid,
pub(crate) request_id: Box<TransactionId>,
/// The underlying outgoing request.
pub(crate) request: Arc<OutgoingRequests>,
}
impl OutgoingRequest {
/// Get the unique id of this request.
pub fn request_id(&self) -> &Uuid {
pub fn request_id(&self) -> &TransactionId {
&self.request_id
}
@@ -368,7 +361,7 @@ pub struct RoomMessageRequest {
/// Clients should generate an ID unique across requests with the
/// same access token; it will be used by the server to ensure
/// idempotency of requests.
pub txn_id: Uuid,
pub txn_id: Box<TransactionId>,
/// The event content to send.
pub content: AnyMessageEventContent,
@@ -395,10 +388,10 @@ pub enum OutgoingVerificationRequest {
impl OutgoingVerificationRequest {
/// Get the unique id of this request.
pub fn request_id(&self) -> Uuid {
pub fn request_id(&self) -> &TransactionId {
match self {
OutgoingVerificationRequest::ToDevice(t) => t.txn_id,
OutgoingVerificationRequest::InRoom(r) => r.txn_id,
OutgoingVerificationRequest::ToDevice(t) => &t.txn_id,
OutgoingVerificationRequest::InRoom(r) => &r.txn_id,
}
}
}

View File

@@ -20,7 +20,7 @@ use std::{
use dashmap::DashMap;
use futures_util::future::join_all;
use matrix_sdk_common::{executor::spawn, uuid::Uuid};
use matrix_sdk_common::executor::spawn;
use ruma::{
events::{
room::{encrypted::RoomEncryptedEventContent, history_visibility::HistoryVisibility},
@@ -28,7 +28,7 @@ use ruma::{
},
serde::Raw,
to_device::DeviceIdOrAllDevices,
DeviceId, RoomId, UserId,
DeviceId, RoomId, TransactionId, UserId,
};
use serde_json::Value;
use tracing::{debug, info, trace};
@@ -46,7 +46,7 @@ pub(crate) struct GroupSessionCache {
sessions: Arc<DashMap<Box<RoomId>, OutboundGroupSession>>,
/// A map from the request id to the group session that the request belongs
/// to. Used to mark requests belonging to the session as shared.
sessions_being_shared: Arc<DashMap<Uuid, OutboundGroupSession>>,
sessions_being_shared: Arc<DashMap<Box<TransactionId>, OutboundGroupSession>>,
}
impl GroupSessionCache {
@@ -137,7 +137,7 @@ impl GroupSessionManager {
}
}
pub async fn mark_request_as_sent(&self, request_id: &Uuid) -> StoreResult<()> {
pub async fn mark_request_as_sent(&self, request_id: &TransactionId) -> StoreResult<()> {
if let Some((_, s)) = self.sessions.sessions_being_shared.remove(request_id) {
s.mark_request_as_sent(request_id);
@@ -221,7 +221,7 @@ impl GroupSessionManager {
devices: Vec<Device>,
message_index: u32,
) -> OlmResult<(
Uuid,
Box<TransactionId>,
ToDeviceRequest,
BTreeMap<Box<UserId>, BTreeMap<Box<DeviceId>, ShareInfo>>,
Vec<Session>,
@@ -298,18 +298,20 @@ impl GroupSessionManager {
}
}
let id = Uuid::new_v4();
let request =
ToDeviceRequest { event_type: EventType::RoomEncrypted, txn_id: id, messages };
let txn_id = TransactionId::new();
let request = ToDeviceRequest {
event_type: EventType::RoomEncrypted,
txn_id: txn_id.clone(),
messages,
};
trace!(
recipient_count = request.message_count(),
transaction_id = ?id,
transaction_id = ?txn_id,
"Created a to-device request carrying a room_key"
);
Ok((id, request, share_infos, changed_sessions))
Ok((txn_id, request, share_infos, changed_sessions))
}
/// Given a list of user and an outbound session, return the list of users
@@ -412,13 +414,13 @@ impl GroupSessionManager {
content: AnyToDeviceEventContent,
outbound: OutboundGroupSession,
message_index: u32,
being_shared: Arc<DashMap<Uuid, OutboundGroupSession>>,
being_shared: Arc<DashMap<Box<TransactionId>, OutboundGroupSession>>,
) -> OlmResult<Vec<Session>> {
let (id, request, share_infos, used_sessions) =
Self::encrypt_session_for(content.clone(), chunk, message_index).await?;
if !request.messages.is_empty() {
outbound.add_request(id, request.into(), share_infos);
outbound.add_request(id.clone(), request.into(), share_infos);
being_shared.insert(id, outbound.clone());
}
@@ -553,7 +555,7 @@ impl GroupSessionManager {
}
}
let transaction_ids: Vec<Uuid> = requests.iter().map(|r| r.txn_id).collect();
let transaction_ids: Vec<_> = requests.iter().map(|r| r.txn_id.clone()).collect();
// TODO log the withheld reasons here as well.
info!(
@@ -586,15 +588,13 @@ impl GroupSessionManager {
#[cfg(test)]
mod test {
use std::ops::Deref;
use matrix_sdk_common::uuid::Uuid;
use matrix_sdk_test::{async_test, response_from_file};
use ruma::{
api::{
client::r0::keys::{claim_keys, get_keys},
IncomingResponse,
},
device_id, room_id, user_id, DeviceId, UserId,
device_id, room_id, user_id, DeviceId, TransactionId, UserId,
};
use serde_json::Value;
@@ -627,12 +627,12 @@ mod test {
async fn machine() -> OlmMachine {
let keys_query = keys_query_response();
let keys_claim = keys_claim_response();
let uuid = Uuid::new_v4();
let txn_id = TransactionId::new();
let machine = OlmMachine::new(alice_id(), alice_device_id());
machine.mark_request_as_sent(&uuid, &keys_query).await.unwrap();
machine.mark_request_as_sent(&uuid, &keys_claim).await.unwrap();
machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap();
machine.mark_request_as_sent(&txn_id, &keys_claim).await.unwrap();
machine
}

View File

@@ -19,14 +19,13 @@ use std::{
};
use dashmap::{DashMap, DashSet};
use matrix_sdk_common::uuid::Uuid;
use ruma::{
api::client::r0::keys::claim_keys::{
Request as KeysClaimRequest, Response as KeysClaimResponse,
},
assign,
events::{dummy::ToDeviceDummyEventContent, AnyToDeviceEventContent},
DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, UserId,
DeviceId, DeviceKeyAlgorithm, EventEncryptionAlgorithm, TransactionId, UserId,
};
use tracing::{debug, error, info, warn};
@@ -50,7 +49,7 @@ pub(crate) struct SessionManager {
users_for_key_claim: Arc<DashMap<Box<UserId>, DashSet<Box<DeviceId>>>>,
wedged_devices: Arc<DashMap<Box<UserId>, DashSet<Box<DeviceId>>>>,
key_request_machine: GossipMachine,
outgoing_to_device_requests: Arc<DashMap<Uuid, OutgoingRequest>>,
outgoing_to_device_requests: Arc<DashMap<Box<TransactionId>, OutgoingRequest>>,
}
impl SessionManager {
@@ -74,7 +73,7 @@ impl SessionManager {
}
/// Mark the outgoing request as sent.
pub fn mark_outgoing_request_as_sent(&self, id: &Uuid) {
pub fn mark_outgoing_request_as_sent(&self, id: &TransactionId) {
self.outgoing_to_device_requests.remove(id);
}
@@ -136,11 +135,11 @@ impl SessionManager {
);
let request = OutgoingRequest {
request_id: request.txn_id,
request_id: request.txn_id.clone(),
request: Arc::new(request.into()),
};
self.outgoing_to_device_requests.insert(request.request_id, request);
self.outgoing_to_device_requests.insert(request.request_id.clone(), request);
}
}
@@ -177,7 +176,7 @@ impl SessionManager {
pub async fn get_missing_sessions(
&self,
users: impl Iterator<Item = &UserId>,
) -> StoreResult<Option<(Uuid, KeysClaimRequest)>> {
) -> StoreResult<Option<(Box<TransactionId>, KeysClaimRequest)>> {
let mut missing = BTreeMap::new();
// Add the list of devices that the user wishes to establish sessions
@@ -240,7 +239,7 @@ impl SessionManager {
debug!(?missing, "Collected user/device pairs that are missing an Olm session");
Ok(Some((
Uuid::new_v4(),
TransactionId::new(),
assign!(KeysClaimRequest::new(missing), {
timeout: Some(Self::KEY_CLAIM_TIMEOUT),
}),
@@ -412,7 +411,7 @@ mod test {
assert!(request.one_time_keys.contains_key(bob.user_id()));
bob.generate_one_time_keys_helper(1).await;
let one_time = bob.signed_one_time_keys_helper().await.unwrap();
let one_time = bob.signed_one_time_keys_helper().await;
bob.mark_keys_as_published().await;
let mut one_time_keys = BTreeMap::new();
@@ -462,7 +461,7 @@ mod test {
assert!(request.one_time_keys.contains_key(bob.user_id()));
bob.generate_one_time_keys_helper(1).await;
let one_time = bob.signed_one_time_keys_helper().await.unwrap();
let one_time = bob.signed_one_time_keys_helper().await;
bob.mark_keys_as_published().await;
let mut one_time_keys = BTreeMap::new();

View File

@@ -7,13 +7,12 @@ macro_rules! cryptostore_integration_tests {
use super::get_store;
use std::collections::BTreeMap;
use matrix_sdk_common::uuid::Uuid;
use matrix_sdk_test::async_test;
use olm_rs::outbound_group_session::OlmOutboundGroupSession;
use ruma::{
encryption::SignedKey, events::room_key_request::RequestedKeyInfo,
room_id, user_id, device_id,
DeviceId, EventEncryptionAlgorithm, UserId,
serde::Base64, user_id, TransactionId, DeviceId, EventEncryptionAlgorithm, UserId,
room_id, device_id,
};
use crate::{
@@ -63,7 +62,7 @@ macro_rules! cryptostore_integration_tests {
bob.generate_one_time_keys_helper(1).await;
let one_time_key =
bob.one_time_keys().await.curve25519().iter().next().unwrap().1.to_owned();
Base64::parse(bob.one_time_keys().await.curve25519().values().next().unwrap()).unwrap();
let one_time_key = SignedKey::new(one_time_key, BTreeMap::new());
let sender_key = bob.identity_keys().curve25519().to_owned();
let session =
@@ -544,7 +543,7 @@ macro_rules! cryptostore_integration_tests {
let dir = "key_request_saving".to_owned();
let (account, store) = get_loaded_store(dir).await;
let id = Uuid::new_v4();
let id = TransactionId::new();
let info: SecretInfo = RequestedKeyInfo::new(
EventEncryptionAlgorithm::MegolmV1AesSha2,
room_id!("!test:localhost").to_owned(),
@@ -555,12 +554,12 @@ macro_rules! cryptostore_integration_tests {
let request = GossipRequest {
request_recipient: account.user_id().to_owned(),
request_id: id,
request_id: id.clone(),
info: info.clone(),
sent_out: false,
};
assert!(store.get_outgoing_secret_requests(id).await.unwrap().is_none());
assert!(store.get_outgoing_secret_requests(&id).await.unwrap().is_none());
let mut changes = Changes::default();
changes.key_requests.push(request.clone());
@@ -568,7 +567,7 @@ macro_rules! cryptostore_integration_tests {
let request = Some(request);
let stored_request = store.get_outgoing_secret_requests(id).await.unwrap();
let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
assert_eq!(request, stored_request);
let stored_request = store.get_secret_request_by_info(&info).await.unwrap();
@@ -577,7 +576,7 @@ macro_rules! cryptostore_integration_tests {
let request = GossipRequest {
request_recipient: account.user_id().to_owned(),
request_id: id,
request_id: id.clone(),
info: info.clone(),
sent_out: true,
};
@@ -587,12 +586,12 @@ macro_rules! cryptostore_integration_tests {
store.save_changes(changes).await.unwrap();
assert!(store.get_unsent_secret_requests().await.unwrap().is_empty());
let stored_request = store.get_outgoing_secret_requests(id).await.unwrap();
let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
assert_eq!(Some(request), stored_request);
store.delete_outgoing_secret_requests(id).await.unwrap();
store.delete_outgoing_secret_requests(&id).await.unwrap();
let stored_request = store.get_outgoing_secret_requests(id).await.unwrap();
let stored_request = store.get_outgoing_secret_requests(&id).await.unwrap();
assert_eq!(None, stored_request);
let stored_request = store.get_secret_request_by_info(&info).await.unwrap();

View File

@@ -18,8 +18,8 @@ use std::{
};
use dashmap::{DashMap, DashSet};
use matrix_sdk_common::{async_trait, locks::Mutex, uuid::Uuid};
use ruma::{DeviceId, RoomId, UserId};
use matrix_sdk_common::{async_trait, locks::Mutex};
use ruma::{DeviceId, RoomId, TransactionId, UserId};
use super::{
caches::{DeviceStore, GroupSessionStore, SessionStore},
@@ -51,8 +51,8 @@ pub struct MemoryStore {
olm_hashes: Arc<DashMap<String, DashSet<String>>>,
devices: DeviceStore,
identities: Arc<DashMap<Box<UserId>, ReadOnlyUserIdentities>>,
outgoing_key_requests: Arc<DashMap<Uuid, GossipRequest>>,
key_requests_by_info: Arc<DashMap<String, Uuid>>,
outgoing_key_requests: Arc<DashMap<Box<TransactionId>, GossipRequest>>,
key_requests_by_info: Arc<DashMap<String, Box<TransactionId>>>,
}
impl Default for MemoryStore {
@@ -137,10 +137,10 @@ impl CryptoStore for MemoryStore {
}
for key_request in changes.key_requests {
let id = key_request.request_id;
let id = key_request.request_id.clone();
let info_string = encode_key_info(&key_request.info);
self.outgoing_key_requests.insert(id, key_request);
self.outgoing_key_requests.insert(id.clone(), key_request);
self.key_requests_by_info.insert(info_string, id);
}
@@ -266,9 +266,9 @@ impl CryptoStore for MemoryStore {
async fn get_outgoing_secret_requests(
&self,
request_id: Uuid,
request_id: &TransactionId,
) -> Result<Option<GossipRequest>> {
Ok(self.outgoing_key_requests.get(&request_id).map(|r| r.clone()))
Ok(self.outgoing_key_requests.get(request_id).map(|r| r.clone()))
}
async fn get_secret_request_by_info(
@@ -280,7 +280,7 @@ impl CryptoStore for MemoryStore {
Ok(self
.key_requests_by_info
.get(&key_info_string)
.and_then(|i| self.outgoing_key_requests.get(&i).map(|r| r.clone())))
.and_then(|i| self.outgoing_key_requests.get(&*i).map(|r| r.clone())))
}
async fn get_unsent_secret_requests(&self) -> Result<Vec<GossipRequest>> {
@@ -292,8 +292,8 @@ impl CryptoStore for MemoryStore {
.collect())
}
async fn delete_outgoing_secret_requests(&self, request_id: Uuid) -> Result<()> {
self.outgoing_key_requests.remove(&request_id).and_then(|(_, i)| {
async fn delete_outgoing_secret_requests(&self, request_id: &TransactionId) -> Result<()> {
self.outgoing_key_requests.remove(request_id).and_then(|(_, i)| {
let key_info_string = encode_key_info(&i.info);
self.key_requests_by_info.remove(&key_info_string)
});

View File

@@ -59,13 +59,13 @@ use std::{
use base64::DecodeError;
#[cfg(feature = "indexeddb_cryptostore")]
use indexed_db_futures::web_sys::DomException;
use matrix_sdk_common::{async_trait, locks::Mutex, uuid::Uuid, AsyncTraitDeps};
use matrix_sdk_common::{async_trait, locks::Mutex, AsyncTraitDeps};
pub use memorystore::MemoryStore;
use olm_rs::errors::{OlmAccountError, OlmGroupSessionError, OlmSessionError};
pub use pickle_key::{EncryptedPickleKey, PickleKey};
use ruma::{
events::secret::request::SecretName, identifiers::Error as IdentifierValidationError, DeviceId,
DeviceKeyAlgorithm, RoomId, UserId,
DeviceKeyAlgorithm, RoomId, TransactionId, UserId,
};
use serde_json::Error as SerdeError;
use thiserror::Error;
@@ -736,8 +736,10 @@ pub trait CryptoStore: AsyncTraitDeps {
///
/// * `request_id` - The unique request id that identifies this outgoing
/// secret request.
async fn get_outgoing_secret_requests(&self, request_id: Uuid)
-> Result<Option<GossipRequest>>;
async fn get_outgoing_secret_requests(
&self,
request_id: &TransactionId,
) -> Result<Option<GossipRequest>>;
/// Get an outgoing key request that we created that matches the given
/// requested key info.
@@ -760,5 +762,5 @@ pub trait CryptoStore: AsyncTraitDeps {
///
/// * `request_id` - The unique request id that identifies this outgoing key
/// request.
async fn delete_outgoing_secret_requests(&self, request_id: Uuid) -> Result<()>;
async fn delete_outgoing_secret_requests(&self, request_id: &TransactionId) -> Result<()>;
}

View File

@@ -20,12 +20,12 @@ use std::{
};
use dashmap::DashSet;
use matrix_sdk_common::{async_trait, locks::Mutex, uuid};
use matrix_sdk_common::{async_trait, locks::Mutex};
use olm_rs::{account::IdentityKeys, PicklingMode};
use ruma::{
encryption::DeviceKeys,
events::{room_key_request::RequestedKeyInfo, secret::request::SecretName},
DeviceId, DeviceKeyId, EventEncryptionAlgorithm, RoomId, UserId,
DeviceId, DeviceKeyId, EventEncryptionAlgorithm, RoomId, TransactionId, UserId,
};
use serde::{Deserialize, Serialize};
pub use sled::Error;
@@ -34,7 +34,6 @@ use sled::{
Config, Db, IVec, Transactional, Tree,
};
use tracing::debug;
use uuid::Uuid;
use super::{
caches::SessionStore, BackupKeys, Changes, CryptoStore, CryptoStoreError, InboundGroupSession,
@@ -57,9 +56,21 @@ trait EncodeKey {
fn encode(&self) -> Vec<u8>;
}
impl EncodeKey for Uuid {
impl<T: EncodeKey> EncodeKey for &T {
fn encode(&self) -> Vec<u8> {
self.as_u128().to_be_bytes().to_vec()
T::encode(self)
}
}
impl<T: EncodeKey> EncodeKey for Box<T> {
fn encode(&self) -> Vec<u8> {
T::encode(self)
}
}
impl EncodeKey for TransactionId {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
@@ -78,7 +89,7 @@ impl EncodeKey for SecretInfo {
}
}
impl EncodeKey for &RequestedKeyInfo {
impl EncodeKey for RequestedKeyInfo {
fn encode(&self) -> Vec<u8> {
[
self.room_id.as_bytes(),
@@ -94,25 +105,31 @@ impl EncodeKey for &RequestedKeyInfo {
}
}
impl EncodeKey for &UserId {
impl EncodeKey for UserId {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
impl EncodeKey for &ReadOnlyDevice {
impl EncodeKey for ReadOnlyDevice {
fn encode(&self) -> Vec<u8> {
(self.user_id().as_str(), self.device_id().as_str()).encode()
}
}
impl EncodeKey for &RoomId {
impl EncodeKey for RoomId {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
impl EncodeKey for &str {
impl EncodeKey for String {
fn encode(&self) -> Vec<u8> {
self.as_str().encode()
}
}
impl EncodeKey for str {
fn encode(&self) -> Vec<u8> {
[self.as_bytes(), &[Self::SEPARATOR]].concat()
}
@@ -424,7 +441,7 @@ impl SledStore {
}
async fn load_tracked_users(&self) -> Result<()> {
for value in self.tracked_users.iter() {
for value in &self.tracked_users {
let (user, dirty) = value?;
let user = Box::<UserId>::try_from(String::from_utf8_lossy(&user).to_string())?;
let dirty = dirty.get(0).map(|d| *d == 1).unwrap_or(true);
@@ -613,7 +630,7 @@ impl SledStore {
for (key, session) in &outbound_session_changes {
outbound_sessions.insert(
(&**key).encode(),
key.encode(),
serde_json::to_vec(&session)
.map_err(ConflictableTransactionError::Abort)?,
)?;
@@ -914,7 +931,7 @@ impl CryptoStore for SledStore {
async fn get_outgoing_secret_requests(
&self,
request_id: Uuid,
request_id: &TransactionId,
) -> Result<Option<GossipRequest>> {
let request_id = request_id.encode();
@@ -944,7 +961,7 @@ impl CryptoStore for SledStore {
requests
}
async fn delete_outgoing_secret_requests(&self, request_id: Uuid) -> Result<()> {
async fn delete_outgoing_secret_requests(&self, request_id: &TransactionId) -> Result<()> {
let ret: Result<(), TransactionError<serde_json::Error>> = (
&self.outgoing_secret_requests,
&self.unsent_secret_requests,

View File

@@ -15,8 +15,7 @@
use std::sync::Arc;
use dashmap::DashMap;
use matrix_sdk_common::uuid::Uuid;
use ruma::{DeviceId, UserId};
use ruma::{DeviceId, TransactionId, UserId};
use tracing::trace;
use super::{event_enums::OutgoingContent, Sas, Verification};
@@ -27,7 +26,7 @@ use crate::{OutgoingRequest, OutgoingVerificationRequest, RoomMessageRequest, To
#[derive(Clone, Debug)]
pub struct VerificationCache {
verification: Arc<DashMap<Box<UserId>, DashMap<String, Verification>>>,
outgoing_requests: Arc<DashMap<Uuid, OutgoingRequest>>,
outgoing_requests: Arc<DashMap<Box<TransactionId>, OutgoingRequest>>,
}
impl VerificationCache {
@@ -119,12 +118,14 @@ impl VerificationCache {
pub fn add_request(&self, request: OutgoingRequest) {
trace!("Adding an outgoing verification request {:?}", request);
self.outgoing_requests.insert(request.request_id, request);
self.outgoing_requests.insert(request.request_id.clone(), request);
}
pub fn add_verification_request(&self, request: OutgoingVerificationRequest) {
let request =
OutgoingRequest { request_id: request.request_id(), request: Arc::new(request.into()) };
let request = OutgoingRequest {
request_id: request.request_id().to_owned(),
request: Arc::new(request.into()),
};
self.add_request(request);
}
@@ -137,21 +138,25 @@ impl VerificationCache {
match content {
OutgoingContent::ToDevice(c) => {
let request = ToDeviceRequest::new(recipient, recipient_device.to_owned(), c);
let request_id = request.txn_id;
let request_id = request.txn_id.clone();
let request = OutgoingRequest { request_id, request: Arc::new(request.into()) };
let request = OutgoingRequest {
request_id: request_id.clone(),
request: Arc::new(request.into()),
};
self.outgoing_requests.insert(request_id, request);
}
OutgoingContent::Room(r, c) => {
let request_id = Uuid::new_v4();
let request_id = TransactionId::new();
let request = OutgoingRequest {
request: Arc::new(
RoomMessageRequest { room_id: r, txn_id: request_id, content: c }.into(),
RoomMessageRequest { room_id: r, txn_id: request_id.clone(), content: c }
.into(),
),
request_id,
request_id: request_id.clone(),
};
self.outgoing_requests.insert(request_id, request);
@@ -159,7 +164,7 @@ impl VerificationCache {
}
}
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
self.outgoing_requests.remove(uuid);
pub fn mark_request_as_sent(&self, txn_id: &TransactionId) {
self.outgoing_requests.remove(txn_id);
}
}

View File

@@ -42,7 +42,7 @@ use ruma::{
room::message::{KeyVerificationRequestEventContent, MessageType},
AnyMessageEvent, AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent,
},
serde::CanonicalJsonValue,
serde::{Base64, CanonicalJsonValue},
DeviceId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
};
@@ -272,6 +272,7 @@ pub enum RequestContent<'a> {
}
impl RequestContent<'_> {
#[allow(clippy::wrong_self_convention)]
pub fn from_device(&self) -> &DeviceId {
match self {
Self::ToDevice(t) => &t.from_device,
@@ -294,6 +295,7 @@ pub enum ReadyContent<'a> {
}
impl ReadyContent<'_> {
#[allow(clippy::wrong_self_convention)]
pub fn from_device(&self) -> &DeviceId {
match self {
Self::ToDevice(t) => &t.from_device,
@@ -422,6 +424,7 @@ pub enum StartContent<'a> {
}
impl<'a> StartContent<'a> {
#[allow(clippy::wrong_self_convention)]
pub fn from_device(&self) -> &DeviceId {
match self {
Self::ToDevice(c) => &c.from_device,
@@ -431,7 +434,7 @@ impl<'a> StartContent<'a> {
pub fn flow_id(&self) -> &str {
match self {
Self::ToDevice(c) => &c.transaction_id,
Self::ToDevice(c) => c.transaction_id.as_str(),
Self::Room(c) => c.relates_to.event_id.as_str(),
}
}
@@ -483,7 +486,7 @@ impl<'a> From<&'a ToDeviceKeyVerificationDoneEventContent> for DoneContent<'a> {
impl<'a> DoneContent<'a> {
pub fn flow_id(&self) -> &str {
match self {
Self::ToDevice(c) => &c.transaction_id,
Self::ToDevice(c) => c.transaction_id.as_str(),
Self::Room(c) => c.relates_to.event_id.as_str(),
}
}
@@ -498,7 +501,7 @@ pub enum AcceptContent<'a> {
impl AcceptContent<'_> {
pub fn flow_id(&self) -> &str {
match self {
Self::ToDevice(c) => &c.transaction_id,
Self::ToDevice(c) => c.transaction_id.as_str(),
Self::Room(c) => c.relates_to.event_id.as_str(),
}
}
@@ -529,12 +532,12 @@ pub enum KeyContent<'a> {
impl KeyContent<'_> {
pub fn flow_id(&self) -> &str {
match self {
Self::ToDevice(c) => &c.transaction_id,
Self::ToDevice(c) => c.transaction_id.as_str(),
Self::Room(c) => c.relates_to.event_id.as_str(),
}
}
pub fn public_key(&self) -> &str {
pub fn public_key(&self) -> &Base64 {
match self {
Self::ToDevice(c) => &c.key,
Self::Room(c) => &c.key,
@@ -551,19 +554,19 @@ pub enum MacContent<'a> {
impl MacContent<'_> {
pub fn flow_id(&self) -> &str {
match self {
Self::ToDevice(c) => &c.transaction_id,
Self::ToDevice(c) => c.transaction_id.as_str(),
Self::Room(c) => c.relates_to.event_id.as_str(),
}
}
pub fn mac(&self) -> &BTreeMap<String, String> {
pub fn mac(&self) -> &BTreeMap<String, Base64> {
match self {
Self::ToDevice(c) => &c.mac,
Self::Room(c) => &c.mac,
}
}
pub fn keys(&self) -> &str {
pub fn keys(&self) -> &Base64 {
match self {
Self::ToDevice(c) => &c.keys,
Self::Room(c) => &c.keys,

View File

@@ -18,14 +18,14 @@ use std::{
};
use dashmap::DashMap;
use matrix_sdk_common::{locks::Mutex, util::milli_seconds_since_unix_epoch, uuid::Uuid};
use matrix_sdk_common::{locks::Mutex, util::milli_seconds_since_unix_epoch};
use ruma::{
events::{
key::verification::VerificationMethod, AnyToDeviceEvent, AnyToDeviceEventContent,
ToDeviceEvent,
},
serde::Raw,
DeviceId, EventId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
DeviceId, EventId, MilliSecondsSinceUnixEpoch, RoomId, TransactionId, UserId,
};
use tracing::{info, trace, warn};
@@ -80,7 +80,7 @@ impl VerificationMachine {
recipient_devices: Vec<Box<DeviceId>>,
methods: Option<Vec<VerificationMethod>>,
) -> (VerificationRequest, OutgoingVerificationRequest) {
let flow_id = FlowId::from(Uuid::new_v4().to_string());
let flow_id = FlowId::from(TransactionId::new());
let verification = VerificationRequest::new(
self.verifications.clone(),
@@ -145,7 +145,7 @@ impl VerificationMachine {
let request = match content {
OutgoingContent::Room(r, c) => {
RoomMessageRequest { room_id: r, txn_id: Uuid::new_v4(), content: c }.into()
RoomMessageRequest { room_id: r, txn_id: TransactionId::new(), content: c }.into()
}
OutgoingContent::ToDevice(c) => {
let request =
@@ -215,8 +215,8 @@ impl VerificationMachine {
self.verifications.queue_up_content(recipient, recipient_device, content)
}
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
self.verifications.mark_request_as_sent(uuid);
pub fn mark_request_as_sent(&self, txn_id: &TransactionId) {
self.verifications.mark_request_as_sent(txn_id);
}
pub fn outgoing_messages(&self) -> Vec<OutgoingRequest> {
@@ -616,7 +616,7 @@ mod test {
assert!(!alice_machine.verifications.outgoing_requests().is_empty());
let request = alice_machine.verifications.outgoing_requests().get(0).cloned().unwrap();
let txn_id = *request.request_id();
let txn_id = request.request_id().to_owned();
let content = OutgoingContent::try_from(request).unwrap();
let content = KeyContent::try_from(&content).unwrap().into();

View File

@@ -47,7 +47,7 @@ use ruma::{
},
AnyMessageEventContent, AnyToDeviceEventContent,
},
DeviceId, DeviceKeyId, EventId, RoomId, UserId,
DeviceId, DeviceKeyId, EventId, RoomId, TransactionId, UserId,
};
pub use sas::{AcceptSettings, Sas};
use tracing::{error, info, trace, warn};
@@ -355,7 +355,7 @@ impl Cancelled {
#[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
pub enum FlowId {
ToDevice(String),
ToDevice(Box<TransactionId>),
InRoom(Box<RoomId>, Box<EventId>),
}
@@ -376,8 +376,8 @@ impl FlowId {
}
}
impl From<String> for FlowId {
fn from(transaction_id: String) -> Self {
impl From<Box<TransactionId>> for FlowId {
fn from(transaction_id: Box<TransactionId>) -> Self {
FlowId::ToDevice(transaction_id)
}
}

View File

@@ -18,7 +18,6 @@ use matrix_qrcode::{
qrcode::QrCode, EncodingError, QrVerificationData, SelfVerificationData,
SelfVerificationNoMasterKey, VerificationData,
};
use matrix_sdk_common::uuid::Uuid;
use ruma::{
api::client::r0::keys::upload_signatures::Request as SignatureUploadRequest,
events::{
@@ -33,7 +32,8 @@ use ruma::{
},
AnyMessageEventContent, AnyToDeviceEventContent,
},
DeviceId, DeviceKeyAlgorithm, RoomId, UserId,
serde::Base64,
DeviceId, DeviceKeyAlgorithm, RoomId, TransactionId, UserId,
};
use thiserror::Error;
use tracing::trace;
@@ -287,7 +287,7 @@ impl QrVerification {
fn content_to_request(&self, content: OutgoingContent) -> OutgoingVerificationRequest {
match content {
OutgoingContent::Room(room_id, content) => {
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
}
OutgoingContent::ToDevice(c) => ToDeviceRequest::new(
self.identities.other_user_id(),
@@ -430,11 +430,11 @@ impl QrVerification {
}
}
fn generate_secret() -> String {
fn generate_secret() -> Base64 {
let mut shared_secret = [0u8; SECRET_SIZE];
getrandom::getrandom(&mut shared_secret)
.expect("Can't generate randomness for the shared secret");
crate::utilities::encode(shared_secret)
Base64::new(shared_secret.to_vec())
}
pub(crate) fn new_self(
@@ -647,7 +647,7 @@ impl<S: Clone> QrState<S> {
#[derive(Clone, Debug)]
struct Created {
secret: String,
secret: Base64,
}
#[derive(Clone, Debug)]
@@ -659,7 +659,7 @@ struct Confirmed {}
#[derive(Clone, Debug)]
struct Reciprocated {
own_device_id: Box<DeviceId>,
secret: String,
secret: Base64,
}
impl Reciprocated {
@@ -830,7 +830,7 @@ mod test {
let store = VerificationStore { account: account.clone(), inner: store };
let private_identity = PrivateCrossSigningIdentity::new(user_id().to_owned()).await;
let flow_id = FlowId::ToDevice("test_transaction".to_owned());
let flow_id = FlowId::ToDevice("test_transaction".into());
let device_key = account.identity_keys().ed25519().to_owned();
let master_key = private_identity.master_public_key().await.unwrap();
@@ -994,7 +994,7 @@ mod test {
assert!(identity.is_verified());
};
let flow_id = FlowId::ToDevice("test_transaction".to_owned());
let flow_id = FlowId::ToDevice("test_transaction".into());
test(flow_id).await;
let flow_id =

View File

@@ -19,7 +19,7 @@ use std::{
#[cfg(feature = "qrcode")]
use matrix_qrcode::QrVerificationData;
use matrix_sdk_common::{instant::Instant, util::milli_seconds_since_unix_epoch, uuid::Uuid};
use matrix_sdk_common::{instant::Instant, util::milli_seconds_since_unix_epoch};
#[cfg(feature = "qrcode")]
use ruma::DeviceKeyAlgorithm;
use ruma::{
@@ -35,7 +35,7 @@ use ruma::{
AnyMessageEventContent, AnyToDeviceEventContent,
},
to_device::DeviceIdOrAllDevices,
DeviceId, RoomId, UserId,
DeviceId, RoomId, TransactionId, UserId,
};
use tracing::{info, trace, warn};
@@ -159,7 +159,7 @@ impl VerificationRequest {
let content = ToDeviceKeyVerificationRequestEventContent::new(
self.account.device_id().into(),
self.flow_id().as_str().to_string(),
self.flow_id().as_str().into(),
methods,
milli_seconds_since_unix_epoch(),
);
@@ -168,7 +168,7 @@ impl VerificationRequest {
self.other_user(),
self.recipient_devices.to_vec(),
AnyToDeviceEventContent::KeyVerificationRequest(content),
Uuid::new_v4(),
TransactionId::new(),
)
}
@@ -399,7 +399,7 @@ impl VerificationRequest {
ToDeviceRequest::new(self.other_user(), inner.other_device_id(), content).into()
}
OutgoingContent::Room(room_id, content) => {
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
}
})
}
@@ -446,7 +446,7 @@ impl VerificationRequest {
self.other_user(),
self.recipient_devices.to_vec(),
content,
Uuid::new_v4(),
TransactionId::new(),
)
.into()
} else {
@@ -454,7 +454,7 @@ impl VerificationRequest {
}
}
OutgoingContent::Room(room_id, content) => {
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
}
});
@@ -541,7 +541,7 @@ impl VerificationRequest {
self.other_user(),
recipients,
c,
Uuid::new_v4(),
TransactionId::new(),
))
}
} else {
@@ -656,7 +656,8 @@ impl VerificationRequest {
)
.into(),
OutgoingContent::Room(room_id, content) => {
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }
.into()
}
};
@@ -1345,6 +1346,7 @@ mod test {
None,
);
#[allow(clippy::needless_borrow)]
let alice_request = VerificationRequest::from_request(
VerificationCache::new(),
alice_identity,
@@ -1405,6 +1407,7 @@ mod test {
None,
);
#[allow(clippy::needless_borrow)]
let alice_request = VerificationRequest::from_request(
VerificationCache::new(),
alice_identity,
@@ -1460,7 +1463,7 @@ mod test {
let bob_store = VerificationStore { account: bob.clone(), inner: bob_store.into() };
let flow_id = FlowId::from("TEST_FLOW_ID".to_owned());
let flow_id = FlowId::ToDevice("TEST_FLOW_ID".into());
let bob_request = VerificationRequest::new(
VerificationCache::new(),

View File

@@ -24,6 +24,7 @@ use ruma::{
},
AnyMessageEventContent, AnyToDeviceEventContent,
},
serde::Base64,
DeviceKeyAlgorithm, DeviceKeyId, UserId,
};
use sha2::{Digest, Sha256};
@@ -32,7 +33,6 @@ use tracing::{trace, warn};
use super::{FlowId, OutgoingContent};
use crate::{
identities::{ReadOnlyDevice, ReadOnlyUserIdentities},
utilities::encode,
verification::event_enums::{MacContent, StartContent},
Emoji, ReadOnlyAccount, ReadOnlyOwnUserIdentity,
};
@@ -55,11 +55,18 @@ pub struct SasIds {
///
/// * `content` - The `m.key.verification.start` event content that started the
/// interactive verification process.
pub fn calculate_commitment(public_key: &str, content: &StartContent) -> String {
pub fn calculate_commitment(public_key: &Base64, content: &StartContent) -> Base64 {
let content = content.canonical_json();
let content_string = content.to_string();
encode(Sha256::new().chain(&public_key).chain(&content_string).finalize())
Base64::new(
Sha256::new()
.chain(public_key.encode())
.chain(&content_string)
.finalize()
.as_slice()
.to_owned(),
)
}
/// Get a tuple of an emoji and a description of the emoji using a number.
@@ -198,11 +205,13 @@ pub fn receive_mac_event(
let mut keys = content.mac().keys().map(|k| k.as_str()).collect::<Vec<_>>();
keys.sort_unstable();
let keys = sas
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
.expect("Can't calculate SAS MAC");
let keys = Base64::parse(
sas.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
.expect("Can't calculate SAS MAC"),
)
.expect("Can't base64-decode SAS MAC");
if keys != content.keys() {
if keys != *content.keys() {
return Err(CancelCode::KeyMismatch);
}
@@ -220,13 +229,14 @@ pub fn receive_mac_event(
};
if let Some(key) = ids.other_device.keys().get(&key_id) {
if key_mac
== &sas
.calculate_mac(key, &format!("{}{}", info, key_id))
.expect("Can't calculate SAS MAC")
{
trace!("Successfully verified the device key {} from {}", key_id, sender);
let calculated_mac = Base64::parse(
sas.calculate_mac(key, &format!("{}{}", info, key_id))
.expect("Can't calculate SAS MAC"),
)
.expect("Can't base64-decode SAS MAC");
if *key_mac == calculated_mac {
trace!("Successfully verified the device key {} from {}", key_id, sender);
verified_devices.push(ids.other_device.clone());
} else {
return Err(CancelCode::KeyMismatch);
@@ -235,11 +245,13 @@ pub fn receive_mac_event(
if let Some(key) = identity.master_key().get_key(&key_id) {
// TODO we should check that the master key signs the device,
// this way we know the master key also trusts the device
if key_mac
== &sas
.calculate_mac(key, &format!("{}{}", info, key_id))
.expect("Can't calculate SAS MAC")
{
let calculated_mac = Base64::parse(
sas.calculate_mac(key, &format!("{}{}", info, key_id))
.expect("Can't calculate SAS MAC"),
)
.expect("Can't base64-decode SAS MAC");
if *key_mac == calculated_mac {
trace!("Successfully verified the master key {} from {}", key_id, sender);
verified_identities.push(identity.clone())
} else {
@@ -294,7 +306,7 @@ fn extra_mac_info_send(ids: &SasIds, flow_id: &str) -> String {
///
/// This will panic if the public key of the other side wasn't set.
pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> OutgoingContent {
let mut mac: BTreeMap<String, String> = BTreeMap::new();
let mut mac: BTreeMap<String, Base64> = BTreeMap::new();
let key_id = DeviceKeyId::from_parts(DeviceKeyAlgorithm::Ed25519, ids.account.device_id());
let key = ids.account.identity_keys().ed25519();
@@ -302,7 +314,11 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> Outgoing
mac.insert(
key_id.to_string(),
sas.calculate_mac(key, &format!("{}{}", info, key_id)).expect("Can't calculate SAS MAC"),
Base64::parse(
sas.calculate_mac(key, &format!("{}{}", info, key_id))
.expect("Can't calculate SAS MAC"),
)
.expect("Can't base64-decode SAS MAC"),
);
if let Some(own_identity) = &ids.own_identity {
@@ -310,9 +326,11 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> Outgoing
if let Some(key) = own_identity.master_key().get_first_key() {
let key_id = format!("{}:{}", DeviceKeyAlgorithm::Ed25519, &key);
let calculated_mac = sas
.calculate_mac(key, &format!("{}{}", info, &key_id))
.expect("Can't calculate SAS Master key MAC");
let calculated_mac = Base64::parse(
sas.calculate_mac(key, &format!("{}{}", info, &key_id))
.expect("Can't calculate SAS Master key MAC"),
)
.expect("Can't base64-decode SAS Master key MAC");
mac.insert(key_id, calculated_mac);
}
@@ -321,15 +339,18 @@ pub fn get_mac_content(sas: &OlmSas, ids: &SasIds, flow_id: &FlowId) -> Outgoing
// TODO Add the cross signing master key here if we trust/have it.
let mut keys = mac.keys().cloned().collect::<Vec<String>>();
keys.sort();
let keys = sas
.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
.expect("Can't calculate SAS MAC");
let mut keys: Vec<_> = mac.keys().map(|s| s.as_str()).collect();
keys.sort_unstable();
let keys = Base64::parse(
sas.calculate_mac(&keys.join(","), &format!("{}KEY_IDS", &info))
.expect("Can't calculate SAS MAC"),
)
.expect("Can't base64-decode SAS MAC");
match flow_id {
FlowId::ToDevice(s) => AnyToDeviceEventContent::KeyVerificationMac(
ToDeviceKeyVerificationMacEventContent::new(s.to_string(), mac, keys),
ToDeviceKeyVerificationMacEventContent::new(s.clone(), mac, keys),
)
.into(),
FlowId::InRoom(r, e) => (
@@ -543,7 +564,9 @@ fn bytes_to_decimal(bytes: Vec<u8>) -> (u16, u16, u16) {
#[cfg(all(test, not(target_arch = "wasm32")))]
mod test {
use proptest::prelude::*;
use ruma::events::key::verification::start::ToDeviceKeyVerificationStartEventContent;
use ruma::{
events::key::verification::start::ToDeviceKeyVerificationStartEventContent, serde::Base64,
};
use serde_json::json;
use super::{
@@ -554,9 +577,9 @@ mod test {
#[test]
fn commitment_calculation() {
let commitment = "CCQmB4JCdB0FW21FdAnHj/Hu8+W9+Nb0vgwPEnZZQ4g";
let commitment = Base64::parse("CCQmB4JCdB0FW21FdAnHj/Hu8+W9+Nb0vgwPEnZZQ4g").unwrap();
let public_key = "Q/NmNFEUS1fS+YeEmiZkjjblKTitrKOAk7cPEumcMlg";
let public_key = Base64::parse("Q/NmNFEUS1fS+YeEmiZkjjblKTitrKOAk7cPEumcMlg").unwrap();
let content = json!({
"from_device":"XOWLHHFSWM",
"transaction_id":"bYxBsirjUJO9osar6ST4i2M2NjrYLA7l",
@@ -570,9 +593,9 @@ mod test {
let content: ToDeviceKeyVerificationStartEventContent =
serde_json::from_value(content).unwrap();
let content = StartContent::from(&content);
let calculated_commitment = calculate_commitment(public_key, &content);
let calculated_commitment = calculate_commitment(&public_key, &content);
assert_eq!(commitment, &calculated_commitment);
assert_eq!(commitment, calculated_commitment);
}
#[test]
@@ -606,8 +629,8 @@ mod test {
fn proptest_emoji(bytes in prop::array::uniform6(0u8..)) {
let numbers = bytes_to_emoji_index(bytes.to_vec());
for number in numbers.iter() {
prop_assert!(*number < 64);
for number in numbers {
prop_assert!(number < 64);
}
}
}

View File

@@ -18,7 +18,7 @@ use std::sync::Arc;
use matrix_sdk_common::instant::Instant;
use ruma::{
events::key::verification::{cancel::CancelCode, ShortAuthenticationString},
EventId, RoomId, UserId,
EventId, RoomId, TransactionId, UserId,
};
use super::{
@@ -57,7 +57,7 @@ impl InnerSas {
other_device: ReadOnlyDevice,
own_identity: Option<ReadOnlyOwnUserIdentity>,
other_identity: Option<ReadOnlyUserIdentities>,
transaction_id: Option<String>,
transaction_id: Option<Box<TransactionId>>,
) -> (InnerSas, OutgoingContent) {
let sas = SasState::<Created>::new(
account,

View File

@@ -21,14 +21,13 @@ use std::sync::{Arc, Mutex};
use inner_sas::InnerSas;
#[cfg(test)]
use matrix_sdk_common::instant::Instant;
use matrix_sdk_common::uuid::Uuid;
use ruma::{
api::client::r0::keys::upload_signatures::Request as SignatureUploadRequest,
events::{
key::verification::{cancel::CancelCode, ShortAuthenticationString},
AnyMessageEventContent, AnyToDeviceEventContent,
},
DeviceId, EventId, RoomId, UserId,
DeviceId, EventId, RoomId, TransactionId, UserId,
};
use tracing::trace;
@@ -190,7 +189,7 @@ impl Sas {
store: VerificationStore,
own_identity: Option<ReadOnlyOwnUserIdentity>,
other_identity: Option<ReadOnlyUserIdentities>,
transaction_id: Option<String>,
transaction_id: Option<Box<TransactionId>>,
we_started: bool,
request_handle: Option<RequestHandle>,
) -> (Sas, OutgoingContent) {
@@ -336,7 +335,7 @@ impl Sas {
}
OwnedAcceptContent::Room(room_id, content) => RoomMessageRequest {
room_id,
txn_id: Uuid::new_v4(),
txn_id: TransactionId::new(),
content: AnyMessageEventContent::KeyVerificationAccept(content),
}
.into(),
@@ -371,7 +370,8 @@ impl Sas {
.map(|c| match c {
OutgoingContent::ToDevice(c) => self.content_to_request(c).into(),
OutgoingContent::Room(r, c) => {
RoomMessageRequest { room_id: r, txn_id: Uuid::new_v4(), content: c }.into()
RoomMessageRequest { room_id: r, txn_id: TransactionId::new(), content: c }
.into()
}
})
.collect::<Vec<_>>();
@@ -438,7 +438,7 @@ impl Sas {
*guard = sas;
content.map(|c| match c {
OutgoingContent::Room(room_id, content) => {
RoomMessageRequest { room_id, txn_id: Uuid::new_v4(), content }.into()
RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
}
OutgoingContent::ToDevice(c) => self.content_to_request(c).into(),
})

View File

@@ -19,7 +19,7 @@ use std::{
time::Duration,
};
use matrix_sdk_common::{instant::Instant, uuid::Uuid};
use matrix_sdk_common::instant::Instant;
use olm_rs::sas::OlmSas;
use ruma::{
events::{
@@ -40,7 +40,8 @@ use ruma::{
},
AnyMessageEventContent, AnyToDeviceEventContent,
},
DeviceId, EventId, RoomId, UserId,
serde::Base64,
DeviceId, EventId, RoomId, TransactionId, UserId,
};
use tracing::info;
@@ -239,7 +240,7 @@ pub struct Created {
/// The initial SAS state if the other side started the SAS verification.
#[derive(Clone, Debug)]
pub struct Started {
commitment: String,
commitment: Base64,
pub accepted_protocols: Arc<AcceptedProtocols>,
}
@@ -249,7 +250,7 @@ pub struct Started {
pub struct Accepted {
pub accepted_protocols: Arc<AcceptedProtocols>,
start_content: Arc<OwnedStartContent>,
commitment: String,
commitment: Base64,
}
/// The SAS state we're going to be in after we accepted our
@@ -258,7 +259,7 @@ pub struct Accepted {
pub struct WeAccepted {
we_started: bool,
pub accepted_protocols: Arc<AcceptedProtocols>,
commitment: String,
commitment: Base64,
}
/// The SAS state we're going to be in after we received the public key of the
@@ -267,7 +268,7 @@ pub struct WeAccepted {
/// From now on we can show the short auth string to the user.
#[derive(Clone, Debug)]
pub struct KeyReceived {
their_pubkey: String,
their_pubkey: Base64,
we_started: bool,
pub accepted_protocols: Arc<AcceptedProtocols>,
}
@@ -286,7 +287,7 @@ pub struct Confirmed {
#[derive(Clone, Debug)]
pub struct MacReceived {
we_started: bool,
their_pubkey: String,
their_pubkey: Base64,
verified_devices: Arc<[ReadOnlyDevice]>,
verified_master_keys: Arc<[ReadOnlyUserIdentities]>,
pub accepted_protocols: Arc<AcceptedProtocols>,
@@ -375,11 +376,10 @@ impl SasState<Created> {
other_device: ReadOnlyDevice,
own_identity: Option<ReadOnlyOwnUserIdentity>,
other_identity: Option<ReadOnlyUserIdentities>,
transaction_id: Option<String>,
transaction_id: Option<Box<TransactionId>>,
) -> SasState<Created> {
let started_from_request = transaction_id.is_some();
let flow_id =
FlowId::ToDevice(transaction_id.unwrap_or_else(|| Uuid::new_v4().to_string()));
let flow_id = FlowId::ToDevice(transaction_id.unwrap_or_else(TransactionId::new));
Self::new_helper(
flow_id,
account,
@@ -440,7 +440,7 @@ impl SasState<Created> {
FlowId::ToDevice(s) => {
OwnedStartContent::ToDevice(ToDeviceKeyVerificationStartEventContent::new(
self.device_id().into(),
s.to_string(),
s.clone(),
StartMethod::SasV1(self.state.protocol_definitions.clone()),
))
}
@@ -540,7 +540,8 @@ impl SasState<Started> {
if let StartMethod::SasV1(method_content) = content.method() {
let sas = OlmSas::new();
let pubkey = sas.public_key();
let pubkey =
Base64::parse(sas.public_key()).expect("Couldn't base64-decode public key");
let commitment = calculate_commitment(&pubkey, content);
info!(
@@ -602,7 +603,7 @@ impl SasState<Started> {
FlowId::ToDevice(s) => {
OwnedStartContent::ToDevice(ToDeviceKeyVerificationStartEventContent::new(
self.device_id().into(),
s.to_string(),
s.clone(),
StartMethod::SasV1(the_protocol_definitions()),
))
}
@@ -695,7 +696,7 @@ impl SasState<WeAccepted> {
match self.verification_flow_id.as_ref() {
FlowId::ToDevice(s) => {
ToDeviceKeyVerificationAcceptEventContent::new(s.to_string(), method).into()
ToDeviceKeyVerificationAcceptEventContent::new(s.clone(), method).into()
}
FlowId::InRoom(r, e) => (
r.clone(),
@@ -725,7 +726,7 @@ impl SasState<WeAccepted> {
self.inner
.lock()
.unwrap()
.set_their_public_key(their_pubkey.clone())
.set_their_public_key(their_pubkey.encode())
.expect("Can't set public key");
Ok(SasState {
@@ -773,7 +774,7 @@ impl SasState<Accepted> {
self.inner
.lock()
.unwrap()
.set_their_public_key(their_pubkey.clone())
.set_their_public_key(their_pubkey.encode())
.expect("Can't set public key");
Ok(SasState {
@@ -799,15 +800,17 @@ impl SasState<Accepted> {
match &*self.verification_flow_id {
FlowId::ToDevice(s) => AnyToDeviceEventContent::KeyVerificationKey(
ToDeviceKeyVerificationKeyEventContent::new(
s.to_string(),
self.inner.lock().unwrap().public_key(),
s.clone(),
Base64::parse(self.inner.lock().unwrap().public_key())
.expect("Couldn't base64-decode public key"),
),
)
.into(),
FlowId::InRoom(r, e) => (
r.clone(),
AnyMessageEventContent::KeyVerificationKey(KeyVerificationKeyEventContent::new(
self.inner.lock().unwrap().public_key(),
Base64::parse(self.inner.lock().unwrap().public_key())
.expect("Couldn't base64-decode public key"),
Relation::new(e.clone()),
)),
)
@@ -825,15 +828,17 @@ impl SasState<KeyReceived> {
match &*self.verification_flow_id {
FlowId::ToDevice(s) => AnyToDeviceEventContent::KeyVerificationKey(
ToDeviceKeyVerificationKeyEventContent::new(
s.to_string(),
self.inner.lock().unwrap().public_key(),
s.clone(),
Base64::parse(self.inner.lock().unwrap().public_key())
.expect("Couldn't base64-decode public key"),
),
)
.into(),
FlowId::InRoom(r, e) => (
r.clone(),
AnyMessageEventContent::KeyVerificationKey(KeyVerificationKeyEventContent::new(
self.inner.lock().unwrap().public_key(),
Base64::parse(self.inner.lock().unwrap().public_key())
.expect("Couldn't base64-decode public key"),
Relation::new(e.clone()),
)),
)
@@ -849,7 +854,7 @@ impl SasState<KeyReceived> {
get_emoji(
&self.inner.lock().unwrap(),
&self.ids,
&self.state.their_pubkey,
&self.state.their_pubkey.encode(),
self.verification_flow_id.as_str(),
self.state.we_started,
)
@@ -863,7 +868,7 @@ impl SasState<KeyReceived> {
get_emoji_index(
&self.inner.lock().unwrap(),
&self.ids,
&self.state.their_pubkey,
&self.state.their_pubkey.encode(),
self.verification_flow_id.as_str(),
self.state.we_started,
)
@@ -877,7 +882,7 @@ impl SasState<KeyReceived> {
get_decimal(
&self.inner.lock().unwrap(),
&self.ids,
&self.state.their_pubkey,
&self.state.their_pubkey.encode(),
self.verification_flow_id.as_str(),
self.state.we_started,
)
@@ -1078,7 +1083,7 @@ impl SasState<MacReceived> {
get_emoji(
&self.inner.lock().unwrap(),
&self.ids,
&self.state.their_pubkey,
&self.state.their_pubkey.encode(),
self.verification_flow_id.as_str(),
self.state.we_started,
)
@@ -1092,7 +1097,7 @@ impl SasState<MacReceived> {
get_emoji_index(
&self.inner.lock().unwrap(),
&self.ids,
&self.state.their_pubkey,
&self.state.their_pubkey.encode(),
self.verification_flow_id.as_str(),
self.state.we_started,
)
@@ -1106,7 +1111,7 @@ impl SasState<MacReceived> {
get_decimal(
&self.inner.lock().unwrap(),
&self.ids,
&self.state.their_pubkey,
&self.state.their_pubkey.encode(),
self.verification_flow_id.as_str(),
self.state.we_started,
)
@@ -1206,13 +1211,17 @@ mod test {
start::{StartMethod, ToDeviceKeyVerificationStartEventContent},
ShortAuthenticationString,
},
serde::Base64,
user_id, DeviceId, UserId,
};
use serde_json::json;
use super::{Accepted, Created, SasState, Started, WeAccepted};
use crate::{
verification::event_enums::{AcceptContent, KeyContent, MacContent, StartContent},
verification::{
event_enums::{AcceptContent, KeyContent, MacContent, StartContent},
FlowId,
},
ReadOnlyAccount, ReadOnlyDevice,
};
@@ -1343,8 +1352,8 @@ mod test {
let mut method = content.method_mut();
match &mut method {
AcceptMethod::SasV1(ref mut c) => {
c.commitment = "".to_string();
AcceptMethod::SasV1(c) => {
c.commitment = Base64::empty();
}
_ => panic!("Unknown accept event content"),
}
@@ -1465,7 +1474,7 @@ mod test {
alice_device,
None,
None,
flow_id.into(),
FlowId::ToDevice(flow_id.into()),
&content,
false,
)

View File

@@ -23,5 +23,5 @@ serde_json = "1.0.64"
[dependencies.ruma]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
features = ["client-api-c"]

View File

@@ -26,13 +26,17 @@ pub enum EventsJson {
HistoryVisibility,
JoinRules,
Member,
MemberInvite,
MemberNameChange,
MessageEmote,
MessageNotice,
MessageText,
Name,
PowerLevels,
PushRules,
Presence,
ReadReceipt,
ReadReceiptOther,
RedactedInvalid,
RedactedState,
Redacted,
@@ -108,6 +112,8 @@ impl EventBuilder {
/// Add an event to the room events `Vec`.
pub fn add_ephemeral(&mut self, json: EventsJson) -> &mut Self {
let val: &JsonValue = match json {
EventsJson::ReadReceipt => &test_json::READ_RECEIPT,
EventsJson::ReadReceiptOther => &test_json::READ_RECEIPT_OTHER,
EventsJson::Typing => &test_json::TYPING,
_ => panic!("unknown ephemeral event {:?}", json),
};
@@ -118,9 +124,10 @@ impl EventBuilder {
}
/// Add an event to the room events `Vec`.
#[allow(clippy::match_single_binding, unused)]
#[allow(unused)]
pub fn add_account(&mut self, json: EventsJson) -> &mut Self {
let val: &JsonValue = match json {
EventsJson::PushRules => &test_json::PUSH_RULES,
_ => panic!("unknown account event {:?}", json),
};
@@ -133,6 +140,7 @@ impl EventBuilder {
pub fn add_room_event(&mut self, json: EventsJson) -> &mut Self {
let val: &JsonValue = match json {
EventsJson::Member => &test_json::MEMBER,
EventsJson::MemberInvite => &test_json::MEMBER_INVITE,
EventsJson::MemberNameChange => &test_json::MEMBER_NAME_CHANGE,
EventsJson::PowerLevels => &test_json::POWER_LEVELS,
_ => panic!("unknown room event json {:?}", json),

View File

@@ -267,6 +267,44 @@ lazy_static! {
});
}
lazy_static! {
pub static ref MEMBER_INVITE: JsonValue = json!({
"content": {
"avatar_url": "mxc://localhost/SEsfnsuifSDFSSEF",
"displayname": "example",
"membership": "invite",
"reason": "Looking for support"
},
"event_id": "$143273582443PhrSn:localhost",
"origin_server_ts": 1432735824,
"room_id": "!jEsUZKDJdhlrceRyVU:localhost",
"sender": "@example:localhost",
"state_key": "@invited:localhost",
"type": "m.room.member",
"unsigned": {
"age": 1234,
"invite_room_state": [
{
"content": {
"name": "Example Room"
},
"sender": "@example:localhost",
"state_key": "",
"type": "m.room.name"
},
{
"content": {
"join_rule": "invite"
},
"sender": "@example:localhost",
"state_key": "",
"type": "m.room.join_rules"
}
]
}
});
}
// TODO: Move `prev_content` into `unsigned` once ruma supports it
lazy_static! {
pub static ref MEMBER_NAME_CHANGE: JsonValue = json!({
@@ -293,6 +331,19 @@ lazy_static! {
});
}
lazy_static! {
pub static ref MEMBER_STRIPPED: JsonValue = json!({
"content": {
"avatar_url": null,
"displayname": "example",
"membership": "join"
},
"sender": "@example:localhost",
"state_key": "@example:localhost",
"type": "m.room.member",
});
}
lazy_static! {
pub static ref MESSAGE_EDIT: JsonValue = json!({
"content": {
@@ -386,6 +437,17 @@ lazy_static! {
});
}
lazy_static! {
pub static ref NAME_STRIPPED: JsonValue = json!({
"content": {
"name": "room name"
},
"sender": "@example:localhost",
"state_key": "",
"type": "m.room.name",
});
}
lazy_static! {
pub static ref POWER_LEVELS: JsonValue = json!({
"content": {
@@ -457,6 +519,205 @@ lazy_static! {
});
}
lazy_static! {
pub static ref PUSH_RULES: JsonValue = json!({
"content": {
"global": {
"content": [
{
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
],
"default": true,
"enabled": true,
"pattern": "example",
"rule_id": ".m.rule.contains_user_name"
}
],
"override": [
{
"actions": [
"dont_notify"
],
"conditions": [],
"default": true,
"enabled": false,
"rule_id": ".m.rule.master"
},
{
"actions": [
"dont_notify"
],
"conditions": [
{
"key": "content.msgtype",
"kind": "event_match",
"pattern": "m.notice"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.suppress_notices"
}
],
"room": [],
"sender": [],
"underride": [
{
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "ring"
},
{
"set_tweak": "highlight",
"value": false
}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.call.invite"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.call"
},
{
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight"
}
],
"conditions": [
{
"kind": "contains_display_name"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.contains_display_name"
},
{
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight",
"value": false
}
],
"conditions": [
{
"is": "2",
"kind": "room_member_count"
},
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.message"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.room_one_to_one"
},
{
"actions": [
"notify",
{
"set_tweak": "sound",
"value": "default"
},
{
"set_tweak": "highlight",
"value": false
}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
},
{
"key": "content.membership",
"kind": "event_match",
"pattern": "invite"
},
{
"key": "state_key",
"kind": "event_match",
"pattern": "@example:localhost"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.invite_for_me"
},
{
"actions": [
"notify",
{
"set_tweak": "highlight",
"value": false
}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.member"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.member_event"
},
{
"actions": [
"notify",
{
"set_tweak": "highlight",
"value": false
}
],
"conditions": [
{
"key": "type",
"kind": "event_match",
"pattern": "m.room.message"
}
],
"default": true,
"enabled": true,
"rule_id": ".m.rule.message"
}
]
}
},
"type": "m.push_rules"
});
}
lazy_static! {
pub static ref REGISTRATION_RESPONSE_ERR: JsonValue = json!({
"errcode": "M_FORBIDDEN",
@@ -498,6 +759,38 @@ lazy_static! {
});
}
lazy_static! {
pub static ref READ_RECEIPT: JsonValue = json!({
"content": {
"$example": {
"m.read": {
"@example:localhost": {
"ts": 1436451550
}
}
}
},
"room_id": "!test:localhost",
"type": "m.receipt"
});
}
lazy_static! {
pub static ref READ_RECEIPT_OTHER: JsonValue = json!({
"content": {
"$other": {
"m.read": {
"@example:localhost": {
"ts": 1436964550
}
}
}
},
"room_id": "!test:localhost",
"type": "m.receipt"
});
}
lazy_static! {
pub static ref REDACTED_INVALID: JsonValue = json!({
"content": {},

View File

@@ -13,9 +13,11 @@ pub mod sync;
pub use events::{
ALIAS, ALIASES, EVENT_ID, KEYS_QUERY, KEYS_UPLOAD, LOGIN, LOGIN_RESPONSE_ERR, LOGIN_TYPES,
LOGIN_WITH_DISCOVERY, LOGOUT, MEMBER, MEMBER_NAME_CHANGE, MESSAGE_EDIT, MESSAGE_TEXT, NAME,
POWER_LEVELS, PRESENCE, PUBLIC_ROOMS, REACTION, REDACTED, REDACTED_INVALID, REDACTED_STATE,
REDACTION, REGISTRATION_RESPONSE_ERR, ROOM_ID, ROOM_MESSAGES, TYPING,
LOGIN_WITH_DISCOVERY, LOGOUT, MEMBER, MEMBER_INVITE, MEMBER_NAME_CHANGE, MEMBER_STRIPPED,
MESSAGE_EDIT, MESSAGE_TEXT, NAME, NAME_STRIPPED, POWER_LEVELS, PRESENCE, PUBLIC_ROOMS,
PUSH_RULES, REACTION, READ_RECEIPT, READ_RECEIPT_OTHER, REDACTED, REDACTED_INVALID,
REDACTED_STATE, REDACTION, REGISTRATION_RESPONSE_ERR, ROOM_ID, ROOM_MESSAGES, TAG, TOPIC,
TYPING,
};
pub use members::MEMBERS;
pub use sync::{

View File

@@ -35,7 +35,7 @@ native-tls = ["reqwest/native-tls"]
rustls-tls = ["reqwest/rustls-tls"]
socks = ["reqwest/socks"]
sso_login = ["warp", "rand", "tokio-stream"]
appservice = ["ruma/appservice-api-s", "ruma/appservice-api-helper", "ruma/rand"]
appservice = ["ruma/appservice-api-s", "ruma/appservice-api-helper"]
docsrs = [
"encryption",
@@ -77,8 +77,8 @@ default_features = false
[dependencies.ruma]
git = "https://github.com/ruma/ruma/"
rev = "fdbc4d6d1dd273c8a6ac95b329943ed8c68df70d"
features = ["client-api-c", "compat", "unstable-pre-spec"]
rev = "37095f88553b311e7a70adaaabe39976fb8ff71c"
features = ["client-api-c", "compat", "rand", "unstable-pre-spec"]
[dependencies.tokio-stream]
version = "0.1.6"

View File

@@ -23,7 +23,8 @@ async fn on_room_message(event: SyncRoomMessageEvent, room: Room) {
println!("sending");
// send our message to the room we found the "!party" command in
// the last parameter is an optional Uuid which we don't care about.
// the last parameter is an optional transaction id which we don't
// care about.
room.send(content, None).await.unwrap();
println!("message sent");

View File

@@ -86,8 +86,9 @@ async fn login(
for event in response.to_device.events.iter().filter_map(|e| e.deserialize().ok()) {
match event {
AnyToDeviceEvent::KeyVerificationStart(e) => {
if let Some(Verification::SasV1(sas)) =
client.get_verification(&e.sender, &e.content.transaction_id).await
if let Some(Verification::SasV1(sas)) = client
.get_verification(&e.sender, e.content.transaction_id.as_str())
.await
{
println!(
"Starting verification with {} {}",
@@ -100,16 +101,18 @@ async fn login(
}
AnyToDeviceEvent::KeyVerificationKey(e) => {
if let Some(Verification::SasV1(sas)) =
client.get_verification(&e.sender, &e.content.transaction_id).await
if let Some(Verification::SasV1(sas)) = client
.get_verification(&e.sender, e.content.transaction_id.as_str())
.await
{
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
}
}
AnyToDeviceEvent::KeyVerificationMac(e) => {
if let Some(Verification::SasV1(sas)) =
client.get_verification(&e.sender, &e.content.transaction_id).await
if let Some(Verification::SasV1(sas)) = client
.get_verification(&e.sender, e.content.transaction_id.as_str())
.await
{
if sas.is_done() {
print_result(&sas);

View File

@@ -15,6 +15,12 @@ wasm-bindgen = { version = "0.2.74", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.24"
console_error_panic_hook = "0.1.6"
web-sys = { version = "0.3.51", features = ["console"] }
# The uuid and getrandom crates are indirect dependencies that require extra features to be enabled
# for (some) wasm use cases. FIXME: These features should be re-exposed by matrix-sdk / Ruma but for
# now adding the extra dependency here is a good-enough workaround.
uuid = { version = "0.8.2", features = ["wasm-bindgen"] }
# https://docs.rs/getrandom/latest/getrandom/#webassembly-support
getrandom = { version = "0.2.4", features = ["js"] }
[dependencies.matrix-sdk]
path = "../.."

View File

@@ -45,7 +45,8 @@ impl WasmBot {
if let Some(room) = self.0.get_joined_room(&room_id) {
// send our message to the room we found the "!party" command in
// the last parameter is an optional Uuid which we don't care about.
// the last parameter is an optional transaction id which we
// don't care about.
room.send(content, None).await.unwrap();
}

View File

@@ -36,6 +36,8 @@ use matrix_sdk_common::{
locks::{Mutex, RwLock, RwLockReadGuard},
};
use mime::{self, Mime};
#[cfg(feature = "encryption")]
use ruma::TransactionId;
use ruma::{
api::{
client::{
@@ -285,7 +287,7 @@ impl Client {
#[cfg(feature = "encryption")]
pub(crate) async fn mark_request_as_sent(
&self,
request_id: &matrix_sdk_base::uuid::Uuid,
request_id: &TransactionId,
response: impl Into<matrix_sdk_base::crypto::IncomingResponse<'_>>,
) -> Result<(), matrix_sdk_base::Error> {
self.base_client().mark_request_as_sent(request_id, response).await
@@ -2404,7 +2406,7 @@ pub(crate) mod test {
},
AnySyncStateEvent, EventType,
},
mxc_uri, room_id, thirdparty, uint, user_id, UserId,
mxc_uri, room_id, thirdparty, uint, user_id, TransactionId, UserId,
};
use serde_json::json;
@@ -3158,8 +3160,6 @@ pub(crate) mod test {
#[async_test]
async fn room_message_send() {
use matrix_sdk_common::uuid::Uuid;
let client = logged_in_client().await;
let _m = mock("PUT", Matcher::Regex(r"^/_matrix/client/r0/rooms/.*/send/".to_string()))
@@ -3181,8 +3181,8 @@ pub(crate) mod test {
let room = client.get_joined_room(room_id!("!SVkFJHzfwvuaIEawgC:localhost")).unwrap();
let content = RoomMessageEventContent::text_plain("Hello world");
let txn_id = Uuid::new_v4();
let response = room.send(content, Some(txn_id)).await.unwrap();
let txn_id = TransactionId::new();
let response = room.send(content, Some(&txn_id)).await.unwrap();
assert_eq!(event_id!("$h29iv0s8:example.com"), response.event_id)
}
@@ -3230,8 +3230,6 @@ pub(crate) mod test {
#[async_test]
async fn room_redact() {
use matrix_sdk_common::uuid::Uuid;
let client = logged_in_client().await;
let _m =
@@ -3255,7 +3253,7 @@ pub(crate) mod test {
let event_id = event_id!("$xxxxxxxx:example.com");
let txn_id = Uuid::new_v4();
let txn_id = TransactionId::new();
let reason = Some("Indecent material");
let response = room.redact(event_id, reason, Some(txn_id)).await.unwrap();

View File

@@ -264,7 +264,7 @@ use matrix_sdk_base::{
},
deserialized_responses::RoomEvent,
};
use matrix_sdk_common::{instant::Duration, uuid::Uuid};
use matrix_sdk_common::instant::Duration;
use ruma::{
api::client::r0::{
backup::add_backup_keys::Response as KeysBackupResponse,
@@ -278,7 +278,7 @@ use ruma::{
assign,
events::{AnyMessageEvent, AnyRoomEvent, AnySyncMessageEvent, EventType},
serde::Raw,
DeviceId, UserId,
DeviceId, TransactionId, UserId,
};
use tracing::{debug, instrument, trace, warn};
@@ -718,7 +718,7 @@ impl Client {
#[instrument]
pub(crate) async fn keys_query(
&self,
request_id: &Uuid,
request_id: &TransactionId,
device_keys: BTreeMap<Box<UserId>, Vec<Box<DeviceId>>>,
) -> Result<get_keys::Response> {
let request = assign!(get_keys::Request::new(), { device_keys });
@@ -880,7 +880,7 @@ impl Client {
#[instrument]
pub(crate) async fn keys_upload(
&self,
request_id: &Uuid,
request_id: &TransactionId,
request: &upload_keys::Request,
) -> Result<upload_keys::Response> {
debug!(
@@ -901,7 +901,7 @@ impl Client {
request: &RoomMessageRequest,
) -> Result<send_message_event::Response> {
let content = request.content.clone();
let txn_id = request.txn_id;
let txn_id = &request.txn_id;
let room_id = &request.room_id;
self.get_joined_room(room_id)
@@ -915,11 +915,9 @@ impl Client {
&self,
request: &ToDeviceRequest,
) -> HttpResult<ToDeviceResponse> {
let txn_id_string = request.txn_id_string();
let request = RumaToDeviceRequest::new_raw(
request.event_type.as_str(),
&txn_id_string,
&request.txn_id,
request.messages.clone(),
);

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use matrix_sdk_base::crypto::{AcceptSettings, CancelInfo, ReadOnlyDevice, Sas as BaseSas};
use ruma::UserId;
use ruma::{events::key::verification::cancel::CancelCode, UserId};
use crate::{error::Result, Client};
@@ -89,6 +89,16 @@ impl SasVerification {
Ok(())
}
/// Cancel the interactive verification flow because the short auth strings didn't match on both sides.
pub async fn mismatch(&self) -> Result<()> {
// FIXME: Use variant once https://github.com/ruma/ruma/pull/804 is merged
if let Some(request) = self.inner.cancel_with_code(CancelCode::from("m.mismatched_sas")) {
self.client.send_verification_request(request).await?;
}
Ok(())
}
/// Cancel the interactive verification flow.
pub async fn cancel(&self) -> Result<()> {
if let Some(request) = self.inner.cancel() {

View File

@@ -49,7 +49,7 @@ impl Deref for Common {
#[derive(Debug)]
pub struct Messages {
/// The token the pagination starts from.
pub start: Option<String>,
pub start: String,
/// The token the pagination ends at.
pub end: Option<String>,

View File

@@ -2,12 +2,9 @@
use std::sync::Arc;
use std::{io::Read, ops::Deref};
use matrix_sdk_common::instant::{Duration, Instant};
#[cfg(feature = "encryption")]
use matrix_sdk_common::locks::Mutex;
use matrix_sdk_common::{
instant::{Duration, Instant},
uuid::Uuid,
};
use mime::{self, Mime};
use ruma::{
api::client::r0::{
@@ -27,7 +24,7 @@ use ruma::{
events::{room::message::RoomMessageEventContent, MessageEventContent, StateEventContent},
receipt::ReceiptType,
serde::Raw,
EventId, UserId,
EventId, TransactionId, UserId,
};
use serde_json::Value;
use tracing::debug;
@@ -406,15 +403,12 @@ impl Joined {
/// # use matrix_sdk::ruma::room_id;
/// # use std::convert::TryFrom;
/// # use serde::{Deserialize, Serialize};
/// use matrix_sdk::{
/// uuid::Uuid,
/// ruma::{
/// events::{
/// macros::EventContent,
/// room::message::{RoomMessageEventContent, TextMessageEventContent},
/// },
/// uint, MilliSecondsSinceUnixEpoch,
/// use matrix_sdk::ruma::{
/// events::{
/// macros::EventContent,
/// room::message::{RoomMessageEventContent, TextMessageEventContent},
/// },
/// uint, MilliSecondsSinceUnixEpoch, TransactionId,
/// };
/// # block_on(async {
/// # let homeserver = Url::parse("http://localhost:8080")?;
@@ -422,10 +416,10 @@ impl Joined {
/// # let room_id = room_id!("!test:localhost");
///
/// let content = RoomMessageEventContent::text_plain("Hello world");
/// let txn_id = Uuid::new_v4();
/// let txn_id = TransactionId::new();
///
/// if let Some(room) = client.get_joined_room(&room_id) {
/// room.send(content, Some(txn_id)).await?;
/// room.send(content, Some(&txn_id)).await?;
/// }
///
/// // Custom events work too:
@@ -445,10 +439,10 @@ impl Joined {
/// MilliSecondsSinceUnixEpoch(now.0 + uint!(30_000))
/// },
/// };
/// let txn_id = Uuid::new_v4();
/// let txn_id = TransactionId::new();
///
/// if let Some(room) = client.get_joined_room(&room_id) {
/// room.send(content, Some(txn_id)).await?;
/// room.send(content, Some(&txn_id)).await?;
/// }
/// # Result::<_, matrix_sdk::Error>::Ok(()) });
/// ```
@@ -459,7 +453,7 @@ impl Joined {
pub async fn send(
&self,
content: impl MessageEventContent,
txn_id: Option<Uuid>,
txn_id: Option<&TransactionId>,
) -> Result<send_message_event::Response> {
let event_type = content.event_type();
let content = serde_json::to_value(&content)?;
@@ -528,9 +522,9 @@ impl Joined {
&self,
content: Value,
event_type: &str,
txn_id: Option<Uuid>,
txn_id: Option<&TransactionId>,
) -> Result<send_message_event::Response> {
let txn_id = txn_id.unwrap_or_else(Uuid::new_v4).to_string();
let txn_id: Box<TransactionId> = txn_id.map_or_else(TransactionId::new, ToOwned::to_owned);
#[cfg(not(feature = "encryption"))]
let content = {
@@ -604,7 +598,7 @@ impl Joined {
/// * `reader` - A `Reader` that will be used to fetch the raw bytes of the
/// media.
///
/// * `txn_id` - A unique `Uuid` that can be attached to a `MessageEvent`
/// * `txn_id` - A unique ID that can be attached to a `MessageEvent`
/// held in its unsigned field as `transaction_id`. If not given one is
/// created for the message.
///
@@ -638,7 +632,7 @@ impl Joined {
body: &str,
content_type: &Mime,
reader: &mut R,
txn_id: Option<Uuid>,
txn_id: Option<&TransactionId>,
) -> Result<send_message_event::Response> {
#[cfg(feature = "encryption")]
let content = if self.is_encrypted() {
@@ -774,7 +768,7 @@ impl Joined {
///
/// * `reason` - The reason for the event being redacted.
///
/// * `txn_id` - A unique [`Uuid`] that can be attached to this event as
/// * `txn_id` - A unique ID that can be attached to this event as
/// its transaction ID. If not given one is created for the message.
///
/// # Example
@@ -797,9 +791,9 @@ impl Joined {
&self,
event_id: &EventId,
reason: Option<&str>,
txn_id: Option<Uuid>,
txn_id: Option<Box<TransactionId>>,
) -> HttpResult<redact_event::Response> {
let txn_id = txn_id.unwrap_or_else(Uuid::new_v4).to_string();
let txn_id = txn_id.unwrap_or_else(TransactionId::new);
let request =
assign!(redact_event::Request::new(self.inner.room_id(), event_id, &txn_id), {
reason

View File

@@ -42,6 +42,7 @@ impl Left {
pub async fn forget(&self) -> Result<()> {
let request = forget_room::Request::new(self.inner.room_id());
let _response = self.client.send(request, None).await?;
self.client.store().remove_room(self.inner.room_id()).await?;
Ok(())
}