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,23 +618,20 @@ 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).expect("event is valid, we just created it"),
content: serde_json::to_value(event) unsigned: None,
.expect("event is valid, we just created it"), state_key: Some(sender_id.to_string()),
unsigned: None, redacts: None,
state_key: Some(sender_id.to_string()), },
redacts: None, &sender_id,
}, &room_id,
&sender_id, &db.globals,
&room_id, &db.sending,
&db.globals, &db.account_data,
&db.sending, )?;
&db.account_data,
)
.await?;
} }
// Remove devices and mark account as deactivated // Remove devices and mark account as deactivated

View file

@ -108,22 +108,20 @@ 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"), unsigned: None,
unsigned: None, state_key: Some(sender_id.to_string()),
state_key: Some(sender_id.to_string()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &body.room_id,
&body.room_id, &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,29 +137,27 @@ 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 { membership: member::MembershipState::Invite,
membership: member::MembershipState::Invite, displayname: db.users.displayname(&user_id)?,
displayname: db.users.displayname(&user_id)?, avatar_url: db.users.avatar_url(&user_id)?,
avatar_url: db.users.avatar_url(&user_id)?, is_direct: None,
is_direct: None, third_party_invite: None,
third_party_invite: None, })
}) .expect("event is valid, we just created it"),
.expect("event is valid, we just created it"), unsigned: None,
unsigned: None, state_key: Some(user_id.to_string()),
state_key: Some(user_id.to_string()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &body.room_id,
&body.room_id, &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,22 +195,20 @@ 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"), unsigned: None,
unsigned: None, state_key: Some(body.user_id.to_string()),
state_key: Some(body.user_id.to_string()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &body.room_id,
&body.room_id, &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,22 +251,20 @@ 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"), unsigned: None,
unsigned: None, state_key: Some(body.user_id.to_string()),
state_key: Some(body.user_id.to_string()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &body.room_id,
&body.room_id, &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,22 +298,20 @@ 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"), unsigned: None,
unsigned: None, state_key: Some(body.user_id.to_string()),
state_key: Some(body.user_id.to_string()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &body.room_id,
&body.room_id, &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,23 +648,20 @@ 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).expect("event is valid, we just created it"),
content: serde_json::to_value(event) unsigned: None,
.expect("event is valid, we just created it"), state_key: Some(sender_id.to_string()),
unsigned: None, redacts: None,
state_key: Some(sender_id.to_string()), },
redacts: None, &sender_id,
}, &room_id,
&sender_id, &db.globals,
&room_id, &db.sending,
&db.globals, &db.account_data,
&db.sending, )?;
&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,29 +49,26 @@ 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 PduBuilder {
.build_and_append_pdu( event_type: body.content.event_type().into(),
PduBuilder { content: serde_json::from_str(
event_type: body.content.event_type().into(), body.json_body
content: serde_json::from_str( .as_ref()
body.json_body .ok_or(Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?
.as_ref() .get(),
.ok_or(Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))? )
.get(), .map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?,
) unsigned: Some(unsigned),
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?, state_key: None,
unsigned: Some(unsigned), redacts: None,
state_key: None, },
redacts: None, &sender_id,
}, &body.room_id,
&sender_id, &db.globals,
&body.room_id, &db.sending,
&db.globals, &db.account_data,
&db.sending, )?;
&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,43 +31,41 @@ 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 { displayname: body.displayname.clone(),
displayname: body.displayname.clone(), ..serde_json::from_value::<Raw<_>>(
..serde_json::from_value::<Raw<_>>( db.rooms
db.rooms .room_state_get(
.room_state_get( &room_id,
&room_id, &EventType::RoomMember,
&EventType::RoomMember, &sender_id.to_string(),
&sender_id.to_string(), )?
)? .ok_or_else(|| {
.ok_or_else(|| { Error::bad_database(
Error::bad_database(
"Tried to send displayname update for user not in the room.", "Tried to send displayname update for user not in the room.",
) )
})? })?
.content .content
.clone(), .clone(),
) )
.expect("from_value::<Raw<..>> can never fail") .expect("from_value::<Raw<..>> can never fail")
.deserialize() .deserialize()
.map_err(|_| Error::bad_database("Database contains invalid PDU."))? .map_err(|_| Error::bad_database("Database contains invalid PDU."))?
}) })
.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,
}, },
&sender_id, &sender_id,
&room_id, &room_id,
&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,43 +123,41 @@ 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 { avatar_url: body.avatar_url.clone(),
avatar_url: body.avatar_url.clone(), ..serde_json::from_value::<Raw<_>>(
..serde_json::from_value::<Raw<_>>( db.rooms
db.rooms .room_state_get(
.room_state_get( &room_id,
&room_id, &EventType::RoomMember,
&EventType::RoomMember, &sender_id.to_string(),
&sender_id.to_string(), )?
)? .ok_or_else(|| {
.ok_or_else(|| { Error::bad_database(
Error::bad_database( "Tried to send avatar url update for user not in the room.",
"Tried to send avatar url update for user not in the room.", )
) })?
})? .content
.content .clone(),
.clone(), )
) .expect("from_value::<Raw<..>> can never fail")
.expect("from_value::<Raw<..>> can never fail") .deserialize()
.deserialize() .map_err(|_| Error::bad_database("Database contains invalid PDU."))?
.map_err(|_| Error::bad_database("Database contains invalid PDU."))? })
}) .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, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &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,26 +18,23 @@ 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 PduBuilder {
.build_and_append_pdu( event_type: EventType::RoomRedaction,
PduBuilder { content: serde_json::to_value(redaction::RedactionEventContent {
event_type: EventType::RoomRedaction, reason: body.reason.clone(),
content: serde_json::to_value(redaction::RedactionEventContent { })
reason: body.reason.clone(), .expect("event is valid, we just created it"),
}) unsigned: None,
.expect("event is valid, we just created it"), state_key: None,
unsigned: None, redacts: Some(body.event_id.clone()),
state_key: None, },
redacts: Some(body.event_id.clone()), &sender_id,
}, &body.room_id,
&sender_id, &db.globals,
&body.room_id, &db.sending,
&db.globals, &db.account_data,
&db.sending, )?;
&db.account_data,
)
.await?;
Ok(redact_event::Response { event_id }.into()) Ok(redact_event::Response { event_id }.into())
} }

