|
|
|
|
@ -22,6 +22,7 @@ use ruma::{
|
|
|
|
|
}, |
|
|
|
|
push::{Action, Ruleset, Tweak}, |
|
|
|
|
state_res, |
|
|
|
|
state_res::Event, |
|
|
|
|
state_res::RoomVersion, |
|
|
|
|
uint, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, |
|
|
|
|
OwnedServerName, RoomAliasId, RoomId, UserId, |
|
|
|
|
@ -683,6 +684,92 @@ impl Service {
|
|
|
|
|
let (pdu, pdu_json) = |
|
|
|
|
self.create_hash_and_sign_event(pdu_builder, sender, room_id, state_lock)?; |
|
|
|
|
|
|
|
|
|
let admin_room = services().rooms.alias.resolve_local_alias( |
|
|
|
|
<&RoomAliasId>::try_from( |
|
|
|
|
format!("#admins:{}", services().globals.server_name()).as_str(), |
|
|
|
|
) |
|
|
|
|
.expect("#admins:server_name is a valid room alias"), |
|
|
|
|
)?; |
|
|
|
|
if admin_room.filter(|v| v == room_id).is_some() { |
|
|
|
|
match pdu.event_type() { |
|
|
|
|
RoomEventType::RoomEncryption => { |
|
|
|
|
warn!("Encryption is not allowed in the admins room"); |
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"Encryption is not allowed in the admins room.", |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
RoomEventType::RoomMember => { |
|
|
|
|
#[derive(Deserialize)] |
|
|
|
|
struct ExtractMembership { |
|
|
|
|
membership: MembershipState, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let target = pdu |
|
|
|
|
.state_key() |
|
|
|
|
.filter(|v| v.starts_with("@")) |
|
|
|
|
.unwrap_or(sender.as_str()); |
|
|
|
|
let server_name = services().globals.server_name(); |
|
|
|
|
let server_user = format!("@conduit:{}", server_name); |
|
|
|
|
let content = serde_json::from_str::<ExtractMembership>(pdu.content.get()) |
|
|
|
|
.map_err(|_| Error::bad_database("Invalid content in pdu."))?; |
|
|
|
|
|
|
|
|
|
if content.membership == MembershipState::Leave { |
|
|
|
|
if target == &server_user { |
|
|
|
|
warn!("Conduit user cannot leave from admins room"); |
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"Conduit user cannot leave from admins room.", |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let count = services() |
|
|
|
|
.rooms |
|
|
|
|
.state_cache |
|
|
|
|
.room_members(room_id) |
|
|
|
|
.filter_map(|m| m.ok()) |
|
|
|
|
.filter(|m| m.server_name() == server_name) |
|
|
|
|
.filter(|m| m != target) |
|
|
|
|
.count(); |
|
|
|
|
if count < 2 { |
|
|
|
|
warn!("Last admin cannot leave from admins room"); |
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"Last admin cannot leave from admins room.", |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if content.membership == MembershipState::Ban && pdu.state_key().is_some() { |
|
|
|
|
if target == &server_user { |
|
|
|
|
warn!("Conduit user cannot be banned in admins room"); |
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"Conduit user cannot be banned in admins room.", |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let count = services() |
|
|
|
|
.rooms |
|
|
|
|
.state_cache |
|
|
|
|
.room_members(room_id) |
|
|
|
|
.filter_map(|m| m.ok()) |
|
|
|
|
.filter(|m| m.server_name() == server_name) |
|
|
|
|
.filter(|m| m != target) |
|
|
|
|
.count(); |
|
|
|
|
if count < 2 { |
|
|
|
|
warn!("Last admin cannot be banned in admins room"); |
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
"Last admin cannot be banned in admins room.", |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
_ => {} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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 fail.
|
|
|
|
|
let statehashid = services().rooms.state.append_to_state(&pdu)?; |
|
|
|
|
|