diff --git a/Cargo.lock b/Cargo.lock index 6bb2699d..32b155d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2520,7 +2520,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.12.3" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "assign", "js_int", @@ -2539,7 +2539,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.12.2" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "js_int", "ruma-common", @@ -2551,7 +2551,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.20.3" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "as_variant", "assign", @@ -2574,7 +2574,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.15.2" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "as_variant", "base64 0.22.1", @@ -2600,12 +2600,13 @@ dependencies = [ "uuid", "web-time", "wildmatch", + "zeroize", ] [[package]] name = "ruma-events" version = "0.30.3" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "as_variant", "indexmap 2.9.0", @@ -2623,12 +2624,13 @@ dependencies = [ "url", "web-time", "wildmatch", + "zeroize", ] [[package]] name = "ruma-federation-api" version = "0.11.1" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "bytes", "headers", @@ -2650,7 +2652,7 @@ dependencies = [ [[package]] name = "ruma-identifiers-validation" version = "0.10.1" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "js_int", "thiserror 2.0.12", @@ -2659,7 +2661,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.15.1" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "cfg-if", "proc-macro-crate", @@ -2674,7 +2676,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.11.0" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "js_int", "ruma-common", @@ -2686,7 +2688,7 @@ dependencies = [ [[package]] name = "ruma-signatures" version = "0.17.1" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "base64 0.22.1", "ed25519-dalek", @@ -2702,7 +2704,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.13.0" -source = "git+https://github.com/ruma/ruma.git#a0e8064064dbdc6c935394c72c6f43d7bd89b92d" +source = "git+https://github.com/ruma/ruma.git#e65c55fe37343e5fe3366e7bb5fc6fdca4f27655" dependencies = [ "js_int", "ruma-common", diff --git a/src/api/client_server/directory.rs b/src/api/client_server/directory.rs index 50ae9f15..ed08989f 100644 --- a/src/api/client_server/directory.rs +++ b/src/api/client_server/directory.rs @@ -11,7 +11,7 @@ use ruma::{ }, federation, }, - directory::{Filter, PublicRoomJoinRule, PublicRoomsChunk, RoomNetwork}, + directory::{Filter, PublicRoomsChunk, RoomNetwork}, events::{ room::{ avatar::RoomAvatarEventContent, @@ -19,7 +19,7 @@ use ruma::{ create::RoomCreateEventContent, guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, - join_rules::{JoinRule, RoomJoinRulesEventContent}, + join_rules::RoomJoinRulesEventContent, topic::RoomTopicEventContent, }, StateEventType, @@ -273,18 +273,13 @@ pub(crate) async fn get_public_rooms_filtered_helper( .room_state_get(&room_id, &StateEventType::RoomJoinRules, "")? .map(|s| { serde_json::from_str(s.content.get()) - .map(|c: RoomJoinRulesEventContent| match c.join_rule { - JoinRule::Public => Some(PublicRoomJoinRule::Public), - JoinRule::Knock => Some(PublicRoomJoinRule::Knock), - _ => None, - }) + .map(|c: RoomJoinRulesEventContent| c.join_rule.kind()) .map_err(|e| { error!("Invalid room join rule event in database: {}", e); Error::BadDatabase("Invalid room join rule event in database.") }) }) .transpose()? - .flatten() .ok_or_else(|| Error::bad_database("Missing room join rule event for room."))?, room_type: services() .rooms diff --git a/src/api/client_server/room.rs b/src/api/client_server/room.rs index 9c49d6a4..9c099984 100644 --- a/src/api/client_server/room.rs +++ b/src/api/client_server/room.rs @@ -463,17 +463,15 @@ pub async fn create_room_route( .await?; } - if let Some(topic) = &body.topic { + if let Some(topic) = body.topic.clone() { services() .rooms .timeline .build_and_append_pdu( PduBuilder { event_type: TimelineEventType::RoomTopic, - content: to_raw_value(&RoomTopicEventContent { - topic: topic.clone(), - }) - .expect("event is valid, we just created it"), + content: to_raw_value(&RoomTopicEventContent::new(topic)) + .expect("event is valid, we just created it"), unsigned: None, state_key: Some("".to_owned()), redacts: None, diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs index e7f169fb..957a5914 100644 --- a/src/service/admin/mod.rs +++ b/src/service/admin/mod.rs @@ -1876,9 +1876,10 @@ impl Service { .build_and_append_pdu( PduBuilder { event_type: TimelineEventType::RoomTopic, - content: to_raw_value(&RoomTopicEventContent { - topic: format!("Manage {}", services().globals.server_name()), - }) + content: to_raw_value(&RoomTopicEventContent::new(format!( + "Manage {}", + services().globals.server_name() + ))) .expect("event is valid, we just created it"), unsigned: None, state_key: Some("".to_owned()), diff --git a/src/service/pdu.rs b/src/service/pdu.rs index 441a187f..bc5e7fae 100644 --- a/src/service/pdu.rs +++ b/src/service/pdu.rs @@ -6,7 +6,8 @@ use ruma::{ room::{member::RoomMemberEventContent, redaction::RoomRedactionEventContent}, space::child::HierarchySpaceChildEvent, AnyEphemeralRoomEvent, AnyMessageLikeEvent, AnyStateEvent, AnyStrippedStateEvent, - AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, StateEvent, TimelineEventType, + AnySyncMessageLikeEvent, AnySyncStateEvent, AnySyncTimelineEvent, AnyTimelineEvent, + StateEvent, TimelineEventType, }, room_version_rules::{RedactionRules, RoomVersionRules}, serde::Raw, @@ -172,6 +173,30 @@ impl PduEvent { serde_json::from_value(json).expect("Raw::from_value always works") } + #[tracing::instrument(skip(self))] + pub fn to_sync_message_like_event(&self) -> Raw { + let (redacts, content) = self.copy_redacts(); + let mut json = json!({ + "content": content, + "type": self.kind, + "event_id": self.event_id, + "sender": self.sender, + "origin_server_ts": self.origin_server_ts, + }); + + if let Some(unsigned) = &self.unsigned { + json["unsigned"] = json!(unsigned); + } + if let Some(state_key) = &self.state_key { + json["state_key"] = json!(state_key); + } + if let Some(redacts) = &redacts { + json["redacts"] = json!(redacts); + } + + serde_json::from_value(json).expect("Raw::from_value always works") + } + /// This only works for events that are also AnyRoomEvents. #[tracing::instrument(skip(self))] pub fn to_any_event(&self) -> Raw { diff --git a/src/service/rooms/spaces/mod.rs b/src/service/rooms/spaces/mod.rs index f8e294da..545869cc 100644 --- a/src/service/rooms/spaces/mod.rs +++ b/src/service/rooms/spaces/mod.rs @@ -8,24 +8,22 @@ use lru_cache::LruCache; use ruma::{ api::{ client::{self, error::ErrorKind, space::SpaceHierarchyRoomsChunk}, - federation::{ - self, - space::{SpaceHierarchyChildSummary, SpaceHierarchyParentSummary}, - }, + federation::{self, space::SpaceHierarchyParentSummary}, }, events::{ room::{ avatar::RoomAvatarEventContent, canonical_alias::RoomCanonicalAliasEventContent, create::RoomCreateEventContent, + encryption::RoomEncryptionEventContent, join_rules::{JoinRule, RoomJoinRulesEventContent}, topic::RoomTopicEventContent, }, space::child::{HierarchySpaceChildEvent, SpaceChildEventContent}, StateEventType, }, + room::{JoinRuleSummary, RestrictedSummary, RoomSummary}, serde::Raw, - space::SpaceRoomJoinRule, OwnedRoomId, OwnedServerName, RoomId, ServerName, UInt, UserId, }; use tokio::sync::Mutex; @@ -130,31 +128,13 @@ pub struct Service { impl From for SpaceHierarchyRoomsChunk { fn from(value: CachedSpaceHierarchySummary) -> Self { let SpaceHierarchyParentSummary { - canonical_alias, - name, - num_joined_members, - room_id, - topic, - world_readable, - guest_can_join, - avatar_url, - join_rule, - room_type, + summary, children_state, .. } = value.summary; SpaceHierarchyRoomsChunk { - canonical_alias, - name, - num_joined_members, - room_id, - topic, - world_readable, - guest_can_join, - avatar_url, - join_rule, - room_type, + summary, children_state, } } @@ -187,7 +167,7 @@ impl Service { .await? { Some(SummaryAccessibility::Accessible(summary)) => { - children.push((*summary).into()); + children.push(summary.summary); } Some(SummaryAccessibility::Inaccessible) => { inaccessible_children.push(child); @@ -227,12 +207,8 @@ impl Service { .as_ref() { return Ok(if let Some(cached) = cached { - if is_accessible_child( - current_room, - &cached.summary.join_rule, - &identifier, - &cached.summary.allowed_room_ids, - ) { + if is_accessible_child(current_room, &cached.summary.summary.join_rule, &identifier) + { Some(SummaryAccessibility::Accessible(Box::new( cached.summary.clone(), ))) @@ -303,35 +279,14 @@ impl Service { current_room.clone(), Some(CachedSpaceHierarchySummary { summary: { - let SpaceHierarchyChildSummary { - canonical_alias, - name, - num_joined_members, - room_id, - topic, - world_readable, - guest_can_join, - avatar_url, - join_rule, - room_type, - allowed_room_ids, - } = child; - SpaceHierarchyParentSummary { - canonical_alias, - name, - num_joined_members, - room_id: room_id.clone(), - topic, - world_readable, - guest_can_join, - avatar_url, - join_rule, - room_type, - children_state: get_stripped_space_child_events(&room_id) - .await? - .unwrap(), - allowed_room_ids, + children_state: get_stripped_space_child_events( + &child.room_id, + ) + .await? + .unwrap(), + + summary: child, } }, }), @@ -340,9 +295,8 @@ impl Service { } if is_accessible_child( current_room, - &response.room.join_rule, + &response.room.summary.join_rule, &Identifier::UserId(user_id), - &response.room.allowed_room_ids, ) { return Ok(Some(SummaryAccessibility::Accessible(Box::new( summary.clone(), @@ -403,17 +357,7 @@ impl Service { .transpose()? .unwrap_or(JoinRule::Invite); - let allowed_room_ids = services() - .rooms - .state_accessor - .allowed_room_ids(join_rule.clone()); - - if !is_accessible_child( - current_room, - &join_rule.clone().into(), - &identifier, - &allowed_room_ids, - ) { + if !is_accessible_child(current_room, &join_rule.clone().into(), &identifier) { debug!("User is not allowed to see room {room_id}"); // This error will be caught later return Err(Error::BadRequest( @@ -425,70 +369,82 @@ impl Service { let join_rule = join_rule.into(); Ok(SpaceHierarchyParentSummary { - canonical_alias: services() - .rooms - .state_accessor - .room_state_get(room_id, &StateEventType::RoomCanonicalAlias, "")? - .map_or(Ok(None), |s| { - serde_json::from_str(s.content.get()) - .map(|c: RoomCanonicalAliasEventContent| c.alias) - .map_err(|_| { - Error::bad_database("Invalid canonical alias event in database.") - }) - })?, - name: services().rooms.state_accessor.get_name(room_id)?, - num_joined_members: services() - .rooms - .state_cache - .room_joined_count(room_id)? - .unwrap_or_else(|| { - warn!("Room {} has no member count", room_id); - 0 - }) - .try_into() - .expect("user count should not be that big"), - room_id: room_id.to_owned(), - topic: services() - .rooms - .state_accessor - .room_state_get(room_id, &StateEventType::RoomTopic, "")? - .map_or(Ok(None), |s| { - serde_json::from_str(s.content.get()) - .map(|c: RoomTopicEventContent| Some(c.topic)) - .map_err(|_| { - error!("Invalid room topic event in database for room {}", room_id); - Error::bad_database("Invalid room topic event in database.") - }) - })?, - world_readable: services().rooms.state_accessor.world_readable(room_id)?, - guest_can_join: services().rooms.state_accessor.guest_can_join(room_id)?, - avatar_url: services() - .rooms - .state_accessor - .room_state_get(room_id, &StateEventType::RoomAvatar, "")? - .map(|s| { - serde_json::from_str(s.content.get()) - .map(|c: RoomAvatarEventContent| c.url) - .map_err(|_| Error::bad_database("Invalid room avatar event in database.")) - }) - .transpose()? - // url is now an Option so we must flatten - .flatten(), - join_rule, - room_type: services() - .rooms - .state_accessor - .room_state_get(room_id, &StateEventType::RoomCreate, "")? - .map(|s| { - serde_json::from_str::(s.content.get()).map_err(|e| { - error!("Invalid room create event in database: {}", e); - Error::BadDatabase("Invalid room create event in database.") + summary: RoomSummary { + canonical_alias: services() + .rooms + .state_accessor + .room_state_get(room_id, &StateEventType::RoomCanonicalAlias, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomCanonicalAliasEventContent| c.alias) + .map_err(|_| { + Error::bad_database("Invalid canonical alias event in database.") + }) + })?, + name: services().rooms.state_accessor.get_name(room_id)?, + num_joined_members: services() + .rooms + .state_cache + .room_joined_count(room_id)? + .unwrap_or_else(|| { + warn!("Room {} has no member count", room_id); + 0 }) - }) - .transpose()? - .and_then(|e| e.room_type), + .try_into() + .expect("user count should not be that big"), + room_id: room_id.to_owned(), + topic: services() + .rooms + .state_accessor + .room_state_get(room_id, &StateEventType::RoomTopic, "")? + .map_or(Ok(None), |s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomTopicEventContent| Some(c.topic)) + .map_err(|_| { + error!("Invalid room topic event in database for room {}", room_id); + Error::bad_database("Invalid room topic event in database.") + }) + })?, + world_readable: services().rooms.state_accessor.world_readable(room_id)?, + guest_can_join: services().rooms.state_accessor.guest_can_join(room_id)?, + avatar_url: services() + .rooms + .state_accessor + .room_state_get(room_id, &StateEventType::RoomAvatar, "")? + .map(|s| { + serde_json::from_str(s.content.get()) + .map(|c: RoomAvatarEventContent| c.url) + .map_err(|_| { + Error::bad_database("Invalid room avatar event in database.") + }) + }) + .transpose()? + // url is now an Option so we must flatten + .flatten(), + join_rule, + room_type: services() + .rooms + .state_accessor + .room_state_get(room_id, &StateEventType::RoomCreate, "")? + .map(|s| { + serde_json::from_str::(s.content.get()).map_err( + |e| { + error!("Invalid room create event in database: {}", e); + Error::BadDatabase("Invalid room create event in database.") + }, + ) + }) + .transpose()? + .and_then(|e| e.room_type), + encryption: services() + .rooms + .state_accessor + .room_state_get(room_id, &StateEventType::RoomEncryption, "")? + .and_then(|pdu| serde_json::from_str(pdu.content.get()).ok()) + .map(|content: RoomEncryptionEventContent| content.algorithm), + room_version: services().rooms.state.get_room_version(room_id).ok(), + }, children_state, - allowed_room_ids, }) } @@ -681,9 +637,8 @@ async fn get_stripped_space_child_events( /// With the given identifier, checks if a room is accessible fn is_accessible_child( current_room: &OwnedRoomId, - join_rule: &SpaceRoomJoinRule, + join_rule: &JoinRuleSummary, identifier: &Identifier<'_>, - allowed_room_ids: &Vec, ) -> bool { // Note: unwrap_or_default for bool means false match identifier { @@ -717,7 +672,7 @@ fn is_accessible_child( } } // Takes care of joinrules match join_rule { - SpaceRoomJoinRule::Restricted => { + JoinRuleSummary::Restricted(RestrictedSummary { allowed_room_ids }) => { for room in allowed_room_ids { match identifier { Identifier::UserId(user) => { @@ -744,10 +699,10 @@ fn is_accessible_child( } false } - SpaceRoomJoinRule::Public - | SpaceRoomJoinRule::Knock - | SpaceRoomJoinRule::KnockRestricted => true, - SpaceRoomJoinRule::Invite | SpaceRoomJoinRule::Private => false, + JoinRuleSummary::Public | JoinRuleSummary::Knock | JoinRuleSummary::KnockRestricted(_) => { + true + } + JoinRuleSummary::Invite | JoinRuleSummary::Private => false, // Custom join rule _ => false, } @@ -756,31 +711,13 @@ fn is_accessible_child( // Here because cannot implement `From` across ruma-federation-api and ruma-client-api types fn summary_to_chunk(summary: SpaceHierarchyParentSummary) -> SpaceHierarchyRoomsChunk { let SpaceHierarchyParentSummary { - canonical_alias, - name, - num_joined_members, - room_id, - topic, - world_readable, - guest_can_join, - avatar_url, - join_rule, - room_type, + summary, children_state, .. } = summary; SpaceHierarchyRoomsChunk { - canonical_alias, - name, - num_joined_members, - room_id, - topic, - world_readable, - guest_can_join, - avatar_url, - join_rule, - room_type, + summary, children_state, } } @@ -807,20 +744,20 @@ fn get_parent_children_via( #[cfg(test)] mod tests { - use ruma::{ - api::federation::space::SpaceHierarchyParentSummaryInit, owned_room_id, owned_server_name, - }; + use ruma::{owned_room_id, owned_server_name}; use super::*; #[test] fn get_summary_children() { - let summary: SpaceHierarchyParentSummary = SpaceHierarchyParentSummaryInit { - num_joined_members: UInt::from(1_u32), - room_id: owned_room_id!("!root:example.org"), - world_readable: true, - guest_can_join: true, - join_rule: SpaceRoomJoinRule::Public, + let summary: SpaceHierarchyParentSummary = SpaceHierarchyParentSummary { + summary: RoomSummary::new( + owned_room_id!("!root:example.org"), + JoinRuleSummary::Public, + true, + UInt::from(1_u32), + true, + ), children_state: vec![ serde_json::from_str( r#"{ @@ -867,9 +804,7 @@ mod tests { ) .unwrap(), ], - allowed_room_ids: vec![], - } - .into(); + }; assert_eq!( get_parent_children_via(summary.clone(), false), diff --git a/src/service/rooms/state_accessor/mod.rs b/src/service/rooms/state_accessor/mod.rs index fcf542c3..55e0cc9d 100644 --- a/src/service/rooms/state_accessor/mod.rs +++ b/src/service/rooms/state_accessor/mod.rs @@ -12,14 +12,14 @@ use ruma::{ avatar::RoomAvatarEventContent, guest_access::{GuestAccess, RoomGuestAccessEventContent}, history_visibility::{HistoryVisibility, RoomHistoryVisibilityEventContent}, - join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent, RoomMembership}, + join_rules::{AllowRule, JoinRule, RoomJoinRulesEventContent}, member::{MembershipState, RoomMemberEventContent}, name::RoomNameEventContent, power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent}, }, StateEventType, }, - space::SpaceRoomJoinRule, + room::{JoinRuleSummary, RoomMembership}, state_res::Event, EventId, JsOption, OwnedRoomId, OwnedServerName, OwnedUserId, RoomId, ServerName, UserId, }; @@ -430,7 +430,7 @@ impl Service { pub fn get_space_room_join_rule( &self, current_room: &RoomId, - ) -> Result<(SpaceRoomJoinRule, Vec), Error> { + ) -> Result<(JoinRuleSummary, Vec), Error> { Ok(self .room_state_get(current_room, &StateEventType::RoomJoinRules, "")? .map(|s| { @@ -447,7 +447,7 @@ impl Service { }) }) .transpose()? - .unwrap_or((SpaceRoomJoinRule::Invite, vec![]))) + .unwrap_or((JoinRuleSummary::Invite, vec![]))) } /// Returns the join rules event content of a room, if there are any and we are aware of it locally diff --git a/src/service/rooms/threads/mod.rs b/src/service/rooms/threads/mod.rs index c6193bc8..0471af2e 100644 --- a/src/service/rooms/threads/mod.rs +++ b/src/service/rooms/threads/mod.rs @@ -68,7 +68,7 @@ impl Service { { // Thread already existed relations.count += uint!(1); - relations.latest_event = pdu.to_message_like_event(); + relations.latest_event = pdu.to_sync_message_like_event(); let content = serde_json::to_value(relations).expect("to_value always works"); @@ -81,7 +81,7 @@ impl Service { } else { // New thread let relations = BundledThread { - latest_event: pdu.to_message_like_event(), + latest_event: pdu.to_sync_message_like_event(), count: uint!(1), current_user_participated: true, };