1
0
Fork 0
mirror of https://gitlab.com/famedly/conduit.git synced 2025-06-27 16:35:59 +00:00
conduit/src/client_server/message.rs

202 lines
6.7 KiB
Rust
Raw Normal View History

2021-07-14 07:07:08 +00:00
use crate::{database::DatabaseGuard, pdu::PduBuilder, utils, ConduitResult, Error, Ruma};
use ruma::{
api::client::{
error::ErrorKind,
r0::message::{get_message_events, send_message_event},
},
2021-04-22 11:26:20 +02:00
events::EventType,
};
2021-11-27 00:30:28 +01:00
use std::{collections::BTreeMap, convert::TryInto, sync::Arc};
2020-07-30 18:14:47 +02:00
#[cfg(feature = "conduit_bin")]
use rocket::{get, put};
2021-08-31 19:14:37 +02:00
/// # `PUT /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}`
///
/// Send a message event into the room.
///
/// - Is a NOOP if the txn id was already used before and returns the same event id again
/// - The only requirement for the content is that it has to be valid json
/// - Tries to send the event into the room, auth rules will determine if it is allowed
2020-07-30 18:14:47 +02:00
#[cfg_attr(
feature = "conduit_bin",
put("/_matrix/client/r0/rooms/<_>/send/<_>/<_>", data = "<body>")
)]
2021-02-28 12:41:03 +01:00
#[tracing::instrument(skip(db, body))]
2020-09-14 20:23:19 +02:00
pub async fn send_message_event_route(
2021-07-14 07:07:08 +00:00
db: DatabaseGuard,
2020-09-08 17:32:03 +02:00
body: Ruma<send_message_event::Request<'_>>,
2020-08-12 23:32:39 +02:00
) -> ConduitResult<send_message_event::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
let sender_device = body.sender_device.as_deref();
2020-08-25 13:24:38 +02:00
2021-08-03 11:10:58 +02:00
let mutex_state = Arc::clone(
2021-07-13 15:44:25 +02:00
db.globals
2021-08-03 11:10:58 +02:00
.roomid_mutex_state
2021-07-13 15:44:25 +02:00
.write()
.unwrap()
.entry(body.room_id.clone())
.or_default(),
);
2021-08-03 11:10:58 +02:00
let state_lock = mutex_state.lock().await;
2021-07-13 15:44:25 +02:00
// Forbid m.room.encrypted if encryption is disabled
if &body.event_type == "m.room.encrypted" && !db.globals.allow_encryption() {
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"Encryption has been disabled",
));
}
2020-08-25 13:24:38 +02:00
// Check if this is a new transaction id
if let Some(response) =
db.transaction_ids
.existing_txnid(sender_user, sender_device, &body.txn_id)?
2020-08-25 13:24:38 +02:00
{
// The client might have sent a txnid of the /sendToDevice endpoint
// This txnid has no response associated with it
if response.is_empty() {
return Err(Error::BadRequest(
ErrorKind::InvalidParam,
"Tried to use txn id already used for an incompatible endpoint.",
));
}
2021-11-27 00:30:28 +01:00
let event_id = utils::string_from_bytes(&response)
.map_err(|_| Error::bad_database("Invalid txnid bytes in database."))?
.try_into()
.map_err(|_| Error::bad_database("Invalid event id in txnid data."))?;
2020-08-25 13:24:38 +02:00
return Ok(send_message_event::Response { event_id }.into());
}
2020-07-30 18:14:47 +02:00
let mut unsigned = BTreeMap::new();
2020-07-30 18:14:47 +02:00
unsigned.insert("transaction_id".to_owned(), body.txn_id.clone().into());
2020-10-05 22:19:22 +02:00
let event_id = db.rooms.build_and_append_pdu(
PduBuilder {
2021-04-22 11:26:20 +02:00
event_type: EventType::from(&body.event_type),
content: serde_json::from_str(body.body.body.json().get())
.map_err(|_| Error::BadRequest(ErrorKind::BadJson, "Invalid JSON body."))?,
2020-10-05 22:19:22 +02:00
unsigned: Some(unsigned),
state_key: None,
redacts: None,
},
sender_user,
2020-10-05 22:19:22 +02:00
&body.room_id,
2021-01-15 11:05:57 -05:00
&db,
2021-08-03 11:10:58 +02:00
&state_lock,
2020-10-05 22:19:22 +02:00
)?;
2020-07-30 18:14:47 +02:00
db.transaction_ids.add_txnid(
sender_user,
sender_device,
&body.txn_id,
event_id.as_bytes(),
)?;
2021-08-03 11:10:58 +02:00
drop(state_lock);
2021-07-13 15:44:25 +02:00
db.flush()?;
Ok(send_message_event::Response::new(event_id).into())
2020-07-30 18:14:47 +02:00
}
2021-08-31 19:14:37 +02:00
/// # `GET /_matrix/client/r0/rooms/{roomId}/messages`
///
/// Allows paginating through room history.
///
/// - Only works if the user is joined (TODO: always allow, but only show events where the user was
/// joined, depending on history_visibility)
2020-07-30 18:14:47 +02:00
#[cfg_attr(
feature = "conduit_bin",
get("/_matrix/client/r0/rooms/<_>/messages", data = "<body>")
)]
2021-02-28 12:41:03 +01:00
#[tracing::instrument(skip(db, body))]
pub async fn get_message_events_route(
2021-07-14 07:07:08 +00:00
db: DatabaseGuard,
2020-09-08 17:32:03 +02:00
body: Ruma<get_message_events::Request<'_>>,
2020-07-30 18:14:47 +02:00
) -> ConduitResult<get_message_events::Response> {
let sender_user = body.sender_user.as_ref().expect("user is authenticated");
2020-07-30 18:14:47 +02:00
if !db.rooms.is_joined(sender_user, &body.room_id)? {
2020-07-30 18:14:47 +02:00
return Err(Error::BadRequest(
ErrorKind::Forbidden,
"You don't have permission to view this room.",
));
}
let from = body
.from
.clone()
.parse()
.map_err(|_| Error::BadRequest(ErrorKind::InvalidParam, "Invalid `from` value."))?;
let to = body.to.as_ref().map(|t| t.parse());
// Use limit or else 10
let limit = body.limit.try_into().map_or(10_usize, |l: u32| l as usize);
2020-07-30 18:14:47 +02:00
match body.dir {
get_message_events::Direction::Forward => {
let events_after: Vec<_> = db
2020-07-30 18:14:47 +02:00
.rooms
.pdus_after(sender_user, &body.room_id, from)?
2020-07-30 18:14:47 +02:00
.take(limit)
.filter_map(|r| r.ok()) // Filter out buggy events
.filter_map(|(pdu_id, pdu)| {
db.rooms
.pdu_count(&pdu_id)
.map(|pdu_count| (pdu_count, pdu))
.ok()
})
2020-07-30 18:14:47 +02:00
.take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to`
.collect();
2020-07-30 18:14:47 +02:00
let end_token = events_after.last().map(|(count, _)| count.to_string());
let events_after: Vec<_> = events_after
2020-07-30 18:14:47 +02:00
.into_iter()
.map(|(_, pdu)| pdu.to_room_event())
.collect();
2020-07-30 18:14:47 +02:00
let mut resp = get_message_events::Response::new();
2020-09-08 17:32:03 +02:00
resp.start = Some(body.from.to_owned());
resp.end = end_token;
resp.chunk = events_after;
resp.state = Vec::new();
Ok(resp.into())
2020-07-30 18:14:47 +02:00
}
get_message_events::Direction::Backward => {
let events_before: Vec<_> = db
2020-07-30 18:14:47 +02:00
.rooms
.pdus_until(sender_user, &body.room_id, from)?
2020-07-30 18:14:47 +02:00
.take(limit)
.filter_map(|r| r.ok()) // Filter out buggy events
.filter_map(|(pdu_id, pdu)| {
db.rooms
.pdu_count(&pdu_id)
.map(|pdu_count| (pdu_count, pdu))
.ok()
})
2020-07-30 18:14:47 +02:00
.take_while(|&(k, _)| Some(Ok(k)) != to) // Stop at `to`
.collect();
2020-07-30 18:14:47 +02:00
let start_token = events_before.last().map(|(count, _)| count.to_string());
let events_before: Vec<_> = events_before
2020-07-30 18:14:47 +02:00
.into_iter()
.map(|(_, pdu)| pdu.to_room_event())
.collect();
2020-07-30 18:14:47 +02:00
let mut resp = get_message_events::Response::new();
2020-09-08 17:32:03 +02:00
resp.start = Some(body.from.to_owned());
resp.end = start_token;
resp.chunk = events_before;
resp.state = Vec::new();
Ok(resp.into())
2020-07-30 18:14:47 +02:00
}
}
}