|
|
|
@ -4,6 +4,7 @@ pub use edus::RoomEdus; |
|
|
|
|
|
|
|
|
|
|
|
use crate::{pdu::PduBuilder, utils, Error, PduEvent, Result}; |
|
|
|
use crate::{pdu::PduBuilder, utils, Error, PduEvent, Result}; |
|
|
|
use log::error; |
|
|
|
use log::error; |
|
|
|
|
|
|
|
// TODO if ruma-signatures re-exports `use ruma::signatures::digest;`
|
|
|
|
use ring::digest; |
|
|
|
use ring::digest; |
|
|
|
use ruma::{ |
|
|
|
use ruma::{ |
|
|
|
api::client::error::ErrorKind, |
|
|
|
api::client::error::ErrorKind, |
|
|
|
@ -99,7 +100,13 @@ impl Rooms { |
|
|
|
/// This adds all current state events (not including the incoming event)
|
|
|
|
/// This adds all current state events (not including the incoming event)
|
|
|
|
/// to `stateid_pduid` and adds the incoming event to `pduid_statehash`.
|
|
|
|
/// to `stateid_pduid` and adds the incoming event to `pduid_statehash`.
|
|
|
|
/// The incoming event is the `pdu_id` passed to this method.
|
|
|
|
/// The incoming event is the `pdu_id` passed to this method.
|
|
|
|
pub fn append_state_pdu(&self, room_id: &RoomId, pdu_id: &[u8]) -> Result<StateHashId> { |
|
|
|
pub fn append_state_pdu( |
|
|
|
|
|
|
|
&self, |
|
|
|
|
|
|
|
room_id: &RoomId, |
|
|
|
|
|
|
|
pdu_id: &[u8], |
|
|
|
|
|
|
|
state_key: &str, |
|
|
|
|
|
|
|
kind: &EventType, |
|
|
|
|
|
|
|
) -> Result<StateHashId> { |
|
|
|
let state_hash = self.new_state_hash_id(room_id)?; |
|
|
|
let state_hash = self.new_state_hash_id(room_id)?; |
|
|
|
let state = self.current_state_pduids(room_id)?; |
|
|
|
let state = self.current_state_pduids(room_id)?; |
|
|
|
|
|
|
|
|
|
|
|
@ -123,6 +130,13 @@ impl Rooms { |
|
|
|
// will be everything up to but not including the incoming event.
|
|
|
|
// will be everything up to but not including the incoming event.
|
|
|
|
self.pduid_statehash.insert(pdu_id, state_hash.as_bytes())?; |
|
|
|
self.pduid_statehash.insert(pdu_id, state_hash.as_bytes())?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut key = room_id.as_bytes().to_vec(); |
|
|
|
|
|
|
|
key.push(0xff); |
|
|
|
|
|
|
|
key.extend_from_slice(kind.to_string().as_bytes()); |
|
|
|
|
|
|
|
key.push(0xff); |
|
|
|
|
|
|
|
key.extend_from_slice(state_key.as_bytes()); |
|
|
|
|
|
|
|
self.roomstateid_pduid.insert(key, pdu_id)?; |
|
|
|
|
|
|
|
|
|
|
|
Ok(state_hash) |
|
|
|
Ok(state_hash) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -535,8 +549,92 @@ 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.
|
|
|
|
#[allow(clippy::blocks_in_if_conditions)] |
|
|
|
|
|
|
|
pub fn append_pdu( |
|
|
|
pub fn append_pdu( |
|
|
|
|
|
|
|
&self, |
|
|
|
|
|
|
|
pdu: PduEvent, |
|
|
|
|
|
|
|
globals: &super::globals::Globals, |
|
|
|
|
|
|
|
account_data: &super::account_data::AccountData, |
|
|
|
|
|
|
|
) -> Result<EventId> { |
|
|
|
|
|
|
|
let mut pdu_json = serde_json::to_value(&pdu).expect("event is valid, we just created it"); |
|
|
|
|
|
|
|
ruma::signatures::hash_and_sign_event( |
|
|
|
|
|
|
|
globals.server_name().as_str(), |
|
|
|
|
|
|
|
globals.keypair(), |
|
|
|
|
|
|
|
&mut pdu_json, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.expect("event is valid, we just created it"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.replace_pdu_leaves(&pdu.room_id, &pdu.event_id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Increment the last index and use that
|
|
|
|
|
|
|
|
// This is also the next_batch/since value
|
|
|
|
|
|
|
|
let index = globals.next_count()?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut pdu_id = pdu.room_id.as_bytes().to_vec(); |
|
|
|
|
|
|
|
pdu_id.push(0xff); |
|
|
|
|
|
|
|
pdu_id.extend_from_slice(&index.to_be_bytes()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.pduid_pdu.insert(&pdu_id, &*pdu_json.to_string())?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.eventid_pduid |
|
|
|
|
|
|
|
.insert(pdu.event_id.as_bytes(), &*pdu_id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(state_key) = &pdu.state_key { |
|
|
|
|
|
|
|
self.append_state_pdu(&pdu.room_id, &pdu_id, state_key, &pdu.kind)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match pdu.kind { |
|
|
|
|
|
|
|
EventType::RoomRedaction => { |
|
|
|
|
|
|
|
if let Some(redact_id) = &pdu.redacts { |
|
|
|
|
|
|
|
// TODO: Reason
|
|
|
|
|
|
|
|
let _reason = serde_json::from_value::<Raw<redaction::RedactionEventContent>>( |
|
|
|
|
|
|
|
pdu.content, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.expect("Raw::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"Invalid redaction event content.", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
})? |
|
|
|
|
|
|
|
.reason; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.redact_pdu(&redact_id)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
EventType::RoomMember => { |
|
|
|
|
|
|
|
if let Some(state_key) = &pdu.state_key { |
|
|
|
|
|
|
|
// if the state_key fails
|
|
|
|
|
|
|
|
let target_user_id = UserId::try_from(state_key.as_str()) |
|
|
|
|
|
|
|
.expect("This state_key was previously validated"); |
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
self.update_membership( |
|
|
|
|
|
|
|
&pdu.room_id, |
|
|
|
|
|
|
|
&target_user_id, |
|
|
|
|
|
|
|
serde_json::from_value::<member::MemberEventContent>(pdu.content).map_err( |
|
|
|
|
|
|
|
|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"Invalid redaction event content.", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
)?, |
|
|
|
|
|
|
|
&pdu.sender, |
|
|
|
|
|
|
|
account_data, |
|
|
|
|
|
|
|
globals, |
|
|
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ => {} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
self.edus.room_read_set(&pdu.room_id, &pdu.sender, index)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(pdu.event_id) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Creates a new persisted data unit and adds it to a room.
|
|
|
|
|
|
|
|
pub fn build_and_append_pdu( |
|
|
|
&self, |
|
|
|
&self, |
|
|
|
pdu_builder: PduBuilder, |
|
|
|
pdu_builder: PduBuilder, |
|
|
|
globals: &super::globals::Globals, |
|
|
|
globals: &super::globals::Globals, |
|
|
|
@ -618,6 +716,7 @@ impl Rooms { |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// Is the event allowed?
|
|
|
|
// Is the event allowed?
|
|
|
|
|
|
|
|
#[allow(clippy::blocks_in_if_conditions)] |
|
|
|
if !match event_type { |
|
|
|
if !match event_type { |
|
|
|
EventType::RoomEncryption => { |
|
|
|
EventType::RoomEncryption => { |
|
|
|
// Don't allow encryption events when it's disabled
|
|
|
|
// Don't allow encryption events when it's disabled
|
|
|
|
@ -687,15 +786,15 @@ impl Rooms { |
|
|
|
|
|
|
|
|
|
|
|
let mut pdu = PduEvent { |
|
|
|
let mut pdu = PduEvent { |
|
|
|
event_id: EventId::try_from("$thiswillbefilledinlater").expect("we know this is valid"), |
|
|
|
event_id: EventId::try_from("$thiswillbefilledinlater").expect("we know this is valid"), |
|
|
|
room_id: room_id.clone(), |
|
|
|
room_id, |
|
|
|
sender: sender.clone(), |
|
|
|
sender, |
|
|
|
origin: globals.server_name().to_owned(), |
|
|
|
origin: globals.server_name().to_owned(), |
|
|
|
origin_server_ts: utils::millis_since_unix_epoch() |
|
|
|
origin_server_ts: utils::millis_since_unix_epoch() |
|
|
|
.try_into() |
|
|
|
.try_into() |
|
|
|
.expect("time is valid"), |
|
|
|
.expect("time is valid"), |
|
|
|
kind: event_type.clone(), |
|
|
|
kind: event_type, |
|
|
|
content: content.clone(), |
|
|
|
content, |
|
|
|
state_key: state_key.clone(), |
|
|
|
state_key, |
|
|
|
prev_events, |
|
|
|
prev_events, |
|
|
|
depth: depth |
|
|
|
depth: depth |
|
|
|
.try_into() |
|
|
|
.try_into() |
|
|
|
@ -704,7 +803,7 @@ impl Rooms { |
|
|
|
.into_iter() |
|
|
|
.into_iter() |
|
|
|
.map(|(_, pdu)| pdu.event_id) |
|
|
|
.map(|(_, pdu)| pdu.event_id) |
|
|
|
.collect(), |
|
|
|
.collect(), |
|
|
|
redacts: redacts.clone(), |
|
|
|
redacts, |
|
|
|
unsigned, |
|
|
|
unsigned, |
|
|
|
hashes: ruma::events::pdu::EventHash { |
|
|
|
hashes: ruma::events::pdu::EventHash { |
|
|
|
sha256: "aaa".to_owned(), |
|
|
|
sha256: "aaa".to_owned(), |
|
|
|
@ -722,105 +821,7 @@ impl Rooms { |
|
|
|
)) |
|
|
|
)) |
|
|
|
.expect("ruma's reference hashes are valid event ids"); |
|
|
|
.expect("ruma's reference hashes are valid event ids"); |
|
|
|
|
|
|
|
|
|
|
|
let mut pdu_json = serde_json::to_value(&pdu).expect("event is valid, we just created it"); |
|
|
|
self.append_pdu(pdu, globals, account_data) |
|
|
|
ruma::signatures::hash_and_sign_event( |
|
|
|
|
|
|
|
globals.server_name().as_str(), |
|
|
|
|
|
|
|
globals.keypair(), |
|
|
|
|
|
|
|
&mut pdu_json, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.expect("event is valid, we just created it"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.replace_pdu_leaves(&room_id, &pdu.event_id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Increment the last index and use that
|
|
|
|
|
|
|
|
// This is also the next_batch/since value
|
|
|
|
|
|
|
|
let index = globals.next_count()?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut pdu_id = room_id.to_string().as_bytes().to_vec(); |
|
|
|
|
|
|
|
pdu_id.push(0xff); |
|
|
|
|
|
|
|
pdu_id.extend_from_slice(&index.to_be_bytes()); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.pduid_pdu.insert(&pdu_id, &*pdu_json.to_string())?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.eventid_pduid |
|
|
|
|
|
|
|
.insert(pdu.event_id.to_string(), &*pdu_id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(state_key) = &pdu.state_key { |
|
|
|
|
|
|
|
// We call this first because our StateHash relies on the
|
|
|
|
|
|
|
|
// state before the new event
|
|
|
|
|
|
|
|
self.append_state_pdu(&room_id, &pdu_id)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let mut key = room_id.as_bytes().to_vec(); |
|
|
|
|
|
|
|
key.push(0xff); |
|
|
|
|
|
|
|
key.extend_from_slice(pdu.kind.to_string().as_bytes()); |
|
|
|
|
|
|
|
key.push(0xff); |
|
|
|
|
|
|
|
key.extend_from_slice(state_key.as_bytes()); |
|
|
|
|
|
|
|
self.roomstateid_pduid.insert(key, pdu_id.as_slice())?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
match event_type { |
|
|
|
|
|
|
|
EventType::RoomRedaction => { |
|
|
|
|
|
|
|
if let Some(redact_id) = &redacts { |
|
|
|
|
|
|
|
// TODO: Reason
|
|
|
|
|
|
|
|
let _reason = |
|
|
|
|
|
|
|
serde_json::from_value::<Raw<redaction::RedactionEventContent>>(content) |
|
|
|
|
|
|
|
.expect("Raw::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"Invalid redaction event content.", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
})? |
|
|
|
|
|
|
|
.reason; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self.redact_pdu(&redact_id)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
EventType::RoomMember => { |
|
|
|
|
|
|
|
if let Some(state_key) = state_key { |
|
|
|
|
|
|
|
// if the state_key fails
|
|
|
|
|
|
|
|
let target_user_id = UserId::try_from(state_key) |
|
|
|
|
|
|
|
.expect("This state_key was previously validated"); |
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
self.update_membership( |
|
|
|
|
|
|
|
&room_id, |
|
|
|
|
|
|
|
&target_user_id, |
|
|
|
|
|
|
|
serde_json::from_value::<member::MemberEventContent>(content).map_err( |
|
|
|
|
|
|
|
|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"Invalid redaction event content.", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
)?, |
|
|
|
|
|
|
|
&sender, |
|
|
|
|
|
|
|
account_data, |
|
|
|
|
|
|
|
globals, |
|
|
|
|
|
|
|
)?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
EventType::RoomMessage => { |
|
|
|
|
|
|
|
if let Some(body) = content.get("body").and_then(|b| b.as_str()) { |
|
|
|
|
|
|
|
for word in body |
|
|
|
|
|
|
|
.split_terminator(|c: char| !c.is_alphanumeric()) |
|
|
|
|
|
|
|
.map(str::to_lowercase) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
let mut key = room_id.to_string().as_bytes().to_vec(); |
|
|
|
|
|
|
|
key.push(0xff); |
|
|
|
|
|
|
|
key.extend_from_slice(word.as_bytes()); |
|
|
|
|
|
|
|
key.push(0xff); |
|
|
|
|
|
|
|
key.extend_from_slice(&pdu_id); |
|
|
|
|
|
|
|
self.tokenids.insert(key, &[])?; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
_ => {} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
self.edus.room_read_set(&room_id, &sender, index)?; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ok(pdu.event_id) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over all PDUs in a room.
|
|
|
|
/// Returns an iterator over all PDUs in a room.
|
|
|
|
@ -999,7 +1000,7 @@ impl Rooms { |
|
|
|
if is_ignored { |
|
|
|
if is_ignored { |
|
|
|
member_content.membership = member::MembershipState::Leave; |
|
|
|
member_content.membership = member::MembershipState::Leave; |
|
|
|
|
|
|
|
|
|
|
|
self.append_pdu( |
|
|
|
self.build_and_append_pdu( |
|
|
|
PduBuilder { |
|
|
|
PduBuilder { |
|
|
|
room_id: room_id.clone(), |
|
|
|
room_id: room_id.clone(), |
|
|
|
sender: user_id.clone(), |
|
|
|
sender: user_id.clone(), |
|
|
|
|