1
0
Fork 0
mirror of https://forgejo.ellis.link/continuwuation/continuwuity.git synced 2025-09-30 18:42:05 +00:00

fix(hydra): Fix v11 room support

This commit is contained in:
nexy7574 2025-09-12 14:15:35 +01:00
parent ff92573103
commit 35b7b45ea0
No known key found for this signature in database
6 changed files with 73 additions and 44 deletions

View file

@ -194,6 +194,7 @@ pub(crate) async fn create_room_route(
// 1. The room create event // 1. The room create event
debug!("Creating room create event for {sender_user} in room {room_id:?}"); debug!("Creating room create event for {sender_user} in room {room_id:?}");
let tmp_id = room_id.as_deref();
let create_event_id = services let create_event_id = services
.rooms .rooms
.timeline .timeline
@ -205,13 +206,13 @@ pub(crate) async fn create_room_route(
..Default::default() ..Default::default()
}, },
sender_user, sender_user,
None, tmp_id,
&state_lock, &state_lock,
) )
.boxed() .boxed()
.await?; .await?;
trace!("Created room create event with ID {}", create_event_id); trace!("Created room create event with ID {}", &create_event_id);
let room_id = match room_id { let room_id = match room_id.clone() {
| Some(room_id) => room_id, | Some(room_id) => room_id,
| None => { | None => {
let as_room_id = create_event_id.as_str().replace('$', "!"); let as_room_id = create_event_id.as_str().replace('$', "!");
@ -287,6 +288,10 @@ pub(crate) async fn create_room_route(
} }
} }
} }
} else {
users.insert(sender_user.to_owned(), int!(100));
creators.clear(); // If this vec is not empty, default_power_levels_content will
// treat this as a v12 room
} }
let power_levels_content = default_power_levels_content( let power_levels_content = default_power_levels_content(

View file

@ -587,6 +587,26 @@ where
Ok(true) Ok(true)
} }
fn is_creator<EV>(v: &RoomVersion, c: &BTreeSet<OwnedUserId>, ce: &EV, user_id: &UserId) -> bool
where
EV: Event + Send + Sync,
{
if v.explicitly_privilege_room_creators {
c.contains(user_id)
} else if v.use_room_create_sender {
ce.sender() == user_id
} else {
#[allow(deprecated)]
let creator = from_json_str::<RoomCreateEventContent>(ce.content().get())
.unwrap()
.creator
.ok_or_else(|| serde_json::Error::missing_field("creator"))
.unwrap();
creator == user_id
}
}
// TODO deserializing the member, power, join_rules event contents is done in // TODO deserializing the member, power, join_rules event contents is done in
// conduit just before this is called. Could they be passed in? // conduit just before this is called. Could they be passed in?
/// Does the user who sent this member event have required power levels to do /// Does the user who sent this member event have required power levels to do
@ -618,9 +638,6 @@ where
E: Event + Send + Sync, E: Event + Send + Sync,
for<'a> &'a E: Event + Send, for<'a> &'a E: Event + Send,
{ {
fn is_creator(v: &RoomVersion, c: &BTreeSet<OwnedUserId>, user_id: &UserId) -> bool {
c.contains(user_id) && v.explicitly_privilege_room_creators
}
#[derive(Deserialize)] #[derive(Deserialize)]
struct GetThirdPartyInvite { struct GetThirdPartyInvite {
third_party_invite: Option<Raw<ThirdPartyInvite>>, third_party_invite: Option<Raw<ThirdPartyInvite>>,
@ -677,6 +694,7 @@ where
target_power = Some(&Int::MAX); target_power = Some(&Int::MAX);
} }
} }
trace!(?creators, "creators for room");
let mut join_rules = JoinRule::Invite; let mut join_rules = JoinRule::Invite;
if let Some(jr) = &join_rules_event { if let Some(jr) = &join_rules_event {
@ -707,7 +725,7 @@ where
(int!(0), int!(0)) (int!(0), int!(0))
}; };
let user_joined = user_for_join_auth_membership == &MembershipState::Join; let user_joined = user_for_join_auth_membership == &MembershipState::Join;
let okay_power = is_creator(room_version, &creators, user_for_join_auth) let okay_power = is_creator(room_version, &creators, create_room, user_for_join_auth)
|| auth_user_pl >= invite_level; || auth_user_pl >= invite_level;
user_joined && okay_power user_joined && okay_power
} else { } else {
@ -715,8 +733,8 @@ where
false false
}; };
let sender_creator = is_creator(room_version, &creators, sender); let sender_creator = is_creator(room_version, &creators, create_room, sender);
let target_creator = is_creator(room_version, &creators, target_user); let target_creator = is_creator(room_version, &creators, create_room, target_user);
Ok(match target_membership { Ok(match target_membership {
| MembershipState::Join => { | MembershipState::Join => {
@ -732,15 +750,14 @@ where
let no_more_prev_events = prev_events.next().is_none(); let no_more_prev_events = prev_events.next().is_none();
if prev_event_is_create_event && no_more_prev_events { if prev_event_is_create_event && no_more_prev_events {
trace!("checking if sender is a room creator for initial membership event"); trace!(
let is_creator = (sender_creator && target_creator) || { sender = %sender,
#[allow(deprecated)] target_user = %target_user,
let creator = from_json_str::<RoomCreateEventContent>(create_room.content().get())? ?sender_creator,
.creator ?target_creator,
.ok_or_else(|| serde_json::Error::missing_field("creator"))?; "checking if sender is a room creator for initial membership event"
);
creator == sender && creator == target_user let is_creator = sender_creator && target_creator;
};
if is_creator { if is_creator {
debug!("sender is room creator, allowing join"); debug!("sender is room creator, allowing join");

View file

@ -140,7 +140,7 @@ async fn migrate(services: &Services) -> Result<()> {
if services.globals.db.database_version().await < 18 { if services.globals.db.database_version().await < 18 {
services.globals.db.bump_database_version(18); services.globals.db.bump_database_version(18);
info!("Migration: Bumped database version to 18") info!("Migration: Bumped database version to 18");
} }
assert_eq!( assert_eq!(

View file

@ -196,7 +196,7 @@ async fn get_auth_chain_inner(
}, },
| Ok(pdu) => { | Ok(pdu) => {
if let Some(claimed_room_id) = pdu.room_id.clone() { if let Some(claimed_room_id) = pdu.room_id.clone() {
if claimed_room_id != room_id.to_owned() { if claimed_room_id != *room_id {
return Err!(Request(Forbidden(error!( return Err!(Request(Forbidden(error!(
?event_id, ?event_id,
?room_id, ?room_id,

View file

@ -1,6 +1,6 @@
use std::{collections::HashSet, iter::once}; use std::{collections::HashSet, iter::once};
use conduwuit::{RoomVersion, trace}; use conduwuit::trace;
use conduwuit_core::{ use conduwuit_core::{
Err, Result, implement, Err, Result, implement,
matrix::{event::Event, pdu::PduBuilder}, matrix::{event::Event, pdu::PduBuilder},
@ -12,7 +12,6 @@ use ruma::{
events::{ events::{
TimelineEventType, TimelineEventType,
room::{ room::{
create::RoomCreateEventContent,
member::{MembershipState, RoomMemberEventContent}, member::{MembershipState, RoomMemberEventContent},
redaction::RoomRedactionEventContent, redaction::RoomRedactionEventContent,
}, },
@ -25,7 +24,7 @@ use super::RoomMutexGuard;
/// takes a roomid_mutex_state, meaning that only this function is able to /// takes a roomid_mutex_state, meaning that only this function is able to
/// mutate the room state. /// mutate the room state.
#[implement(super::Service)] #[implement(super::Service)]
#[tracing::instrument(skip(self, state_lock), level = "trace")] #[tracing::instrument(skip(self, state_lock, pdu_builder), level = "trace")]
pub async fn build_and_append_pdu( pub async fn build_and_append_pdu(
&self, &self,
pdu_builder: PduBuilder, pdu_builder: PduBuilder,
@ -99,23 +98,19 @@ pub async fn build_and_append_pdu(
} }
} }
if *pdu.kind() == TimelineEventType::RoomCreate { if *pdu.kind() == TimelineEventType::RoomCreate {
trace!("Running room create checks for room {room_id}"); trace!("Creating shortroomid for {room_id}");
let content: RoomCreateEventContent = pdu.get_content()?;
let room_features = RoomVersion::new(&content.room_version)?;
if room_features.room_ids_as_hashes {
// bootstrap shortid for room
self.services self.services
.short .short
.get_or_create_shortroomid(&room_id) .get_or_create_shortroomid(&room_id)
.await; .await;
} }
}
// We append to state before appending the pdu, so we don't have a moment in // We append to state before appending the pdu, so we don't have a moment in
// time with the pdu without it's state. This is okay because append_pdu can't // time with the pdu without it's state. This is okay because append_pdu can't
// fail. // fail.
trace!("Appending {} state for room {room_id}", pdu.event_id()); trace!("Appending {} state for room {room_id}", pdu.event_id());
let statehashid = self.services.state.append_to_state(&pdu, &room_id).await?; let statehashid = self.services.state.append_to_state(&pdu, &room_id).await?;
trace!("State hash ID for {room_id}: {statehashid:?}");
trace!("Generating raw ID for PDU {}", pdu.event_id()); trace!("Generating raw ID for PDU {}", pdu.event_id());
let pdu_id = self let pdu_id = self

View file

@ -57,18 +57,30 @@ pub async fn create_hash_and_sign_event(
timestamp, timestamp,
} = pdu_builder; } = pdu_builder;
// If there was no create event yet, assume we are creating a room // If there was no create event yet, assume we are creating a room
trace!(
"Creating event of type {} in room {}",
event_type,
room_id.as_ref().map_or("None", |id| id.as_str())
);
let room_version_id = match room_id { let room_version_id = match room_id {
| Some(room_id) => self | Some(room_id) => {
.services trace!(%room_id, "Looking up existing room ID");
self.services
.state .state
.get_room_version(room_id) .get_room_version(room_id)
.await .await
.or_else(|_| from_evt(room_id.to_owned(), &event_type.clone(), &content.clone()))?, .or_else(|_| {
| None => from_evt( from_evt(room_id.to_owned(), &event_type.clone(), &content.clone())
})?
},
| None => {
trace!("No room ID, assuming room creation");
from_evt(
RoomId::new(self.services.globals.server_name()), RoomId::new(self.services.globals.server_name()),
&event_type.clone(), &event_type.clone(),
&content.clone(), &content.clone(),
)?, )?
},
}; };
let room_version = RoomVersion::new(&room_version_id).expect("room version is supported"); let room_version = RoomVersion::new(&room_version_id).expect("room version is supported");