feat: admin room

This commit is contained in:
Timo Kösters 2020-10-05 22:19:22 +02:00
parent 0d6159c2da
commit bcd1fe1856
No known key found for this signature in database
GPG key ID: 24DA7517711A2BA4
12 changed files with 864 additions and 574 deletions

15
Cargo.lock generated
View file

@ -1547,7 +1547,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma" name = "ruma"
version = "0.0.1" version = "0.0.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"ruma-api", "ruma-api",
"ruma-appservice-api", "ruma-appservice-api",
@ -1563,7 +1562,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-api" name = "ruma-api"
version = "0.17.0-alpha.1" version = "0.17.0-alpha.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"http", "http",
"percent-encoding", "percent-encoding",
@ -1578,7 +1576,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-api-macros" name = "ruma-api-macros"
version = "0.17.0-alpha.1" version = "0.17.0-alpha.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@ -1589,7 +1586,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-appservice-api" name = "ruma-appservice-api"
version = "0.2.0-alpha.1" version = "0.2.0-alpha.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"ruma-api", "ruma-api",
"ruma-common", "ruma-common",
@ -1602,7 +1598,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-client-api" name = "ruma-client-api"
version = "0.10.0-alpha.1" version = "0.10.0-alpha.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"assign", "assign",
"http", "http",
@ -1621,7 +1616,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-common" name = "ruma-common"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-api", "ruma-api",
@ -1635,7 +1629,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events" name = "ruma-events"
version = "0.22.0-alpha.1" version = "0.22.0-alpha.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-common", "ruma-common",
@ -1650,7 +1643,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-events-macros" name = "ruma-events-macros"
version = "0.22.0-alpha.1" version = "0.22.0-alpha.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@ -1661,7 +1653,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-federation-api" name = "ruma-federation-api"
version = "0.0.3" version = "0.0.3"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"js_int", "js_int",
"ruma-api", "ruma-api",
@ -1676,7 +1667,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers" name = "ruma-identifiers"
version = "0.17.4" version = "0.17.4"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"rand", "rand",
"ruma-identifiers-macros", "ruma-identifiers-macros",
@ -1688,7 +1678,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-macros" name = "ruma-identifiers-macros"
version = "0.17.4" version = "0.17.4"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -1699,7 +1688,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-identifiers-validation" name = "ruma-identifiers-validation"
version = "0.1.1" version = "0.1.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"serde", "serde",
"strum", "strum",
@ -1708,7 +1696,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-serde" name = "ruma-serde"
version = "0.2.3" version = "0.2.3"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"form_urlencoded", "form_urlencoded",
"itoa", "itoa",
@ -1720,7 +1707,6 @@ dependencies = [
[[package]] [[package]]
name = "ruma-signatures" name = "ruma-signatures"
version = "0.6.0-dev.1" version = "0.6.0-dev.1"
source = "git+https://github.com/timokoesters/ruma?branch=timo-fed-fixes#47fab87325b71b7f6c2fb3cd276d1f813e42abf7"
dependencies = [ dependencies = [
"base64", "base64",
"ring", "ring",
@ -1970,7 +1956,6 @@ checksum = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
[[package]] [[package]]
name = "state-res" name = "state-res"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/timokoesters/state-res?branch=spec-comp#d11a3feb5307715ab5d86af8f25d4bccfee6264b"
dependencies = [ dependencies = [
"itertools", "itertools",
"js_int", "js_int",

View file

@ -1,3 +1,5 @@
use std::{collections::BTreeMap, convert::TryInto};
use super::{State, DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH}; use super::{State, DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH};
use crate::{pdu::PduBuilder, utils, ConduitResult, Database, Error, Ruma}; use crate::{pdu::PduBuilder, utils, ConduitResult, Database, Error, Ruma};
use ruma::{ use ruma::{
@ -11,8 +13,11 @@ use ruma::{
uiaa::{AuthFlow, UiaaInfo}, uiaa::{AuthFlow, UiaaInfo},
}, },
}, },
events::{room::member, EventType}, events::{
UserId, room::canonical_alias, room::guest_access, room::history_visibility, room::join_rules,
room::member, room::name, room::topic, EventType,
},
RoomAliasId, RoomId, RoomVersionId, UserId,
}; };
use register::RegistrationKind; use register::RegistrationKind;
@ -73,7 +78,7 @@ pub fn get_register_available_route(
feature = "conduit_bin", feature = "conduit_bin",
post("/_matrix/client/r0/register", data = "<body>") post("/_matrix/client/r0/register", data = "<body>")
)] )]
pub fn register_route( pub async fn register_route(
db: State<'_, Database>, db: State<'_, Database>,
body: Ruma<register::Request<'_>>, body: Ruma<register::Request<'_>>,
) -> ConduitResult<register::Response> { ) -> ConduitResult<register::Response> {
@ -202,6 +207,265 @@ pub fn register_route(
body.initial_device_display_name.clone(), body.initial_device_display_name.clone(),
)?; )?;
// If this is the first user on this server, create the admins room
if db.users.count() == 1 {
// Create a user for the server
let conduit_user = UserId::parse_with_server_name("conduit", db.globals.server_name())
.expect("@conduit:server_name is valid");
db.users.create(&conduit_user, "")?;
let room_id = RoomId::new(db.globals.server_name());
let mut content = ruma::events::room::create::CreateEventContent::new(conduit_user.clone());
content.federate = true;
content.predecessor = None;
content.room_version = RoomVersionId::Version6;
// 1. The room create event
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomCreate,
content: serde_json::to_value(content).expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 2. Make conduit bot join
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Join,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(conduit_user.to_string()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 3. Power levels
let mut users = BTreeMap::new();
users.insert(conduit_user.clone(), 100.into());
users.insert(user_id.clone(), 100.into());
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomPowerLevels,
content: serde_json::to_value(
ruma::events::room::power_levels::PowerLevelsEventContent {
ban: 50.into(),
events: BTreeMap::new(),
events_default: 0.into(),
invite: 50.into(),
kick: 50.into(),
redact: 50.into(),
state_default: 50.into(),
users,
users_default: 0.into(),
notifications: ruma::events::room::power_levels::NotificationPowerLevels {
room: 50.into(),
},
},
)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 4.1 Join Rules
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomJoinRules,
content: serde_json::to_value(join_rules::JoinRulesEventContent::new(
join_rules::JoinRule::Invite,
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 4.2 History Visibility
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomHistoryVisibility,
content: serde_json::to_value(
history_visibility::HistoryVisibilityEventContent::new(
history_visibility::HistoryVisibility::Shared,
),
)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 4.3 Guest Access
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomGuestAccess,
content: serde_json::to_value(guest_access::GuestAccessEventContent::new(
guest_access::GuestAccess::Forbidden,
))
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 6. Events implied by name and topic
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomName,
content: serde_json::to_value(
name::NameEventContent::new("Admin Room".to_owned()).map_err(|_| {
Error::BadRequest(ErrorKind::InvalidParam, "Name is invalid.")
})?,
)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomTopic,
content: serde_json::to_value(topic::TopicEventContent {
topic: format!("Manage {}", db.globals.server_name()),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// Room alias
let alias: RoomAliasId = format!("#admins:{}", db.globals.server_name())
.try_into()
.expect("#admins:server_name is a valid alias name");
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomCanonicalAlias,
content: serde_json::to_value(canonical_alias::CanonicalAliasEventContent {
alias: Some(alias.clone()),
alt_aliases: Vec::new(),
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some("".to_owned()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
db.rooms.set_alias(&alias, Some(&room_id), &db.globals)?;
// Invite and join the real user
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Invite,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
&conduit_user,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
db.rooms.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent {
membership: member::MembershipState::Join,
displayname: None,
avatar_url: None,
is_direct: None,
third_party_invite: None,
})
.expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(user_id.to_string()),
redacts: None,
},
&user_id,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
}
Ok(register::Response { Ok(register::Response {
access_token: Some(token), access_token: Some(token),
user_id, user_id,
@ -354,12 +618,10 @@ pub async fn deactivate_route(
third_party_invite: None, third_party_invite: None,
}; };
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(event) content: serde_json::to_value(event).expect("event is valid, we just created it"),
.expect("event is valid, we just created it"),
unsigned: None, unsigned: None,
state_key: Some(sender_id.to_string()), state_key: Some(sender_id.to_string()),
redacts: None, redacts: None,
@ -369,8 +631,7 @@ pub async fn deactivate_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
// Remove devices and mark account as deactivated // Remove devices and mark account as deactivated

View file

@ -108,8 +108,7 @@ pub async fn leave_room_route(
event.membership = member::MembershipState::Leave; event.membership = member::MembershipState::Leave;
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(event).expect("event is valid, we just created it"), content: serde_json::to_value(event).expect("event is valid, we just created it"),
@ -122,8 +121,7 @@ pub async fn leave_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(leave_room::Response::new().into()) Ok(leave_room::Response::new().into())
} }
@ -139,8 +137,7 @@ pub async fn invite_user_route(
let sender_id = body.sender_id.as_ref().expect("user is authenticated"); let sender_id = body.sender_id.as_ref().expect("user is authenticated");
if let invite_user::IncomingInvitationRecipient::UserId { user_id } = &body.recipient { if let invite_user::IncomingInvitationRecipient::UserId { user_id } = &body.recipient {
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent { content: serde_json::to_value(member::MemberEventContent {
@ -160,8 +157,7 @@ pub async fn invite_user_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(invite_user::Response.into()) Ok(invite_user::Response.into())
} else { } else {
@ -199,8 +195,7 @@ pub async fn kick_user_route(
event.membership = ruma::events::room::member::MembershipState::Leave; event.membership = ruma::events::room::member::MembershipState::Leave;
// TODO: reason // TODO: reason
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(event).expect("event is valid, we just created it"), content: serde_json::to_value(event).expect("event is valid, we just created it"),
@ -213,8 +208,7 @@ pub async fn kick_user_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(kick_user::Response::new().into()) Ok(kick_user::Response::new().into())
} }
@ -257,8 +251,7 @@ pub async fn ban_user_route(
}, },
)?; )?;
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(event).expect("event is valid, we just created it"), content: serde_json::to_value(event).expect("event is valid, we just created it"),
@ -271,8 +264,7 @@ pub async fn ban_user_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(ban_user::Response::new().into()) Ok(ban_user::Response::new().into())
} }
@ -306,8 +298,7 @@ pub async fn unban_user_route(
event.membership = ruma::events::room::member::MembershipState::Leave; event.membership = ruma::events::room::member::MembershipState::Leave;
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(event).expect("event is valid, we just created it"), content: serde_json::to_value(event).expect("event is valid, we just created it"),
@ -320,8 +311,7 @@ pub async fn unban_user_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(unban_user::Response::new().into()) Ok(unban_user::Response::new().into())
} }
@ -640,6 +630,7 @@ async fn join_room_by_id_helper(
&serde_json::to_value(&**pdu).expect("PDU is valid value"), &serde_json::to_value(&**pdu).expect("PDU is valid value"),
&db.globals, &db.globals,
&db.account_data, &db.account_data,
&db.sending,
)?; )?;
if state_events.contains(ev_id) { if state_events.contains(ev_id) {
@ -657,12 +648,10 @@ async fn join_room_by_id_helper(
third_party_invite: None, third_party_invite: None,
}; };
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(event) content: serde_json::to_value(event).expect("event is valid, we just created it"),
.expect("event is valid, we just created it"),
unsigned: None, unsigned: None,
state_key: Some(sender_id.to_string()), state_key: Some(sender_id.to_string()),
redacts: None, redacts: None,
@ -672,8 +661,7 @@ async fn join_room_by_id_helper(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
Ok(join_room_by_id::Response::new(room_id.clone()).into()) Ok(join_room_by_id::Response::new(room_id.clone()).into())

View file

@ -49,9 +49,7 @@ pub async fn send_message_event_route(
let mut unsigned = serde_json::Map::new(); let mut unsigned = serde_json::Map::new();
unsigned.insert("transaction_id".to_owned(), body.txn_id.clone().into()); unsigned.insert("transaction_id".to_owned(), body.txn_id.clone().into());
let event_id = db let event_id = db.rooms.build_and_append_pdu(
.rooms
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: body.content.event_type().into(), event_type: body.content.event_type().into(),
content: serde_json::from_str( content: serde_json::from_str(
@ -70,8 +68,7 @@ pub async fn send_message_event_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
db.transaction_ids db.transaction_ids
.add_txnid(sender_id, device_id, &body.txn_id, event_id.as_bytes())?; .add_txnid(sender_id, device_id, &body.txn_id, event_id.as_bytes())?;

View file

@ -31,8 +31,7 @@ pub async fn set_displayname_route(
// Send a new membership event and presence update into all joined rooms // Send a new membership event and presence update into all joined rooms
for room_id in db.rooms.rooms_joined(&sender_id) { for room_id in db.rooms.rooms_joined(&sender_id) {
let room_id = room_id?; let room_id = room_id?;
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(ruma::events::room::member::MemberEventContent { content: serde_json::to_value(ruma::events::room::member::MemberEventContent {
@ -66,8 +65,7 @@ pub async fn set_displayname_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// Presence update // Presence update
db.rooms.edus.update_presence( db.rooms.edus.update_presence(
@ -125,8 +123,7 @@ pub async fn set_avatar_url_route(
// Send a new membership event and presence update into all joined rooms // Send a new membership event and presence update into all joined rooms
for room_id in db.rooms.rooms_joined(&sender_id) { for room_id in db.rooms.rooms_joined(&sender_id) {
let room_id = room_id?; let room_id = room_id?;
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(ruma::events::room::member::MemberEventContent { content: serde_json::to_value(ruma::events::room::member::MemberEventContent {
@ -160,8 +157,7 @@ pub async fn set_avatar_url_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// Presence update // Presence update
db.rooms.edus.update_presence( db.rooms.edus.update_presence(

View file

@ -18,9 +18,7 @@ pub async fn redact_event_route(
) -> ConduitResult<redact_event::Response> { ) -> ConduitResult<redact_event::Response> {
let sender_id = body.sender_id.as_ref().expect("user is authenticated"); let sender_id = body.sender_id.as_ref().expect("user is authenticated");
let event_id = db let event_id = db.rooms.build_and_append_pdu(
.rooms
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomRedaction, event_type: EventType::RoomRedaction,
content: serde_json::to_value(redaction::RedactionEventContent { content: serde_json::to_value(redaction::RedactionEventContent {
@ -36,8 +34,7 @@ pub async fn redact_event_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(redact_event::Response { event_id }.into()) Ok(redact_event::Response { event_id }.into())
} }

View file

@ -53,8 +53,7 @@ pub async fn create_room_route(
content.room_version = RoomVersionId::Version6; content.room_version = RoomVersionId::Version6;
// 1. The room create event // 1. The room create event
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomCreate, event_type: EventType::RoomCreate,
content: serde_json::to_value(content).expect("event is valid, we just created it"), content: serde_json::to_value(content).expect("event is valid, we just created it"),
@ -67,12 +66,10 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// 2. Let the room creator join // 2. Let the room creator join
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent { content: serde_json::to_value(member::MemberEventContent {
@ -92,8 +89,7 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// 3. Power levels // 3. Power levels
let mut users = BTreeMap::new(); let mut users = BTreeMap::new();
@ -123,8 +119,7 @@ pub async fn create_room_route(
}) })
.expect("event is valid, we just created it") .expect("event is valid, we just created it")
}; };
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomPowerLevels, event_type: EventType::RoomPowerLevels,
content: power_levels_content, content: power_levels_content,
@ -137,8 +132,7 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// 4. Events set by preset // 4. Events set by preset
@ -149,8 +143,7 @@ pub async fn create_room_route(
}); });
// 4.1 Join Rules // 4.1 Join Rules
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomJoinRules, event_type: EventType::RoomJoinRules,
content: match preset { content: match preset {
@ -173,19 +166,15 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// 4.2 History Visibility // 4.2 History Visibility
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomHistoryVisibility, event_type: EventType::RoomHistoryVisibility,
content: serde_json::to_value( content: serde_json::to_value(history_visibility::HistoryVisibilityEventContent::new(
history_visibility::HistoryVisibilityEventContent::new(
history_visibility::HistoryVisibility::Shared, history_visibility::HistoryVisibility::Shared,
), ))
)
.expect("event is valid, we just created it"), .expect("event is valid, we just created it"),
unsigned: None, unsigned: None,
state_key: Some("".to_owned()), state_key: Some("".to_owned()),
@ -196,12 +185,10 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// 4.3 Guest Access // 4.3 Guest Access
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomGuestAccess, event_type: EventType::RoomGuestAccess,
content: match preset { content: match preset {
@ -225,8 +212,7 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// 5. Events listed in initial_state // 5. Events listed in initial_state
for event in &body.initial_state { for event in &body.initial_state {
@ -240,22 +226,19 @@ pub async fn create_room_route(
continue; continue;
} }
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
pdu_builder, pdu_builder,
&sender_id, &sender_id,
&room_id, &room_id,
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
// 6. Events implied by name and topic // 6. Events implied by name and topic
if let Some(name) = &body.name { if let Some(name) = &body.name {
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomName, event_type: EventType::RoomName,
content: serde_json::to_value( content: serde_json::to_value(
@ -273,13 +256,11 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
if let Some(topic) = &body.topic { if let Some(topic) = &body.topic {
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomTopic, event_type: EventType::RoomTopic,
content: serde_json::to_value(topic::TopicEventContent { content: serde_json::to_value(topic::TopicEventContent {
@ -295,14 +276,12 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
// 7. Events implied by invite (and TODO: invite_3pid) // 7. Events implied by invite (and TODO: invite_3pid)
for user in &body.invite { for user in &body.invite {
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent { content: serde_json::to_value(member::MemberEventContent {
@ -322,8 +301,7 @@ pub async fn create_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
// Homeserver specific stuff // Homeserver specific stuff
@ -395,17 +373,13 @@ pub async fn upgrade_room_route(
// Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further // Send a m.room.tombstone event to the old room to indicate that it is not intended to be used any further
// Fail if the sender does not have the required permissions // Fail if the sender does not have the required permissions
let tombstone_event_id = db let tombstone_event_id = db.rooms.build_and_append_pdu(
.rooms
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomTombstone, event_type: EventType::RoomTombstone,
content: serde_json::to_value( content: serde_json::to_value(ruma::events::room::tombstone::TombstoneEventContent {
ruma::events::room::tombstone::TombstoneEventContent {
body: "This room has been replaced".to_string(), body: "This room has been replaced".to_string(),
replacement_room: replacement_room.clone(), replacement_room: replacement_room.clone(),
}, })
)
.expect("event is valid, we just created it"), .expect("event is valid, we just created it"),
unsigned: None, unsigned: None,
state_key: Some("".to_owned()), state_key: Some("".to_owned()),
@ -416,8 +390,7 @@ pub async fn upgrade_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// Get the old room federations status // Get the old room federations status
let federate = serde_json::from_value::<Raw<ruma::events::room::create::CreateEventContent>>( let federate = serde_json::from_value::<Raw<ruma::events::room::create::CreateEventContent>>(
@ -444,8 +417,7 @@ pub async fn upgrade_room_route(
create_event_content.room_version = new_version; create_event_content.room_version = new_version;
create_event_content.predecessor = predecessor; create_event_content.predecessor = predecessor;
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomCreate, event_type: EventType::RoomCreate,
content: serde_json::to_value(create_event_content) content: serde_json::to_value(create_event_content)
@ -459,12 +431,10 @@ pub async fn upgrade_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// Join the new room // Join the new room
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomMember, event_type: EventType::RoomMember,
content: serde_json::to_value(member::MemberEventContent { content: serde_json::to_value(member::MemberEventContent {
@ -484,8 +454,7 @@ pub async fn upgrade_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
// Recommended transferable state events list from the specs // Recommended transferable state events list from the specs
let transferable_state_events = vec![ let transferable_state_events = vec![
@ -507,8 +476,7 @@ pub async fn upgrade_room_route(
None => continue, // Skipping missing events. None => continue, // Skipping missing events.
}; };
db.rooms db.rooms.build_and_append_pdu(
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type, event_type,
content: event_content, content: event_content,
@ -521,8 +489,7 @@ pub async fn upgrade_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
} }
// Moves any local aliases to the new room // Moves any local aliases to the new room
@ -552,9 +519,7 @@ pub async fn upgrade_room_route(
power_levels_event_content.invite = new_level; power_levels_event_content.invite = new_level;
// Modify the power levels in the old room to prevent sending of events and inviting new users // Modify the power levels in the old room to prevent sending of events and inviting new users
let _ = db let _ = db.rooms.build_and_append_pdu(
.rooms
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: EventType::RoomPowerLevels, event_type: EventType::RoomPowerLevels,
content: serde_json::to_value(power_levels_event_content) content: serde_json::to_value(power_levels_event_content)
@ -568,8 +533,7 @@ pub async fn upgrade_room_route(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await;
// Return the replacement room id // Return the replacement room id
Ok(upgrade_room::Response { replacement_room }.into()) Ok(upgrade_room::Response { replacement_room }.into())

View file

@ -213,9 +213,7 @@ pub async fn send_state_event_for_key_helper(
} }
} }
let event_id = db let event_id = db.rooms.build_and_append_pdu(
.rooms
.build_and_append_pdu(
PduBuilder { PduBuilder {
event_type: content.event_type().into(), event_type: content.event_type().into(),
content: json, content: json,
@ -228,8 +226,7 @@ pub async fn send_state_event_for_key_helper(
&db.globals, &db.globals,
&db.sending, &db.sending,
&db.account_data, &db.account_data,
) )?;
.await?;
Ok(event_id) Ok(event_id)
} }

View file

@ -10,7 +10,7 @@ use ruma::{
events::{ events::{
ignored_user_list, ignored_user_list,
room::{ room::{
member, member, message,
power_levels::{self, PowerLevelsEventContent}, power_levels::{self, PowerLevelsEventContent},
}, },
EventType, EventType,
@ -440,6 +440,7 @@ impl Rooms {
pdu_json: &serde_json::Value, pdu_json: &serde_json::Value,
globals: &super::globals::Globals, globals: &super::globals::Globals,
account_data: &super::account_data::AccountData, account_data: &super::account_data::AccountData,
sending: &super::sending::Sending,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
self.replace_pdu_leaves(&pdu.room_id, &pdu.event_id)?; self.replace_pdu_leaves(&pdu.room_id, &pdu.event_id)?;
@ -452,7 +453,8 @@ impl Rooms {
self.edus self.edus
.private_read_set(&pdu.room_id, &pdu.sender, index, &globals)?; .private_read_set(&pdu.room_id, &pdu.sender, index, &globals)?;
let mut pdu_id = pdu.room_id.as_bytes().to_vec(); let room_id = pdu.room_id.clone();
let mut pdu_id = room_id.as_bytes().to_vec();
pdu_id.push(0xff); pdu_id.push(0xff);
pdu_id.extend_from_slice(&index.to_be_bytes()); pdu_id.extend_from_slice(&index.to_be_bytes());
@ -503,6 +505,45 @@ impl Rooms {
key.extend_from_slice(&pdu_id); key.extend_from_slice(&pdu_id);
self.tokenids.insert(key, &[])?; self.tokenids.insert(key, &[])?;
} }
if body.starts_with(&format!("@conduit:{}: ", globals.server_name()))
&& self
.id_from_alias(
&format!("#admins:{}", globals.server_name())
.try_into()
.expect("#admins:server_name is a valid room alias"),
)?
.as_ref()
== Some(&pdu.room_id)
{
let mut parts = body.split_whitespace().skip(1);
if let Some(command) = parts.next() {
let args = parts.collect::<Vec<_>>();
self.build_and_append_pdu(
PduBuilder {
event_type: EventType::RoomMessage,
content: serde_json::to_value(
message::TextMessageEventContent {
body: format!("Command: {}, Args: {:?}", command, args),
formatted: None,
relates_to: None,
},
)
.expect("event is valid, we just created it"),
unsigned: None,
state_key: None,
redacts: None,
},
&UserId::try_from(format!("@conduit:{}", globals.server_name()))
.expect("@conduit:server_name is valid"),
&room_id,
&globals,
&sending,
&account_data,
)?;
}
}
} }
} }
_ => {} _ => {}
@ -570,7 +611,7 @@ impl Rooms {
} }
/// Creates a new persisted data unit and adds it to a room. /// Creates a new persisted data unit and adds it to a room.
pub async fn build_and_append_pdu( pub fn build_and_append_pdu(
&self, &self,
pdu_builder: PduBuilder, pdu_builder: PduBuilder,
sender: &UserId, sender: &UserId,
@ -793,7 +834,7 @@ impl Rooms {
.expect("json is object") .expect("json is object")
.insert("event_id".to_owned(), pdu.event_id.to_string().into()); .insert("event_id".to_owned(), pdu.event_id.to_string().into());
let pdu_id = self.append_pdu(&pdu, &pdu_json, globals, account_data)?; let pdu_id = self.append_pdu(&pdu, &pdu_json, globals, account_data, sending)?;
self.append_to_state(&pdu_id, &pdu)?; self.append_to_state(&pdu_id, &pdu)?;

View file

@ -57,6 +57,11 @@ impl Users {
Ok(()) Ok(())
} }
/// Returns the number of users registered on this server.
pub fn count(&self) -> usize {
self.userid_password.iter().count()
}
/// Find out which user an access token belongs to. /// Find out which user an access token belongs to.
pub fn find_from_token(&self, token: &str) -> Result<Option<(UserId, String)>> { pub fn find_from_token(&self, token: &str) -> Result<Option<(UserId, String)>> {
self.token_userdeviceid self.token_userdeviceid

View file

@ -126,6 +126,7 @@ fn setup_rocket() -> rocket::Rocket {
server_server::get_public_rooms_filtered_route, server_server::get_public_rooms_filtered_route,
server_server::send_transaction_message_route, server_server::send_transaction_message_route,
server_server::get_missing_events_route, server_server::get_missing_events_route,
server_server::get_profile_information_route,
], ],
) )
.attach(AdHoc::on_attach("Config", |mut rocket| async { .attach(AdHoc::on_attach("Config", |mut rocket| async {

View file

@ -1,4 +1,5 @@
use crate::{client_server, ConduitResult, Database, Error, PduEvent, Result, Ruma}; use crate::{client_server, ConduitResult, Database, Error, PduEvent, Result, Ruma};
use get_profile_information::v1::ProfileField;
use http::header::{HeaderValue, AUTHORIZATION, HOST}; use http::header::{HeaderValue, AUTHORIZATION, HOST};
use log::warn; use log::warn;
use rocket::{get, post, put, response::content::Json, State}; use rocket::{get, post, put, response::content::Json, State};
@ -10,6 +11,7 @@ use ruma::{
get_server_keys, get_server_version::v1 as get_server_version, ServerKey, VerifyKey, get_server_keys, get_server_version::v1 as get_server_version, ServerKey, VerifyKey,
}, },
event::get_missing_events, event::get_missing_events,
query::get_profile_information,
transactions::send_transaction_message, transactions::send_transaction_message,
}, },
OutgoingRequest, OutgoingRequest,
@ -362,9 +364,9 @@ pub fn send_transaction_message_route<'a>(
let pdu = serde_json::from_value::<PduEvent>(value.clone()) let pdu = serde_json::from_value::<PduEvent>(value.clone())
.expect("all ruma pdus are conduit pdus"); .expect("all ruma pdus are conduit pdus");
if db.rooms.exists(&pdu.room_id)? { if db.rooms.exists(&pdu.room_id)? {
let pdu_id = db let pdu_id =
.rooms db.rooms
.append_pdu(&pdu, &value, &db.globals, &db.account_data)?; .append_pdu(&pdu, &value, &db.globals, &db.account_data, &db.sending)?;
db.rooms.append_to_state(&pdu_id, &pdu)?; db.rooms.append_to_state(&pdu_id, &pdu)?;
} }
} }
@ -416,3 +418,59 @@ pub fn get_missing_events_route<'a>(
Ok(get_missing_events::v1::Response { events }.into()) Ok(get_missing_events::v1::Response { events }.into())
} }
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/federation/v1/query/profile", data = "<body>")
)]
pub fn get_profile_information_route<'a>(
db: State<'a, Database>,
body: Ruma<get_profile_information::v1::Request<'_>>,
) -> ConduitResult<get_profile_information::v1::Response> {
let mut displayname = None;
let mut avatar_url = None;
match body.field {
Some(ProfileField::DisplayName) => displayname = db.users.displayname(&body.user_id)?,
Some(ProfileField::AvatarUrl) => avatar_url = db.users.avatar_url(&body.user_id)?,
None => {
displayname = db.users.displayname(&body.user_id)?;
avatar_url = db.users.avatar_url(&body.user_id)?;
}
}
Ok(get_profile_information::v1::Response {
displayname,
avatar_url,
}
.into())
}
/*
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/federation/v2/invite/<_>/<_>", data = "<body>")
)]
pub fn get_user_devices_route<'a>(
db: State<'a, Database>,
body: Ruma<membership::v1::Request<'_>>,
) -> ConduitResult<get_profile_information::v1::Response> {
let mut displayname = None;
let mut avatar_url = None;
match body.field {
Some(ProfileField::DisplayName) => displayname = db.users.displayname(&body.user_id)?,
Some(ProfileField::AvatarUrl) => avatar_url = db.users.avatar_url(&body.user_id)?,
None => {
displayname = db.users.displayname(&body.user_id)?;
avatar_url = db.users.avatar_url(&body.user_id)?;
}
}
Ok(get_profile_information::v1::Response {
displayname,
avatar_url,
}
.into())
}
*/