2024-07-03 00:06:00 +00:00
|
|
|
use std::{collections::BTreeMap, net::IpAddr, time::Instant};
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-07-15 10:37:16 +00:00
|
|
|
use axum::extract::State;
|
2024-06-10 21:04:51 -04:00
|
|
|
use axum_client_ip::InsecureClientIp;
|
2024-12-15 00:05:47 -05:00
|
|
|
use conduwuit::{
|
2025-01-26 10:43:53 +00:00
|
|
|
debug, debug_warn, err, error,
|
|
|
|
result::LogErr,
|
|
|
|
trace,
|
|
|
|
utils::{
|
|
|
|
stream::{automatic_width, BroadbandExt, TryBroadbandExt},
|
|
|
|
IterStream, ReadyExt,
|
|
|
|
},
|
|
|
|
warn, Err, Error, Result,
|
2024-12-15 00:05:47 -05:00
|
|
|
};
|
2025-01-26 10:43:53 +00:00
|
|
|
use futures::{FutureExt, Stream, StreamExt, TryFutureExt, TryStreamExt};
|
|
|
|
use itertools::Itertools;
|
2024-06-05 04:32:58 +00:00
|
|
|
use ruma::{
|
|
|
|
api::{
|
|
|
|
client::error::ErrorKind,
|
|
|
|
federation::transactions::{
|
2024-07-03 00:06:00 +00:00
|
|
|
edu::{
|
2024-12-15 00:05:47 -05:00
|
|
|
DeviceListUpdateContent, DirectDeviceContent, Edu, PresenceContent,
|
|
|
|
ReceiptContent, SigningKeyUpdateContent, TypingContent,
|
2024-07-03 00:06:00 +00:00
|
|
|
},
|
2024-06-05 04:32:58 +00:00
|
|
|
send_transaction_message,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
events::receipt::{ReceiptEvent, ReceiptEventContent, ReceiptType},
|
|
|
|
to_device::DeviceIdOrAllDevices,
|
2025-01-26 10:43:53 +00:00
|
|
|
CanonicalJsonObject, OwnedEventId, OwnedRoomId, ServerName,
|
2024-06-05 04:32:58 +00:00
|
|
|
};
|
2024-10-22 05:30:28 +00:00
|
|
|
use service::{
|
|
|
|
sending::{EDU_LIMIT, PDU_LIMIT},
|
|
|
|
Services,
|
|
|
|
};
|
2024-06-05 04:32:58 +00:00
|
|
|
|
|
|
|
use crate::{
|
|
|
|
utils::{self},
|
2024-08-08 17:18:30 +00:00
|
|
|
Ruma,
|
2024-06-05 04:32:58 +00:00
|
|
|
};
|
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
type ResolvedMap = BTreeMap<OwnedEventId, Result>;
|
|
|
|
type Pdu = (OwnedRoomId, OwnedEventId, CanonicalJsonObject);
|
2024-07-03 00:06:00 +00:00
|
|
|
|
2024-06-05 04:32:58 +00:00
|
|
|
/// # `PUT /_matrix/federation/v1/send/{txnId}`
|
|
|
|
///
|
|
|
|
/// Push EDUs and PDUs to this server.
|
2025-01-14 05:20:42 +00:00
|
|
|
#[tracing::instrument(
|
|
|
|
name = "send",
|
|
|
|
level = "debug",
|
|
|
|
skip_all,
|
|
|
|
fields(
|
|
|
|
%client,
|
|
|
|
origin = body.origin().as_str()
|
|
|
|
),
|
|
|
|
)]
|
2024-06-05 04:32:58 +00:00
|
|
|
pub(crate) async fn send_transaction_message_route(
|
2024-12-15 00:05:47 -05:00
|
|
|
State(services): State<crate::State>,
|
|
|
|
InsecureClientIp(client): InsecureClientIp,
|
2024-07-15 10:37:16 +00:00
|
|
|
body: Ruma<send_transaction_message::v1::Request>,
|
2024-06-05 04:32:58 +00:00
|
|
|
) -> Result<send_transaction_message::v1::Response> {
|
2024-10-24 12:03:56 +00:00
|
|
|
if body.origin() != body.body.origin {
|
2024-07-15 04:19:43 +00:00
|
|
|
return Err!(Request(Forbidden(
|
|
|
|
"Not allowed to send transactions on behalf of other servers"
|
|
|
|
)));
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|
|
|
|
|
2024-08-08 17:18:30 +00:00
|
|
|
if body.pdus.len() > PDU_LIMIT {
|
|
|
|
return Err!(Request(Forbidden(
|
|
|
|
"Not allowed to send more than {PDU_LIMIT} PDUs in one transaction"
|
|
|
|
)));
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|
|
|
|
|
2024-08-08 17:18:30 +00:00
|
|
|
if body.edus.len() > EDU_LIMIT {
|
|
|
|
return Err!(Request(Forbidden(
|
|
|
|
"Not allowed to send more than {EDU_LIMIT} EDUs in one transaction"
|
|
|
|
)));
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let txn_start_time = Instant::now();
|
2024-07-03 00:06:00 +00:00
|
|
|
trace!(
|
2025-01-26 10:43:53 +00:00
|
|
|
pdus = body.pdus.len(),
|
|
|
|
edus = body.edus.len(),
|
2024-07-03 00:06:00 +00:00
|
|
|
elapsed = ?txn_start_time.elapsed(),
|
|
|
|
id = ?body.transaction_id,
|
2024-10-24 12:03:56 +00:00
|
|
|
origin =?body.origin(),
|
2024-07-03 00:06:00 +00:00
|
|
|
"Starting txn",
|
|
|
|
);
|
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
let pdus = body
|
|
|
|
.pdus
|
|
|
|
.iter()
|
|
|
|
.stream()
|
|
|
|
.broad_then(|pdu| services.rooms.event_handler.parse_incoming_pdu(pdu))
|
|
|
|
.inspect_err(|e| debug_warn!("Could not parse PDU: {e}"))
|
|
|
|
.ready_filter_map(Result::ok);
|
2024-12-28 00:57:02 +00:00
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
let edus = body
|
|
|
|
.edus
|
|
|
|
.iter()
|
|
|
|
.map(|edu| edu.json().get())
|
|
|
|
.map(serde_json::from_str)
|
|
|
|
.filter_map(Result::ok)
|
|
|
|
.stream();
|
|
|
|
|
|
|
|
let results = handle(&services, &client, body.origin(), txn_start_time, pdus, edus).await?;
|
2024-07-03 00:06:00 +00:00
|
|
|
|
|
|
|
debug!(
|
2025-01-26 10:43:53 +00:00
|
|
|
pdus = body.pdus.len(),
|
|
|
|
edus = body.edus.len(),
|
2024-07-03 00:06:00 +00:00
|
|
|
elapsed = ?txn_start_time.elapsed(),
|
|
|
|
id = ?body.transaction_id,
|
2024-10-24 12:03:56 +00:00
|
|
|
origin =?body.origin(),
|
2024-07-03 00:06:00 +00:00
|
|
|
"Finished txn",
|
|
|
|
);
|
2025-01-26 10:43:53 +00:00
|
|
|
for (id, result) in &results {
|
|
|
|
if let Err(e) = result {
|
|
|
|
if matches!(e, Error::BadRequest(ErrorKind::NotFound, _)) {
|
|
|
|
warn!("Incoming PDU failed {id}: {e:?}");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-07-03 00:06:00 +00:00
|
|
|
|
|
|
|
Ok(send_transaction_message::v1::Response {
|
2025-01-26 10:43:53 +00:00
|
|
|
pdus: results
|
2024-07-03 00:06:00 +00:00
|
|
|
.into_iter()
|
2024-10-04 17:07:31 +00:00
|
|
|
.map(|(e, r)| (e, r.map_err(error::sanitized_message)))
|
2024-07-03 00:06:00 +00:00
|
|
|
.collect(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
async fn handle(
|
2024-12-15 00:05:47 -05:00
|
|
|
services: &Services,
|
2025-01-26 10:43:53 +00:00
|
|
|
client: &IpAddr,
|
2024-12-15 00:05:47 -05:00
|
|
|
origin: &ServerName,
|
2025-01-26 10:43:53 +00:00
|
|
|
started: Instant,
|
|
|
|
pdus: impl Stream<Item = Pdu> + Send,
|
|
|
|
edus: impl Stream<Item = Edu> + Send,
|
2024-10-22 07:15:28 +00:00
|
|
|
) -> Result<ResolvedMap> {
|
2025-01-26 10:43:53 +00:00
|
|
|
// group pdus by room
|
|
|
|
let pdus = pdus
|
|
|
|
.collect()
|
|
|
|
.map(|mut pdus: Vec<_>| {
|
|
|
|
pdus.sort_by(|(room_a, ..), (room_b, ..)| room_a.cmp(room_b));
|
|
|
|
pdus.into_iter()
|
|
|
|
.into_grouping_map_by(|(room_id, ..)| room_id.clone())
|
|
|
|
.collect()
|
|
|
|
})
|
|
|
|
.await;
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
// we can evaluate rooms concurrently
|
|
|
|
let results: ResolvedMap = pdus
|
|
|
|
.into_iter()
|
|
|
|
.try_stream()
|
|
|
|
.broad_and_then(|(room_id, pdus)| {
|
|
|
|
handle_room(services, client, origin, started, room_id, pdus)
|
|
|
|
.map_ok(Vec::into_iter)
|
|
|
|
.map_ok(IterStream::try_stream)
|
|
|
|
})
|
|
|
|
.try_flatten()
|
|
|
|
.try_collect()
|
|
|
|
.boxed()
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// evaluate edus after pdus, at least for now.
|
|
|
|
edus.for_each_concurrent(automatic_width(), |edu| handle_edu(services, client, origin, edu))
|
|
|
|
.boxed()
|
|
|
|
.await;
|
|
|
|
|
|
|
|
Ok(results)
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_room(
|
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
txn_start_time: Instant,
|
|
|
|
room_id: OwnedRoomId,
|
|
|
|
pdus: Vec<Pdu>,
|
|
|
|
) -> Result<Vec<(OwnedEventId, Result)>> {
|
|
|
|
let _room_lock = services
|
|
|
|
.rooms
|
|
|
|
.event_handler
|
|
|
|
.mutex_federation
|
|
|
|
.lock(&room_id)
|
|
|
|
.await;
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
let mut results = Vec::with_capacity(pdus.len());
|
|
|
|
for (_, event_id, value) in pdus {
|
2024-10-22 07:15:28 +00:00
|
|
|
services.server.check_running()?;
|
2024-06-05 04:32:58 +00:00
|
|
|
let pdu_start_time = Instant::now();
|
2024-10-22 07:07:42 +00:00
|
|
|
let result = services
|
|
|
|
.rooms
|
|
|
|
.event_handler
|
|
|
|
.handle_incoming_pdu(origin, &room_id, &event_id, value, true)
|
|
|
|
.await
|
|
|
|
.map(|_| ());
|
2024-06-05 04:32:58 +00:00
|
|
|
|
|
|
|
debug!(
|
|
|
|
pdu_elapsed = ?pdu_start_time.elapsed(),
|
|
|
|
txn_elapsed = ?txn_start_time.elapsed(),
|
|
|
|
"Finished PDU {event_id}",
|
|
|
|
);
|
2024-10-22 07:07:42 +00:00
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
results.push((event_id, result));
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
Ok(results)
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
2025-01-26 10:43:53 +00:00
|
|
|
async fn handle_edu(services: &Services, client: &IpAddr, origin: &ServerName, edu: Edu) {
|
|
|
|
match edu {
|
|
|
|
| Edu::Presence(presence) => {
|
|
|
|
handle_edu_presence(services, client, origin, presence).await;
|
|
|
|
},
|
|
|
|
| Edu::Receipt(receipt) => handle_edu_receipt(services, client, origin, receipt).await,
|
|
|
|
| Edu::Typing(typing) => handle_edu_typing(services, client, origin, typing).await,
|
|
|
|
| Edu::DeviceListUpdate(content) => {
|
|
|
|
handle_edu_device_list_update(services, client, origin, content).await;
|
|
|
|
},
|
|
|
|
| Edu::DirectToDevice(content) => {
|
|
|
|
handle_edu_direct_to_device(services, client, origin, content).await;
|
|
|
|
},
|
|
|
|
| Edu::SigningKeyUpdate(content) => {
|
|
|
|
handle_edu_signing_key_update(services, client, origin, content).await;
|
|
|
|
},
|
|
|
|
| Edu::_Custom(ref _custom) => {
|
|
|
|
debug_warn!(?edu, "received custom/unknown EDU");
|
|
|
|
},
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-12-15 00:05:47 -05:00
|
|
|
async fn handle_edu_presence(
|
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
presence: PresenceContent,
|
|
|
|
) {
|
2024-07-15 10:37:16 +00:00
|
|
|
if !services.globals.allow_incoming_presence() {
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-07-03 00:06:00 +00:00
|
|
|
for update in presence.push {
|
|
|
|
if update.user_id.server_name() != origin {
|
|
|
|
debug_warn!(
|
|
|
|
%update.user_id, %origin,
|
|
|
|
"received presence EDU for user not belonging to origin"
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-08-08 17:18:30 +00:00
|
|
|
services
|
|
|
|
.presence
|
|
|
|
.set_presence(
|
|
|
|
&update.user_id,
|
|
|
|
&update.presence,
|
|
|
|
Some(update.currently_active),
|
|
|
|
Some(update.last_active_ago),
|
|
|
|
update.status_msg.clone(),
|
|
|
|
)
|
|
|
|
.await
|
|
|
|
.log_err()
|
|
|
|
.ok();
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-12-15 00:05:47 -05:00
|
|
|
async fn handle_edu_receipt(
|
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
receipt: ReceiptContent,
|
|
|
|
) {
|
2024-07-15 10:37:16 +00:00
|
|
|
if !services.globals.allow_incoming_read_receipts() {
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-07-03 00:06:00 +00:00
|
|
|
for (room_id, room_updates) in receipt.receipts {
|
2024-07-15 10:37:16 +00:00
|
|
|
if services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.event_handler
|
|
|
|
.acl_check(origin, &room_id)
|
2024-08-08 17:18:30 +00:00
|
|
|
.await
|
2024-07-03 00:06:00 +00:00
|
|
|
.is_err()
|
|
|
|
{
|
|
|
|
debug_warn!(
|
|
|
|
%origin, %room_id,
|
|
|
|
"received read receipt EDU from ACL'd server"
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-07-03 00:06:00 +00:00
|
|
|
for (user_id, user_updates) in room_updates.read {
|
|
|
|
if user_id.server_name() != origin {
|
|
|
|
debug_warn!(
|
|
|
|
%user_id, %origin,
|
|
|
|
"received read receipt EDU for user not belonging to origin"
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-07-15 10:37:16 +00:00
|
|
|
if services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.state_cache
|
|
|
|
.room_members(&room_id)
|
2024-08-08 17:18:30 +00:00
|
|
|
.ready_any(|member| member.server_name() == user_id.server_name())
|
|
|
|
.await
|
2024-07-03 00:06:00 +00:00
|
|
|
{
|
|
|
|
for event_id in &user_updates.event_ids {
|
2024-12-15 00:05:47 -05:00
|
|
|
let user_receipts =
|
|
|
|
BTreeMap::from([(user_id.clone(), user_updates.data.clone())]);
|
2024-07-03 00:06:00 +00:00
|
|
|
let receipts = BTreeMap::from([(ReceiptType::Read, user_receipts)]);
|
|
|
|
let receipt_content = BTreeMap::from([(event_id.to_owned(), receipts)]);
|
|
|
|
let event = ReceiptEvent {
|
|
|
|
content: ReceiptEventContent(receipt_content),
|
|
|
|
room_id: room_id.clone(),
|
|
|
|
};
|
2024-06-05 04:32:58 +00:00
|
|
|
|
2024-07-15 10:37:16 +00:00
|
|
|
services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.read_receipt
|
2024-12-18 11:26:18 -05:00
|
|
|
.readreceipt_update(&user_id, &room_id, &event)
|
2024-08-08 17:18:30 +00:00
|
|
|
.await;
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|
2024-07-03 00:06:00 +00:00
|
|
|
} else {
|
|
|
|
debug_warn!(
|
|
|
|
%user_id, %room_id, %origin,
|
|
|
|
"received read receipt EDU from server who does not have a member in the room",
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-15 00:05:47 -05:00
|
|
|
async fn handle_edu_typing(
|
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
typing: TypingContent,
|
|
|
|
) {
|
2025-01-24 07:02:56 +00:00
|
|
|
if !services.server.config.allow_incoming_typing {
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if typing.user_id.server_name() != origin {
|
|
|
|
debug_warn!(
|
|
|
|
%typing.user_id, %origin,
|
|
|
|
"received typing EDU for user not belonging to origin"
|
|
|
|
);
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:37:16 +00:00
|
|
|
if services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.event_handler
|
|
|
|
.acl_check(typing.user_id.server_name(), &typing.room_id)
|
2024-08-08 17:18:30 +00:00
|
|
|
.await
|
2024-07-03 00:06:00 +00:00
|
|
|
.is_err()
|
|
|
|
{
|
|
|
|
debug_warn!(
|
|
|
|
%typing.user_id, %typing.room_id, %origin,
|
|
|
|
"received typing EDU for ACL'd user's server"
|
|
|
|
);
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
2024-07-15 10:37:16 +00:00
|
|
|
if services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.state_cache
|
2024-08-08 17:18:30 +00:00
|
|
|
.is_joined(&typing.user_id, &typing.room_id)
|
|
|
|
.await
|
2024-07-03 00:06:00 +00:00
|
|
|
{
|
|
|
|
if typing.typing {
|
|
|
|
let timeout = utils::millis_since_unix_epoch().saturating_add(
|
2024-07-15 10:37:16 +00:00
|
|
|
services
|
2025-01-24 07:02:56 +00:00
|
|
|
.server
|
2024-07-03 00:06:00 +00:00
|
|
|
.config
|
|
|
|
.typing_federation_timeout_s
|
|
|
|
.saturating_mul(1000),
|
|
|
|
);
|
2024-07-15 10:37:16 +00:00
|
|
|
services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.typing
|
|
|
|
.typing_add(&typing.user_id, &typing.room_id, timeout)
|
2024-08-08 17:18:30 +00:00
|
|
|
.await
|
|
|
|
.log_err()
|
|
|
|
.ok();
|
2024-07-03 00:06:00 +00:00
|
|
|
} else {
|
2024-07-15 10:37:16 +00:00
|
|
|
services
|
2024-07-03 00:06:00 +00:00
|
|
|
.rooms
|
|
|
|
.typing
|
|
|
|
.typing_remove(&typing.user_id, &typing.room_id)
|
2024-08-08 17:18:30 +00:00
|
|
|
.await
|
|
|
|
.log_err()
|
|
|
|
.ok();
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
debug_warn!(
|
|
|
|
%typing.user_id, %typing.room_id, %origin,
|
|
|
|
"received typing EDU for user not in room"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_edu_device_list_update(
|
2024-12-15 00:05:47 -05:00
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
content: DeviceListUpdateContent,
|
2024-08-08 17:18:30 +00:00
|
|
|
) {
|
2024-12-15 00:05:47 -05:00
|
|
|
let DeviceListUpdateContent { user_id, .. } = content;
|
2024-07-03 00:06:00 +00:00
|
|
|
|
|
|
|
if user_id.server_name() != origin {
|
|
|
|
debug_warn!(
|
|
|
|
%user_id, %origin,
|
|
|
|
"received device list update EDU for user not belonging to origin"
|
|
|
|
);
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
2024-08-08 17:18:30 +00:00
|
|
|
services.users.mark_device_key_update(&user_id).await;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_edu_direct_to_device(
|
2024-12-15 00:05:47 -05:00
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
content: DirectDeviceContent,
|
2024-08-08 17:18:30 +00:00
|
|
|
) {
|
2024-12-15 00:05:47 -05:00
|
|
|
let DirectDeviceContent { sender, ev_type, message_id, messages } = content;
|
2024-07-03 00:06:00 +00:00
|
|
|
|
|
|
|
if sender.server_name() != origin {
|
|
|
|
debug_warn!(
|
|
|
|
%sender, %origin,
|
|
|
|
"received direct to device EDU for user not belonging to origin"
|
|
|
|
);
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check if this is a new transaction id
|
2024-07-15 10:37:16 +00:00
|
|
|
if services
|
2024-07-03 00:06:00 +00:00
|
|
|
.transaction_ids
|
2024-08-08 17:18:30 +00:00
|
|
|
.existing_txnid(&sender, None, &message_id)
|
|
|
|
.await
|
|
|
|
.is_ok()
|
2024-07-03 00:06:00 +00:00
|
|
|
{
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (target_user_id, map) in &messages {
|
|
|
|
for (target_device_id_maybe, event) in map {
|
2024-12-15 00:05:47 -05:00
|
|
|
let Ok(event) = event.deserialize_as().map_err(|e| {
|
|
|
|
err!(Request(InvalidParam(error!("To-Device event is invalid: {e}"))))
|
|
|
|
}) else {
|
2024-08-08 17:18:30 +00:00
|
|
|
continue;
|
|
|
|
};
|
|
|
|
|
|
|
|
let ev_type = ev_type.to_string();
|
2024-07-03 00:06:00 +00:00
|
|
|
match target_device_id_maybe {
|
2024-12-15 00:05:47 -05:00
|
|
|
| DeviceIdOrAllDevices::DeviceId(target_device_id) => {
|
2024-08-08 17:18:30 +00:00
|
|
|
services
|
|
|
|
.users
|
2024-12-15 00:05:47 -05:00
|
|
|
.add_to_device_event(
|
|
|
|
&sender,
|
|
|
|
target_user_id,
|
|
|
|
target_device_id,
|
|
|
|
&ev_type,
|
|
|
|
event,
|
|
|
|
)
|
2024-08-08 17:18:30 +00:00
|
|
|
.await;
|
2024-07-03 00:06:00 +00:00
|
|
|
},
|
|
|
|
|
2024-12-15 00:05:47 -05:00
|
|
|
| DeviceIdOrAllDevices::AllDevices => {
|
2024-08-08 17:18:30 +00:00
|
|
|
let (sender, ev_type, event) = (&sender, &ev_type, &event);
|
|
|
|
services
|
|
|
|
.users
|
|
|
|
.all_device_ids(target_user_id)
|
|
|
|
.for_each(|target_device_id| {
|
|
|
|
services.users.add_to_device_event(
|
|
|
|
sender,
|
|
|
|
target_user_id,
|
|
|
|
target_device_id,
|
|
|
|
ev_type,
|
|
|
|
event.clone(),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.await;
|
2024-07-03 00:06:00 +00:00
|
|
|
},
|
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-03 00:06:00 +00:00
|
|
|
// Save transaction id with empty data
|
2024-07-15 10:37:16 +00:00
|
|
|
services
|
2024-07-03 00:06:00 +00:00
|
|
|
.transaction_ids
|
2024-08-08 17:18:30 +00:00
|
|
|
.add_txnid(&sender, None, &message_id, &[]);
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn handle_edu_signing_key_update(
|
2024-12-15 00:05:47 -05:00
|
|
|
services: &Services,
|
|
|
|
_client: &IpAddr,
|
|
|
|
origin: &ServerName,
|
|
|
|
content: SigningKeyUpdateContent,
|
2024-08-08 17:18:30 +00:00
|
|
|
) {
|
2024-12-15 00:05:47 -05:00
|
|
|
let SigningKeyUpdateContent { user_id, master_key, self_signing_key } = content;
|
2024-07-03 00:06:00 +00:00
|
|
|
|
|
|
|
if user_id.server_name() != origin {
|
|
|
|
debug_warn!(
|
|
|
|
%user_id, %origin,
|
|
|
|
"received signing key update EDU from server that does not belong to user's server"
|
|
|
|
);
|
2024-08-08 17:18:30 +00:00
|
|
|
return;
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(master_key) = master_key {
|
2024-07-15 10:37:16 +00:00
|
|
|
services
|
2024-07-03 00:06:00 +00:00
|
|
|
.users
|
2024-08-08 17:18:30 +00:00
|
|
|
.add_cross_signing_keys(&user_id, &master_key, &self_signing_key, &None, true)
|
|
|
|
.await
|
|
|
|
.log_err()
|
|
|
|
.ok();
|
2024-07-03 00:06:00 +00:00
|
|
|
}
|
2024-06-05 04:32:58 +00:00
|
|
|
}
|