2026-04-10 11:47:01 -04:00
use conduwuit ::{ Result , info , pdu ::PartialPdu };
2025-04-08 03:17:23 +00:00
use futures ::FutureExt ;
2024-06-10 06:02:17 +00:00
use ruma ::{
2026-06-26 05:57:59 +01:00
Int , RoomId ,
events ::{
TimelineEventType ,
room ::{
canonical_alias ::RoomCanonicalAliasEventContent ,
create ::RoomCreateEventContent ,
guest_access ::{ GuestAccess , RoomGuestAccessEventContent },
history_visibility ::{ HistoryVisibility , RoomHistoryVisibilityEventContent },
join_rules ::{ JoinRule , RoomJoinRulesEventContent },
member ::{ MembershipState , RoomMemberEventContent },
name ::RoomNameEventContent ,
power_levels ::RoomPowerLevelsEventContent ,
topic ::RoomTopicEventContent ,
},
2024-06-10 06:02:17 +00:00
},
2026-06-26 05:57:59 +01:00
room_version_rules ::RoomIdFormatVersion ,
2024-06-10 06:02:17 +00:00
};
2024-07-20 23:38:20 +00:00
use crate ::Services ;
2024-06-10 06:02:17 +00:00
/// Create the admin room.
///
2025-03-02 23:16:30 -05:00
/// Users in this room are considered admins by conduwuit, and the room can be
2024-06-10 06:02:17 +00:00
/// used to issue admin commands by talking to the server user inside it.
2025-03-02 23:16:30 -05:00
pub async fn create_admin_room ( services : & Services ) -> Result {
2026-06-26 05:57:59 +01:00
let room_version = services . config . default_room_version . clone ();
let room_version_rules = room_version
. rules ()
. expect ( "default_room_version must be supported" );
let room_id = match room_version_rules . room_id_format {
| RoomIdFormatVersion ::V1 => {
let room_id = RoomId ::new_v1 ( services . globals . server_name ());
services
. rooms
. short
. get_or_create_shortroomid ( & room_id )
. await ;
Some ( room_id )
},
| RoomIdFormatVersion ::V2 => None ,
| _ => panic! ( "Unknown room version format" ),
};
2024-06-10 06:02:17 +00:00
2026-06-26 05:57:59 +01:00
let state_lock = services . rooms . state . mutex . lock ( "!new-room" ). await ;
2024-06-10 06:02:17 +00:00
// Create a user for the server
2025-03-02 23:16:30 -05:00
let server_user = services . globals . server_user . as_ref ();
2026-06-29 12:58:22 -04:00
services . users . create_shadow_account ( server_user ). await ? ;
2024-06-10 06:02:17 +00:00
2026-06-26 05:57:59 +01:00
let mut create_content = if room_version_rules . authorization . use_room_create_sender {
RoomCreateEventContent ::new_v1 ( server_user . into ())
} else {
RoomCreateEventContent ::new_v11 ()
2024-06-10 06:02:17 +00:00
};
2026-03-29 12:25:42 -04:00
create_content . federate = true ;
create_content . room_version = room_version . clone ();
2026-06-26 05:57:59 +01:00
info! (
"Creating admin room {} with version {}" ,
room_id
. clone ()
. map_or_else ( || "<not known ahead of time>" . to_owned (), | id | id . as_str (). to_owned ()),
room_version
);
2025-09-17 20:46:03 +00:00
2024-06-10 06:02:17 +00:00
// 1. The room create event
2026-06-26 05:57:59 +01:00
let create_event_id = services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state ( String ::new (), & create_content ),
2024-06-10 06:02:17 +00:00
server_user ,
2026-06-26 05:57:59 +01:00
room_id . as_deref (),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
2026-06-26 05:57:59 +01:00
let room_id = room_id . unwrap_or_else ( || {
RoomId ::new_v2 (
create_event_id
. as_str ()
. strip_prefix ( "$" )
. expect ( "event ID must start with a $ sigil" ),
)
. expect ( "event ID without sigil must be a valid room ID" )
});
2024-06-10 06:02:17 +00:00
2024-12-14 21:58:01 -05:00
// 2. Make server user/bot join
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state (
2025-03-02 23:16:30 -05:00
String ::from ( server_user ),
2024-12-15 00:05:47 -05:00
& RoomMemberEventContent ::new ( MembershipState ::Join ),
),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
// 3. Power levels
2026-04-07 14:40:10 +01:00
let mut power_levels_content =
2026-06-26 05:57:59 +01:00
RoomPowerLevelsEventContent ::new ( & room_version_rules . authorization );
if ! room_version_rules
. authorization
. explicitly_privilege_room_creators
{
power_levels_content
. users
. insert ( server_user . into (), Int ::MAX );
}
// Prevent common foot-shotguns
power_levels_content
. events
. insert ( TimelineEventType ::RoomTombstone , Int ::MAX );
power_levels_content
. events
. insert ( TimelineEventType ::RoomEncryption , Int ::MAX );
power_levels_content
. events
. insert ( TimelineEventType ::RoomCanonicalAlias , Int ::MAX );
power_levels_content . invite = power_levels_content . state_default ;
2026-03-29 12:25:42 -04:00
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state ( String ::new (), & power_levels_content ),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
// 4.1 Join Rules
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state ( String ::new (), & RoomJoinRulesEventContent ::new ( JoinRule ::Invite )),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
// 4.2 History Visibility
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state (
2024-10-04 20:25:32 +00:00
String ::new (),
& RoomHistoryVisibilityEventContent ::new ( HistoryVisibility ::Shared ),
),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
// 4.3 Guest Access
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state (
2024-12-15 00:05:47 -05:00
String ::new (),
& RoomGuestAccessEventContent ::new ( GuestAccess ::Forbidden ),
),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
// 5. Events implied by name and topic
2025-03-02 23:16:30 -05:00
let room_name = format! ( " {} Admin Room" , services . config . server_name );
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state ( String ::new (), & RoomNameEventContent ::new ( room_name )),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
2026-03-29 12:25:42 -04:00
let room_topic = format! ( "Manage {} | Run commands prefixed with `!admin` | Run `!admin -h` for help | Documentation: https://continuwuity.org/" , services . config . server_name );
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state ( String ::new (), & RoomTopicEventContent ::markdown ( room_topic )),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
// 6. Room alias
2026-03-29 12:25:42 -04:00
let mut alias_content = RoomCanonicalAliasEventContent ::new ();
alias_content . alias = Some ( services . globals . admin_alias . clone ());
2024-06-10 06:02:17 +00:00
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. timeline
. build_and_append_pdu (
2026-04-10 11:47:01 -04:00
PartialPdu ::state ( String ::new (), & alias_content ),
2024-06-10 06:02:17 +00:00
server_user ,
2025-09-17 20:46:03 +00:00
Some ( & room_id ),
2024-06-10 06:02:17 +00:00
& state_lock ,
)
2025-04-08 03:17:23 +00:00
. boxed ()
2024-06-10 06:02:17 +00:00
. await ? ;
2024-07-20 23:38:20 +00:00
services
2024-06-10 06:02:17 +00:00
. rooms
. alias
2026-03-29 12:25:42 -04:00
. set_alias ( & services . globals . admin_alias , & room_id , server_user ) ? ;
2024-06-10 06:02:17 +00:00
Ok (())
}