View file

@ -53,47 +53,43 @@ 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"), unsigned: None,
unsigned: None, state_key: Some("".to_owned()),
state_key: Some("".to_owned()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &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 { membership: member::MembershipState::Join,
membership: member::MembershipState::Join, displayname: db.users.displayname(&sender_id)?,
displayname: db.users.displayname(&sender_id)?, avatar_url: db.users.avatar_url(&sender_id)?,
avatar_url: db.users.avatar_url(&sender_id)?, is_direct: Some(body.is_direct),
is_direct: Some(body.is_direct), third_party_invite: None,
third_party_invite: None, })
}) .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, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &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,22 +119,20 @@ 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, unsigned: None,
unsigned: None, state_key: Some("".to_owned()),
state_key: Some("".to_owned()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &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,84 +143,76 @@ 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 { create_room::RoomPreset::PublicChat => serde_json::to_value(
create_room::RoomPreset::PublicChat => serde_json::to_value( join_rules::JoinRulesEventContent::new(join_rules::JoinRule::Public),
join_rules::JoinRulesEventContent::new(join_rules::JoinRule::Public),
)
.expect("event is valid, we just created it"),
// according to spec "invite" is the default
_ => 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,
},
&sender_id,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)
.await?;
// 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"), .expect("event is valid, we just created it"),
unsigned: None, // according to spec "invite" is the default
state_key: Some("".to_owned()), _ => serde_json::to_value(join_rules::JoinRulesEventContent::new(
redacts: None, join_rules::JoinRule::Invite,
))
.expect("event is valid, we just created it"),
}, },
&sender_id, unsigned: None,
&room_id, state_key: Some("".to_owned()),
&db.globals, redacts: None,
&db.sending, },
&db.account_data, &sender_id,
) &room_id,
.await?; &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,
},
&sender_id,
&room_id,
&db.globals,
&db.sending,
&db.account_data,
)?;
// 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 { create_room::RoomPreset::PublicChat => {
create_room::RoomPreset::PublicChat => { serde_json::to_value(guest_access::GuestAccessEventContent::new(
serde_json::to_value(guest_access::GuestAccessEventContent::new( guest_access::GuestAccess::Forbidden,
guest_access::GuestAccess::Forbidden,
))
.expect("event is valid, we just created it")
}
_ => serde_json::to_value(guest_access::GuestAccessEventContent::new(
guest_access::GuestAccess::CanJoin,
)) ))
.expect("event is valid, we just created it"), .expect("event is valid, we just created it")
}, }
unsigned: None, _ => serde_json::to_value(guest_access::GuestAccessEventContent::new(
state_key: Some("".to_owned()), guest_access::GuestAccess::CanJoin,
redacts: None, ))
.expect("event is valid, we just created it"),
}, },
&sender_id, unsigned: None,
&room_id, state_key: Some("".to_owned()),
&db.globals, redacts: None,
&db.sending, },
&db.account_data, &sender_id,
) &room_id,
.await?; &db.globals,
&db.sending,
&db.account_data,
)?;
// 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,90 +226,82 @@ 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( name::NameEventContent::new(name.clone()).map_err(|_| {
name::NameEventContent::new(name.clone()).map_err(|_| { Error::BadRequest(ErrorKind::InvalidParam, "Name is invalid.")
Error::BadRequest(ErrorKind::InvalidParam, "Name is invalid.") })?,
})?, )
) .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()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &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 { topic: topic.clone(),
topic: topic.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()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &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 { membership: member::MembershipState::Invite,
membership: member::MembershipState::Invite, displayname: db.users.displayname(&user)?,
displayname: db.users.displayname(&user)?, avatar_url: db.users.avatar_url(&user)?,
avatar_url: db.users.avatar_url(&user)?, is_direct: Some(body.is_direct),
is_direct: Some(body.is_direct), third_party_invite: None,
third_party_invite: None, })
}) .expect("event is valid, we just created it"),
.expect("event is valid, we just created it"), unsigned: None,
unsigned: None, state_key: Some(user.to_string()),
state_key: Some(user.to_string()), redacts: None,
redacts: None, },
}, &sender_id,
&sender_id, &room_id,
&room_id, &db.globals,
&db.globals, &db.sending,
&db.sending, &db.account_data,
&db.account_data, )?;
)
.await?;
} }
// Homeserver specific stuff // Homeserver specific stuff
@ -395,29 +373,24 @@ 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 PduBuilder {
.build_and_append_pdu( event_type: EventType::RoomTombstone,
PduBuilder { content: serde_json::to_value(ruma::events::room::tombstone::TombstoneEventContent {
event_type: EventType::RoomTombstone, body: "This room has been replaced".to_string(),
content: serde_json::to_value( replacement_room: replacement_room.clone(),
ruma::events::room::tombstone::TombstoneEventContent { })
body: "This room has been replaced".to_string(), .expect("event is valid, we just created it"),
replacement_room: replacement_room.clone(), unsigned: None,
}, state_key: Some("".to_owned()),
) redacts: None,
.expect("event is valid, we just created it"), },
unsigned: None, sender_id,
state_key: Some("".to_owned()), &body.room_id,
redacts: None, &db.globals,
}, &db.sending,
sender_id, &db.account_data,
&body.room_id, )?;
&db.globals,
&db.sending,
&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,48 +417,44 @@ 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) .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()), redacts: None,
redacts: None, },
}, sender_id,
sender_id, &replacement_room,
&replacement_room, &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 { membership: member::MembershipState::Join,
membership: member::MembershipState::Join, displayname: db.users.displayname(&sender_id)?,
displayname: db.users.displayname(&sender_id)?, avatar_url: db.users.avatar_url(&sender_id)?,
avatar_url: db.users.avatar_url(&sender_id)?, is_direct: None,
is_direct: None, third_party_invite: None,
third_party_invite: None, })
}) .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, },
}, sender_id,
sender_id, &replacement_room,
&replacement_room, &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,22 +476,20 @@ 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, unsigned: None,
unsigned: None, state_key: Some("".to_owned()),
state_key: Some("".to_owned()), redacts: None,
redacts: None, },
}, sender_id,
sender_id, &replacement_room,
&replacement_room, &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,24 +519,21 @@ 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 PduBuilder {
.build_and_append_pdu( event_type: EventType::RoomPowerLevels,
PduBuilder { content: serde_json::to_value(power_levels_event_content)
event_type: EventType::RoomPowerLevels, .expect("event is valid, we just created it"),
content: serde_json::to_value(power_levels_event_content) unsigned: None,
.expect("event is valid, we just created it"), state_key: Some("".to_owned()),
unsigned: None, redacts: None,
state_key: Some("".to_owned()), },
redacts: None, sender_id,
}, &body.room_id,
sender_id, &db.globals,
&body.room_id, &db.sending,
&db.globals, &db.account_data,
&db.sending, )?;
&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,23 +213,20 @@ pub async fn send_state_event_for_key_helper(
} }
} }
let event_id = db let event_id = db.rooms.build_and_append_pdu(
.rooms PduBuilder {
.build_and_append_pdu( event_type: content.event_type().into(),
PduBuilder { content: json,
event_type: content.event_type().into(), unsigned: None,
content: json, state_key,
unsigned: None, redacts: None,
state_key, },
redacts: None, &sender_id,
}, &room_id,
&sender_id, &db.globals,
&room_id, &db.sending,
&db.globals, &db.account_data,
&db.sending, )?;
&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())
}
*/