mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-18 05:30:33 -04:00
Merge remote-tracking branch 'origin/main' into ben-remove-store-key
This commit is contained in:
@@ -12,7 +12,7 @@ criterion = { version = "0.3.4", features = ["async", "async_tokio", "html_repor
|
||||
matrix-sdk-crypto = { path = "../crates/matrix-sdk-crypto" }
|
||||
matrix-sdk-sled = { path = "../crates/matrix-sdk-sled", default-features = false, features = ["crypto-store"] }
|
||||
matrix-sdk-test = { path = "../crates/matrix-sdk-test" }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "deea762b8" }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "548232ef5" }
|
||||
serde_json = "1.0.79"
|
||||
tempfile = "3.2.0"
|
||||
tokio = { version = "1.7.1", default-features = false, features = ["rt-multi-thread"] }
|
||||
|
||||
@@ -47,7 +47,7 @@ features = ["rt-multi-thread"]
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma"
|
||||
rev = "deea762b8"
|
||||
rev = "548232ef5"
|
||||
features = ["client-api-c"]
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -31,7 +31,7 @@ use ruma::{
|
||||
IncomingResponse,
|
||||
},
|
||||
events::{
|
||||
key::verification::VerificationMethod, room::encrypted::SyncRoomEncryptedEvent,
|
||||
key::verification::VerificationMethod, room::encrypted::OriginalSyncRoomEncryptedEvent,
|
||||
AnyMessageLikeEventContent, EventContent,
|
||||
},
|
||||
DeviceKeyAlgorithm, EventId, RoomId, TransactionId, UserId,
|
||||
@@ -535,7 +535,7 @@ impl OlmMachine {
|
||||
content: &'a RawValue,
|
||||
}
|
||||
|
||||
let event: SyncRoomEncryptedEvent = serde_json::from_str(event)?;
|
||||
let event: OriginalSyncRoomEncryptedEvent = serde_json::from_str(event)?;
|
||||
let room_id = RoomId::parse(room_id)?;
|
||||
|
||||
let decrypted = self.runtime.block_on(self.inner.decrypt_room_event(&event, &room_id))?;
|
||||
@@ -573,7 +573,7 @@ impl OlmMachine {
|
||||
event: &str,
|
||||
room_id: &str,
|
||||
) -> Result<KeyRequestPair, DecryptionError> {
|
||||
let event: SyncRoomEncryptedEvent = serde_json::from_str(event)?;
|
||||
let event: OriginalSyncRoomEncryptedEvent = serde_json::from_str(event)?;
|
||||
let room_id = RoomId::parse(room_id)?;
|
||||
|
||||
let (cancel, request) =
|
||||
|
||||
@@ -24,10 +24,10 @@ base64 = "0.13.0"
|
||||
byteorder = "1.4.3"
|
||||
image = { version = "0.23.14", optional = true }
|
||||
qrcode = { version = "0.12.0", default-features = false }
|
||||
ruma-common = { git = "https://github.com/ruma/ruma", rev = "deea762b8" }
|
||||
ruma-common = { git = "https://github.com/ruma/ruma", rev = "548232ef5" }
|
||||
rqrr = { version = "0.4.0", optional = true }
|
||||
thiserror = "1.0.25"
|
||||
|
||||
[dependencies.vodozemac]
|
||||
git = "https://github.com/matrix-org/vodozemac"
|
||||
rev = "443b6530510004a60a9e5937ff4021f7b06f63c8"
|
||||
rev = "e09c93f2c8df9770793abeec57ed984d5e1f3834"
|
||||
|
||||
@@ -29,7 +29,7 @@ http = "0.2"
|
||||
matrix-sdk = { version = "0.4", path = "../matrix-sdk", default-features = false, features = ["appservice"] }
|
||||
percent-encoding = "2.1.0"
|
||||
regex = "1"
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "deea762b8", features = ["client-api-c", "appservice-api-s"] }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "548232ef5", features = ["client-api-c", "appservice-api-s"] }
|
||||
serde = "1"
|
||||
serde_json = "1"
|
||||
serde_yaml = "0.8"
|
||||
|
||||
@@ -5,7 +5,7 @@ use matrix_sdk_appservice::{
|
||||
event_handler::Ctx,
|
||||
room::Room,
|
||||
ruma::{
|
||||
events::room::member::{MembershipState, SyncRoomMemberEvent},
|
||||
events::room::member::{MembershipState, OriginalSyncRoomMemberEvent},
|
||||
UserId,
|
||||
},
|
||||
},
|
||||
@@ -16,7 +16,7 @@ use tracing::trace;
|
||||
pub async fn handle_room_member(
|
||||
appservice: AppService,
|
||||
room: Room,
|
||||
event: SyncRoomMemberEvent,
|
||||
event: OriginalSyncRoomMemberEvent,
|
||||
) -> Result<()> {
|
||||
if !appservice.user_id_is_in_namespace(&event.state_key)? {
|
||||
trace!("not an appservice user: {}", event.state_key);
|
||||
@@ -44,7 +44,9 @@ pub async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
appservice
|
||||
.register_event_handler_context(appservice.clone())?
|
||||
.register_event_handler(
|
||||
move |event: SyncRoomMemberEvent, room: Room, Ctx(appservice): Ctx<AppService>| {
|
||||
move |event: OriginalSyncRoomMemberEvent,
|
||||
room: Room,
|
||||
Ctx(appservice): Ctx<AppService>| {
|
||||
handle_room_member(appservice, room, event)
|
||||
},
|
||||
)
|
||||
|
||||
@@ -5,7 +5,7 @@ use std::{
|
||||
|
||||
use matrix_sdk::{
|
||||
config::RequestConfig,
|
||||
ruma::{api::appservice::Registration, events::room::member::SyncRoomMemberEvent},
|
||||
ruma::{api::appservice::Registration, events::room::member::OriginalSyncRoomMemberEvent},
|
||||
Client,
|
||||
};
|
||||
use matrix_sdk_appservice::*;
|
||||
@@ -204,7 +204,7 @@ async fn test_event_handler() -> Result<()> {
|
||||
appservice
|
||||
.register_event_handler({
|
||||
let on_state_member = on_state_member.clone();
|
||||
move |_ev: SyncRoomMemberEvent| {
|
||||
move |_ev: OriginalSyncRoomMemberEvent| {
|
||||
*on_state_member.lock().unwrap() = true;
|
||||
future::ready(())
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ matrix-sdk-common = { version = "0.4.0", path = "../matrix-sdk-common" }
|
||||
matrix-sdk-crypto = { version = "0.4.0", path = "../matrix-sdk-crypto", optional = true }
|
||||
pbkdf2 = { version = "0.10.0", default-features = false, optional = true }
|
||||
rand = { version = "0.8.4", optional = true }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "deea762b8", features = ["client-api-c", "signatures"] }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "548232ef5", features = ["client-api-c", "signatures"] }
|
||||
serde = { version = "1.0.126", features = ["rc"] }
|
||||
serde_json = "1.0.64"
|
||||
sha2 = { version = "0.10.1", optional = true }
|
||||
|
||||
@@ -45,7 +45,7 @@ use ruma::{
|
||||
api::client::keys::claim_keys::v3::Request as KeysClaimRequest,
|
||||
events::{
|
||||
room::{encrypted::RoomEncryptedEventContent, history_visibility::HistoryVisibility},
|
||||
AnySyncMessageLikeEvent, EventContent, MessageLikeEventType,
|
||||
AnySyncMessageLikeEvent, MessageLikeEventContent, SyncMessageLikeEvent,
|
||||
},
|
||||
DeviceId, TransactionId,
|
||||
};
|
||||
@@ -55,6 +55,7 @@ use ruma::{
|
||||
push_rules::PushRulesEvent, room::member::MembershipState, AnyGlobalAccountDataEvent,
|
||||
AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncEphemeralRoomEvent,
|
||||
AnySyncRoomEvent, AnySyncStateEvent, GlobalAccountDataEventType, StateEventType,
|
||||
SyncStateEvent,
|
||||
},
|
||||
push::{Action, PushConditionRoomCtx, Ruleset},
|
||||
serde::Raw,
|
||||
@@ -260,7 +261,7 @@ impl BaseClient {
|
||||
#[allow(clippy::single_match)]
|
||||
match &e {
|
||||
AnySyncRoomEvent::State(s) => match s {
|
||||
AnySyncStateEvent::RoomMember(member) => {
|
||||
AnySyncStateEvent::RoomMember(SyncStateEvent::Original(member)) => {
|
||||
if let Ok(member) = MemberEvent::try_from(member.clone()) {
|
||||
ambiguity_cache.handle_event(changes, room_id, &member).await?;
|
||||
|
||||
@@ -293,7 +294,7 @@ impl BaseClient {
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
room_info.handle_state_event(&s.content());
|
||||
room_info.handle_state_event(s);
|
||||
let raw_event: Raw<AnySyncStateEvent> = event.event.clone().cast();
|
||||
changes.add_state_event(room_id, s.clone(), raw_event);
|
||||
}
|
||||
@@ -301,7 +302,7 @@ impl BaseClient {
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(
|
||||
encrypted,
|
||||
SyncMessageLikeEvent::Original(encrypted),
|
||||
)) => {
|
||||
if let Some(olm) = self.olm_machine().await {
|
||||
if let Ok(decrypted) =
|
||||
@@ -385,7 +386,7 @@ impl BaseClient {
|
||||
}
|
||||
}
|
||||
Ok(e) => {
|
||||
room_info.handle_state_event(&e.content());
|
||||
room_info.handle_stripped_state_event(&e);
|
||||
state_events
|
||||
.entry(e.event_type())
|
||||
.or_insert_with(BTreeMap::new)
|
||||
@@ -429,9 +430,9 @@ impl BaseClient {
|
||||
}
|
||||
};
|
||||
|
||||
room_info.handle_state_event(&event.content());
|
||||
room_info.handle_state_event(&event);
|
||||
|
||||
if let AnySyncStateEvent::RoomMember(member) = event {
|
||||
if let AnySyncStateEvent::RoomMember(SyncStateEvent::Original(member)) = event {
|
||||
match MemberEvent::try_from(member) {
|
||||
Ok(m) => {
|
||||
ambiguity_cache.handle_event(changes, &room_id, &m).await?;
|
||||
@@ -1020,7 +1021,7 @@ impl BaseClient {
|
||||
pub async fn encrypt(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
content: impl EventContent<EventType = MessageLikeEventType>,
|
||||
content: impl MessageLikeEventContent,
|
||||
) -> Result<RoomEncryptedEventContent> {
|
||||
match self.olm_machine().await {
|
||||
Some(o) => Ok(o.encrypt(room_id, content).await?),
|
||||
@@ -1210,14 +1211,14 @@ impl BaseClient {
|
||||
.and_then(|events| events.get(""))
|
||||
.and_then(|e| e.deserialize().ok())
|
||||
{
|
||||
event.content
|
||||
event.power_levels()
|
||||
} else if let Some(AnySyncStateEvent::RoomPowerLevels(event)) = self
|
||||
.store
|
||||
.get_state_event(room_id, StateEventType::RoomPowerLevels, "")
|
||||
.await?
|
||||
.and_then(|e| e.deserialize().ok())
|
||||
{
|
||||
event.content
|
||||
event.power_levels()
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
@@ -1260,7 +1261,7 @@ impl BaseClient {
|
||||
.and_then(|events| events.get(""))
|
||||
.and_then(|e| e.deserialize().ok())
|
||||
{
|
||||
let room_power_levels = event.content;
|
||||
let room_power_levels = event.power_levels();
|
||||
|
||||
push_rules.users_power_levels = room_power_levels.users;
|
||||
push_rules.default_power_level = room_power_levels.users_default;
|
||||
|
||||
@@ -92,11 +92,11 @@ impl RoomMember {
|
||||
(*self.power_levels)
|
||||
.as_ref()
|
||||
.map(|e| {
|
||||
e.content
|
||||
.users
|
||||
let pls = e.power_levels();
|
||||
pls.users
|
||||
.get(self.user_id())
|
||||
.map(|p| (*p).into())
|
||||
.unwrap_or_else(|| e.content.users_default.into())
|
||||
.unwrap_or_else(|| pls.users_default.into())
|
||||
})
|
||||
.unwrap_or_else(|| if self.is_room_creator { 100 } else { 0 })
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ use ruma::{
|
||||
guest_access::GuestAccess, history_visibility::HistoryVisibility, join_rules::JoinRule,
|
||||
tombstone::RoomTombstoneEventContent,
|
||||
},
|
||||
AnyStateEventContent,
|
||||
AnyStrippedStateEvent, AnySyncStateEvent, SyncStateEvent,
|
||||
},
|
||||
MxcUri, RoomAliasId, UserId,
|
||||
};
|
||||
@@ -72,42 +72,103 @@ impl BaseRoomInfo {
|
||||
/// Handle a state event for this room and update our info accordingly.
|
||||
///
|
||||
/// Returns true if the event modified the info, false otherwise.
|
||||
pub fn handle_state_event(&mut self, content: &AnyStateEventContent) -> bool {
|
||||
match content {
|
||||
AnyStateEventContent::RoomEncryption(encryption) => {
|
||||
self.encryption = Some(encryption.clone());
|
||||
pub fn handle_state_event(&mut self, ev: &AnySyncStateEvent) -> bool {
|
||||
match ev {
|
||||
// No redacted branch - enabling encryption cannot be undone.
|
||||
AnySyncStateEvent::RoomEncryption(SyncStateEvent::Original(encryption)) => {
|
||||
self.encryption = Some(encryption.content.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomAvatar(a) => {
|
||||
self.avatar_url = a.url.clone();
|
||||
AnySyncStateEvent::RoomAvatar(a) => {
|
||||
self.avatar_url = a.as_original().and_then(|a| a.content.url.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomName(n) => {
|
||||
self.name = n.name.as_ref().map(|n| n.to_string());
|
||||
AnySyncStateEvent::RoomName(n) => {
|
||||
self.name =
|
||||
n.as_original().and_then(|n| n.content.name.as_ref().map(|n| n.to_string()));
|
||||
}
|
||||
AnyStateEventContent::RoomCreate(c) if self.create.is_none() => {
|
||||
self.create = Some(c.clone());
|
||||
AnySyncStateEvent::RoomCreate(SyncStateEvent::Original(c)) if self.create.is_none() => {
|
||||
self.create = Some(c.content.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomHistoryVisibility(h) => {
|
||||
self.history_visibility = h.history_visibility.clone();
|
||||
AnySyncStateEvent::RoomHistoryVisibility(h) => {
|
||||
self.history_visibility = match h {
|
||||
SyncStateEvent::Original(h) => h.content.history_visibility.clone(),
|
||||
SyncStateEvent::Redacted(h) => h.content.history_visibility.clone(),
|
||||
};
|
||||
}
|
||||
AnyStateEventContent::RoomGuestAccess(g) => {
|
||||
self.guest_access = g.guest_access.clone();
|
||||
AnySyncStateEvent::RoomGuestAccess(g) => {
|
||||
self.guest_access = g
|
||||
.as_original()
|
||||
.map_or(GuestAccess::Forbidden, |g| g.content.guest_access.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomJoinRules(c) => {
|
||||
self.join_rule = c.join_rule.clone();
|
||||
AnySyncStateEvent::RoomJoinRules(c) => {
|
||||
self.join_rule = match c {
|
||||
SyncStateEvent::Original(c) => c.content.join_rule.clone(),
|
||||
SyncStateEvent::Redacted(c) => c.content.join_rule.clone(),
|
||||
};
|
||||
}
|
||||
AnyStateEventContent::RoomCanonicalAlias(a) => {
|
||||
self.canonical_alias = a.alias.clone();
|
||||
AnySyncStateEvent::RoomCanonicalAlias(a) => {
|
||||
self.canonical_alias = a.as_original().and_then(|a| a.content.alias.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomTopic(t) => {
|
||||
self.topic = Some(t.topic.clone());
|
||||
AnySyncStateEvent::RoomTopic(t) => {
|
||||
self.topic = t.as_original().map(|t| t.content.topic.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomTombstone(t) => {
|
||||
self.tombstone = Some(t.clone());
|
||||
AnySyncStateEvent::RoomTombstone(t) => {
|
||||
self.tombstone = t.as_original().map(|t| t.content.clone());
|
||||
}
|
||||
AnyStateEventContent::RoomPowerLevels(p) => {
|
||||
let max_power_level =
|
||||
p.users.values().fold(self.max_power_level, |acc, &p| max(acc, p.into()));
|
||||
self.max_power_level = max_power_level;
|
||||
AnySyncStateEvent::RoomPowerLevels(p) => {
|
||||
self.max_power_level = p
|
||||
.power_levels()
|
||||
.users
|
||||
.values()
|
||||
.fold(self.max_power_level, |acc, &p| max(acc, p.into()));
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
/// Handle a stripped state event for this room and update our info
|
||||
/// accordingly.
|
||||
///
|
||||
/// Returns true if the event modified the info, false otherwise.
|
||||
pub fn handle_stripped_state_event(&mut self, ev: &AnyStrippedStateEvent) -> bool {
|
||||
match ev {
|
||||
AnyStrippedStateEvent::RoomEncryption(encryption) => {
|
||||
self.encryption = Some(encryption.content.clone());
|
||||
}
|
||||
AnyStrippedStateEvent::RoomAvatar(a) => {
|
||||
self.avatar_url = a.content.url.clone();
|
||||
}
|
||||
AnyStrippedStateEvent::RoomName(n) => {
|
||||
self.name = n.content.name.as_ref().map(|n| n.to_string());
|
||||
}
|
||||
AnyStrippedStateEvent::RoomCreate(c) if self.create.is_none() => {
|
||||
self.create = Some(c.content.clone());
|
||||
}
|
||||
AnyStrippedStateEvent::RoomHistoryVisibility(h) => {
|
||||
self.history_visibility = h.content.history_visibility.clone();
|
||||
}
|
||||
AnyStrippedStateEvent::RoomGuestAccess(g) => {
|
||||
self.guest_access = g.content.guest_access.clone();
|
||||
}
|
||||
AnyStrippedStateEvent::RoomJoinRules(c) => {
|
||||
self.join_rule = c.content.join_rule.clone();
|
||||
}
|
||||
AnyStrippedStateEvent::RoomCanonicalAlias(a) => {
|
||||
self.canonical_alias = a.content.alias.clone();
|
||||
}
|
||||
AnyStrippedStateEvent::RoomTopic(t) => {
|
||||
self.topic = Some(t.content.topic.clone());
|
||||
}
|
||||
AnyStrippedStateEvent::RoomTombstone(t) => {
|
||||
self.tombstone = Some(t.content.clone());
|
||||
}
|
||||
AnyStrippedStateEvent::RoomPowerLevels(p) => {
|
||||
self.max_power_level = p
|
||||
.content
|
||||
.users
|
||||
.values()
|
||||
.fold(self.max_power_level, |acc, &p| max(acc, p.into()));
|
||||
}
|
||||
_ => return false,
|
||||
}
|
||||
@@ -124,7 +185,7 @@ impl Default for BaseRoomInfo {
|
||||
create: None,
|
||||
dm_target: None,
|
||||
encryption: None,
|
||||
guest_access: GuestAccess::CanJoin,
|
||||
guest_access: GuestAccess::Forbidden,
|
||||
history_visibility: HistoryVisibility::WorldReadable,
|
||||
join_rule: JoinRule::Public,
|
||||
max_power_level: 100,
|
||||
|
||||
@@ -29,8 +29,8 @@ use ruma::{
|
||||
tombstone::RoomTombstoneEventContent,
|
||||
},
|
||||
tag::Tags,
|
||||
AnyRoomAccountDataEvent, AnyStateEventContent, AnySyncStateEvent, RoomAccountDataEventType,
|
||||
StateEventType,
|
||||
AnyRoomAccountDataEvent, AnyStrippedStateEvent, AnySyncStateEvent,
|
||||
RoomAccountDataEventType, StateEventType,
|
||||
},
|
||||
receipt::ReceiptType,
|
||||
room::RoomType as CreateRoomType,
|
||||
@@ -654,13 +654,20 @@ impl RoomInfo {
|
||||
self.base_info.encryption.is_some()
|
||||
}
|
||||
|
||||
/// handle the given State event.
|
||||
/// Handle the given state event.
|
||||
///
|
||||
/// Returns true if the event modified the info, false otherwise.
|
||||
pub fn handle_state_event(&mut self, event: &AnyStateEventContent) -> bool {
|
||||
pub fn handle_state_event(&mut self, event: &AnySyncStateEvent) -> bool {
|
||||
self.base_info.handle_state_event(event)
|
||||
}
|
||||
|
||||
/// Handle the given stripped tate event.
|
||||
///
|
||||
/// Returns true if the event modified the info, false otherwise.
|
||||
pub fn handle_stripped_state_event(&mut self, event: &AnyStrippedStateEvent) -> bool {
|
||||
self.base_info.handle_stripped_state_event(event)
|
||||
}
|
||||
|
||||
/// Update the notifications count
|
||||
pub fn update_notification_count(&mut self, notification_counts: UnreadNotificationsCount) {
|
||||
self.notification_counts = notification_counts;
|
||||
|
||||
@@ -147,14 +147,14 @@ macro_rules! statestore_integration_tests {
|
||||
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());
|
||||
room.handle_state_event(&name_event);
|
||||
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());
|
||||
room.handle_state_event(&topic_event);
|
||||
changes.add_state_event(room_id, topic_event, topic_raw);
|
||||
|
||||
let mut room_ambiguity_map = BTreeMap::new();
|
||||
@@ -213,7 +213,7 @@ macro_rules! statestore_integration_tests {
|
||||
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());
|
||||
stripped_room.handle_stripped_state_event(&stripped_name_event);
|
||||
changes.stripped_state.insert(
|
||||
stripped_room_id.to_owned(),
|
||||
BTreeMap::from([(
|
||||
|
||||
@@ -26,7 +26,10 @@ use ruma::{
|
||||
events::{
|
||||
presence::PresenceEvent,
|
||||
receipt::Receipt,
|
||||
room::member::{MembershipState, RoomMemberEventContent},
|
||||
room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
redaction::SyncRoomRedactionEvent,
|
||||
},
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent,
|
||||
AnySyncMessageLikeEvent, AnySyncRoomEvent, AnySyncStateEvent, GlobalAccountDataEventType,
|
||||
RoomAccountDataEventType, StateEventType,
|
||||
@@ -361,7 +364,9 @@ impl MemoryStore {
|
||||
for event in &timeline.events {
|
||||
// Redact events already in store only on sync response
|
||||
if let Ok(AnySyncRoomEvent::MessageLike(
|
||||
AnySyncMessageLikeEvent::RoomRedaction(redaction),
|
||||
AnySyncMessageLikeEvent::RoomRedaction(SyncRoomRedactionEvent::Original(
|
||||
redaction,
|
||||
)),
|
||||
)) = event.event.deserialize()
|
||||
{
|
||||
let pos = data.event_id_to_position.get(&redaction.redacts).copied();
|
||||
|
||||
@@ -17,7 +17,7 @@ targets = ["x86_64-unknown-linux-gnu", "wasm32-unknown-unknown"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1.50"
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "deea762b8", features = ["client-api-c"] }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "548232ef5", features = ["client-api-c"] }
|
||||
serde = "1.0.126"
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
|
||||
|
||||
@@ -10,7 +10,8 @@ use ruma::{
|
||||
},
|
||||
events::{
|
||||
room::member::{
|
||||
RoomMemberEvent, RoomMemberEventContent, StrippedRoomMemberEvent, SyncRoomMemberEvent,
|
||||
OriginalRoomMemberEvent, OriginalSyncRoomMemberEvent, RoomMemberEventContent,
|
||||
StrippedRoomMemberEvent,
|
||||
},
|
||||
AnyRoomEvent, AnySyncRoomEvent, StateUnsigned,
|
||||
},
|
||||
@@ -296,7 +297,7 @@ impl TimelineSlice {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[serde(try_from = "SyncRoomMemberEvent", into = "SyncRoomMemberEvent")]
|
||||
#[serde(try_from = "OriginalSyncRoomMemberEvent", into = "OriginalSyncRoomMemberEvent")]
|
||||
pub struct MemberEvent {
|
||||
pub content: RoomMemberEventContent,
|
||||
pub event_id: Box<EventId>,
|
||||
@@ -306,10 +307,10 @@ pub struct MemberEvent {
|
||||
pub unsigned: StateUnsigned<RoomMemberEventContent>,
|
||||
}
|
||||
|
||||
impl TryFrom<SyncRoomMemberEvent> for MemberEvent {
|
||||
impl TryFrom<OriginalSyncRoomMemberEvent> for MemberEvent {
|
||||
type Error = ruma::IdParseError;
|
||||
|
||||
fn try_from(event: SyncRoomMemberEvent) -> Result<Self, Self::Error> {
|
||||
fn try_from(event: OriginalSyncRoomMemberEvent) -> Result<Self, Self::Error> {
|
||||
Ok(MemberEvent {
|
||||
content: event.content,
|
||||
event_id: event.event_id,
|
||||
@@ -321,10 +322,10 @@ impl TryFrom<SyncRoomMemberEvent> for MemberEvent {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RoomMemberEvent> for MemberEvent {
|
||||
impl TryFrom<OriginalRoomMemberEvent> for MemberEvent {
|
||||
type Error = ruma::IdParseError;
|
||||
|
||||
fn try_from(event: RoomMemberEvent) -> Result<Self, Self::Error> {
|
||||
fn try_from(event: OriginalRoomMemberEvent) -> Result<Self, Self::Error> {
|
||||
Ok(MemberEvent {
|
||||
content: event.content,
|
||||
event_id: event.event_id,
|
||||
@@ -336,7 +337,7 @@ impl TryFrom<RoomMemberEvent> for MemberEvent {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MemberEvent> for SyncRoomMemberEvent {
|
||||
impl From<MemberEvent> for OriginalSyncRoomMemberEvent {
|
||||
fn from(other: MemberEvent) -> Self {
|
||||
Self {
|
||||
content: other.content,
|
||||
@@ -395,8 +396,8 @@ mod tests {
|
||||
use ruma::{
|
||||
event_id,
|
||||
events::{
|
||||
room::message::RoomMessageEventContent, AnyMessageLikeEvent, AnySyncMessageLikeEvent,
|
||||
AnySyncRoomEvent, MessageLikeEvent, MessageLikeUnsigned,
|
||||
room::message::RoomMessageEventContent, AnySyncMessageLikeEvent, AnySyncRoomEvent,
|
||||
MessageLikeUnsigned, OriginalMessageLikeEvent, SyncMessageLikeEvent,
|
||||
},
|
||||
room_id,
|
||||
serde::Raw,
|
||||
@@ -409,7 +410,7 @@ mod tests {
|
||||
fn room_event_to_sync_room_event() {
|
||||
let content = RoomMessageEventContent::text_plain("foobar");
|
||||
|
||||
let event = MessageLikeEvent {
|
||||
let event = OriginalMessageLikeEvent {
|
||||
content,
|
||||
event_id: event_id!("$xxxxx:example.org").to_owned(),
|
||||
room_id: room_id!("!someroom:example.com").to_owned(),
|
||||
@@ -425,9 +426,9 @@ mod tests {
|
||||
|
||||
let converted_event: AnySyncRoomEvent = converted_room_event.event.deserialize().unwrap();
|
||||
|
||||
let event: AnyMessageLikeEvent = event.into();
|
||||
let sync_event: AnySyncMessageLikeEvent = event.into();
|
||||
let sync_event: AnySyncRoomEvent = sync_event.into();
|
||||
let sync_event = AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(
|
||||
SyncMessageLikeEvent::Original(event.into()),
|
||||
));
|
||||
|
||||
// There is no PartialEq implementation for AnySyncRoomEvent, so we
|
||||
// just compare a couple of fields here. The important thing is that
|
||||
|
||||
@@ -52,16 +52,16 @@ http = { version = "0.2.4", optional = true }
|
||||
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.vodozemac]
|
||||
git = "https://github.com/matrix-org/vodozemac"
|
||||
rev = "443b6530510004a60a9e5937ff4021f7b06f63c8"
|
||||
rev = "e09c93f2c8df9770793abeec57ed984d5e1f3834"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.vodozemac]
|
||||
git = "https://github.com/matrix-org/vodozemac"
|
||||
rev = "443b6530510004a60a9e5937ff4021f7b06f63c8"
|
||||
rev = "e09c93f2c8df9770793abeec57ed984d5e1f3834"
|
||||
features = ["js"]
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma"
|
||||
rev = "deea762b8"
|
||||
rev = "548232ef5"
|
||||
features = ["client-api-c", "rand", "unstable-msc2676", "unstable-msc2677"]
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -39,7 +39,7 @@ pub enum OlmError {
|
||||
|
||||
/// The received room key couldn't be converted into a valid Megolm session.
|
||||
#[error(transparent)]
|
||||
SessionCreation(#[from] vodozemac::megolm::SessionCreationError),
|
||||
SessionCreation(#[from] vodozemac::megolm::SessionKeyDecodeError),
|
||||
|
||||
/// The storage layer returned an error.
|
||||
#[error("failed to read or write to the crypto store {0}")]
|
||||
|
||||
@@ -336,7 +336,7 @@ mod tests {
|
||||
let decrypted = decrypt_key_export(Cursor::new(encrypted), "1234").unwrap();
|
||||
|
||||
for (exported, decrypted) in export.iter().zip(decrypted.iter()) {
|
||||
assert_eq!(exported.session_key.as_str(), decrypted.session_key.as_str());
|
||||
assert_eq!(exported.session_key.to_base64(), decrypted.session_key.to_base64());
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
use std::{
|
||||
collections::{BTreeMap, BTreeSet, HashSet},
|
||||
mem,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
@@ -36,18 +35,19 @@ use ruma::{
|
||||
assign,
|
||||
events::{
|
||||
room::encrypted::{
|
||||
EncryptedEventScheme, MegolmV1AesSha2Content, RoomEncryptedEventContent,
|
||||
SyncRoomEncryptedEvent, ToDeviceRoomEncryptedEvent,
|
||||
EncryptedEventScheme, MegolmV1AesSha2Content, OriginalSyncRoomEncryptedEvent,
|
||||
RoomEncryptedEventContent, ToDeviceRoomEncryptedEvent,
|
||||
},
|
||||
room_key::ToDeviceRoomKeyEvent,
|
||||
secret::request::SecretName,
|
||||
AnyRoomEvent, AnyToDeviceEvent, EventContent, MessageLikeEventType,
|
||||
AnyRoomEvent, AnyToDeviceEvent, MessageLikeEventContent,
|
||||
},
|
||||
DeviceId, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId, TransactionId,
|
||||
UInt, UserId,
|
||||
};
|
||||
use serde_json::Value;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "backups_v1")]
|
||||
use crate::backups::BackupMachine;
|
||||
@@ -556,16 +556,17 @@ impl OlmMachine {
|
||||
) -> OlmResult<(Option<AnyToDeviceEvent>, Option<InboundGroupSession>)> {
|
||||
match event.content.algorithm {
|
||||
EventEncryptionAlgorithm::MegolmV1AesSha2 => {
|
||||
let session_key = SessionKey(mem::take(&mut event.content.session_key));
|
||||
match SessionKey::from_base64(&event.content.session_key) {
|
||||
Ok(session_key) => {
|
||||
event.content.session_key.zeroize();
|
||||
let session = InboundGroupSession::new(
|
||||
sender_key,
|
||||
signing_key,
|
||||
&event.content.room_id,
|
||||
session_key,
|
||||
None,
|
||||
);
|
||||
|
||||
match InboundGroupSession::new(
|
||||
sender_key,
|
||||
signing_key,
|
||||
&event.content.room_id,
|
||||
session_key,
|
||||
None,
|
||||
) {
|
||||
Ok(session) => {
|
||||
info!(
|
||||
sender = event.sender.as_str(),
|
||||
sender_key = sender_key,
|
||||
@@ -658,7 +659,7 @@ impl OlmMachine {
|
||||
pub async fn encrypt(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
content: impl EventContent<EventType = MessageLikeEventType>,
|
||||
content: impl MessageLikeEventContent,
|
||||
) -> MegolmResult<RoomEncryptedEventContent> {
|
||||
let event_type = content.event_type().to_string();
|
||||
let content = serde_json::to_value(&content)?;
|
||||
@@ -985,7 +986,7 @@ impl OlmMachine {
|
||||
/// * `session_id` - The id that uniquely identifies the session.
|
||||
pub async fn request_room_key(
|
||||
&self,
|
||||
event: &SyncRoomEncryptedEvent,
|
||||
event: &OriginalSyncRoomEncryptedEvent,
|
||||
room_id: &RoomId,
|
||||
) -> MegolmResult<(Option<OutgoingRequest>, OutgoingRequest)> {
|
||||
let content = match &event.content.scheme {
|
||||
@@ -1038,7 +1039,7 @@ impl OlmMachine {
|
||||
async fn decrypt_megolm_v1_event(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event: &SyncRoomEncryptedEvent,
|
||||
event: &OriginalSyncRoomEncryptedEvent,
|
||||
content: &MegolmV1AesSha2Content,
|
||||
) -> MegolmResult<RoomEvent> {
|
||||
if let Some(session) = self
|
||||
@@ -1099,7 +1100,7 @@ impl OlmMachine {
|
||||
/// * `room_id` - The ID of the room where the event was sent to.
|
||||
pub async fn decrypt_room_event(
|
||||
&self,
|
||||
event: &SyncRoomEncryptedEvent,
|
||||
event: &OriginalSyncRoomEncryptedEvent,
|
||||
room_id: &RoomId,
|
||||
) -> MegolmResult<RoomEvent> {
|
||||
match &event.content.scheme {
|
||||
@@ -1312,7 +1313,7 @@ impl OlmMachine {
|
||||
let mut keys = BTreeMap::new();
|
||||
|
||||
for (i, key) in exported_keys.into_iter().enumerate() {
|
||||
let session = InboundGroupSession::from_export(key)?;
|
||||
let session = InboundGroupSession::from_export(key);
|
||||
|
||||
// Only import the session if we didn't have this session or if it's
|
||||
// a better version of the same session, that is the first known
|
||||
@@ -1535,8 +1536,8 @@ pub(crate) mod tests {
|
||||
message::{MessageType, RoomMessageEventContent},
|
||||
},
|
||||
AnyMessageLikeEvent, AnyMessageLikeEventContent, AnyRoomEvent, AnyToDeviceEvent,
|
||||
AnyToDeviceEventContent, MessageLikeEvent, MessageLikeUnsigned, SyncMessageLikeEvent,
|
||||
ToDeviceEvent,
|
||||
AnyToDeviceEventContent, MessageLikeEvent, MessageLikeUnsigned,
|
||||
OriginalMessageLikeEvent, OriginalSyncMessageLikeEvent, ToDeviceEvent,
|
||||
},
|
||||
room_id,
|
||||
serde::Raw,
|
||||
@@ -1956,7 +1957,7 @@ pub(crate) mod tests {
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let event = SyncMessageLikeEvent {
|
||||
let event = OriginalSyncMessageLikeEvent {
|
||||
event_id: event_id!("$xxxxx:example.org").to_owned(),
|
||||
origin_server_ts: milli_seconds_since_unix_epoch(),
|
||||
sender: alice.user_id().to_owned(),
|
||||
@@ -1967,11 +1968,9 @@ pub(crate) mod tests {
|
||||
let decrypted_event =
|
||||
bob.decrypt_room_event(&event, room_id).await.unwrap().event.deserialize().unwrap();
|
||||
|
||||
if let AnyRoomEvent::MessageLike(AnyMessageLikeEvent::RoomMessage(MessageLikeEvent {
|
||||
sender,
|
||||
content,
|
||||
..
|
||||
})) = decrypted_event
|
||||
if let AnyRoomEvent::MessageLike(AnyMessageLikeEvent::RoomMessage(
|
||||
MessageLikeEvent::Original(OriginalMessageLikeEvent { sender, content, .. }),
|
||||
)) = decrypted_event
|
||||
{
|
||||
assert_eq!(&sender, alice.user_id());
|
||||
if let MessageType::Text(c) = &content.msgtype {
|
||||
|
||||
@@ -1077,8 +1077,7 @@ impl ReadOnlyAccount {
|
||||
room_id,
|
||||
outbound.session_key().await,
|
||||
Some(visibility),
|
||||
)
|
||||
.expect("Can't create inbound group session from a newly created outbound group session");
|
||||
);
|
||||
|
||||
Ok((outbound, inbound))
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
convert::TryFrom,
|
||||
fmt, mem,
|
||||
fmt,
|
||||
sync::{
|
||||
atomic::{AtomicBool, Ordering::SeqCst},
|
||||
Arc,
|
||||
@@ -29,7 +28,7 @@ use ruma::{
|
||||
events::{
|
||||
forwarded_room_key::ToDeviceForwardedRoomKeyEventContent,
|
||||
room::{
|
||||
encrypted::{EncryptedEventScheme, SyncRoomEncryptedEvent},
|
||||
encrypted::{EncryptedEventScheme, OriginalSyncRoomEncryptedEvent},
|
||||
history_visibility::HistoryVisibility,
|
||||
},
|
||||
AnyRoomEvent,
|
||||
@@ -42,10 +41,11 @@ use serde_json::Value;
|
||||
use vodozemac::{
|
||||
megolm::{
|
||||
DecryptedMessage, DecryptionError, ExportedSessionKey, InboundGroupSession as InnerSession,
|
||||
InboundGroupSessionPickle, MegolmMessage, SessionCreationError,
|
||||
InboundGroupSessionPickle, MegolmMessage, SessionKeyDecodeError,
|
||||
},
|
||||
PickleError,
|
||||
};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
use super::{BackedUpRoomKey, ExportedRoomKey, SessionKey};
|
||||
use crate::error::{EventError, MegolmResult};
|
||||
@@ -99,15 +99,15 @@ impl InboundGroupSession {
|
||||
room_id: &RoomId,
|
||||
session_key: SessionKey,
|
||||
history_visibility: Option<HistoryVisibility>,
|
||||
) -> Result<Self, SessionCreationError> {
|
||||
let session = InnerSession::new(&session_key)?;
|
||||
) -> Self {
|
||||
let session = InnerSession::new(&session_key);
|
||||
let session_id = session.session_id();
|
||||
let first_known_index = session.first_known_index();
|
||||
|
||||
let mut keys: BTreeMap<DeviceKeyAlgorithm, String> = BTreeMap::new();
|
||||
keys.insert(DeviceKeyAlgorithm::Ed25519, signing_key.to_owned());
|
||||
|
||||
Ok(InboundGroupSession {
|
||||
InboundGroupSession {
|
||||
inner: Arc::new(Mutex::new(session)),
|
||||
session_id: session_id.into(),
|
||||
history_visibility: history_visibility.into(),
|
||||
@@ -118,7 +118,7 @@ impl InboundGroupSession {
|
||||
forwarding_chains: Vec::new().into(),
|
||||
imported: false,
|
||||
backed_up: AtomicBool::new(false).into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a InboundGroupSession from an exported version of the group
|
||||
@@ -127,20 +127,14 @@ impl InboundGroupSession {
|
||||
/// Most notably this can be called with an `ExportedRoomKey` from a
|
||||
/// previous [`export()`] call.
|
||||
///
|
||||
///
|
||||
/// [`export()`]: #method.export
|
||||
pub fn from_export(
|
||||
exported_session: impl Into<ExportedRoomKey>,
|
||||
) -> Result<Self, SessionCreationError> {
|
||||
Self::try_from(exported_session.into())
|
||||
pub fn from_export(exported_session: ExportedRoomKey) -> Self {
|
||||
Self::from(exported_session)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn from_backup(
|
||||
room_id: &RoomId,
|
||||
backup: BackedUpRoomKey,
|
||||
) -> Result<Self, SessionCreationError> {
|
||||
let session = InnerSession::import(&backup.session_key)?;
|
||||
fn from_backup(room_id: &RoomId, backup: BackedUpRoomKey) -> Self {
|
||||
let session = InnerSession::import(&backup.session_key);
|
||||
let session_id = session.session_id();
|
||||
|
||||
Self::from_export(ExportedRoomKey {
|
||||
@@ -166,10 +160,11 @@ impl InboundGroupSession {
|
||||
pub fn from_forwarded_key(
|
||||
sender_key: &str,
|
||||
content: &mut ToDeviceForwardedRoomKeyEventContent,
|
||||
) -> Result<Self, SessionCreationError> {
|
||||
let key = ExportedSessionKey(mem::take(&mut content.session_key));
|
||||
) -> Result<Self, SessionKeyDecodeError> {
|
||||
let key = ExportedSessionKey::from_base64(&content.session_key)?;
|
||||
content.session_key.zeroize();
|
||||
|
||||
let session = InnerSession::import(&key)?;
|
||||
let session = InnerSession::import(&key);
|
||||
let first_known_index = session.first_known_index();
|
||||
let mut forwarding_chains = content.forwarding_curve25519_key_chain.clone();
|
||||
forwarding_chains.push(sender_key.to_owned());
|
||||
@@ -348,7 +343,7 @@ impl InboundGroupSession {
|
||||
/// * `event` - The event that should be decrypted.
|
||||
pub async fn decrypt(
|
||||
&self,
|
||||
event: &SyncRoomEncryptedEvent,
|
||||
event: &OriginalSyncRoomEncryptedEvent,
|
||||
) -> MegolmResult<(Raw<AnyRoomEvent>, u32)> {
|
||||
let content = match &event.content.scheme {
|
||||
EncryptedEventScheme::MegolmV1AesSha2(c) => c,
|
||||
@@ -440,14 +435,12 @@ pub struct PickledInboundGroupSession {
|
||||
pub history_visibility: Option<HistoryVisibility>,
|
||||
}
|
||||
|
||||
impl TryFrom<ExportedRoomKey> for InboundGroupSession {
|
||||
type Error = SessionCreationError;
|
||||
|
||||
fn try_from(key: ExportedRoomKey) -> Result<Self, Self::Error> {
|
||||
let session = InnerSession::import(&key.session_key)?;
|
||||
impl From<ExportedRoomKey> for InboundGroupSession {
|
||||
fn from(key: ExportedRoomKey) -> Self {
|
||||
let session = InnerSession::import(&key.session_key);
|
||||
let first_known_index = session.first_known_index();
|
||||
|
||||
Ok(InboundGroupSession {
|
||||
InboundGroupSession {
|
||||
inner: Mutex::new(session).into(),
|
||||
session_id: key.session_id.into(),
|
||||
sender_key: key.sender_key.into(),
|
||||
@@ -458,6 +451,6 @@ impl TryFrom<ExportedRoomKey> for InboundGroupSession {
|
||||
forwarding_chains: key.forwarding_curve25519_key_chain.into(),
|
||||
imported: true,
|
||||
backed_up: AtomicBool::from(false).into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,9 @@ pub(crate) use outbound::ShareState;
|
||||
pub use outbound::{
|
||||
EncryptionSettings, GroupSession, OutboundGroupSession, PickledOutboundGroupSession, ShareInfo,
|
||||
};
|
||||
use vodozemac::megolm::SessionKeyDecodeError;
|
||||
pub use vodozemac::megolm::{ExportedSessionKey, SessionKey};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
/// An exported version of an `InboundGroupSession`
|
||||
///
|
||||
@@ -110,7 +112,7 @@ impl TryInto<ToDeviceForwardedRoomKeyEventContent> for ExportedRoomKey {
|
||||
room_id: self.room_id,
|
||||
sender_key: self.sender_key,
|
||||
session_id: self.session_id,
|
||||
session_key: self.session_key.0.clone(),
|
||||
session_key: self.session_key.to_base64(),
|
||||
sender_claimed_ed25519_key: claimed_key.to_owned(),
|
||||
forwarding_curve25519_key_chain: self.forwarding_curve25519_key_chain,
|
||||
}
|
||||
@@ -131,22 +133,29 @@ impl From<ExportedRoomKey> for BackedUpRoomKey {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ToDeviceForwardedRoomKeyEventContent> for ExportedRoomKey {
|
||||
impl TryFrom<ToDeviceForwardedRoomKeyEventContent> for ExportedRoomKey {
|
||||
type Error = SessionKeyDecodeError;
|
||||
|
||||
/// Convert the content of a forwarded room key into a exported room key.
|
||||
fn from(forwarded_key: ToDeviceForwardedRoomKeyEventContent) -> Self {
|
||||
fn try_from(
|
||||
mut forwarded_key: ToDeviceForwardedRoomKeyEventContent,
|
||||
) -> Result<Self, Self::Error> {
|
||||
let mut sender_claimed_keys: BTreeMap<DeviceKeyAlgorithm, String> = BTreeMap::new();
|
||||
sender_claimed_keys
|
||||
.insert(DeviceKeyAlgorithm::Ed25519, forwarded_key.sender_claimed_ed25519_key);
|
||||
|
||||
Self {
|
||||
let session_key = ExportedSessionKey::from_base64(&forwarded_key.session_key)?;
|
||||
forwarded_key.session_key.zeroize();
|
||||
|
||||
Ok(Self {
|
||||
algorithm: forwarded_key.algorithm,
|
||||
room_id: forwarded_key.room_id,
|
||||
session_id: forwarded_key.session_id,
|
||||
forwarding_curve25519_key_chain: forwarded_key.forwarding_curve25519_key_chain,
|
||||
sender_claimed_keys,
|
||||
sender_key: forwarded_key.sender_key,
|
||||
session_key: ExportedSessionKey(forwarded_key.session_key),
|
||||
}
|
||||
session_key,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -372,7 +372,7 @@ impl OutboundGroupSession {
|
||||
EventEncryptionAlgorithm::MegolmV1AesSha2,
|
||||
self.room_id().to_owned(),
|
||||
self.session_id().to_owned(),
|
||||
session_key.0.clone(),
|
||||
session_key.to_base64(),
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
@@ -67,13 +67,14 @@ pub(crate) mod tests {
|
||||
forwarded_room_key::ToDeviceForwardedRoomKeyEventContent,
|
||||
room::message::{Relation, Replacement, RoomMessageEventContent},
|
||||
AnyMessageLikeEvent, AnyRoomEvent, AnySyncMessageLikeEvent, AnySyncRoomEvent,
|
||||
MessageLikeEvent, SyncMessageLikeEvent,
|
||||
},
|
||||
room_id, user_id, DeviceId, UserId,
|
||||
};
|
||||
use serde_json::json;
|
||||
use vodozemac::olm::OlmMessage;
|
||||
|
||||
use crate::olm::{InboundGroupSession, ReadOnlyAccount, Session};
|
||||
use crate::olm::{ExportedRoomKey, InboundGroupSession, ReadOnlyAccount, Session};
|
||||
|
||||
fn alice_id() -> &'static UserId {
|
||||
user_id!("@alice:example.org")
|
||||
@@ -185,8 +186,7 @@ pub(crate) mod tests {
|
||||
room_id,
|
||||
outbound.session_key().await,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
assert_eq!(0, inbound.first_known_index());
|
||||
|
||||
@@ -223,8 +223,7 @@ pub(crate) mod tests {
|
||||
room_id,
|
||||
outbound.session_key().await,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
assert_eq!(0, inbound.first_known_index());
|
||||
|
||||
@@ -245,19 +244,20 @@ pub(crate) mod tests {
|
||||
|
||||
let event: AnySyncRoomEvent = serde_json::from_str(&event).unwrap();
|
||||
|
||||
let event =
|
||||
if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(event)) =
|
||||
event
|
||||
{
|
||||
event
|
||||
} else {
|
||||
panic!("Invalid event type")
|
||||
};
|
||||
let event = if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomEncrypted(
|
||||
SyncMessageLikeEvent::Original(event),
|
||||
)) = event
|
||||
{
|
||||
event
|
||||
} else {
|
||||
panic!("Invalid event type")
|
||||
};
|
||||
|
||||
let decrypted = inbound.decrypt(&event).await.unwrap().0;
|
||||
|
||||
if let AnyRoomEvent::MessageLike(AnyMessageLikeEvent::RoomMessage(e)) =
|
||||
decrypted.deserialize().unwrap()
|
||||
if let AnyRoomEvent::MessageLike(AnyMessageLikeEvent::RoomMessage(
|
||||
MessageLikeEvent::Original(e),
|
||||
)) = decrypted.deserialize().unwrap()
|
||||
{
|
||||
assert_matches!(e.content.relates_to, Some(Relation::Replacement(_)));
|
||||
} else {
|
||||
@@ -274,8 +274,9 @@ pub(crate) mod tests {
|
||||
|
||||
let export = inbound.export().await;
|
||||
let export: ToDeviceForwardedRoomKeyEventContent = export.try_into().unwrap();
|
||||
let export = ExportedRoomKey::try_from(export).unwrap();
|
||||
|
||||
let imported = InboundGroupSession::from_export(export).unwrap();
|
||||
let imported = InboundGroupSession::from_export(export);
|
||||
|
||||
assert_eq!(inbound.session_id(), imported.session_id());
|
||||
}
|
||||
|
||||
@@ -246,8 +246,7 @@ mod tests {
|
||||
room_id,
|
||||
outbound.session_key().await,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
let store = GroupSessionStore::new();
|
||||
store.add(inbound.clone());
|
||||
|
||||
@@ -275,7 +275,7 @@ macro_rules! cryptostore_integration_tests {
|
||||
|
||||
export.forwarding_curve25519_key_chain = vec!["some_chain".to_owned()];
|
||||
|
||||
let session = InboundGroupSession::from_export(export).unwrap();
|
||||
let session = InboundGroupSession::from_export(export);
|
||||
|
||||
let changes =
|
||||
Changes { inbound_group_sessions: vec![session.clone()], ..Default::default() };
|
||||
|
||||
@@ -347,8 +347,7 @@ mod tests {
|
||||
room_id,
|
||||
outbound.session_key().await,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
let store = MemoryStore::new();
|
||||
let _ = store.save_inbound_group_sessions(vec![inbound.clone()]).await;
|
||||
|
||||
@@ -590,7 +590,7 @@ pub enum CryptoStoreError {
|
||||
|
||||
/// The received room key couldn't be converted into a valid Megolm session.
|
||||
#[error(transparent)]
|
||||
SessionCreation(#[from] vodozemac::megolm::SessionCreationError),
|
||||
SessionCreation(#[from] vodozemac::megolm::SessionKeyDecodeError),
|
||||
|
||||
/// A Matrix identifier failed to be validated.
|
||||
#[error(transparent)]
|
||||
|
||||
@@ -41,6 +41,7 @@ use ruma::{
|
||||
},
|
||||
room::message::{KeyVerificationRequestEventContent, MessageType},
|
||||
AnyMessageLikeEvent, AnyMessageLikeEventContent, AnyToDeviceEvent, AnyToDeviceEventContent,
|
||||
MessageLikeEvent,
|
||||
},
|
||||
serde::{Base64, CanonicalJsonValue},
|
||||
DeviceId, MilliSecondsSinceUnixEpoch, RoomId, UserId,
|
||||
@@ -79,51 +80,37 @@ impl AnyEvent<'_> {
|
||||
pub fn verification_content(&self) -> Option<AnyVerificationContent<'_>> {
|
||||
match self {
|
||||
AnyEvent::Room(e) => match e {
|
||||
AnyMessageLikeEvent::CallAnswer(_)
|
||||
| AnyMessageLikeEvent::CallInvite(_)
|
||||
| AnyMessageLikeEvent::CallHangup(_)
|
||||
| AnyMessageLikeEvent::CallCandidates(_)
|
||||
| AnyMessageLikeEvent::Reaction(_)
|
||||
| AnyMessageLikeEvent::RoomEncrypted(_)
|
||||
| AnyMessageLikeEvent::RoomMessageFeedback(_)
|
||||
| AnyMessageLikeEvent::RoomRedaction(_)
|
||||
| AnyMessageLikeEvent::Sticker(_) => None,
|
||||
AnyMessageLikeEvent::RoomMessage(m) => {
|
||||
AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(m)) => {
|
||||
if let MessageType::VerificationRequest(v) = &m.content.msgtype {
|
||||
Some(RequestContent::from(v).into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationReady(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationReady(MessageLikeEvent::Original(e)) => {
|
||||
Some(ReadyContent::from(&e.content).into())
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationStart(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationStart(MessageLikeEvent::Original(e)) => {
|
||||
Some(StartContent::from(&e.content).into())
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationCancel(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationCancel(MessageLikeEvent::Original(e)) => {
|
||||
Some(CancelContent::from(&e.content).into())
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationAccept(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationAccept(MessageLikeEvent::Original(e)) => {
|
||||
Some(AcceptContent::from(&e.content).into())
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationKey(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationKey(MessageLikeEvent::Original(e)) => {
|
||||
Some(KeyContent::from(&e.content).into())
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationMac(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationMac(MessageLikeEvent::Original(e)) => {
|
||||
Some(MacContent::from(&e.content).into())
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationDone(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationDone(MessageLikeEvent::Original(e)) => {
|
||||
Some(DoneContent::from(&e.content).into())
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
AnyEvent::ToDevice(e) => match e {
|
||||
AnyToDeviceEvent::Dummy(_)
|
||||
| AnyToDeviceEvent::RoomKey(_)
|
||||
| AnyToDeviceEvent::RoomKeyRequest(_)
|
||||
| AnyToDeviceEvent::ForwardedRoomKey(_)
|
||||
| AnyToDeviceEvent::RoomEncrypted(_) => None,
|
||||
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
||||
Some(RequestContent::from(&e.content).into())
|
||||
}
|
||||
@@ -182,35 +169,28 @@ impl TryFrom<&AnyMessageLikeEvent> for FlowId {
|
||||
|
||||
fn try_from(value: &AnyMessageLikeEvent) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
AnyMessageLikeEvent::CallAnswer(_)
|
||||
| AnyMessageLikeEvent::CallInvite(_)
|
||||
| AnyMessageLikeEvent::CallHangup(_)
|
||||
| AnyMessageLikeEvent::CallCandidates(_)
|
||||
| AnyMessageLikeEvent::Reaction(_)
|
||||
| AnyMessageLikeEvent::RoomEncrypted(_)
|
||||
| AnyMessageLikeEvent::RoomMessageFeedback(_)
|
||||
| AnyMessageLikeEvent::RoomRedaction(_)
|
||||
| AnyMessageLikeEvent::Sticker(_) => Err(()),
|
||||
AnyMessageLikeEvent::KeyVerificationReady(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationReady(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::RoomMessage(e) => Ok(FlowId::from((&*e.room_id, &*e.event_id))),
|
||||
AnyMessageLikeEvent::KeyVerificationStart(e) => {
|
||||
AnyMessageLikeEvent::RoomMessage(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationStart(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationCancel(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationCancel(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationAccept(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationAccept(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationKey(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationKey(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationMac(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationMac(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
AnyMessageLikeEvent::KeyVerificationDone(e) => {
|
||||
AnyMessageLikeEvent::KeyVerificationDone(MessageLikeEvent::Original(e)) => {
|
||||
Ok(FlowId::from((&*e.room_id, &*e.content.relates_to.event_id)))
|
||||
}
|
||||
_ => Err(()),
|
||||
@@ -223,11 +203,6 @@ impl TryFrom<&AnyToDeviceEvent> for FlowId {
|
||||
|
||||
fn try_from(value: &AnyToDeviceEvent) -> Result<Self, Self::Error> {
|
||||
match value {
|
||||
AnyToDeviceEvent::Dummy(_)
|
||||
| AnyToDeviceEvent::RoomKey(_)
|
||||
| AnyToDeviceEvent::RoomKeyRequest(_)
|
||||
| AnyToDeviceEvent::ForwardedRoomKey(_)
|
||||
| AnyToDeviceEvent::RoomEncrypted(_) => Err(()),
|
||||
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
||||
Ok(FlowId::from(e.content.transaction_id.to_owned()))
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ use matrix_sdk_common::{
|
||||
events::{
|
||||
presence::PresenceEvent,
|
||||
receipt::Receipt,
|
||||
room::member::{MembershipState, RoomMemberEventContent},
|
||||
room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
redaction::SyncRoomRedactionEvent,
|
||||
},
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncMessageLikeEvent,
|
||||
AnySyncRoomEvent, AnySyncStateEvent, GlobalAccountDataEventType,
|
||||
RoomAccountDataEventType, StateEventType,
|
||||
@@ -706,7 +709,9 @@ impl IndexeddbStore {
|
||||
for event in &timeline.events {
|
||||
// Redact events already in store only on sync response
|
||||
if let Ok(AnySyncRoomEvent::MessageLike(
|
||||
AnySyncMessageLikeEvent::RoomRedaction(redaction),
|
||||
AnySyncMessageLikeEvent::RoomRedaction(
|
||||
SyncRoomRedactionEvent::Original(redaction),
|
||||
),
|
||||
)) = event.event.deserialize()
|
||||
{
|
||||
let redacts_key = self.encode_key(
|
||||
|
||||
@@ -26,7 +26,10 @@ use futures_util::stream::{self, StreamExt, TryStreamExt};
|
||||
use matrix_sdk_base::{
|
||||
deserialized_responses::{MemberEvent, SyncRoomEvent},
|
||||
media::{MediaRequest, UniqueKey},
|
||||
store::{BoxStream, Result as StoreResult, StateChanges, StateStore, StoreError},
|
||||
ruma::events::room::redaction::SyncRoomRedactionEvent,
|
||||
store::{
|
||||
BoxStream, Result as StoreResult, StateChanges, StateStore, StoreError,
|
||||
},
|
||||
RoomInfo,
|
||||
};
|
||||
use matrix_sdk_common::{
|
||||
@@ -713,9 +716,7 @@ impl SledStore {
|
||||
pub async fn get_room_infos(&self) -> Result<impl Stream<Item = Result<RoomInfo>>> {
|
||||
let db = self.clone();
|
||||
spawn_blocking(move || {
|
||||
stream::iter(
|
||||
db.room_info.iter().map(move |r| db.deserialize_event(&r?.1)),
|
||||
)
|
||||
stream::iter(db.room_info.iter().map(move |r| db.deserialize_event(&r?.1)))
|
||||
})
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
@@ -724,11 +725,7 @@ impl SledStore {
|
||||
pub async fn get_stripped_room_infos(&self) -> Result<impl Stream<Item = Result<RoomInfo>>> {
|
||||
let db = self.clone();
|
||||
spawn_blocking(move || {
|
||||
stream::iter(
|
||||
db.stripped_room_infos
|
||||
.iter()
|
||||
.map(move |r| db.deserialize_event(&r?.1)),
|
||||
)
|
||||
stream::iter(db.stripped_room_infos.iter().map(move |r| db.deserialize_event(&r?.1)))
|
||||
})
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
@@ -1158,7 +1155,9 @@ impl SledStore {
|
||||
for event in &timeline.events {
|
||||
// Redact events already in store only on sync response
|
||||
if let Ok(AnySyncRoomEvent::MessageLike(
|
||||
AnySyncMessageLikeEvent::RoomRedaction(redaction),
|
||||
AnySyncMessageLikeEvent::RoomRedaction(SyncRoomRedactionEvent::Original(
|
||||
redaction,
|
||||
)),
|
||||
)) = event.event.deserialize()
|
||||
{
|
||||
let redacts_key =
|
||||
|
||||
@@ -18,6 +18,6 @@ appservice = []
|
||||
http = "0.2.4"
|
||||
lazy_static = "1.4.0"
|
||||
matrix-sdk-test-macros = { version = "0.1.0", path = "../matrix-sdk-test-macros" }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "deea762b8", features = ["client-api-c"] }
|
||||
ruma = { git = "https://github.com/ruma/ruma", rev = "548232ef5", features = ["client-api-c"] }
|
||||
serde = "1.0.126"
|
||||
serde_json = "1.0.64"
|
||||
|
||||
@@ -103,7 +103,7 @@ default_features = false
|
||||
|
||||
[dependencies.ruma]
|
||||
git = "https://github.com/ruma/ruma"
|
||||
rev = "deea762b8"
|
||||
rev = "548232ef5"
|
||||
features = ["client-api-c", "compat", "rand", "unstable-msc2448"]
|
||||
|
||||
[dependencies.tokio-stream]
|
||||
|
||||
@@ -4,12 +4,12 @@ use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
room::Room,
|
||||
ruma::events::room::message::{
|
||||
MessageType, RoomMessageEventContent, SyncRoomMessageEvent, TextMessageEventContent,
|
||||
MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent, TextMessageEventContent,
|
||||
},
|
||||
Client,
|
||||
};
|
||||
|
||||
async fn on_room_message(event: SyncRoomMessageEvent, room: Room) {
|
||||
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
|
||||
if let Room::Joined(room) = room {
|
||||
let msg_body = match event.content.msgtype {
|
||||
MessageType::Text(TextMessageEventContent { body, .. }) => body,
|
||||
|
||||
@@ -19,6 +19,7 @@ use matrix_sdk::{
|
||||
},
|
||||
Client, LoopCtrl,
|
||||
};
|
||||
use ruma::events::SyncMessageLikeEvent;
|
||||
use url::Url;
|
||||
|
||||
async fn wait_for_confirmation(client: Client, sas: SasVerification) {
|
||||
@@ -135,7 +136,9 @@ async fn login(
|
||||
{
|
||||
if let AnySyncRoomEvent::MessageLike(event) = event {
|
||||
match event {
|
||||
AnySyncMessageLikeEvent::RoomMessage(m) => {
|
||||
AnySyncMessageLikeEvent::RoomMessage(
|
||||
SyncMessageLikeEvent::Original(m),
|
||||
) => {
|
||||
if let MessageType::VerificationRequest(_) = &m.content.msgtype
|
||||
{
|
||||
let request = client
|
||||
@@ -150,7 +153,9 @@ async fn login(
|
||||
.expect("Can't accept verification request");
|
||||
}
|
||||
}
|
||||
AnySyncMessageLikeEvent::KeyVerificationKey(e) => {
|
||||
AnySyncMessageLikeEvent::KeyVerificationKey(
|
||||
SyncMessageLikeEvent::Original(e),
|
||||
) => {
|
||||
if let Some(Verification::SasV1(sas)) = client
|
||||
.encryption()
|
||||
.get_verification(
|
||||
@@ -162,7 +167,9 @@ async fn login(
|
||||
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
|
||||
}
|
||||
}
|
||||
AnySyncMessageLikeEvent::KeyVerificationMac(e) => {
|
||||
AnySyncMessageLikeEvent::KeyVerificationMac(
|
||||
SyncMessageLikeEvent::Original(e),
|
||||
) => {
|
||||
if let Some(Verification::SasV1(sas)) = client
|
||||
.encryption()
|
||||
.get_verification(
|
||||
|
||||
@@ -13,16 +13,16 @@ use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
room::Room,
|
||||
ruma::events::room::message::{
|
||||
MessageType, RoomMessageEventContent, SyncRoomMessageEvent, TextMessageEventContent,
|
||||
MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent, TextMessageEventContent,
|
||||
},
|
||||
Client,
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
use url::Url;
|
||||
|
||||
async fn on_room_message(event: SyncRoomMessageEvent, room: Room, image: Arc<Mutex<File>>) {
|
||||
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room, image: Arc<Mutex<File>>) {
|
||||
if let Room::Joined(room) = room {
|
||||
let msg_body = if let SyncRoomMessageEvent {
|
||||
let msg_body = if let OriginalSyncRoomMessageEvent {
|
||||
content:
|
||||
RoomMessageEventContent {
|
||||
msgtype: MessageType::Text(TextMessageEventContent { body: msg_body, .. }),
|
||||
|
||||
@@ -5,15 +5,15 @@ use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
room::Room,
|
||||
ruma::events::room::message::{
|
||||
MessageType, RoomMessageEventContent, SyncRoomMessageEvent, TextMessageEventContent,
|
||||
MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent, TextMessageEventContent,
|
||||
},
|
||||
Client,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
async fn on_room_message(event: SyncRoomMessageEvent, room: Room) {
|
||||
async fn on_room_message(event: OriginalSyncRoomMessageEvent, room: Room) {
|
||||
if let Room::Joined(room) = room {
|
||||
if let SyncRoomMessageEvent {
|
||||
if let OriginalSyncRoomMessageEvent {
|
||||
content:
|
||||
RoomMessageEventContent {
|
||||
msgtype: MessageType::Text(TextMessageEventContent { body: msg_body, .. }),
|
||||
|
||||
@@ -8,7 +8,7 @@ use matrix_sdk::{
|
||||
ruma::{
|
||||
api::client::filter::{FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter},
|
||||
assign,
|
||||
events::{AnyMessageLikeEventContent, AnySyncRoomEvent},
|
||||
events::{AnySyncMessageLikeEvent, AnySyncRoomEvent, SyncMessageLikeEvent},
|
||||
},
|
||||
store::make_store_config,
|
||||
Client, LoopCtrl,
|
||||
@@ -32,12 +32,14 @@ async fn login(homeserver_url: String, username: &str, password: &str) -> Client
|
||||
}
|
||||
|
||||
fn event_content(event: AnySyncRoomEvent) -> Option<String> {
|
||||
if let AnySyncRoomEvent::MessageLike(event) = event {
|
||||
if let AnyMessageLikeEventContent::RoomMessage(content) = event.content() {
|
||||
return Some(content.msgtype.body().to_owned());
|
||||
}
|
||||
if let AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(
|
||||
SyncMessageLikeEvent::Original(event),
|
||||
)) = event
|
||||
{
|
||||
Some(event.content.msgtype.body().to_owned())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
None
|
||||
}
|
||||
async fn print_timeline(room: Room) {
|
||||
let backward_stream = room.timeline_backward().await.unwrap();
|
||||
|
||||
@@ -4,9 +4,11 @@ use matrix_sdk::{
|
||||
ruma::{
|
||||
events::{
|
||||
room::message::{
|
||||
MessageType, RoomMessageEventContent, SyncRoomMessageEvent, TextMessageEventContent,
|
||||
MessageType, OriginalSyncRoomMessageEvent, RoomMessageEventContent,
|
||||
TextMessageEventContent,
|
||||
},
|
||||
AnyMessageLikeEventContent, AnySyncMessageLikeEvent, AnySyncRoomEvent,
|
||||
SyncMessageLikeEvent,
|
||||
},
|
||||
RoomId,
|
||||
},
|
||||
@@ -19,8 +21,8 @@ use web_sys::console;
|
||||
struct WasmBot(Client);
|
||||
|
||||
impl WasmBot {
|
||||
async fn on_room_message(&self, room_id: &RoomId, event: &SyncRoomMessageEvent) {
|
||||
let msg_body = if let SyncRoomMessageEvent {
|
||||
async fn on_room_message(&self, room_id: &RoomId, event: &OriginalSyncRoomMessageEvent) {
|
||||
let msg_body = if let OriginalSyncRoomMessageEvent {
|
||||
content:
|
||||
RoomMessageEventContent {
|
||||
msgtype: MessageType::Text(TextMessageEventContent { body: msg_body, .. }),
|
||||
@@ -59,8 +61,9 @@ impl WasmBot {
|
||||
|
||||
for (room_id, room) in response.rooms.join {
|
||||
for event in room.timeline.events {
|
||||
if let Ok(AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(ev))) =
|
||||
event.event.deserialize()
|
||||
if let Ok(AnySyncRoomEvent::MessageLike(AnySyncMessageLikeEvent::RoomMessage(
|
||||
SyncMessageLikeEvent::Original(ev),
|
||||
))) = event.event.deserialize()
|
||||
{
|
||||
self.on_room_message(&room_id, &ev).await
|
||||
}
|
||||
|
||||
@@ -1660,7 +1660,7 @@ impl Client {
|
||||
/// # let password = "";
|
||||
/// use matrix_sdk::{
|
||||
/// Client, config::SyncSettings,
|
||||
/// ruma::events::room::message::SyncRoomMessageEvent,
|
||||
/// ruma::events::room::message::OriginalSyncRoomMessageEvent,
|
||||
/// };
|
||||
///
|
||||
/// let client = Client::new(homeserver).await?;
|
||||
@@ -1671,7 +1671,7 @@ impl Client {
|
||||
///
|
||||
/// // Register our handler so we start responding once we receive a new
|
||||
/// // event.
|
||||
/// client.register_event_handler(|ev: SyncRoomMessageEvent| async move {
|
||||
/// client.register_event_handler(|ev: OriginalSyncRoomMessageEvent| async move {
|
||||
/// println!("Received event {}: {:?}", ev.sender, ev.content);
|
||||
/// }).await;
|
||||
///
|
||||
@@ -1765,7 +1765,7 @@ impl Client {
|
||||
/// # let password = "";
|
||||
/// use matrix_sdk::{
|
||||
/// Client, config::SyncSettings,
|
||||
/// ruma::events::room::message::SyncRoomMessageEvent,
|
||||
/// ruma::events::room::message::OriginalSyncRoomMessageEvent,
|
||||
/// };
|
||||
///
|
||||
/// let client = Client::new(homeserver).await?;
|
||||
@@ -1773,7 +1773,7 @@ impl Client {
|
||||
///
|
||||
/// // Register our handler so we start responding once we receive a new
|
||||
/// // event.
|
||||
/// client.register_event_handler(|ev: SyncRoomMessageEvent| async move {
|
||||
/// client.register_event_handler(|ev: OriginalSyncRoomMessageEvent| async move {
|
||||
/// println!("Received event {}: {:?}", ev.sender, ev.content);
|
||||
/// }).await;
|
||||
///
|
||||
|
||||
@@ -56,7 +56,10 @@ use ruma::{
|
||||
};
|
||||
use tracing::{debug, instrument, trace, warn};
|
||||
#[cfg(feature = "encryption")]
|
||||
use {ruma::api::client::config::set_global_account_data, ruma::events::EventContent};
|
||||
use {
|
||||
ruma::api::client::config::set_global_account_data,
|
||||
ruma::events::{GlobalAccountDataEventContent, SyncMessageLikeEvent},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
attachment::{AttachmentInfo, Thumbnail},
|
||||
@@ -80,7 +83,10 @@ impl Client {
|
||||
// Turn the AnyMessageLikeEvent into a AnySyncMessageLikeEvent
|
||||
let event = event.clone().into();
|
||||
|
||||
if let AnySyncMessageLikeEvent::RoomEncrypted(e) = event {
|
||||
if let AnySyncMessageLikeEvent::RoomEncrypted(SyncMessageLikeEvent::Original(
|
||||
e,
|
||||
)) = event
|
||||
{
|
||||
if let Ok(decrypted) = machine.decrypt_room_event(&e, room_id).await {
|
||||
return decrypted;
|
||||
}
|
||||
@@ -90,6 +96,7 @@ impl Client {
|
||||
}
|
||||
|
||||
// Fallback to still-encrypted room event
|
||||
|
||||
RoomEvent { event, encryption_info: None }
|
||||
}
|
||||
|
||||
@@ -237,7 +244,7 @@ impl Client {
|
||||
content: T,
|
||||
) -> Result<set_global_account_data::v3::Response>
|
||||
where
|
||||
T: EventContent<EventType = GlobalAccountDataEventType>,
|
||||
T: GlobalAccountDataEventContent,
|
||||
{
|
||||
let own_user =
|
||||
self.user_id().await.ok_or_else(|| Error::from(HttpError::AuthenticationRequired))?;
|
||||
|
||||
@@ -47,14 +47,36 @@ pub enum EventKind {
|
||||
GlobalAccountData,
|
||||
RoomAccountData,
|
||||
EphemeralRoomData,
|
||||
Message { redacted: bool },
|
||||
State { redacted: bool },
|
||||
MessageLike,
|
||||
OriginalMessageLike,
|
||||
RedactedMessageLike,
|
||||
State,
|
||||
OriginalState,
|
||||
RedactedState,
|
||||
StrippedState,
|
||||
InitialState,
|
||||
ToDevice,
|
||||
Presence,
|
||||
}
|
||||
|
||||
impl EventKind {
|
||||
fn message_like_redacted(redacted: bool) -> Self {
|
||||
if redacted {
|
||||
Self::RedactedMessageLike
|
||||
} else {
|
||||
Self::OriginalMessageLike
|
||||
}
|
||||
}
|
||||
|
||||
fn state_redacted(redacted: bool) -> Self {
|
||||
if redacted {
|
||||
Self::RedactedState
|
||||
} else {
|
||||
Self::OriginalState
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A statically-known event kind/type that can be retrieved from an event sync.
|
||||
pub trait SyncEvent {
|
||||
#[doc(hidden)]
|
||||
@@ -269,6 +291,10 @@ impl Client {
|
||||
unsigned: Option<UnsignedDetails>,
|
||||
}
|
||||
|
||||
// Event handlers for possibly-redacted state events
|
||||
self.handle_sync_events(EventKind::State, room, state_events).await?;
|
||||
|
||||
// Event handlers specifically for redacted OR unredacted state events
|
||||
self.handle_sync_events_wrapped_with(
|
||||
room,
|
||||
state_events,
|
||||
@@ -276,10 +302,12 @@ impl Client {
|
||||
|raw| {
|
||||
let StateEventDetails { event_type, unsigned } = raw.deserialize_as()?;
|
||||
let redacted = unsigned.and_then(|u| u.redacted_because).is_some();
|
||||
Ok((EventKind::State { redacted }, event_type))
|
||||
Ok((EventKind::state_redacted(redacted), event_type))
|
||||
},
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) async fn handle_sync_timeline_events(
|
||||
@@ -295,6 +323,25 @@ impl Client {
|
||||
unsigned: Option<UnsignedDetails>,
|
||||
}
|
||||
|
||||
// Event handlers for possibly-redacted timeline events
|
||||
self.handle_sync_events_wrapped_with(
|
||||
room,
|
||||
timeline_events,
|
||||
|e| (&e.event, e.encryption_info.as_ref()),
|
||||
|raw| {
|
||||
let TimelineEventDetails { event_type, state_key, .. } = raw.deserialize_as()?;
|
||||
|
||||
let kind = match state_key {
|
||||
Some(_) => EventKind::State,
|
||||
None => EventKind::MessageLike,
|
||||
};
|
||||
|
||||
Ok((kind, event_type))
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
// Event handlers specifically for redacted OR unredacted timeline events
|
||||
self.handle_sync_events_wrapped_with(
|
||||
room,
|
||||
timeline_events,
|
||||
@@ -305,14 +352,16 @@ impl Client {
|
||||
|
||||
let redacted = unsigned.and_then(|u| u.redacted_because).is_some();
|
||||
let kind = match state_key {
|
||||
Some(_) => EventKind::State { redacted },
|
||||
None => EventKind::Message { redacted },
|
||||
Some(_) => EventKind::state_redacted(redacted),
|
||||
None => EventKind::message_like_redacted(redacted),
|
||||
};
|
||||
|
||||
Ok((kind, event_type))
|
||||
},
|
||||
)
|
||||
.await
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_sync_events_wrapped_with<'a, T: 'a, U: 'a>(
|
||||
@@ -390,72 +439,107 @@ mod static_events {
|
||||
use ruma::events::{
|
||||
self,
|
||||
presence::{PresenceEvent, PresenceEventContent},
|
||||
EphemeralRoomEventType, EventContent, GlobalAccountDataEventType, MessageLikeEventType,
|
||||
RedactedEventContent, RoomAccountDataEventType, StateEventType, StaticEventContent,
|
||||
ToDeviceEventType,
|
||||
EphemeralRoomEventContent, GlobalAccountDataEventContent, MessageLikeEventContent,
|
||||
RedactContent, RedactedEventContent, RoomAccountDataEventContent, StateEventContent,
|
||||
StaticEventContent, ToDeviceEventContent,
|
||||
};
|
||||
|
||||
use super::{EventKind, SyncEvent};
|
||||
|
||||
impl<C> SyncEvent for events::GlobalAccountDataEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = GlobalAccountDataEventType>,
|
||||
C: StaticEventContent + GlobalAccountDataEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::GlobalAccountData, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RoomAccountDataEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = RoomAccountDataEventType>,
|
||||
C: StaticEventContent + RoomAccountDataEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::RoomAccountData, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::SyncEphemeralRoomEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = EphemeralRoomEventType>,
|
||||
C: StaticEventContent + EphemeralRoomEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::EphemeralRoomData, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::SyncMessageLikeEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = MessageLikeEventType>,
|
||||
C: StaticEventContent + MessageLikeEventContent + RedactContent,
|
||||
C::Redacted: MessageLikeEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::Message { redacted: false }, C::TYPE);
|
||||
const ID: (EventKind, &'static str) = (EventKind::MessageLike, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::OriginalSyncMessageLikeEvent<C>
|
||||
where
|
||||
C: StaticEventContent + MessageLikeEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::OriginalMessageLike, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RedactedSyncMessageLikeEvent<C>
|
||||
where
|
||||
C: StaticEventContent + MessageLikeEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::RedactedMessageLike, C::TYPE);
|
||||
}
|
||||
|
||||
impl SyncEvent for events::room::redaction::SyncRoomRedactionEvent {
|
||||
const ID: (EventKind, &'static str) =
|
||||
(EventKind::MessageLike, events::room::redaction::RoomRedactionEventContent::TYPE);
|
||||
}
|
||||
|
||||
impl SyncEvent for events::room::redaction::RedactedSyncRoomRedactionEvent {
|
||||
const ID: (EventKind, &'static str) = (
|
||||
EventKind::Message { redacted: false },
|
||||
EventKind::OriginalMessageLike,
|
||||
events::room::redaction::RoomRedactionEventContent::TYPE,
|
||||
);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::SyncStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = StateEventType>,
|
||||
C: StaticEventContent + StateEventContent + RedactContent,
|
||||
C::Redacted: StateEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::State { redacted: false }, C::TYPE);
|
||||
const ID: (EventKind, &'static str) = (EventKind::State, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::OriginalSyncStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + StateEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::OriginalState, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RedactedSyncStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + StateEventContent + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::RedactedState, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::StrippedStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = StateEventType>,
|
||||
C: StaticEventContent + StateEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::StrippedState, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::InitialStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = StateEventType>,
|
||||
C: StaticEventContent + StateEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::InitialState, C::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::ToDeviceEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = ToDeviceEventType>,
|
||||
C: StaticEventContent + ToDeviceEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::ToDevice, C::TYPE);
|
||||
}
|
||||
@@ -463,29 +547,6 @@ mod static_events {
|
||||
impl SyncEvent for PresenceEvent {
|
||||
const ID: (EventKind, &'static str) = (EventKind::Presence, PresenceEventContent::TYPE);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RedactedSyncMessageLikeEvent<C>
|
||||
where
|
||||
C: StaticEventContent
|
||||
+ EventContent<EventType = MessageLikeEventType>
|
||||
+ RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::Message { redacted: true }, C::TYPE);
|
||||
}
|
||||
|
||||
impl SyncEvent for events::room::redaction::RedactedSyncRoomRedactionEvent {
|
||||
const ID: (EventKind, &'static str) = (
|
||||
EventKind::Message { redacted: true },
|
||||
events::room::redaction::RoomRedactionEventContent::TYPE,
|
||||
);
|
||||
}
|
||||
|
||||
impl<C> SyncEvent for events::RedactedSyncStateEvent<C>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = StateEventType> + RedactedEventContent,
|
||||
{
|
||||
const ID: (EventKind, &'static str) = (EventKind::State { redacted: true }, C::TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(target_arch = "wasm32")))]
|
||||
@@ -497,7 +558,7 @@ mod tests {
|
||||
|
||||
use matrix_sdk_test::{EventBuilder, EventsJson};
|
||||
use ruma::{
|
||||
events::room::member::{StrippedRoomMemberEvent, SyncRoomMemberEvent},
|
||||
events::room::member::{OriginalSyncRoomMemberEvent, StrippedRoomMemberEvent},
|
||||
room_id,
|
||||
};
|
||||
use serde_json::json;
|
||||
@@ -518,7 +579,7 @@ mod tests {
|
||||
client
|
||||
.register_event_handler({
|
||||
let member_count = member_count.clone();
|
||||
move |_ev: SyncRoomMemberEvent, _room: room::Room| {
|
||||
move |_ev: OriginalSyncRoomMemberEvent, _room: room::Room| {
|
||||
member_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
@@ -526,7 +587,7 @@ mod tests {
|
||||
.await
|
||||
.register_event_handler({
|
||||
let typing_count = typing_count.clone();
|
||||
move |_ev: SyncRoomMemberEvent| {
|
||||
move |_ev: OriginalSyncRoomMemberEvent| {
|
||||
typing_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
@@ -534,7 +595,7 @@ mod tests {
|
||||
.await
|
||||
.register_event_handler({
|
||||
let power_levels_count = power_levels_count.clone();
|
||||
move |_ev: SyncRoomMemberEvent, _client: Client, _room: room::Room| {
|
||||
move |_ev: OriginalSyncRoomMemberEvent, _client: Client, _room: room::Room| {
|
||||
power_levels_count.fetch_add(1, SeqCst);
|
||||
future::ready(())
|
||||
}
|
||||
|
||||
@@ -18,8 +18,9 @@ use ruma::{
|
||||
events::{
|
||||
room::{history_visibility::HistoryVisibility, MediaSource},
|
||||
tag::{TagInfo, TagName},
|
||||
AnyRoomAccountDataEvent, AnyStateEvent, AnySyncStateEvent, EventContent,
|
||||
RoomAccountDataEvent, RoomAccountDataEventType, StateEventType, StaticEventContent,
|
||||
AnyRoomAccountDataEvent, AnyStateEvent, AnySyncStateEvent, RedactContent,
|
||||
RedactedEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
|
||||
RoomAccountDataEventType, StateEventContent, StateEventType, StaticEventContent,
|
||||
SyncStateEvent,
|
||||
},
|
||||
serde::Raw,
|
||||
@@ -662,7 +663,8 @@ impl Common {
|
||||
/// ```
|
||||
pub async fn get_state_events_static<C>(&self) -> Result<Vec<Raw<SyncStateEvent<C>>>>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = StateEventType>,
|
||||
C: StaticEventContent + StateEventContent + RedactContent,
|
||||
C::Redacted: StateEventContent + RedactedEventContent,
|
||||
{
|
||||
// FIXME: Could be more efficient, if we had streaming store accessor functions
|
||||
Ok(self.get_state_events(C::TYPE.into()).await?.into_iter().map(Raw::cast).collect())
|
||||
@@ -702,7 +704,8 @@ impl Common {
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<SyncStateEvent<C>>>>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = StateEventType>,
|
||||
C: StaticEventContent + StateEventContent + RedactContent,
|
||||
C::Redacted: StateEventContent + RedactedEventContent,
|
||||
{
|
||||
Ok(self.get_state_event(C::TYPE.into(), state_key).await?.map(Raw::cast))
|
||||
}
|
||||
@@ -737,7 +740,7 @@ impl Common {
|
||||
/// ```
|
||||
pub async fn account_data_static<C>(&self) -> Result<Option<Raw<RoomAccountDataEvent<C>>>>
|
||||
where
|
||||
C: StaticEventContent + EventContent<EventType = RoomAccountDataEventType>,
|
||||
C: StaticEventContent + RoomAccountDataEventContent,
|
||||
{
|
||||
Ok(self.account_data(C::TYPE.into()).await?.map(Raw::cast))
|
||||
}
|
||||
|
||||
@@ -26,9 +26,7 @@ use ruma::{
|
||||
typing::create_typing_event::v3::{Request as TypingRequest, Typing},
|
||||
},
|
||||
assign,
|
||||
events::{
|
||||
room::message::RoomMessageEventContent, EventContent, MessageLikeEventType, StateEventType,
|
||||
},
|
||||
events::{room::message::RoomMessageEventContent, MessageLikeEventContent, StateEventContent},
|
||||
receipt::ReceiptType,
|
||||
serde::Raw,
|
||||
EventId, TransactionId, UserId,
|
||||
@@ -468,7 +466,7 @@ impl Joined {
|
||||
/// [`transaction_id`]: ruma::events::MessageLikeUnsigned#structfield.transaction_id
|
||||
pub async fn send(
|
||||
&self,
|
||||
content: impl EventContent<EventType = MessageLikeEventType>,
|
||||
content: impl MessageLikeEventContent,
|
||||
txn_id: Option<&TransactionId>,
|
||||
) -> Result<send_message_event::v3::Response> {
|
||||
let event_type = content.event_type().to_string();
|
||||
@@ -808,7 +806,7 @@ impl Joined {
|
||||
/// ```
|
||||
pub async fn send_state_event(
|
||||
&self,
|
||||
content: impl EventContent<EventType = StateEventType>,
|
||||
content: impl StateEventContent,
|
||||
state_key: &str,
|
||||
) -> Result<send_state_event::v3::Response> {
|
||||
let request =
|
||||
|
||||
Reference in New Issue
Block a user