Files
continuwuity/src/service/rooms/timeline/mod.rs
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1252 lines
36 KiB
Rust
Raw Normal View History

2024-05-26 21:29:19 +00:00
mod data;
2022-10-05 20:41:05 +02:00
2023-02-26 16:29:06 +01:00
use std::{
2024-07-03 23:11:05 +00:00
collections::{BTreeMap, HashSet},
2024-07-04 03:26:19 +00:00
fmt::Write,
sync::Arc,
2022-10-10 14:09:11 +02:00
};
2022-09-06 23:15:09 +02:00
use conduit::{
2024-07-18 06:37:47 +00:00
debug, error, info,
pdu::{EventHash, PduBuilder, PduCount, PduEvent},
utils,
utils::{MutexMap, MutexMapGuard},
2024-07-18 06:37:47 +00:00
validated, warn, Error, Result, Server,
};
use itertools::Itertools;
2022-10-05 20:34:31 +02:00
use ruma::{
2023-02-26 16:29:06 +01:00
api::{client::error::ErrorKind, federation},
2022-10-10 14:09:11 +02:00
canonical_json::to_canonical_value,
2022-10-05 20:34:31 +02:00
events::{
push_rules::PushRulesEvent,
2022-10-10 14:09:11 +02:00
room::{
create::RoomCreateEventContent,
encrypted::Relation,
member::{MembershipState, RoomMemberEventContent},
2022-10-10 14:09:11 +02:00
power_levels::RoomPowerLevelsEventContent,
redaction::RoomRedactionEventContent,
2022-10-10 14:09:11 +02:00
},
2023-02-26 16:29:06 +01:00
GlobalAccountDataEventType, StateEventType, TimelineEventType,
2022-10-05 20:34:31 +02:00
},
2022-10-10 14:09:11 +02:00
push::{Action, Ruleset, Tweak},
serde::Base64,
state_res::{self, Event, RoomVersion},
uint, user_id, CanonicalJsonObject, CanonicalJsonValue, EventId, OwnedEventId, OwnedRoomId, OwnedServerName,
RoomId, RoomVersionId, ServerName, UserId,
2022-10-05 20:34:31 +02:00
};
2022-09-06 23:15:09 +02:00
use serde::Deserialize;
2023-02-20 22:59:45 +01:00
use serde_json::value::{to_raw_value, RawValue as RawJsonValue};
2024-07-03 23:11:05 +00:00
use tokio::sync::RwLock;
2024-07-18 06:37:47 +00:00
use self::data::Data;
2022-10-05 20:34:31 +02:00
use crate::{
2024-07-18 06:37:47 +00:00
account_data, admin, appservice, appservice::NamespaceRegex, globals, pusher, rooms,
rooms::state_compressor::CompressedStateEvent, sending, server_keys, Dep,
2022-10-05 20:34:31 +02:00
};
2022-09-07 13:25:51 +02:00
// Update Relationships
#[derive(Deserialize)]
struct ExtractRelatesTo {
#[serde(rename = "m.relates_to")]
relates_to: Relation,
}
#[derive(Clone, Debug, Deserialize)]
struct ExtractEventId {
event_id: OwnedEventId,
}
#[derive(Clone, Debug, Deserialize)]
struct ExtractRelatesToEventId {
#[serde(rename = "m.relates_to")]
relates_to: ExtractEventId,
}
2024-06-12 00:33:12 -04:00
#[derive(Deserialize)]
struct ExtractBody {
body: Option<String>,
}
2024-05-09 15:59:08 -07:00
pub struct Service {
2024-07-18 06:37:47 +00:00
services: Services,
2024-06-28 22:51:39 +00:00
db: Data,
pub mutex_insert: RoomMutexMap,
}
2024-07-18 06:37:47 +00:00
struct Services {
server: Arc<Server>,
account_data: Dep<account_data::Service>,
appservice: Dep<appservice::Service>,
admin: Dep<admin::Service>,
alias: Dep<rooms::alias::Service>,
globals: Dep<globals::Service>,
short: Dep<rooms::short::Service>,
state: Dep<rooms::state::Service>,
state_cache: Dep<rooms::state_cache::Service>,
state_accessor: Dep<rooms::state_accessor::Service>,
pdu_metadata: Dep<rooms::pdu_metadata::Service>,
read_receipt: Dep<rooms::read_receipt::Service>,
sending: Dep<sending::Service>,
server_keys: Dep<server_keys::Service>,
2024-07-18 06:37:47 +00:00
user: Dep<rooms::user::Service>,
pusher: Dep<pusher::Service>,
threads: Dep<rooms::threads::Service>,
search: Dep<rooms::search::Service>,
spaces: Dep<rooms::spaces::Service>,
event_handler: Dep<rooms::event_handler::Service>,
}
type RoomMutexMap = MutexMap<OwnedRoomId, ()>;
pub type RoomMutexGuard = MutexMapGuard<OwnedRoomId, ()>;
2024-07-04 03:26:19 +00:00
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self {
2024-07-18 06:37:47 +00:00
services: Services {
server: args.server.clone(),
account_data: args.depend::<account_data::Service>("account_data"),
appservice: args.depend::<appservice::Service>("appservice"),
admin: args.depend::<admin::Service>("admin"),
alias: args.depend::<rooms::alias::Service>("rooms::alias"),
globals: args.depend::<globals::Service>("globals"),
short: args.depend::<rooms::short::Service>("rooms::short"),
state: args.depend::<rooms::state::Service>("rooms::state"),
state_cache: args.depend::<rooms::state_cache::Service>("rooms::state_cache"),
state_accessor: args.depend::<rooms::state_accessor::Service>("rooms::state_accessor"),
pdu_metadata: args.depend::<rooms::pdu_metadata::Service>("rooms::pdu_metadata"),
read_receipt: args.depend::<rooms::read_receipt::Service>("rooms::read_receipt"),
sending: args.depend::<sending::Service>("sending"),
server_keys: args.depend::<server_keys::Service>("server_keys"),
2024-07-18 06:37:47 +00:00
user: args.depend::<rooms::user::Service>("rooms::user"),
pusher: args.depend::<pusher::Service>("pusher"),
threads: args.depend::<rooms::threads::Service>("rooms::threads"),
search: args.depend::<rooms::search::Service>("rooms::search"),
spaces: args.depend::<rooms::spaces::Service>("rooms::spaces"),
event_handler: args.depend::<rooms::event_handler::Service>("rooms::event_handler"),
},
db: Data::new(&args),
mutex_insert: RoomMutexMap::new(),
2024-07-04 03:26:19 +00:00
}))
}
fn memory_usage(&self, out: &mut dyn Write) -> Result<()> {
let lasttimelinecount_cache = self
.db
.lasttimelinecount_cache
.lock()
.expect("locked")
.len();
writeln!(out, "lasttimelinecount_cache: {lasttimelinecount_cache}")?;
let mutex_insert = self.mutex_insert.len();
writeln!(out, "insert_mutex: {mutex_insert}")?;
2024-07-04 03:26:19 +00:00
Ok(())
2024-05-27 03:17:20 +00:00
}
2024-07-04 03:26:19 +00:00
fn clear_cache(&self) {
self.db
.lasttimelinecount_cache
.lock()
.expect("locked")
.clear();
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
impl Service {
2024-07-07 19:03:15 +00:00
#[tracing::instrument(skip(self), level = "debug")]
2024-05-09 15:59:08 -07:00
pub fn first_pdu_in_room(&self, room_id: &RoomId) -> Result<Option<Arc<PduEvent>>> {
self.all_pdus(user_id!("@doesntmatter:conduit.rs"), room_id)?
2023-02-21 00:56:26 +01:00
.next()
.map(|o| o.map(|(_, p)| Arc::new(p)))
.transpose()
}
2024-03-05 19:48:54 -05:00
2024-07-07 19:03:15 +00:00
#[tracing::instrument(skip(self), level = "debug")]
2024-05-30 23:36:48 -04:00
pub fn latest_pdu_in_room(&self, room_id: &RoomId) -> Result<Option<Arc<PduEvent>>> {
self.all_pdus(user_id!("@placeholder:conduwuit.placeholder"), room_id)?
.last()
.map(|o| o.map(|(_, p)| Arc::new(p)))
.transpose()
}
2024-07-07 19:03:15 +00:00
#[tracing::instrument(skip(self), level = "debug")]
2024-05-09 15:59:08 -07:00
pub fn last_timeline_count(&self, sender_user: &UserId, room_id: &RoomId) -> Result<PduCount> {
2022-09-07 13:25:51 +02:00
self.db.last_timeline_count(sender_user, room_id)
2022-06-19 22:56:14 +02:00
}
2024-03-05 19:48:54 -05:00
2023-02-20 22:59:45 +01:00
/// Returns the `count` of this pdu's id.
2024-05-09 15:59:08 -07:00
pub fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<PduCount>> { self.db.get_pdu_count(event_id) }
2024-03-05 19:48:54 -05:00
2022-06-19 22:56:14 +02:00
// TODO Is this the same as the function above?
/*
2022-06-19 22:56:14 +02:00
#[tracing::instrument(skip(self))]
2024-05-09 15:59:08 -07:00
pub fn latest_pdu_count(&self, room_id: &RoomId) -> Result<u64> {
2022-06-19 22:56:14 +02:00
let prefix = self
.get_shortroomid(room_id)?
.expect("room exists")
.to_be_bytes()
.to_vec();
2024-03-05 19:48:54 -05:00
2022-06-19 22:56:14 +02:00
let mut last_possible_key = prefix.clone();
last_possible_key.extend_from_slice(&u64::MAX.to_be_bytes());
2024-03-05 19:48:54 -05:00
2022-06-19 22:56:14 +02:00
self.pduid_pdu
.iter_from(&last_possible_key, true)
.take_while(move |(k, _)| k.starts_with(&prefix))
.next()
.map(|b| self.pdu_count(&b.0))
.transpose()
.map(|op| op.unwrap_or_default())
2021-08-11 19:15:38 +02:00
}
*/
2024-03-05 19:48:54 -05:00
2022-06-19 22:56:14 +02:00
/// Returns the json of a pdu.
2024-05-09 15:59:08 -07:00
pub fn get_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
self.db.get_pdu_json(event_id)
2021-08-12 23:04:00 +02:00
}
2024-03-05 19:48:54 -05:00
2022-06-19 22:56:14 +02:00
/// Returns the json of a pdu.
#[inline]
2024-05-09 15:59:08 -07:00
pub fn get_non_outlier_pdu_json(&self, event_id: &EventId) -> Result<Option<CanonicalJsonObject>> {
2022-10-05 20:33:55 +02:00
self.db.get_non_outlier_pdu_json(event_id)
2021-07-15 19:54:04 +02:00
}
2024-03-05 19:48:54 -05:00
2020-05-26 10:27:51 +02:00
/// Returns the pdu's id.
#[inline]
2024-07-02 05:56:10 +00:00
pub fn get_pdu_id(&self, event_id: &EventId) -> Result<Option<database::Handle<'_>>> {
self.db.get_pdu_id(event_id)
}
2024-03-05 19:48:54 -05:00
2021-03-26 11:10:45 +01:00
/// Returns the pdu.
///
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
#[inline]
2024-05-09 15:59:08 -07:00
pub fn get_non_outlier_pdu(&self, event_id: &EventId) -> Result<Option<PduEvent>> {
self.db.get_non_outlier_pdu(event_id)
2021-03-26 11:10:45 +01:00
}
2024-03-05 19:48:54 -05:00
2020-05-24 18:25:52 +02:00
/// Returns the pdu.
2021-02-01 12:44:30 -05:00
///
/// Checks the `eventid_outlierpdu` Tree if not found in the timeline.
2024-05-09 15:59:08 -07:00
pub fn get_pdu(&self, event_id: &EventId) -> Result<Option<Arc<PduEvent>>> { self.db.get_pdu(event_id) }
2024-03-05 19:48:54 -05:00
2020-05-26 10:27:51 +02:00
/// Returns the pdu.
///
/// This does __NOT__ check the outliers `Tree`.
2024-05-09 15:59:08 -07:00
pub fn get_pdu_from_id(&self, pdu_id: &[u8]) -> Result<Option<PduEvent>> { self.db.get_pdu_from_id(pdu_id) }
2024-03-05 19:48:54 -05:00
/// Returns the pdu as a `BTreeMap<String, CanonicalJsonValue>`.
2024-05-09 15:59:08 -07:00
pub fn get_pdu_json_from_id(&self, pdu_id: &[u8]) -> Result<Option<CanonicalJsonObject>> {
self.db.get_pdu_json_from_id(pdu_id)
2020-09-15 16:13:54 +02:00
}
2024-03-05 19:48:54 -05:00
2020-06-09 15:13:17 +02:00
/// Removes a pdu and creates a new one with the same id.
2024-07-07 19:03:15 +00:00
#[tracing::instrument(skip(self), level = "debug")]
2024-05-09 15:59:08 -07:00
pub fn replace_pdu(&self, pdu_id: &[u8], pdu_json: &CanonicalJsonObject, pdu: &PduEvent) -> Result<()> {
2023-06-25 19:31:40 +02:00
self.db.replace_pdu(pdu_id, pdu_json, pdu)
2020-05-26 10:27:51 +02:00
}
2024-03-05 19:48:54 -05:00
/// Creates a new persisted data unit and adds it to a room.
///
/// By this point the incoming event should be fully authenticated, no auth
/// happens in `append_pdu`.
2021-08-12 23:04:00 +02:00
///
/// Returns pdu id
2024-06-14 22:08:44 +00:00
#[tracing::instrument(skip_all)]
2024-05-09 15:59:08 -07:00
pub async fn append_pdu(
&self,
2020-09-13 22:24:36 +02:00
pdu: &PduEvent,
mut pdu_json: CanonicalJsonObject,
2022-10-09 17:25:06 +02:00
leaves: Vec<OwnedEventId>,
2024-07-09 20:04:43 +00:00
state_lock: &RoomMutexGuard, // Take mutex guard to make sure users get the room state mutex
2021-07-01 11:06:05 +02:00
) -> Result<Vec<u8>> {
// Coalesce database writes for the remainder of this scope.
2024-07-18 06:37:47 +00:00
let _cork = self.db.db.cork_and_flush();
2024-07-18 06:37:47 +00:00
let shortroomid = self
.services
2024-03-25 17:05:11 -04:00
.short
.get_shortroomid(&pdu.room_id)?
.expect("room exists");
2024-03-05 19:48:54 -05:00
// Make unsigned fields correct. This is not properly documented in the spec,
// but state events need to have previous content in the unsigned field, so
// clients can easily interpret things like membership changes
if let Some(state_key) = &pdu.state_key {
2024-03-25 17:05:11 -04:00
if let CanonicalJsonValue::Object(unsigned) = pdu_json
.entry("unsigned".to_owned())
.or_insert_with(|| CanonicalJsonValue::Object(BTreeMap::default()))
{
2024-07-18 06:37:47 +00:00
if let Some(shortstatehash) = self
.services
2024-03-25 17:05:11 -04:00
.state_accessor
.pdu_shortstatehash(&pdu.event_id)
.unwrap()
2022-10-05 20:34:31 +02:00
{
2024-07-18 06:37:47 +00:00
if let Some(prev_state) = self
.services
2022-10-05 20:34:31 +02:00
.state_accessor
2022-04-06 21:31:29 +02:00
.state_get(shortstatehash, &pdu.kind.to_string().into(), state_key)
.unwrap()
{
unsigned.insert(
"prev_content".to_owned(),
CanonicalJsonValue::Object(
utils::to_canonical_object(prev_state.content.clone()).map_err(|e| {
error!("Failed to convert prev_state to canonical JSON: {e}");
Error::bad_database("Failed to convert prev_state to canonical JSON.")
})?,
),
);
unsigned.insert(
String::from("prev_sender"),
CanonicalJsonValue::String(prev_state.sender.clone().to_string()),
);
unsigned.insert(
String::from("replaces_state"),
CanonicalJsonValue::String(prev_state.event_id.clone().to_string()),
);
2024-03-05 19:48:54 -05:00
}
}
} else {
error!("Invalid unsigned type in pdu.");
2024-03-05 19:48:54 -05:00
}
}
2024-03-05 19:48:54 -05:00
// We must keep track of all events that have been referenced.
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.pdu_metadata
.mark_as_referenced(&pdu.room_id, &pdu.prev_events)?;
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.state
.set_forward_extremities(&pdu.room_id, leaves, state_lock)?;
let insert_lock = self.mutex_insert.lock(&pdu.room_id).await;
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let count1 = self.services.globals.next_count()?;
// Mark as read first so the sending client doesn't get a notification even if
2022-10-05 20:34:31 +02:00
// appending fails
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.read_receipt
.private_read_set(&pdu.room_id, &pdu.sender, count1)?;
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.user
.reset_notification_counts(&pdu.sender, &pdu.room_id)?;
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let count2 = self.services.globals.next_count()?;
2020-09-17 19:58:19 +02:00
let mut pdu_id = shortroomid.to_be_bytes().to_vec();
pdu_id.extend_from_slice(&count2.to_be_bytes());
2024-03-05 19:48:54 -05:00
2022-10-05 20:33:55 +02:00
// Insert pdu
self.db.append_pdu(&pdu_id, pdu, &pdu_json, count2)?;
2024-03-05 19:48:54 -05:00
2021-08-03 11:10:58 +02:00
drop(insert_lock);
2024-03-05 19:48:54 -05:00
// See if the event matches any known pushers
2024-07-18 06:37:47 +00:00
let power_levels: RoomPowerLevelsEventContent = self
.services
.state_accessor
2022-09-07 13:25:51 +02:00
.room_state_get(&pdu.room_id, &StateEventType::RoomPowerLevels, "")?
.map(|ev| {
2022-09-07 13:25:51 +02:00
serde_json::from_str(ev.content.get())
2022-04-06 21:31:29 +02:00
.map_err(|_| Error::bad_database("invalid m.room.power_levels event"))
2021-10-13 10:16:45 +02:00
})
.transpose()?
.unwrap_or_default();
2024-03-05 19:48:54 -05:00
let sync_pdu = pdu.to_sync_room_event();
2024-03-05 19:48:54 -05:00
2021-08-15 13:17:42 +02:00
let mut notifies = Vec::new();
let mut highlights = Vec::new();
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let mut push_target = self
.services
2024-03-25 17:05:11 -04:00
.state_cache
.active_local_users_in_room(&pdu.room_id)
.collect_vec();
2024-03-05 19:48:54 -05:00
if pdu.kind == TimelineEventType::RoomMember {
if let Some(state_key) = &pdu.state_key {
let target_user_id = UserId::parse(state_key.clone()).expect("This state_key was previously validated");
2024-03-05 19:48:54 -05:00
if !push_target.contains(&target_user_id) {
push_target.push(target_user_id);
}
}
}
2024-03-05 19:48:54 -05:00
for user in &push_target {
// Don't notify the user of their own events
2022-10-08 13:02:52 +02:00
if user == &pdu.sender {
continue;
}
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let rules_for_user = self
.services
.account_data
2022-04-06 21:31:29 +02:00
.get(None, user, GlobalAccountDataEventType::PushRules.to_string().into())?
.map(|event| {
2022-10-05 20:34:31 +02:00
serde_json::from_str::<PushRulesEvent>(event.get()).map_err(|e| {
warn!("Invalid push rules event in db for user ID {user}: {e}");
Error::bad_database("Invalid push rules event in db.")
})
2022-10-05 20:34:31 +02:00
})
.transpose()?
2024-03-02 20:55:02 -05:00
.map_or_else(|| Ruleset::server_default(user), |ev: PushRulesEvent| ev.content.global);
2024-03-05 19:48:54 -05:00
let mut highlight = false;
2024-03-02 20:55:02 -05:00
let mut notify = false;
2024-03-05 19:48:54 -05:00
for action in
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.pusher
.get_actions(user, &rules_for_user, &power_levels, &sync_pdu, &pdu.room_id)?
2024-03-05 19:48:54 -05:00
{
2022-09-07 13:25:51 +02:00
match action {
2022-10-10 14:09:11 +02:00
Action::Notify => notify = true,
Action::SetTweak(Tweak::Highlight(true)) => {
highlight = true;
},
2023-06-25 19:31:40 +02:00
_ => {},
2024-03-05 19:48:54 -05:00
};
}
2023-06-25 19:31:40 +02:00
if notify {
notifies.push(user.clone());
2024-03-05 19:48:54 -05:00
}
if highlight {
2022-10-08 13:02:52 +02:00
highlights.push(user.clone());
}
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
for push_key in self.services.pusher.get_pushkeys(user) {
self.services
.sending
.send_pdu_push(&pdu_id, user, push_key?)?;
}
}
2024-03-05 19:48:54 -05:00
2024-03-25 17:05:11 -04:00
self.db
.increment_notification_counts(&pdu.room_id, notifies, highlights)?;
2024-03-05 19:48:54 -05:00
match pdu.kind {
2023-02-26 16:29:06 +01:00
TimelineEventType::RoomRedaction => {
2024-07-12 01:08:53 +00:00
use RoomVersionId::*;
2024-07-18 06:37:47 +00:00
let room_version_id = self.services.state.get_room_version(&pdu.room_id)?;
match room_version_id {
2024-07-12 01:08:53 +00:00
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
if let Some(redact_id) = &pdu.redacts {
2024-07-18 06:37:47 +00:00
if self.services.state_accessor.user_can_redact(
2024-06-22 21:21:16 +00:00
redact_id,
&pdu.sender,
&pdu.room_id,
false,
)? {
self.redact_pdu(redact_id, pdu, shortroomid)?;
}
}
},
2024-07-12 01:08:53 +00:00
V11 => {
let content =
serde_json::from_str::<RoomRedactionEventContent>(pdu.content.get()).map_err(|e| {
warn!("Invalid content in redaction pdu: {e}");
2024-06-22 21:21:16 +00:00
Error::bad_database("Invalid content in redaction pdu")
})?;
2024-06-22 21:21:16 +00:00
if let Some(redact_id) = &content.redacts {
2024-07-18 06:37:47 +00:00
if self.services.state_accessor.user_can_redact(
2024-06-22 21:21:16 +00:00
redact_id,
&pdu.sender,
&pdu.room_id,
false,
)? {
self.redact_pdu(redact_id, pdu, shortroomid)?;
}
}
},
_ => {
2024-06-22 21:21:16 +00:00
warn!("Unexpected or unsupported room version {room_version_id}");
return Err(Error::BadRequest(
ErrorKind::BadJson,
"Unexpected or unsupported room version found",
));
},
};
},
2023-07-02 22:50:50 +02:00
TimelineEventType::SpaceChild => {
if let Some(_state_key) = &pdu.state_key {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.spaces
.roomid_spacehierarchy_cache
.lock()
.await
.remove(&pdu.room_id);
2023-07-02 22:50:50 +02:00
}
},
2023-02-26 16:29:06 +01:00
TimelineEventType::RoomMember => {
2020-09-13 22:24:36 +02:00
if let Some(state_key) = &pdu.state_key {
// if the state_key fails
2021-11-27 00:30:28 +01:00
let target_user_id =
UserId::parse(state_key.clone()).expect("This state_key was previously validated");
2024-03-05 19:48:54 -05:00
let content = serde_json::from_str::<RoomMemberEventContent>(pdu.content.get()).map_err(|e| {
error!("Invalid room member event content in pdu: {e}");
Error::bad_database("Invalid room member event content in pdu.")
})?;
2024-03-05 19:48:54 -05:00
2021-10-13 10:16:45 +02:00
let invite_state = match content.membership {
MembershipState::Invite => {
2024-07-18 06:37:47 +00:00
let state = self.services.state.calculate_invite_state(pdu)?;
2021-04-11 21:01:27 +02:00
Some(state)
},
_ => None,
};
2024-03-05 19:48:54 -05:00
// Update our membership info, we do this here incase a user is invited
// and immediately leaves we need the DB to record the invite event for auth
2024-07-18 06:37:47 +00:00
self.services.state_cache.update_membership(
2024-04-11 19:39:17 -04:00
&pdu.room_id,
&target_user_id,
content,
&pdu.sender,
invite_state,
None,
true,
)?;
}
},
2023-02-26 16:29:06 +01:00
TimelineEventType::RoomMessage => {
2022-10-05 20:33:55 +02:00
let content = serde_json::from_str::<ExtractBody>(pdu.content.get())
2021-10-13 10:16:45 +02:00
.map_err(|_| Error::bad_database("Invalid content in pdu."))?;
2024-03-05 19:48:54 -05:00
2021-10-13 10:16:45 +02:00
if let Some(body) = content.body {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.search
.index_pdu(shortroomid, &pdu_id, &body)?;
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
if self.services.admin.is_admin_command(pdu, &body).await {
self.services
.admin
.command(body, Some((*pdu.event_id).into()))
.await;
2024-03-05 19:48:54 -05:00
}
2020-10-05 22:19:22 +02:00
}
},
_ => {},
}
2024-03-05 19:48:54 -05:00
2023-06-25 19:31:40 +02:00
if let Ok(content) = serde_json::from_str::<ExtractRelatesToEventId>(pdu.content.get()) {
if let Some(related_pducount) = self.get_pdu_count(&content.relates_to.event_id)? {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.pdu_metadata
.add_relation(PduCount::Normal(count2), related_pducount)?;
2024-03-05 19:48:54 -05:00
}
}
2024-03-05 19:48:54 -05:00
2023-06-25 19:31:40 +02:00
if let Ok(content) = serde_json::from_str::<ExtractRelatesTo>(pdu.content.get()) {
match content.relates_to {
Relation::Reply {
in_reply_to,
} => {
// We need to do it again here, because replies don't have
// event_id as a top level field
if let Some(related_pducount) = self.get_pdu_count(&in_reply_to.event_id)? {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.pdu_metadata
.add_relation(PduCount::Normal(count2), related_pducount)?;
}
2023-06-25 19:31:40 +02:00
},
Relation::Thread(thread) => {
2024-07-18 06:37:47 +00:00
self.services.threads.add_to_thread(&thread.event_id, pdu)?;
2023-06-25 19:31:40 +02:00
},
_ => {}, // TODO: Aggregate other types
}
}
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
for appservice in self.services.appservice.read().await.values() {
if self
.services
2024-03-25 17:05:11 -04:00
.state_cache
.appservice_in_room(&pdu.room_id, appservice)?
{
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.sending
.send_pdu_appservice(appservice.registration.id.clone(), pdu_id.clone())?;
continue;
2024-03-05 19:48:54 -05:00
}
2022-10-05 20:34:31 +02:00
// If the RoomMember event has a non-empty state_key, it is targeted at someone.
// If it is our appservice user, we send this PDU to it.
if pdu.kind == TimelineEventType::RoomMember {
2024-03-25 17:05:11 -04:00
if let Some(state_key_uid) = &pdu
.state_key
.as_ref()
.and_then(|state_key| UserId::parse(state_key.as_str()).ok())
2024-03-05 19:48:54 -05:00
{
2024-03-08 10:50:52 -05:00
let appservice_uid = appservice.registration.sender_localpart.as_str();
2022-10-05 20:34:31 +02:00
if state_key_uid == appservice_uid {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.sending
.send_pdu_appservice(appservice.registration.id.clone(), pdu_id.clone())?;
2022-06-20 11:31:27 +02:00
continue;
}
2024-03-05 19:48:54 -05:00
}
}
2024-03-08 10:50:52 -05:00
let matching_users = |users: &NamespaceRegex| {
appservice.users.is_match(pdu.sender.as_str())
|| pdu.kind == TimelineEventType::RoomMember
2024-03-25 17:05:11 -04:00
&& pdu
.state_key
.as_ref()
.map_or(false, |state_key| users.is_match(state_key))
};
2024-03-08 10:50:52 -05:00
let matching_aliases = |aliases: &NamespaceRegex| {
2024-07-18 06:37:47 +00:00
self.services
.alias
.local_aliases_for_room(&pdu.room_id)
.filter_map(Result::ok)
.any(|room_alias| aliases.is_match(room_alias.as_str()))
};
2024-03-05 19:48:54 -05:00
2024-03-08 10:50:52 -05:00
if matching_aliases(&appservice.aliases)
|| appservice.rooms.is_match(pdu.room_id.as_str())
|| matching_users(&appservice.users)
{
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.sending
.send_pdu_appservice(appservice.registration.id.clone(), pdu_id.clone())?;
2024-03-05 19:48:54 -05:00
}
}
Ok(pdu_id)
2024-03-05 19:48:54 -05:00
}
2024-05-09 15:59:08 -07:00
pub fn create_hash_and_sign_event(
&self,
pdu_builder: PduBuilder,
sender: &UserId,
2022-10-05 20:34:31 +02:00
room_id: &RoomId,
2024-07-09 20:04:43 +00:00
_mutex_lock: &RoomMutexGuard, // Take mutex guard to make sure users get the room state mutex
) -> Result<(PduEvent, CanonicalJsonObject)> {
let PduBuilder {
event_type,
content,
unsigned,
2022-06-19 22:56:14 +02:00
state_key,
2024-03-05 19:48:54 -05:00
redacts,
2024-08-14 20:01:34 -04:00
timestamp,
} = pdu_builder;
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let prev_events: Vec<_> = self
.services
2024-03-25 17:05:11 -04:00
.state
.get_forward_extremities(room_id)?
.into_iter()
.take(20)
.collect();
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
// If there was no create event yet, assume we are creating a room
2024-07-18 06:37:47 +00:00
let room_version_id = self.services.state.get_room_version(room_id).or_else(|_| {
if event_type == TimelineEventType::RoomCreate {
let content = serde_json::from_str::<RoomCreateEventContent>(content.get())
.expect("Invalid content in RoomCreate pdu.");
Ok(content.room_version)
} else {
Err(Error::InconsistentRoomState(
"non-create event for room of unknown version",
room_id.to_owned(),
))
}
})?;
2024-03-05 19:48:54 -05:00
let room_version = RoomVersion::new(&room_version_id).expect("room version is supported");
2024-03-05 19:48:54 -05:00
let auth_events =
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.state
.get_auth_events(room_id, &event_type, sender, state_key.as_deref(), &content)?;
2024-03-05 19:48:54 -05:00
2023-12-24 19:02:03 +01:00
// Our depth is the maximum depth of prev_events + 1
let depth = prev_events
.iter()
.filter_map(|event_id| Some(self.get_pdu(event_id).ok()??.depth))
2024-03-05 19:48:54 -05:00
.max()
2023-12-24 19:02:03 +01:00
.unwrap_or_else(|| uint!(0))
2024-07-07 04:46:16 +00:00
.saturating_add(uint!(1));
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
let mut unsigned = unsigned.unwrap_or_default();
2024-03-05 19:48:54 -05:00
2022-10-05 20:34:31 +02:00
if let Some(state_key) = &state_key {
if let Some(prev_pdu) =
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.state_accessor
.room_state_get(room_id, &event_type.to_string().into(), state_key)?
2024-03-05 19:48:54 -05:00
{
2022-10-05 20:34:31 +02:00
unsigned.insert(
"prev_content".to_owned(),
2022-10-05 20:33:55 +02:00
serde_json::from_str(prev_pdu.content.get()).expect("string is valid json"),
2024-03-05 19:48:54 -05:00
);
2021-10-13 10:16:45 +02:00
unsigned.insert(
2022-10-05 20:33:55 +02:00
"prev_sender".to_owned(),
serde_json::to_value(&prev_pdu.sender).expect("UserId::to_value always works"),
2024-03-05 19:48:54 -05:00
);
unsigned.insert(
"replaces_state".to_owned(),
serde_json::to_value(&prev_pdu.event_id).expect("EventId is valid json"),
);
2024-03-05 19:48:54 -05:00
}
}
let mut pdu = PduEvent {
2022-10-05 20:33:55 +02:00
event_id: ruma::event_id!("$thiswillbefilledinlater").into(),
2022-10-05 20:34:31 +02:00
room_id: room_id.to_owned(),
2021-10-13 10:16:45 +02:00
sender: sender.to_owned(),
2024-04-09 02:09:25 -07:00
origin: None,
2024-08-14 20:01:34 -04:00
origin_server_ts: timestamp.map_or_else(
|| {
utils::millis_since_unix_epoch()
.try_into()
.expect("u64 fits into UInt")
},
|ts| ts.get(),
),
kind: event_type,
2021-10-13 10:16:45 +02:00
content,
state_key,
prev_events,
depth,
2024-03-25 17:05:11 -04:00
auth_events: auth_events
.values()
.map(|pdu| pdu.event_id.clone())
.collect(),
2024-03-05 19:48:54 -05:00
redacts,
2020-06-26 10:07:02 +02:00
unsigned: if unsigned.is_empty() {
None
2021-06-30 09:52:01 +02:00
} else {
Some(to_raw_value(&unsigned).expect("to_raw_value always works"))
},
2022-10-08 13:02:52 +02:00
hashes: EventHash {
sha256: "aaa".to_owned(),
2024-03-05 19:48:54 -05:00
},
2021-10-13 10:16:45 +02:00
signatures: None,
2024-03-05 19:48:54 -05:00
};
2022-10-08 13:02:52 +02:00
let auth_check = state_res::auth_check(
2021-11-27 17:44:52 +01:00
&room_version,
2024-03-05 19:48:54 -05:00
&pdu,
2021-11-27 17:44:52 +01:00
None::<PduEvent>, // TODO: third_party_invite
2022-09-07 13:25:51 +02:00
|k, s| auth_events.get(&(k.clone(), s.to_owned())),
2022-10-10 14:09:11 +02:00
)
.map_err(|e| {
2021-10-13 10:16:45 +02:00
error!("Auth check failed: {:?}", e);
Error::BadRequest(ErrorKind::forbidden(), "Auth check failed.")
})?;
2024-03-05 19:48:54 -05:00
2021-03-26 13:41:05 +01:00
if !auth_check {
return Err(Error::BadRequest(ErrorKind::forbidden(), "Event is not authorized."));
2024-03-05 19:48:54 -05:00
}
2021-09-01 15:28:02 +02:00
// Hash and sign
let mut pdu_json = utils::to_canonical_object(&pdu).map_err(|e| {
2024-06-22 21:21:16 +00:00
error!("Failed to convert PDU to canonical JSON: {e}");
Error::bad_database("Failed to convert PDU to canonical JSON.")
2021-03-26 13:41:05 +01:00
})?;
2024-03-05 19:48:54 -05:00
// room v3 and above removed the "event_id" field from remote PDU format
match room_version_id {
RoomVersionId::V1 | RoomVersionId::V2 => {},
_ => {
pdu_json.remove("event_id");
},
};
2024-03-05 19:48:54 -05:00
// Add origin because synapse likes that (and it's required in the spec)
pdu_json.insert(
"origin".to_owned(),
2024-07-18 06:37:47 +00:00
to_canonical_value(self.services.globals.server_name()).expect("server name is a valid CanonicalJsonValue"),
);
2024-03-05 19:48:54 -05:00
match ruma::signatures::hash_and_sign_event(
2024-07-18 06:37:47 +00:00
self.services.globals.server_name().as_str(),
self.services.globals.keypair(),
&mut pdu_json,
2022-09-07 13:25:51 +02:00
&room_version_id,
2024-03-05 19:48:54 -05:00
) {
Ok(()) => {},
2022-09-07 13:25:51 +02:00
Err(e) => {
2022-04-08 22:05:13 +02:00
return match e {
ruma::signatures::Error::PduSize => {
2022-09-07 13:25:51 +02:00
Err(Error::BadRequest(ErrorKind::TooLarge, "Message is too long"))
2024-03-05 19:48:54 -05:00
},
2022-09-07 13:25:51 +02:00
_ => Err(Error::BadRequest(ErrorKind::Unknown, "Signing event failed")),
2024-03-05 19:48:54 -05:00
}
2020-09-14 20:23:19 +02:00
},
2024-03-05 19:48:54 -05:00
}
2021-05-08 01:54:24 +02:00
// Generate event id
2022-04-13 00:08:55 +02:00
pdu.event_id = EventId::parse_arc(format!(
2024-03-05 19:48:54 -05:00
"${}",
2022-04-13 00:08:55 +02:00
ruma::signatures::reference_hash(&pdu_json, &room_version_id).expect("ruma can calculate reference hashes")
))
2022-04-08 22:05:13 +02:00
.expect("ruma's reference hashes are valid event ids");
2024-03-05 19:48:54 -05:00
2022-04-08 22:05:13 +02:00
pdu_json.insert(
"event_id".to_owned(),
CanonicalJsonValue::String(pdu.event_id.as_str().to_owned()),
);
2024-03-05 19:48:54 -05:00
// Generate short event id
2024-07-18 06:37:47 +00:00
let _shorteventid = self
.services
2024-03-25 17:05:11 -04:00
.short
.get_or_create_shorteventid(&pdu.event_id)?;
2024-03-05 19:48:54 -05:00
2021-05-08 01:54:24 +02:00
Ok((pdu, pdu_json))
2024-03-05 19:48:54 -05:00
}
2020-06-09 15:13:17 +02:00
/// Creates a new persisted data unit and adds it to a room. This function
2021-04-26 18:20:20 +02:00
/// takes a roomid_mutex_state, meaning that only this function is able to
2022-06-20 11:31:27 +02:00
/// mutate the room state.
2021-04-26 18:20:20 +02:00
#[tracing::instrument(skip(self, state_lock))]
2024-05-09 15:59:08 -07:00
pub async fn build_and_append_pdu(
2022-10-05 20:34:31 +02:00
&self,
2022-10-05 09:34:25 +02:00
pdu_builder: PduBuilder,
2022-06-20 11:31:27 +02:00
sender: &UserId,
room_id: &RoomId,
2024-07-09 20:04:43 +00:00
state_lock: &RoomMutexGuard, // Take mutex guard to make sure users get the room state mutex
2022-06-20 11:31:27 +02:00
) -> Result<Arc<EventId>> {
2022-09-07 13:25:51 +02:00
let (pdu, pdu_json) = self.create_hash_and_sign_event(pdu_builder, sender, room_id, state_lock)?;
2024-07-18 06:37:47 +00:00
if let Some(admin_room) = self.services.admin.get_admin_room()? {
if admin_room == room_id {
match pdu.event_type() {
TimelineEventType::RoomEncryption => {
warn!("Encryption is not allowed in the admins room");
return Err(Error::BadRequest(
ErrorKind::forbidden(),
2024-06-22 21:21:16 +00:00
"Encryption is not allowed in the admins room",
));
},
TimelineEventType::RoomMember => {
2024-03-25 17:05:11 -04:00
let target = pdu
.state_key()
.filter(|v| v.starts_with('@'))
.unwrap_or(sender.as_str());
2024-07-18 06:37:47 +00:00
let server_user = &self.services.globals.server_user.to_string();
let content = serde_json::from_str::<RoomMemberEventContent>(pdu.content.get())
2024-06-22 21:21:16 +00:00
.map_err(|_| Error::bad_database("Invalid content in pdu"))?;
if content.membership == MembershipState::Leave {
if target == server_user {
2024-06-22 21:21:16 +00:00
warn!("Server user cannot leave from admins room");
return Err(Error::BadRequest(
ErrorKind::forbidden(),
2024-06-22 21:21:16 +00:00
"Server user cannot leave from admins room.",
));
}
2024-07-18 06:37:47 +00:00
let count = self
.services
.state_cache
.room_members(room_id)
.filter_map(Result::ok)
2024-07-22 07:43:51 +00:00
.filter(|m| self.services.globals.server_is_ours(m.server_name()) && 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.",
));
}
}
2024-03-05 19:48:54 -05:00
if content.membership == MembershipState::Ban && pdu.state_key().is_some() {
if target == server_user {
2024-06-22 21:21:16 +00:00
warn!("Server user cannot be banned in admins room");
return Err(Error::BadRequest(
ErrorKind::forbidden(),
2024-06-22 21:21:16 +00:00
"Server user cannot be banned in admins room.",
));
}
2024-07-18 06:37:47 +00:00
let count = self
.services
.state_cache
.room_members(room_id)
.filter_map(Result::ok)
2024-07-22 07:43:51 +00:00
.filter(|m| self.services.globals.server_is_ours(m.server_name()) && 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.",
));
}
2024-03-05 19:48:54 -05:00
}
},
_ => {},
}
}
}
2024-03-05 19:48:54 -05:00
2024-06-22 21:21:16 +00:00
// If redaction event is not authorized, do not append it to the timeline
2024-06-30 23:26:36 -04:00
if pdu.kind == TimelineEventType::RoomRedaction {
2024-07-12 01:08:53 +00:00
use RoomVersionId::*;
2024-07-18 06:37:47 +00:00
match self.services.state.get_room_version(&pdu.room_id)? {
2024-07-12 01:08:53 +00:00
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | V9 | V10 => {
2024-06-30 23:26:36 -04:00
if let Some(redact_id) = &pdu.redacts {
2024-07-18 06:37:47 +00:00
if !self
.services
.state_accessor
.user_can_redact(redact_id, &pdu.sender, &pdu.room_id, false)?
{
2024-06-30 23:26:36 -04:00
return Err(Error::BadRequest(ErrorKind::forbidden(), "User cannot redact this event."));
}
};
},
_ => {
let content = serde_json::from_str::<RoomRedactionEventContent>(pdu.content.get())
.map_err(|_| Error::bad_database("Invalid content in redaction pdu."))?;
if let Some(redact_id) = &content.redacts {
2024-07-18 06:37:47 +00:00
if !self
.services
.state_accessor
.user_can_redact(redact_id, &pdu.sender, &pdu.room_id, false)?
{
2024-06-30 23:26:36 -04:00
return Err(Error::BadRequest(ErrorKind::forbidden(), "User cannot redact this event."));
}
}
},
2024-06-22 21:21:16 +00:00
}
};
2020-10-18 08:56:21 +02:00
// 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.
2024-07-18 06:37:47 +00:00
let statehashid = self.services.state.append_to_state(&pdu)?;
2024-03-05 19:48:54 -05:00
let pdu_id = self
.append_pdu(
&pdu,
pdu_json,
// Since this PDU references all pdu_leaves we can update the leaves
// of the room
vec![(*pdu.event_id).to_owned()],
state_lock,
)
.await?;
2024-03-05 19:48:54 -05:00
2020-12-31 14:52:08 +01:00
// We set the room state after inserting the pdu, so that we never have a moment
// in time where events in the current room state do not exist
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.state
.set_room_state(room_id, statehashid, state_lock)?;
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let mut servers: HashSet<OwnedServerName> = self
.services
2024-03-25 17:05:11 -04:00
.state_cache
.room_servers(room_id)
.filter_map(Result::ok)
.collect();
2024-03-05 19:48:54 -05:00
// In case we are kicking or banning a user, we need to inform their server of
// the change
2023-02-26 16:29:06 +01:00
if pdu.kind == TimelineEventType::RoomMember {
2024-03-25 17:05:11 -04:00
if let Some(state_key_uid) = &pdu
.state_key
.as_ref()
.and_then(|state_key| UserId::parse(state_key.as_str()).ok())
{
2022-10-09 17:25:06 +02:00
servers.insert(state_key_uid.server_name().to_owned());
}
}
2024-03-05 19:48:54 -05:00
// Remove our server from the server list since it will be added to it by
// room_servers() and/or the if statement above
2024-07-18 06:37:47 +00:00
servers.remove(self.services.globals.server_name());
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
self.services
2024-03-29 16:29:25 -07:00
.sending
.send_pdu_servers(servers.into_iter(), &pdu_id)?;
2024-03-05 19:48:54 -05:00
2022-06-20 11:31:27 +02:00
Ok(pdu.event_id)
}
2024-03-05 19:48:54 -05:00
2022-06-20 11:31:27 +02:00
/// Append the incoming event setting the state snapshot to the state from
/// the server that sent the event.
#[tracing::instrument(skip_all)]
2024-05-09 15:59:08 -07:00
pub async fn append_incoming_pdu(
2022-10-05 18:36:12 +02:00
&self,
2022-06-20 11:31:27 +02:00
pdu: &PduEvent,
pdu_json: CanonicalJsonObject,
2022-10-09 17:25:06 +02:00
new_room_leaves: Vec<OwnedEventId>,
state_ids_compressed: Arc<HashSet<CompressedStateEvent>>,
2022-06-20 11:31:27 +02:00
soft_fail: bool,
2024-07-09 20:04:43 +00:00
state_lock: &RoomMutexGuard, // Take mutex guard to make sure users get the room state mutex
2022-06-20 11:31:27 +02:00
) -> Result<Option<Vec<u8>>> {
// 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.
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.state
.set_event_state(&pdu.event_id, &pdu.room_id, state_ids_compressed)?;
2024-03-05 19:48:54 -05:00
2022-06-20 11:31:27 +02:00
if soft_fail {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.pdu_metadata
.mark_as_referenced(&pdu.room_id, &pdu.prev_events)?;
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.state
.set_forward_extremities(&pdu.room_id, new_room_leaves, state_lock)?;
2022-06-20 11:31:27 +02:00
return Ok(None);
2020-12-08 10:33:44 +01:00
}
2024-03-05 19:48:54 -05:00
let pdu_id = self
2024-03-25 17:05:11 -04:00
.append_pdu(pdu, pdu_json, new_room_leaves, state_lock)
.await?;
2024-03-05 19:48:54 -05:00
2022-06-20 11:31:27 +02:00
Ok(Some(pdu_id))
}
2024-03-05 19:48:54 -05:00
/// Returns an iterator over all PDUs in a room.
#[inline]
2024-05-09 15:59:08 -07:00
pub fn all_pdus<'a>(
2020-06-16 12:11:38 +02:00
&'a self, user_id: &UserId, room_id: &RoomId,
2023-02-20 22:59:45 +01:00
) -> Result<impl Iterator<Item = Result<(PduCount, PduEvent)>> + 'a> {
self.pdus_after(user_id, room_id, PduCount::min())
}
2024-03-05 19:48:54 -05:00
2020-07-26 17:34:12 +02:00
/// Returns an iterator over all events and their tokens in a room that
/// happened before the event with id `until` in reverse-chronological
/// order.
2024-07-07 19:03:15 +00:00
#[tracing::instrument(skip(self), level = "debug")]
2024-05-09 15:59:08 -07:00
pub fn pdus_until<'a>(
2020-06-16 12:11:38 +02:00
&'a self, user_id: &UserId, room_id: &RoomId, until: PduCount,
2023-02-20 22:59:45 +01:00
) -> Result<impl Iterator<Item = Result<(PduCount, PduEvent)>> + 'a> {
self.db.pdus_until(user_id, room_id, until)
}
2024-03-05 19:48:54 -05:00
2020-07-26 17:34:12 +02:00
/// Returns an iterator over all events and their token in a room that
/// happened after the event with id `from` in chronological order.
2024-07-07 19:03:15 +00:00
#[tracing::instrument(skip(self), level = "debug")]
2024-05-09 15:59:08 -07:00
pub fn pdus_after<'a>(
2020-06-16 12:11:38 +02:00
&'a self, user_id: &UserId, room_id: &RoomId, from: PduCount,
2023-02-20 22:59:45 +01:00
) -> Result<impl Iterator<Item = Result<(PduCount, PduEvent)>> + 'a> {
self.db.pdus_after(user_id, room_id, from)
2020-06-04 13:58:55 +02:00
}
2024-03-05 19:48:54 -05:00
2020-05-26 10:27:51 +02:00
/// Replace a PDU with the redacted form.
#[tracing::instrument(skip(self, reason))]
2024-06-12 00:33:12 -04:00
pub fn redact_pdu(&self, event_id: &EventId, reason: &PduEvent, shortroomid: u64) -> Result<()> {
2023-06-25 19:31:40 +02:00
// TODO: Don't reserialize, keep original json
2020-05-26 10:27:51 +02:00
if let Some(pdu_id) = self.get_pdu_id(event_id)? {
2024-03-25 17:05:11 -04:00
let mut pdu = self
.get_pdu_from_id(&pdu_id)?
.ok_or_else(|| Error::bad_database("PDU ID points to invalid PDU."))?;
2024-06-12 00:33:12 -04:00
if let Ok(content) = serde_json::from_str::<ExtractBody>(pdu.content.get()) {
if let Some(body) = content.body {
2024-07-18 06:37:47 +00:00
self.services
2024-06-12 00:33:12 -04:00
.search
.deindex_pdu(shortroomid, &pdu_id, &body)?;
}
}
2024-07-18 06:37:47 +00:00
let room_version_id = self.services.state.get_room_version(&pdu.room_id)?;
2024-06-12 00:33:12 -04:00
pdu.redact(room_version_id, reason)?;
2024-06-12 00:33:12 -04:00
2023-06-25 19:31:40 +02:00
self.replace_pdu(
&pdu_id,
&utils::to_canonical_object(&pdu).map_err(|e| {
error!("Failed to convert PDU to canonical JSON: {}", e);
Error::bad_database("Failed to convert PDU to canonical JSON.")
})?,
2023-06-25 19:31:40 +02:00
&pdu,
)?;
2020-05-26 10:27:51 +02:00
}
2022-02-10 20:59:11 +01:00
// If event does not exist, just noop
Ok(())
2020-05-26 10:27:51 +02:00
}
2024-03-05 19:48:54 -05:00
#[tracing::instrument(skip(self))]
2024-05-09 15:59:08 -07:00
pub async fn backfill_if_required(&self, room_id: &RoomId, from: PduCount) -> Result<()> {
2024-03-25 17:05:11 -04:00
let first_pdu = self
.all_pdus(user_id!("@doesntmatter:conduit.rs"), room_id)?
.next()
.expect("Room is not empty")?;
2024-03-05 19:48:54 -05:00
2023-02-20 22:59:45 +01:00
if first_pdu.0 < from {
// No backfill required, there are still events between them
return Ok(());
}
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let power_levels: RoomPowerLevelsEventContent = self
.services
2023-02-20 22:59:45 +01:00
.state_accessor
.room_state_get(room_id, &StateEventType::RoomPowerLevels, "")?
2023-02-20 22:59:45 +01:00
.map(|ev| {
serde_json::from_str(ev.content.get())
.map_err(|_| Error::bad_database("invalid m.room.power_levels event"))
})
.transpose()?
.unwrap_or_default();
let room_mods = power_levels.users.iter().filter_map(|(user_id, level)| {
2024-07-22 07:43:51 +00:00
if level > &power_levels.users_default && !self.services.globals.user_is_local(user_id) {
Some(user_id.server_name().to_owned())
} else {
None
}
});
2024-07-18 06:37:47 +00:00
let room_alias_servers = self
.services
.alias
.local_aliases_for_room(room_id)
.filter_map(|alias| {
alias
.ok()
2024-07-22 07:43:51 +00:00
.filter(|alias| !self.services.globals.server_is_ours(alias.server_name()))
.map(|alias| alias.server_name().to_owned())
});
let servers = room_mods
.chain(room_alias_servers)
2024-07-18 06:37:47 +00:00
.chain(self.services.server.config.trusted_servers.clone())
.filter(|server_name| {
2024-07-22 07:43:51 +00:00
if self.services.globals.server_is_ours(server_name) {
return false;
}
2024-07-18 06:37:47 +00:00
self.services
.state_cache
.server_in_room(server_name, room_id)
.unwrap_or(false)
});
2024-03-05 19:48:54 -05:00
for backfill_server in servers {
2023-02-20 22:59:45 +01:00
info!("Asking {backfill_server} for backfill");
2024-07-18 06:37:47 +00:00
let response = self
.services
2023-02-20 22:59:45 +01:00
.sending
.send_federation_request(
&backfill_server,
2023-02-20 22:59:45 +01:00
federation::backfill::get_backfill::v1::Request {
room_id: room_id.to_owned(),
v: vec![first_pdu.1.event_id.as_ref().to_owned()],
limit: uint!(100),
},
)
.await;
match response {
Ok(response) => {
let pub_key_map = RwLock::new(BTreeMap::new());
2023-02-20 22:59:45 +01:00
for pdu in response.pdus {
if let Err(e) = self.backfill_pdu(&backfill_server, pdu, &pub_key_map).await {
2024-03-22 00:32:57 -04:00
warn!("Failed to add backfilled pdu in room {room_id}: {e}");
2023-02-20 22:59:45 +01:00
}
2024-03-05 19:48:54 -05:00
}
2023-02-20 22:59:45 +01:00
return Ok(());
},
Err(e) => {
2024-03-22 00:32:57 -04:00
warn!("{backfill_server} failed to provide backfill for room {room_id}: {e}");
2023-02-20 22:59:45 +01:00
},
}
2024-03-05 19:48:54 -05:00
}
2024-03-22 00:32:57 -04:00
info!("No servers could backfill, but backfill was needed in room {room_id}");
2024-03-05 19:48:54 -05:00
Ok(())
}
2024-04-14 03:54:54 -07:00
#[tracing::instrument(skip(self, pdu, pub_key_map))]
2024-05-09 15:59:08 -07:00
pub async fn backfill_pdu(
2023-02-20 22:59:45 +01:00
&self, origin: &ServerName, pdu: Box<RawJsonValue>,
pub_key_map: &RwLock<BTreeMap<String, BTreeMap<String, Base64>>>,
2023-02-20 22:59:45 +01:00
) -> Result<()> {
2024-07-18 06:37:47 +00:00
let (event_id, value, room_id) = self.services.event_handler.parse_incoming_pdu(&pdu)?;
2024-03-05 19:48:54 -05:00
// Lock so we cannot backfill the same pdu twice at the same time
2024-07-18 06:37:47 +00:00
let mutex_lock = self
.services
.event_handler
.mutex_federation
2024-06-14 21:39:37 +00:00
.lock(&room_id)
.await;
2024-03-05 19:48:54 -05:00
// Skip the PDU if we already have it as a timeline event
if let Some(pdu_id) = self.get_pdu_id(&event_id)? {
2024-07-02 05:56:10 +00:00
let pdu_id = pdu_id.to_vec();
debug!("We already know {event_id} at {pdu_id:?}");
return Ok(());
}
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
self.services
.server_keys
2024-03-25 17:05:11 -04:00
.fetch_required_signing_keys([&value], pub_key_map)
.await?;
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
self.services
2023-02-20 22:59:45 +01:00
.event_handler
2024-04-23 11:34:20 -07:00
.handle_incoming_pdu(origin, &room_id, &event_id, value, false, pub_key_map)
2023-02-20 22:59:45 +01:00
.await?;
2024-03-05 19:48:54 -05:00
2023-02-20 22:59:45 +01:00
let value = self.get_pdu_json(&event_id)?.expect("We just created it");
let pdu = self.get_pdu(&event_id)?.expect("We just created it");
2024-03-05 19:48:54 -05:00
2024-07-18 06:37:47 +00:00
let shortroomid = self
.services
2024-03-25 17:05:11 -04:00
.short
.get_shortroomid(&room_id)?
.expect("room exists");
let insert_lock = self.mutex_insert.lock(&room_id).await;
2024-03-05 19:48:54 -05:00
2024-07-07 04:46:16 +00:00
let max = u64::MAX;
2024-07-18 06:37:47 +00:00
let count = self.services.globals.next_count()?;
2023-02-20 22:59:45 +01:00
let mut pdu_id = shortroomid.to_be_bytes().to_vec();
pdu_id.extend_from_slice(&0_u64.to_be_bytes());
2024-07-07 04:46:16 +00:00
pdu_id.extend_from_slice(&(validated!(max - count)?).to_be_bytes());
2024-03-05 19:48:54 -05:00
2023-02-20 22:59:45 +01:00
// Insert pdu
self.db.prepend_backfill_pdu(&pdu_id, &event_id, &value)?;
2024-03-05 19:48:54 -05:00
2023-02-20 22:59:45 +01:00
drop(insert_lock);
2024-03-05 19:48:54 -05:00
if pdu.kind == TimelineEventType::RoomMessage {
let content = serde_json::from_str::<ExtractBody>(pdu.content.get())
.map_err(|_| Error::bad_database("Invalid content in pdu."))?;
2024-03-05 19:48:54 -05:00
if let Some(body) = content.body {
2024-07-18 06:37:47 +00:00
self.services
2024-03-25 17:05:11 -04:00
.search
.index_pdu(shortroomid, &pdu_id, &body)?;
2024-03-05 19:48:54 -05:00
}
}
drop(mutex_lock);
2024-03-05 19:48:54 -05:00
2024-04-14 03:54:54 -07:00
debug!("Prepended backfill pdu");
2023-02-20 22:59:45 +01:00
Ok(())
}
2022-09-06 23:15:09 +02:00
}
#[cfg(test)]
mod tests {
use super::*;
2024-03-05 19:48:54 -05:00
#[test]
fn comparisons() {
assert!(PduCount::Normal(1) < PduCount::Normal(2));
assert!(PduCount::Backfilled(2) < PduCount::Backfilled(1));
assert!(PduCount::Normal(1) > PduCount::Backfilled(1));
assert!(PduCount::Backfilled(1) < PduCount::Normal(1));
}
}