|
|
|
|
@ -2,7 +2,7 @@ mod edus;
@@ -2,7 +2,7 @@ mod edus;
|
|
|
|
|
|
|
|
|
|
pub use edus::RoomEdus; |
|
|
|
|
|
|
|
|
|
use crate::{pdu::PduBuilder, utils, Error, PduEvent, Result}; |
|
|
|
|
use crate::{pdu::PduBuilder, utils, Database, Error, PduEvent, Result}; |
|
|
|
|
use log::error; |
|
|
|
|
use regex::Regex; |
|
|
|
|
use ring::digest; |
|
|
|
|
@ -20,7 +20,7 @@ use ruma::{
@@ -20,7 +20,7 @@ use ruma::{
|
|
|
|
|
EventId, RoomAliasId, RoomId, RoomVersionId, ServerName, UserId, |
|
|
|
|
}; |
|
|
|
|
use sled::IVec; |
|
|
|
|
use state_res::{event_auth, Error as StateError, Requester, StateEvent, StateMap, StateStore}; |
|
|
|
|
use state_res::{event_auth, StateMap}; |
|
|
|
|
|
|
|
|
|
use std::{ |
|
|
|
|
collections::{BTreeMap, HashMap}, |
|
|
|
|
@ -67,44 +67,6 @@ pub struct Rooms {
@@ -67,44 +67,6 @@ pub struct Rooms {
|
|
|
|
|
pub(super) stateid_pduid: sled::Tree, // StateId = StateHash + Short, PduId = Count (without roomid)
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl StateStore for Rooms { |
|
|
|
|
fn get_event( |
|
|
|
|
&self, |
|
|
|
|
room_id: &RoomId, |
|
|
|
|
event_id: &EventId, |
|
|
|
|
) -> state_res::Result<Arc<StateEvent>> { |
|
|
|
|
let pid = self |
|
|
|
|
.get_pdu_id(event_id) |
|
|
|
|
.map_err(StateError::custom)? |
|
|
|
|
.ok_or_else(|| { |
|
|
|
|
StateError::NotFound(format!( |
|
|
|
|
"PDU via room_id and event_id not found in the db: {}", |
|
|
|
|
event_id.as_str() |
|
|
|
|
)) |
|
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
serde_json::from_slice( |
|
|
|
|
&self |
|
|
|
|
.pduid_pdu |
|
|
|
|
.get(pid) |
|
|
|
|
.map_err(StateError::custom)? |
|
|
|
|
.ok_or_else(|| StateError::NotFound("PDU via pduid not found in db.".into()))?, |
|
|
|
|
) |
|
|
|
|
.map_err(Into::into) |
|
|
|
|
.and_then(|pdu: StateEvent| { |
|
|
|
|
// conduit's PDU's always contain a room_id but some
|
|
|
|
|
// of ruma's do not so this must be an Option
|
|
|
|
|
if pdu.room_id() == room_id { |
|
|
|
|
Ok(Arc::new(pdu)) |
|
|
|
|
} else { |
|
|
|
|
Err(StateError::NotFound( |
|
|
|
|
"Found PDU for incorrect room in db.".into(), |
|
|
|
|
)) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Rooms { |
|
|
|
|
/// Builds a StateMap by iterating over all keys that start
|
|
|
|
|
/// with state_hash, this gives the full state for the given state_hash.
|
|
|
|
|
@ -112,7 +74,7 @@ impl Rooms {
@@ -112,7 +74,7 @@ impl Rooms {
|
|
|
|
|
&self, |
|
|
|
|
room_id: &RoomId, |
|
|
|
|
state_hash: &StateHashId, |
|
|
|
|
) -> Result<StateMap<PduEvent>> { |
|
|
|
|
) -> Result<BTreeMap<(EventType, String), PduEvent>> { |
|
|
|
|
self.stateid_pduid |
|
|
|
|
.scan_prefix(&state_hash) |
|
|
|
|
.values() |
|
|
|
|
@ -141,7 +103,7 @@ impl Rooms {
@@ -141,7 +103,7 @@ impl Rooms {
|
|
|
|
|
pdu, |
|
|
|
|
)) |
|
|
|
|
}) |
|
|
|
|
.collect::<Result<StateMap<_>>>() |
|
|
|
|
.collect() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns a single PDU from `room_id` with key (`event_type`, `state_key`).
|
|
|
|
|
@ -181,7 +143,7 @@ impl Rooms {
@@ -181,7 +143,7 @@ impl Rooms {
|
|
|
|
|
))) |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
return Ok(None); |
|
|
|
|
Ok(None) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -205,7 +167,7 @@ impl Rooms {
@@ -205,7 +167,7 @@ impl Rooms {
|
|
|
|
|
content: serde_json::Value, |
|
|
|
|
) -> Result<StateMap<PduEvent>> { |
|
|
|
|
let auth_events = state_res::auth_types_for_event( |
|
|
|
|
kind.clone(), |
|
|
|
|
&kind, |
|
|
|
|
sender, |
|
|
|
|
state_key.map(|s| s.to_string()), |
|
|
|
|
content, |
|
|
|
|
@ -213,7 +175,13 @@ impl Rooms {
@@ -213,7 +175,13 @@ impl Rooms {
|
|
|
|
|
|
|
|
|
|
let mut events = StateMap::new(); |
|
|
|
|
for (event_type, state_key) in auth_events { |
|
|
|
|
if let Some((_, pdu)) = self.room_state_get(room_id, &event_type, &state_key)? { |
|
|
|
|
if let Some((_, pdu)) = self.room_state_get( |
|
|
|
|
room_id, |
|
|
|
|
&event_type, |
|
|
|
|
&state_key |
|
|
|
|
.as_deref() |
|
|
|
|
.ok_or_else(|| Error::Conflict("Found a non state event in auth events"))?, |
|
|
|
|
)? { |
|
|
|
|
events.insert((event_type, state_key), pdu); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -290,7 +258,10 @@ impl Rooms {
@@ -290,7 +258,10 @@ impl Rooms {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// Returns the full room state.
|
|
|
|
|
pub fn room_state_full(&self, room_id: &RoomId) -> Result<StateMap<PduEvent>> { |
|
|
|
|
pub fn room_state_full( |
|
|
|
|
&self, |
|
|
|
|
room_id: &RoomId, |
|
|
|
|
) -> Result<BTreeMap<(EventType, String), PduEvent>> { |
|
|
|
|
if let Some(current_state_hash) = self.current_state_hash(room_id)? { |
|
|
|
|
self.state_full(&room_id, ¤t_state_hash) |
|
|
|
|
} else { |
|
|
|
|
@ -448,9 +419,7 @@ impl Rooms {
@@ -448,9 +419,7 @@ impl Rooms {
|
|
|
|
|
mut pdu_json: CanonicalJsonObject, |
|
|
|
|
count: u64, |
|
|
|
|
pdu_id: IVec, |
|
|
|
|
globals: &super::globals::Globals, |
|
|
|
|
account_data: &super::account_data::AccountData, |
|
|
|
|
admin: &super::admin::Admin, |
|
|
|
|
db: &Database, |
|
|
|
|
) -> Result<()> { |
|
|
|
|
// 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
|
|
|
|
|
@ -484,7 +453,7 @@ impl Rooms {
@@ -484,7 +453,7 @@ impl Rooms {
|
|
|
|
|
// Mark as read first so the sending client doesn't get a notification even if appending
|
|
|
|
|
// fails
|
|
|
|
|
self.edus |
|
|
|
|
.private_read_set(&pdu.room_id, &pdu.sender, count, &globals)?; |
|
|
|
|
.private_read_set(&pdu.room_id, &pdu.sender, count, &db.globals)?; |
|
|
|
|
|
|
|
|
|
self.pduid_pdu.insert( |
|
|
|
|
&pdu_id, |
|
|
|
|
@ -522,8 +491,8 @@ impl Rooms {
@@ -522,8 +491,8 @@ impl Rooms {
|
|
|
|
|
) |
|
|
|
|
})?, |
|
|
|
|
&pdu.sender, |
|
|
|
|
account_data, |
|
|
|
|
globals, |
|
|
|
|
&db.account_data, |
|
|
|
|
&db.globals, |
|
|
|
|
)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -541,10 +510,10 @@ impl Rooms {
@@ -541,10 +510,10 @@ impl Rooms {
|
|
|
|
|
self.tokenids.insert(key, &[])?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if body.starts_with(&format!("@conduit:{}: ", globals.server_name())) |
|
|
|
|
if body.starts_with(&format!("@conduit:{}: ", db.globals.server_name())) |
|
|
|
|
&& self |
|
|
|
|
.id_from_alias( |
|
|
|
|
&format!("#admins:{}", globals.server_name()) |
|
|
|
|
&format!("#admins:{}", db.globals.server_name()) |
|
|
|
|
.try_into() |
|
|
|
|
.expect("#admins:server_name is a valid room alias"), |
|
|
|
|
)? |
|
|
|
|
@ -571,10 +540,11 @@ impl Rooms {
@@ -571,10 +540,11 @@ impl Rooms {
|
|
|
|
|
); |
|
|
|
|
match parsed_config { |
|
|
|
|
Ok(yaml) => { |
|
|
|
|
admin.send(AdminCommand::RegisterAppservice(yaml)); |
|
|
|
|
db.admin |
|
|
|
|
.send(AdminCommand::RegisterAppservice(yaml)); |
|
|
|
|
} |
|
|
|
|
Err(e) => { |
|
|
|
|
admin.send(AdminCommand::SendMessage( |
|
|
|
|
db.admin.send(AdminCommand::SendMessage( |
|
|
|
|
message::MessageEventContent::text_plain( |
|
|
|
|
format!( |
|
|
|
|
"Could not parse appservice config: {}", |
|
|
|
|
@ -585,7 +555,7 @@ impl Rooms {
@@ -585,7 +555,7 @@ impl Rooms {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
admin.send(AdminCommand::SendMessage( |
|
|
|
|
db.admin.send(AdminCommand::SendMessage( |
|
|
|
|
message::MessageEventContent::text_plain( |
|
|
|
|
"Expected code block in command body.", |
|
|
|
|
), |
|
|
|
|
@ -593,10 +563,10 @@ impl Rooms {
@@ -593,10 +563,10 @@ impl Rooms {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
"list_appservices" => { |
|
|
|
|
admin.send(AdminCommand::ListAppservices); |
|
|
|
|
db.admin.send(AdminCommand::ListAppservices); |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
admin.send(AdminCommand::SendMessage( |
|
|
|
|
db.admin.send(AdminCommand::SendMessage( |
|
|
|
|
message::MessageEventContent::text_plain(format!( |
|
|
|
|
"Command: {}, Args: {:?}", |
|
|
|
|
command, args |
|
|
|
|
@ -703,11 +673,7 @@ impl Rooms {
@@ -703,11 +673,7 @@ impl Rooms {
|
|
|
|
|
pdu_builder: PduBuilder, |
|
|
|
|
sender: &UserId, |
|
|
|
|
room_id: &RoomId, |
|
|
|
|
globals: &super::globals::Globals, |
|
|
|
|
sending: &super::sending::Sending, |
|
|
|
|
admin: &super::admin::Admin, |
|
|
|
|
account_data: &super::account_data::AccountData, |
|
|
|
|
appservice: &super::appservice::Appservice, |
|
|
|
|
db: &Database, |
|
|
|
|
) -> Result<EventId> { |
|
|
|
|
let PduBuilder { |
|
|
|
|
event_type, |
|
|
|
|
@ -790,7 +756,7 @@ impl Rooms {
@@ -790,7 +756,7 @@ impl Rooms {
|
|
|
|
|
if !match event_type { |
|
|
|
|
EventType::RoomEncryption => { |
|
|
|
|
// Only allow encryption events if it's allowed in the config
|
|
|
|
|
globals.allow_encryption() |
|
|
|
|
db.globals.allow_encryption() |
|
|
|
|
} |
|
|
|
|
EventType::RoomMember => { |
|
|
|
|
let prev_event = self |
|
|
|
|
@ -798,23 +764,17 @@ impl Rooms {
@@ -798,23 +764,17 @@ impl Rooms {
|
|
|
|
|
ErrorKind::Unknown, |
|
|
|
|
"Membership can't be the first event", |
|
|
|
|
))?)? |
|
|
|
|
.map(|pdu| pdu.convert_for_state_res()); |
|
|
|
|
.map(Arc::new); |
|
|
|
|
event_auth::valid_membership_change( |
|
|
|
|
// TODO this is a bit of a hack but not sure how to have a type
|
|
|
|
|
// declared in `state_res` crate easily convert to/from conduit::PduEvent
|
|
|
|
|
Requester { |
|
|
|
|
prev_event_ids: prev_events.to_owned(), |
|
|
|
|
room_id: &room_id, |
|
|
|
|
content: &content, |
|
|
|
|
state_key: Some(state_key.to_owned()), |
|
|
|
|
sender: &sender, |
|
|
|
|
}, |
|
|
|
|
Some(state_key.as_str()), |
|
|
|
|
sender, |
|
|
|
|
content.clone(), |
|
|
|
|
prev_event, |
|
|
|
|
None, // TODO: third party invite
|
|
|
|
|
&auth_events |
|
|
|
|
.iter() |
|
|
|
|
.map(|((ty, key), pdu)| { |
|
|
|
|
Ok(((ty.clone(), key.clone()), pdu.convert_for_state_res())) |
|
|
|
|
Ok(((ty.clone(), key.clone()), Arc::new(pdu.clone()))) |
|
|
|
|
}) |
|
|
|
|
.collect::<Result<StateMap<_>>>()?, |
|
|
|
|
) |
|
|
|
|
@ -902,13 +862,13 @@ impl Rooms {
@@ -902,13 +862,13 @@ impl Rooms {
|
|
|
|
|
// Add origin because synapse likes that (and it's required in the spec)
|
|
|
|
|
pdu_json.insert( |
|
|
|
|
"origin".to_owned(), |
|
|
|
|
to_canonical_value(globals.server_name()) |
|
|
|
|
to_canonical_value(db.globals.server_name()) |
|
|
|
|
.expect("server name is a valid CanonicalJsonValue"), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
ruma::signatures::hash_and_sign_event( |
|
|
|
|
globals.server_name().as_str(), |
|
|
|
|
globals.keypair(), |
|
|
|
|
db.globals.server_name().as_str(), |
|
|
|
|
db.globals.keypair(), |
|
|
|
|
&mut pdu_json, |
|
|
|
|
&RoomVersionId::Version6, |
|
|
|
|
) |
|
|
|
|
@ -929,24 +889,16 @@ impl Rooms {
@@ -929,24 +889,16 @@ impl Rooms {
|
|
|
|
|
|
|
|
|
|
// Increment the last index and use that
|
|
|
|
|
// This is also the next_batch/since value
|
|
|
|
|
let count = globals.next_count()?; |
|
|
|
|
let count = db.globals.next_count()?; |
|
|
|
|
let mut pdu_id = room_id.as_bytes().to_vec(); |
|
|
|
|
pdu_id.push(0xff); |
|
|
|
|
pdu_id.extend_from_slice(&count.to_be_bytes()); |
|
|
|
|
|
|
|
|
|
// We append to state before appending the pdu, so we don't have a moment in time with the
|
|
|
|
|
// pdu without it's state. This is okay because append_pdu can't fail.
|
|
|
|
|
let statehashid = self.append_to_state(&pdu_id, &pdu, &globals)?; |
|
|
|
|
|
|
|
|
|
self.append_pdu( |
|
|
|
|
&pdu, |
|
|
|
|
pdu_json, |
|
|
|
|
count, |
|
|
|
|
pdu_id.clone().into(), |
|
|
|
|
globals, |
|
|
|
|
account_data, |
|
|
|
|
admin, |
|
|
|
|
)?; |
|
|
|
|
let statehashid = self.append_to_state(&pdu_id, &pdu, &db.globals)?; |
|
|
|
|
|
|
|
|
|
self.append_pdu(&pdu, pdu_json, count, pdu_id.clone().into(), db)?; |
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
@ -955,12 +907,12 @@ impl Rooms {
@@ -955,12 +907,12 @@ impl Rooms {
|
|
|
|
|
for server in self |
|
|
|
|
.room_servers(room_id) |
|
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
|
.filter(|server| &**server != globals.server_name()) |
|
|
|
|
.filter(|server| &**server != db.globals.server_name()) |
|
|
|
|
{ |
|
|
|
|
sending.send_pdu(&server, &pdu_id)?; |
|
|
|
|
db.sending.send_pdu(&server, &pdu_id)?; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for appservice in appservice.iter_all().filter_map(|r| r.ok()) { |
|
|
|
|
for appservice in db.appservice.iter_all().filter_map(|r| r.ok()) { |
|
|
|
|
if let Some(namespaces) = appservice.1.get("namespaces") { |
|
|
|
|
let users = namespaces |
|
|
|
|
.get("users") |
|
|
|
|
@ -996,7 +948,7 @@ impl Rooms {
@@ -996,7 +948,7 @@ impl Rooms {
|
|
|
|
|
.get("sender_localpart") |
|
|
|
|
.and_then(|string| string.as_str()) |
|
|
|
|
.and_then(|string| { |
|
|
|
|
UserId::parse_with_server_name(string, globals.server_name()).ok() |
|
|
|
|
UserId::parse_with_server_name(string, db.globals.server_name()).ok() |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
if bridge_user_id.map_or(false, |bridge_user_id| { |
|
|
|
|
@ -1018,7 +970,7 @@ impl Rooms {
@@ -1018,7 +970,7 @@ impl Rooms {
|
|
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
|
.any(|member| users.iter().any(|regex| regex.is_match(member.as_str()))) |
|
|
|
|
{ |
|
|
|
|
sending.send_pdu_appservice(&appservice.0, &pdu_id)?; |
|
|
|
|
db.sending.send_pdu_appservice(&appservice.0, &pdu_id)?; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|