|
|
|
@ -5,6 +5,7 @@ pub use edus::RoomEdus; |
|
|
|
use crate::{utils, Error, PduEvent, Result}; |
|
|
|
use crate::{utils, Error, PduEvent, Result}; |
|
|
|
use log::error; |
|
|
|
use log::error; |
|
|
|
use ruma::{ |
|
|
|
use ruma::{ |
|
|
|
|
|
|
|
api::client::error::ErrorKind, |
|
|
|
events::{ |
|
|
|
events::{ |
|
|
|
room::{ |
|
|
|
room::{ |
|
|
|
join_rules, member, |
|
|
|
join_rules, member, |
|
|
|
@ -61,30 +62,34 @@ impl Rooms { |
|
|
|
.roomstateid_pdu |
|
|
|
.roomstateid_pdu |
|
|
|
.scan_prefix(&room_id.to_string().as_bytes()) |
|
|
|
.scan_prefix(&room_id.to_string().as_bytes()) |
|
|
|
.values() |
|
|
|
.values() |
|
|
|
.map(|value| Ok::<_, Error>(serde_json::from_slice::<PduEvent>(&value?)?)) |
|
|
|
.map(|value| { |
|
|
|
|
|
|
|
Ok::<_, Error>( |
|
|
|
|
|
|
|
serde_json::from_slice::<PduEvent>(&value?) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid PDU in db."))?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}) |
|
|
|
{ |
|
|
|
{ |
|
|
|
let pdu = pdu?; |
|
|
|
let pdu = pdu?; |
|
|
|
hashmap.insert( |
|
|
|
let state_key = pdu.state_key.clone().ok_or_else(|| { |
|
|
|
( |
|
|
|
Error::bad_database("Room state contains event without state_key.") |
|
|
|
pdu.kind.clone(), |
|
|
|
})?; |
|
|
|
pdu.state_key |
|
|
|
hashmap.insert((pdu.kind.clone(), state_key), pdu); |
|
|
|
.clone() |
|
|
|
|
|
|
|
.expect("state events have a state key"), |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
pdu, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
Ok(hashmap) |
|
|
|
Ok(hashmap) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns the `count` of this pdu's id.
|
|
|
|
/// Returns the `count` of this pdu's id.
|
|
|
|
pub fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<u64>> { |
|
|
|
pub fn get_pdu_count(&self, event_id: &EventId) -> Result<Option<u64>> { |
|
|
|
Ok(self |
|
|
|
self.eventid_pduid |
|
|
|
.eventid_pduid |
|
|
|
|
|
|
|
.get(event_id.to_string().as_bytes())? |
|
|
|
.get(event_id.to_string().as_bytes())? |
|
|
|
.map(|pdu_id| { |
|
|
|
.map_or(Ok(None), |pdu_id| { |
|
|
|
utils::u64_from_bytes(&pdu_id[pdu_id.len() - mem::size_of::<u64>()..pdu_id.len()]) |
|
|
|
Ok(Some( |
|
|
|
})) |
|
|
|
utils::u64_from_bytes( |
|
|
|
|
|
|
|
&pdu_id[pdu_id.len() - mem::size_of::<u64>()..pdu_id.len()], |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("PDU has invalid count bytes."))?, |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns the json of a pdu.
|
|
|
|
/// Returns the json of a pdu.
|
|
|
|
@ -92,11 +97,12 @@ impl Rooms { |
|
|
|
self.eventid_pduid |
|
|
|
self.eventid_pduid |
|
|
|
.get(event_id.to_string().as_bytes())? |
|
|
|
.get(event_id.to_string().as_bytes())? |
|
|
|
.map_or(Ok(None), |pdu_id| { |
|
|
|
.map_or(Ok(None), |pdu_id| { |
|
|
|
Ok(Some(serde_json::from_slice( |
|
|
|
Ok(Some( |
|
|
|
&self.pduid_pdu.get(pdu_id)?.ok_or(Error::BadDatabase( |
|
|
|
serde_json::from_slice(&self.pduid_pdu.get(pdu_id)?.ok_or_else(|| { |
|
|
|
"eventid_pduid points to nonexistent pdu", |
|
|
|
Error::bad_database("eventid_pduid points to nonexistent pdu.") |
|
|
|
))?, |
|
|
|
})?) |
|
|
|
)?)) |
|
|
|
.map_err(|_| Error::bad_database("Invalid PDU in db."))?, |
|
|
|
|
|
|
|
)) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -112,28 +118,37 @@ impl Rooms { |
|
|
|
self.eventid_pduid |
|
|
|
self.eventid_pduid |
|
|
|
.get(event_id.to_string().as_bytes())? |
|
|
|
.get(event_id.to_string().as_bytes())? |
|
|
|
.map_or(Ok(None), |pdu_id| { |
|
|
|
.map_or(Ok(None), |pdu_id| { |
|
|
|
Ok(Some(serde_json::from_slice( |
|
|
|
Ok(Some( |
|
|
|
&self.pduid_pdu.get(pdu_id)?.ok_or(Error::BadDatabase( |
|
|
|
serde_json::from_slice(&self.pduid_pdu.get(pdu_id)?.ok_or_else(|| { |
|
|
|
"eventid_pduid points to nonexistent pdu", |
|
|
|
Error::bad_database("eventid_pduid points to nonexistent pdu.") |
|
|
|
))?, |
|
|
|
})?) |
|
|
|
)?)) |
|
|
|
.map_err(|_| Error::bad_database("Invalid PDU in db."))?, |
|
|
|
|
|
|
|
)) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
/// Returns the pdu.
|
|
|
|
/// Returns the pdu.
|
|
|
|
pub fn get_pdu_from_id(&self, pdu_id: &IVec) -> Result<Option<PduEvent>> { |
|
|
|
pub fn get_pdu_from_id(&self, pdu_id: &IVec) -> Result<Option<PduEvent>> { |
|
|
|
self.pduid_pdu |
|
|
|
self.pduid_pdu.get(pdu_id)?.map_or(Ok(None), |pdu| { |
|
|
|
.get(pdu_id)? |
|
|
|
Ok(Some( |
|
|
|
.map_or(Ok(None), |pdu| Ok(Some(serde_json::from_slice(&pdu)?))) |
|
|
|
serde_json::from_slice(&pdu) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid PDU in db."))?, |
|
|
|
|
|
|
|
)) |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns the pdu.
|
|
|
|
/// Removes a pdu and creates a new one with the same id.
|
|
|
|
pub fn replace_pdu(&self, pdu_id: &IVec, pdu: &PduEvent) -> Result<()> { |
|
|
|
fn replace_pdu(&self, pdu_id: &IVec, pdu: &PduEvent) -> Result<()> { |
|
|
|
if self.pduid_pdu.get(&pdu_id)?.is_some() { |
|
|
|
if self.pduid_pdu.get(&pdu_id)?.is_some() { |
|
|
|
self.pduid_pdu |
|
|
|
self.pduid_pdu.insert( |
|
|
|
.insert(&pdu_id, &*serde_json::to_string(pdu)?)?; |
|
|
|
&pdu_id, |
|
|
|
|
|
|
|
&*serde_json::to_string(pdu).expect("PduEvent::to_string always works"), |
|
|
|
|
|
|
|
)?; |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(Error::BadRequest("pdu does not exist")) |
|
|
|
Err(Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::NotFound, |
|
|
|
|
|
|
|
"PDU does not exist.", |
|
|
|
|
|
|
|
)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -148,7 +163,14 @@ impl Rooms { |
|
|
|
.roomid_pduleaves |
|
|
|
.roomid_pduleaves |
|
|
|
.scan_prefix(prefix) |
|
|
|
.scan_prefix(prefix) |
|
|
|
.values() |
|
|
|
.values() |
|
|
|
.map(|bytes| Ok::<_, Error>(EventId::try_from(&*utils::string_from_bytes(&bytes?)?)?)) |
|
|
|
.map(|bytes| { |
|
|
|
|
|
|
|
Ok::<_, Error>( |
|
|
|
|
|
|
|
EventId::try_from(utils::string_from_bytes(&bytes?).map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("EventID in roomid_pduleaves is invalid unicode.") |
|
|
|
|
|
|
|
})?) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("EventId in roomid_pduleaves is invalid."))?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}) |
|
|
|
{ |
|
|
|
{ |
|
|
|
events.push(event?); |
|
|
|
events.push(event?); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -214,12 +236,13 @@ impl Rooms { |
|
|
|
Ok( |
|
|
|
Ok( |
|
|
|
serde_json::from_value::<EventJson<PowerLevelsEventContent>>( |
|
|
|
serde_json::from_value::<EventJson<PowerLevelsEventContent>>( |
|
|
|
power_levels.content.clone(), |
|
|
|
power_levels.content.clone(), |
|
|
|
)? |
|
|
|
) |
|
|
|
.deserialize()?, |
|
|
|
.expect("EventJson::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid PowerLevels event in db."))?, |
|
|
|
) |
|
|
|
) |
|
|
|
}, |
|
|
|
}, |
|
|
|
)?; |
|
|
|
)?; |
|
|
|
{ |
|
|
|
|
|
|
|
let sender_membership = self |
|
|
|
let sender_membership = self |
|
|
|
.room_state(&room_id)? |
|
|
|
.room_state(&room_id)? |
|
|
|
.get(&(EventType::RoomMember, sender.to_string())) |
|
|
|
.get(&(EventType::RoomMember, sender.to_string())) |
|
|
|
@ -227,8 +250,10 @@ impl Rooms { |
|
|
|
Ok( |
|
|
|
Ok( |
|
|
|
serde_json::from_value::<EventJson<member::MemberEventContent>>( |
|
|
|
serde_json::from_value::<EventJson<member::MemberEventContent>>( |
|
|
|
pdu.content.clone(), |
|
|
|
pdu.content.clone(), |
|
|
|
)? |
|
|
|
) |
|
|
|
.deserialize()? |
|
|
|
.expect("EventJson::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid Member event in db."))? |
|
|
|
.membership, |
|
|
|
.membership, |
|
|
|
) |
|
|
|
) |
|
|
|
})?; |
|
|
|
})?; |
|
|
|
@ -247,23 +272,34 @@ impl Rooms { |
|
|
|
|
|
|
|
|
|
|
|
if !match event_type { |
|
|
|
if !match event_type { |
|
|
|
EventType::RoomMember => { |
|
|
|
EventType::RoomMember => { |
|
|
|
let target_user_id = UserId::try_from(&**state_key)?; |
|
|
|
let target_user_id = UserId::try_from(&**state_key).map_err(|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"State key of member event does not contain user id.", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
|
|
let current_membership = self |
|
|
|
let current_membership = self |
|
|
|
.room_state(&room_id)? |
|
|
|
.room_state(&room_id)? |
|
|
|
.get(&(EventType::RoomMember, target_user_id.to_string())) |
|
|
|
.get(&(EventType::RoomMember, target_user_id.to_string())) |
|
|
|
.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { |
|
|
|
.map_or(Ok::<_, Error>(member::MembershipState::Leave), |pdu| { |
|
|
|
Ok(serde_json::from_value::< |
|
|
|
Ok( |
|
|
|
EventJson<member::MemberEventContent>, |
|
|
|
serde_json::from_value::<EventJson<member::MemberEventContent>>( |
|
|
|
>(pdu.content.clone())? |
|
|
|
pdu.content.clone(), |
|
|
|
.deserialize()? |
|
|
|
) |
|
|
|
.membership) |
|
|
|
.expect("EventJson::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid Member event in db."))? |
|
|
|
|
|
|
|
.membership, |
|
|
|
|
|
|
|
) |
|
|
|
})?; |
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
|
|
let target_membership = serde_json::from_value::< |
|
|
|
let target_membership = serde_json::from_value::< |
|
|
|
EventJson<member::MemberEventContent>, |
|
|
|
EventJson<member::MemberEventContent>, |
|
|
|
>(content.clone())? |
|
|
|
>(content.clone()) |
|
|
|
.deserialize()? |
|
|
|
.expect("EventJson::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Invalid Member event in db."))? |
|
|
|
.membership; |
|
|
|
.membership; |
|
|
|
|
|
|
|
|
|
|
|
let target_power = power_levels.users.get(&target_user_id).map_or_else( |
|
|
|
let target_power = power_levels.users.get(&target_user_id).map_or_else( |
|
|
|
@ -278,26 +314,31 @@ impl Rooms { |
|
|
|
Some, |
|
|
|
Some, |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
let join_rules = self |
|
|
|
let join_rules = |
|
|
|
.room_state(&room_id)? |
|
|
|
self.room_state(&room_id)? |
|
|
|
.get(&(EventType::RoomJoinRules, "".to_owned())) |
|
|
|
.get(&(EventType::RoomJoinRules, "".to_owned())) |
|
|
|
.map_or(join_rules::JoinRule::Public, |pdu| { |
|
|
|
.map_or(Ok::<_, Error>(join_rules::JoinRule::Public), |pdu| { |
|
|
|
serde_json::from_value::< |
|
|
|
Ok(serde_json::from_value::< |
|
|
|
EventJson<join_rules::JoinRulesEventContent>, |
|
|
|
EventJson<join_rules::JoinRulesEventContent>, |
|
|
|
>(pdu.content.clone()) |
|
|
|
>(pdu.content.clone()) |
|
|
|
.unwrap() |
|
|
|
.expect("EventJson::from_value always works.") |
|
|
|
.deserialize() |
|
|
|
.deserialize() |
|
|
|
.unwrap() |
|
|
|
.map_err(|_| { |
|
|
|
.join_rule |
|
|
|
Error::bad_database("Database contains invalid JoinRules event") |
|
|
|
}); |
|
|
|
})? |
|
|
|
|
|
|
|
.join_rule) |
|
|
|
|
|
|
|
})?; |
|
|
|
|
|
|
|
|
|
|
|
let authorized = if target_membership == member::MembershipState::Join { |
|
|
|
let authorized = if target_membership == member::MembershipState::Join { |
|
|
|
let mut prev_events = prev_events.iter(); |
|
|
|
let mut prev_events = prev_events.iter(); |
|
|
|
let prev_event = self |
|
|
|
let prev_event = self |
|
|
|
.get_pdu(prev_events.next().ok_or(Error::BadRequest( |
|
|
|
.get_pdu(prev_events.next().ok_or(Error::BadRequest( |
|
|
|
"membership can't be the first event", |
|
|
|
ErrorKind::Unknown, |
|
|
|
|
|
|
|
"Membership can't be the first event", |
|
|
|
))?)? |
|
|
|
))?)? |
|
|
|
.ok_or(Error::BadDatabase("pdu leave points to valid event"))?; |
|
|
|
.ok_or_else(|| { |
|
|
|
|
|
|
|
Error::bad_database("PDU leaf points to invalid event!") |
|
|
|
|
|
|
|
})?; |
|
|
|
if prev_event.kind == EventType::RoomCreate |
|
|
|
if prev_event.kind == EventType::RoomCreate |
|
|
|
&& prev_event.prev_events.is_empty() |
|
|
|
&& prev_event.prev_events.is_empty() |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -313,15 +354,20 @@ impl Rooms { |
|
|
|
|| join_rules == join_rules::JoinRule::Public |
|
|
|
|| join_rules == join_rules::JoinRule::Public |
|
|
|
} |
|
|
|
} |
|
|
|
} else if target_membership == member::MembershipState::Invite { |
|
|
|
} else if target_membership == member::MembershipState::Invite { |
|
|
|
if let Some(third_party_invite_json) = content.get("third_party_invite") |
|
|
|
if let Some(third_party_invite_json) = content.get("third_party_invite") { |
|
|
|
{ |
|
|
|
|
|
|
|
if current_membership == member::MembershipState::Ban { |
|
|
|
if current_membership == member::MembershipState::Ban { |
|
|
|
false |
|
|
|
false |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
let _third_party_invite = |
|
|
|
let _third_party_invite = |
|
|
|
serde_json::from_value::<member::ThirdPartyInvite>( |
|
|
|
serde_json::from_value::<member::ThirdPartyInvite>( |
|
|
|
third_party_invite_json.clone(), |
|
|
|
third_party_invite_json.clone(), |
|
|
|
)?; |
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"ThirdPartyInvite is invalid", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
})?; |
|
|
|
todo!("handle third party invites"); |
|
|
|
todo!("handle third party invites"); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if sender_membership != member::MembershipState::Join |
|
|
|
} else if sender_membership != member::MembershipState::Join |
|
|
|
@ -377,11 +423,18 @@ impl Rooms { |
|
|
|
} { |
|
|
|
} { |
|
|
|
error!("Unauthorized"); |
|
|
|
error!("Unauthorized"); |
|
|
|
// Not authorized
|
|
|
|
// Not authorized
|
|
|
|
return Err(Error::BadRequest("event not authorized")); |
|
|
|
return Err(Error::BadRequest( |
|
|
|
} |
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
|
|
|
"Event is not authorized", |
|
|
|
|
|
|
|
)); |
|
|
|
} |
|
|
|
} |
|
|
|
} else if !self.is_joined(&sender, &room_id)? { |
|
|
|
} else if !self.is_joined(&sender, &room_id)? { |
|
|
|
return Err(Error::BadRequest("event not authorized")); |
|
|
|
// TODO: auth rules apply to all events, not only those with a state key
|
|
|
|
|
|
|
|
error!("Unauthorized"); |
|
|
|
|
|
|
|
return Err(Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::Forbidden, |
|
|
|
|
|
|
|
"Event is not authorized", |
|
|
|
|
|
|
|
)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Our depth is the maximum depth of prev_events + 1
|
|
|
|
// Our depth is the maximum depth of prev_events + 1
|
|
|
|
@ -410,14 +463,14 @@ impl Rooms { |
|
|
|
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("this only fails many years in the future"), |
|
|
|
.expect("time is valid"), |
|
|
|
kind: event_type.clone(), |
|
|
|
kind: event_type.clone(), |
|
|
|
content: content.clone(), |
|
|
|
content: content.clone(), |
|
|
|
state_key, |
|
|
|
state_key, |
|
|
|
prev_events, |
|
|
|
prev_events, |
|
|
|
depth: depth |
|
|
|
depth: depth |
|
|
|
.try_into() |
|
|
|
.try_into() |
|
|
|
.expect("depth can overflow and should be deprecated..."), |
|
|
|
.map_err(|_| Error::bad_database("Depth is invalid"))?, |
|
|
|
auth_events: Vec::new(), |
|
|
|
auth_events: Vec::new(), |
|
|
|
redacts: redacts.clone(), |
|
|
|
redacts: redacts.clone(), |
|
|
|
unsigned, |
|
|
|
unsigned, |
|
|
|
@ -430,18 +483,20 @@ impl Rooms { |
|
|
|
// Generate event id
|
|
|
|
// Generate event id
|
|
|
|
pdu.event_id = EventId::try_from(&*format!( |
|
|
|
pdu.event_id = EventId::try_from(&*format!( |
|
|
|
"${}", |
|
|
|
"${}", |
|
|
|
ruma::signatures::reference_hash(&serde_json::to_value(&pdu)?) |
|
|
|
ruma::signatures::reference_hash( |
|
|
|
|
|
|
|
&serde_json::to_value(&pdu).expect("event is valid, we just created it") |
|
|
|
|
|
|
|
) |
|
|
|
.expect("ruma can calculate reference hashes") |
|
|
|
.expect("ruma can calculate reference hashes") |
|
|
|
)) |
|
|
|
)) |
|
|
|
.expect("ruma's reference hashes are correct"); |
|
|
|
.expect("ruma's reference hashes are valid event ids"); |
|
|
|
|
|
|
|
|
|
|
|
let mut pdu_json = serde_json::to_value(&pdu)?; |
|
|
|
let mut pdu_json = serde_json::to_value(&pdu).expect("event is valid, we just created it"); |
|
|
|
ruma::signatures::hash_and_sign_event( |
|
|
|
ruma::signatures::hash_and_sign_event( |
|
|
|
globals.server_name(), |
|
|
|
globals.server_name(), |
|
|
|
globals.keypair(), |
|
|
|
globals.keypair(), |
|
|
|
&mut pdu_json, |
|
|
|
&mut pdu_json, |
|
|
|
) |
|
|
|
) |
|
|
|
.expect("our new event can be hashed and signed"); |
|
|
|
.expect("event is valid, we just created it"); |
|
|
|
|
|
|
|
|
|
|
|
self.replace_pdu_leaves(&room_id, &pdu.event_id)?; |
|
|
|
self.replace_pdu_leaves(&room_id, &pdu.event_id)?; |
|
|
|
|
|
|
|
|
|
|
|
@ -473,8 +528,15 @@ impl Rooms { |
|
|
|
// TODO: Reason
|
|
|
|
// TODO: Reason
|
|
|
|
let _reason = serde_json::from_value::< |
|
|
|
let _reason = serde_json::from_value::< |
|
|
|
EventJson<redaction::RedactionEventContent>, |
|
|
|
EventJson<redaction::RedactionEventContent>, |
|
|
|
>(content)? |
|
|
|
>(content) |
|
|
|
.deserialize()? |
|
|
|
.expect("EventJson::from_value always works.") |
|
|
|
|
|
|
|
.deserialize() |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::InvalidParam, |
|
|
|
|
|
|
|
"Invalid redaction event content.", |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
})? |
|
|
|
.reason; |
|
|
|
.reason; |
|
|
|
|
|
|
|
|
|
|
|
self.redact_pdu(&redact_id)?; |
|
|
|
self.redact_pdu(&redact_id)?; |
|
|
|
@ -528,7 +590,10 @@ impl Rooms { |
|
|
|
}) |
|
|
|
}) |
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
.take_while(move |(k, _)| k.starts_with(&prefix)) |
|
|
|
.take_while(move |(k, _)| k.starts_with(&prefix)) |
|
|
|
.map(|(_, v)| Ok(serde_json::from_slice(&v)?))) |
|
|
|
.map(|(_, v)| { |
|
|
|
|
|
|
|
Ok(serde_json::from_slice(&v) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("PDU in db is invalid."))?) |
|
|
|
|
|
|
|
})) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over all events in a room that happened before the event with id
|
|
|
|
/// Returns an iterator over all events in a room that happened before the event with id
|
|
|
|
@ -552,7 +617,10 @@ impl Rooms { |
|
|
|
.rev() |
|
|
|
.rev() |
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
.take_while(move |(k, _)| k.starts_with(&prefix)) |
|
|
|
.take_while(move |(k, _)| k.starts_with(&prefix)) |
|
|
|
.map(|(_, v)| Ok(serde_json::from_slice(&v)?)) |
|
|
|
.map(|(_, v)| { |
|
|
|
|
|
|
|
Ok(serde_json::from_slice(&v) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("PDU in db is invalid."))?) |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over all events in a room that happened after the event with id
|
|
|
|
/// Returns an iterator over all events in a room that happened after the event with id
|
|
|
|
@ -575,7 +643,10 @@ impl Rooms { |
|
|
|
.range(current..) |
|
|
|
.range(current..) |
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
.filter_map(|r| r.ok()) |
|
|
|
.take_while(move |(k, _)| k.starts_with(&prefix)) |
|
|
|
.take_while(move |(k, _)| k.starts_with(&prefix)) |
|
|
|
.map(|(_, v)| Ok(serde_json::from_slice(&v)?)) |
|
|
|
.map(|(_, v)| { |
|
|
|
|
|
|
|
Ok(serde_json::from_slice(&v) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("PDU in db is invalid."))?) |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Replace a PDU with the redacted form.
|
|
|
|
/// Replace a PDU with the redacted form.
|
|
|
|
@ -583,12 +654,15 @@ impl Rooms { |
|
|
|
if let Some(pdu_id) = self.get_pdu_id(event_id)? { |
|
|
|
if let Some(pdu_id) = self.get_pdu_id(event_id)? { |
|
|
|
let mut pdu = self |
|
|
|
let mut pdu = self |
|
|
|
.get_pdu_from_id(&pdu_id)? |
|
|
|
.get_pdu_from_id(&pdu_id)? |
|
|
|
.ok_or(Error::BadDatabase("pduid points to invalid pdu"))?; |
|
|
|
.ok_or_else(|| Error::bad_database("PDU ID points to invalid PDU."))?; |
|
|
|
pdu.redact(); |
|
|
|
pdu.redact()?; |
|
|
|
self.replace_pdu(&pdu_id, &pdu)?; |
|
|
|
self.replace_pdu(&pdu_id, &pdu)?; |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
Err(Error::BadRequest("eventid does not exist")) |
|
|
|
Err(Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::NotFound, |
|
|
|
|
|
|
|
"Event ID does not exist.", |
|
|
|
|
|
|
|
)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -664,7 +738,10 @@ impl Rooms { |
|
|
|
let room_id = self |
|
|
|
let room_id = self |
|
|
|
.alias_roomid |
|
|
|
.alias_roomid |
|
|
|
.remove(alias.alias())? |
|
|
|
.remove(alias.alias())? |
|
|
|
.ok_or(Error::BadRequest("Alias does not exist"))?; |
|
|
|
.ok_or(Error::BadRequest( |
|
|
|
|
|
|
|
ErrorKind::NotFound, |
|
|
|
|
|
|
|
"Alias does not exist.", |
|
|
|
|
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
for key in self.aliasid_alias.scan_prefix(room_id).keys() { |
|
|
|
for key in self.aliasid_alias.scan_prefix(room_id).keys() { |
|
|
|
self.aliasid_alias.remove(key?)?; |
|
|
|
self.aliasid_alias.remove(key?)?; |
|
|
|
@ -678,7 +755,12 @@ impl Rooms { |
|
|
|
self.alias_roomid |
|
|
|
self.alias_roomid |
|
|
|
.get(alias.alias())? |
|
|
|
.get(alias.alias())? |
|
|
|
.map_or(Ok(None), |bytes| { |
|
|
|
.map_or(Ok(None), |bytes| { |
|
|
|
Ok(Some(RoomId::try_from(utils::string_from_bytes(&bytes)?)?)) |
|
|
|
Ok(Some( |
|
|
|
|
|
|
|
RoomId::try_from(utils::string_from_bytes(&bytes).map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("Room ID in alias_roomid is invalid unicode.") |
|
|
|
|
|
|
|
})?) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Room ID in alias_roomid is invalid."))?, |
|
|
|
|
|
|
|
)) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -689,7 +771,10 @@ impl Rooms { |
|
|
|
self.aliasid_alias |
|
|
|
self.aliasid_alias |
|
|
|
.scan_prefix(prefix) |
|
|
|
.scan_prefix(prefix) |
|
|
|
.values() |
|
|
|
.values() |
|
|
|
.map(|bytes| Ok(RoomAliasId::try_from(utils::string_from_bytes(&bytes?)?)?)) |
|
|
|
.map(|bytes| { |
|
|
|
|
|
|
|
Ok(serde_json::from_slice(&bytes?) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Alias in aliasid_alias is invalid."))?) |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn set_public(&self, room_id: &RoomId, public: bool) -> Result<()> { |
|
|
|
pub fn set_public(&self, room_id: &RoomId, public: bool) -> Result<()> { |
|
|
|
@ -707,54 +792,76 @@ impl Rooms { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn public_rooms(&self) -> impl Iterator<Item = Result<RoomId>> { |
|
|
|
pub fn public_rooms(&self) -> impl Iterator<Item = Result<RoomId>> { |
|
|
|
self.publicroomids |
|
|
|
self.publicroomids.iter().keys().map(|bytes| { |
|
|
|
.iter() |
|
|
|
Ok( |
|
|
|
.keys() |
|
|
|
RoomId::try_from(utils::string_from_bytes(&bytes?).map_err(|_| { |
|
|
|
.map(|bytes| Ok(RoomId::try_from(utils::string_from_bytes(&bytes?)?)?)) |
|
|
|
Error::bad_database("Room ID in publicroomids is invalid unicode.") |
|
|
|
|
|
|
|
})?) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Room ID in publicroomids is invalid."))?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over all rooms a user joined.
|
|
|
|
/// Returns an iterator over all joined members of a room.
|
|
|
|
pub fn room_members(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> { |
|
|
|
pub fn room_members(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> { |
|
|
|
self.roomuserid_joined |
|
|
|
self.roomuserid_joined |
|
|
|
.scan_prefix(room_id.to_string()) |
|
|
|
.scan_prefix(room_id.to_string()) |
|
|
|
.values() |
|
|
|
.keys() |
|
|
|
.map(|key| { |
|
|
|
.map(|key| { |
|
|
|
Ok(UserId::try_from(&*utils::string_from_bytes( |
|
|
|
Ok(UserId::try_from( |
|
|
|
|
|
|
|
utils::string_from_bytes( |
|
|
|
&key? |
|
|
|
&key? |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.next() |
|
|
|
.next() |
|
|
|
.ok_or(Error::BadDatabase("userroomid is invalid"))?, |
|
|
|
.expect("rsplit always returns an element"), |
|
|
|
)?)?) |
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("User ID in roomuserid_joined is invalid unicode.") |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("User ID in roomuserid_joined is invalid."))?) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over all rooms a user joined.
|
|
|
|
/// Returns an iterator over all invited members of a room.
|
|
|
|
pub fn room_members_invited(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> { |
|
|
|
pub fn room_members_invited(&self, room_id: &RoomId) -> impl Iterator<Item = Result<UserId>> { |
|
|
|
self.roomuserid_invited |
|
|
|
self.roomuserid_invited |
|
|
|
.scan_prefix(room_id.to_string()) |
|
|
|
.scan_prefix(room_id.to_string()) |
|
|
|
.keys() |
|
|
|
.keys() |
|
|
|
.map(|key| { |
|
|
|
.map(|key| { |
|
|
|
Ok(UserId::try_from(&*utils::string_from_bytes( |
|
|
|
Ok(UserId::try_from( |
|
|
|
|
|
|
|
utils::string_from_bytes( |
|
|
|
&key? |
|
|
|
&key? |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.next() |
|
|
|
.next() |
|
|
|
.ok_or(Error::BadDatabase("userroomid is invalid"))?, |
|
|
|
.expect("rsplit always returns an element"), |
|
|
|
)?)?) |
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("User ID in roomuserid_invited is invalid unicode.") |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("User ID in roomuserid_invited is invalid."))?) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns an iterator over all rooms a user joined.
|
|
|
|
/// Returns an iterator over all left members of a room.
|
|
|
|
pub fn rooms_joined(&self, user_id: &UserId) -> impl Iterator<Item = Result<RoomId>> { |
|
|
|
pub fn rooms_joined(&self, user_id: &UserId) -> impl Iterator<Item = Result<RoomId>> { |
|
|
|
self.userroomid_joined |
|
|
|
self.userroomid_joined |
|
|
|
.scan_prefix(user_id.to_string()) |
|
|
|
.scan_prefix(user_id.to_string()) |
|
|
|
.keys() |
|
|
|
.keys() |
|
|
|
.map(|key| { |
|
|
|
.map(|key| { |
|
|
|
Ok(RoomId::try_from(&*utils::string_from_bytes( |
|
|
|
Ok(RoomId::try_from( |
|
|
|
|
|
|
|
utils::string_from_bytes( |
|
|
|
&key? |
|
|
|
&key? |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.next() |
|
|
|
.next() |
|
|
|
.ok_or(Error::BadDatabase("userroomid is invalid"))?, |
|
|
|
.expect("rsplit always returns an element"), |
|
|
|
)?)?) |
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("Room ID in userroomid_joined is invalid unicode.") |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Room ID in userroomid_joined is invalid."))?) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -764,12 +871,18 @@ impl Rooms { |
|
|
|
.scan_prefix(&user_id.to_string()) |
|
|
|
.scan_prefix(&user_id.to_string()) |
|
|
|
.keys() |
|
|
|
.keys() |
|
|
|
.map(|key| { |
|
|
|
.map(|key| { |
|
|
|
Ok(RoomId::try_from(&*utils::string_from_bytes( |
|
|
|
Ok(RoomId::try_from( |
|
|
|
|
|
|
|
utils::string_from_bytes( |
|
|
|
&key? |
|
|
|
&key? |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.next() |
|
|
|
.next() |
|
|
|
.ok_or(Error::BadDatabase("userroomid is invalid"))?, |
|
|
|
.expect("rsplit always returns an element"), |
|
|
|
)?)?) |
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("Room ID in userroomid_invited is invalid unicode.") |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Room ID in userroomid_invited is invalid."))?) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -779,12 +892,18 @@ impl Rooms { |
|
|
|
.scan_prefix(&user_id.to_string()) |
|
|
|
.scan_prefix(&user_id.to_string()) |
|
|
|
.keys() |
|
|
|
.keys() |
|
|
|
.map(|key| { |
|
|
|
.map(|key| { |
|
|
|
Ok(RoomId::try_from(&*utils::string_from_bytes( |
|
|
|
Ok(RoomId::try_from( |
|
|
|
|
|
|
|
utils::string_from_bytes( |
|
|
|
&key? |
|
|
|
&key? |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.rsplit(|&b| b == 0xff) |
|
|
|
.next() |
|
|
|
.next() |
|
|
|
.ok_or(Error::BadDatabase("userroomid is invalid"))?, |
|
|
|
.expect("rsplit always returns an element"), |
|
|
|
)?)?) |
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| { |
|
|
|
|
|
|
|
Error::bad_database("Room ID in userroomid_left is invalid unicode.") |
|
|
|
|
|
|
|
})?, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.map_err(|_| Error::bad_database("Room ID in userroomid_left is invalid."))?) |
|
|
|
}) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|