mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-13 04:06:54 +00:00
238 lines
5.5 KiB
Rust
238 lines
5.5 KiB
Rust
use conduwuit::{Result, info, pdu::PartialPdu};
|
|
use futures::FutureExt;
|
|
use ruma::{
|
|
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,
|
|
},
|
|
},
|
|
room_version_rules::RoomIdFormatVersion,
|
|
};
|
|
|
|
use crate::Services;
|
|
|
|
/// Create the admin room.
|
|
///
|
|
/// Users in this room are considered admins by conduwuit, and the room can be
|
|
/// used to issue admin commands by talking to the server user inside it.
|
|
pub async fn create_admin_room(services: &Services) -> Result {
|
|
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"),
|
|
};
|
|
|
|
let state_lock = services.rooms.state.mutex.lock("!new-room").await;
|
|
|
|
// Create a user for the server
|
|
let server_user = services.globals.server_user.as_ref();
|
|
services.users.create_shadow_account(server_user).await?;
|
|
|
|
let mut create_content = if room_version_rules.authorization.use_room_create_sender {
|
|
RoomCreateEventContent::new_v1(server_user.into())
|
|
} else {
|
|
RoomCreateEventContent::new_v11()
|
|
};
|
|
|
|
create_content.federate = true;
|
|
create_content.room_version = room_version.clone();
|
|
|
|
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
|
|
);
|
|
|
|
// 1. The room create event
|
|
let create_event_id = services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(String::new(), &create_content),
|
|
server_user,
|
|
room_id.as_deref(),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
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")
|
|
});
|
|
|
|
// 2. Make server user/bot join
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(
|
|
String::from(server_user),
|
|
&RoomMemberEventContent::new(MembershipState::Join),
|
|
),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
// 3. Power levels
|
|
let mut power_levels_content =
|
|
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;
|
|
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(String::new(), &power_levels_content),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
// 4.1 Join Rules
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(String::new(), &RoomJoinRulesEventContent::new(JoinRule::Invite)),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
// 4.2 History Visibility
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(
|
|
String::new(),
|
|
&RoomHistoryVisibilityEventContent::new(HistoryVisibility::Shared),
|
|
),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
// 4.3 Guest Access
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(
|
|
String::new(),
|
|
&RoomGuestAccessEventContent::new(GuestAccess::Forbidden),
|
|
),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
// 5. Events implied by name and topic
|
|
let room_name = format!("{} Admin Room", services.config.server_name);
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(String::new(), &RoomNameEventContent::new(room_name)),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
let room_topic = format!("Manage {} | Run commands prefixed with `!admin` | Run `!admin -h` for help | Documentation: https://continuwuity.org/", services.config.server_name);
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(String::new(), &RoomTopicEventContent::markdown(room_topic)),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
// 6. Room alias
|
|
let mut alias_content = RoomCanonicalAliasEventContent::new();
|
|
alias_content.alias = Some(services.globals.admin_alias.clone());
|
|
|
|
services
|
|
.rooms
|
|
.timeline
|
|
.build_and_append_pdu(
|
|
PartialPdu::state(String::new(), &alias_content),
|
|
server_user,
|
|
Some(&room_id),
|
|
&state_lock,
|
|
)
|
|
.boxed()
|
|
.await?;
|
|
|
|
services
|
|
.rooms
|
|
.alias
|
|
.set_alias(&services.globals.admin_alias, &room_id, server_user)?;
|
|
|
|
Ok(())
|
|
}
|