mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-11-13 04:06:54 +00:00
121 lines
3.3 KiB
Rust
121 lines
3.3 KiB
Rust
use axum::extract::State;
|
|
use conduwuit::{Err, Event, Result, debug_info, err, matrix::pdu::PduEvent, warn};
|
|
use futures::FutureExt;
|
|
use ruma::{
|
|
api::federation::membership::create_knock_event, events::room::member::MembershipState,
|
|
};
|
|
|
|
use crate::{Ruma, server::utils::validate_any_membership_event};
|
|
|
|
/// # `PUT /_matrix/federation/v1/send_knock/{roomId}/{eventId}`
|
|
///
|
|
/// Submits a signed knock event.
|
|
pub(crate) async fn create_knock_event_v1_route(
|
|
State(services): State<crate::State>,
|
|
body: Ruma<create_knock_event::v1::Request>,
|
|
) -> Result<create_knock_event::v1::Response> {
|
|
if services
|
|
.moderation
|
|
.is_remote_server_forbidden(&body.identity)
|
|
{
|
|
warn!(
|
|
"Server {} tried knocking room ID {} who has a server name that is globally \
|
|
forbidden. Rejecting.",
|
|
body.identity, &body.room_id,
|
|
);
|
|
return Err!(Request(Forbidden("Federation denied with {}", body.identity)));
|
|
}
|
|
|
|
if !services.rooms.metadata.exists(&body.room_id).await {
|
|
return Err!(Request(NotFound("Room is unknown to this server.")));
|
|
}
|
|
|
|
if !services
|
|
.rooms
|
|
.state_cache
|
|
.server_in_room(services.globals.server_name(), &body.room_id)
|
|
.await
|
|
{
|
|
debug_info!(
|
|
origin = body.identity.as_str(),
|
|
room_id = %body.room_id,
|
|
"Refusing to serve send_knock for room we aren't participating in"
|
|
);
|
|
return Err!(Request(NotFound("This server is not participating in that room.")));
|
|
}
|
|
|
|
// ACL check origin server
|
|
services
|
|
.rooms
|
|
.event_handler
|
|
.acl_check(&body.identity, &body.room_id)
|
|
.await?;
|
|
|
|
let room_version = services.rooms.state.get_room_version(&body.room_id).await?;
|
|
let create_event = services
|
|
.rooms
|
|
.state_accessor
|
|
.get_room_create_event(&body.room_id)
|
|
.await;
|
|
let room_version_rules = room_version.rules().unwrap();
|
|
|
|
if !room_version_rules.authorization.knocking {
|
|
return Err!(Request(Forbidden("Room version does not support knocking.")));
|
|
}
|
|
|
|
let (mut event, target_membership, sender, target) = validate_any_membership_event(
|
|
&services,
|
|
&body.pdu,
|
|
&room_version_rules,
|
|
create_event.event_id().to_owned(),
|
|
body.room_id.clone(),
|
|
body.event_id.clone(),
|
|
)
|
|
.await?;
|
|
|
|
if target_membership != MembershipState::Knock {
|
|
return Err!(Request(InvalidParam("Invalid membership (expected `knock`)")));
|
|
}
|
|
if sender.server_name() != body.identity {
|
|
return Err!(Request(InvalidParam("Sender belongs to a different server")));
|
|
}
|
|
if sender != target {
|
|
return Err!(Request(InvalidParam("Sender does not match state key")));
|
|
}
|
|
|
|
event.insert("event_id".to_owned(), body.event_id.as_str().into());
|
|
|
|
let pdu = PduEvent::from_id_val(&body.event_id, event.clone())
|
|
.map_err(|e| err!(Request(InvalidParam("Invalid knock event PDU: {e}"))))?;
|
|
|
|
let mutex_lock = services
|
|
.rooms
|
|
.event_handler
|
|
.mutex_federation
|
|
.lock(body.room_id.as_str())
|
|
.await;
|
|
|
|
let pdu_id = services
|
|
.rooms
|
|
.event_handler
|
|
.handle_incoming_pdu(sender.server_name(), &body.room_id, &body.event_id, event, false)
|
|
.boxed()
|
|
.await?
|
|
.ok_or_else(|| err!(Request(InvalidParam("Could not accept as timeline event."))))?;
|
|
|
|
drop(mutex_lock);
|
|
|
|
services
|
|
.sending
|
|
.send_pdu_room(&body.room_id, &pdu_id)
|
|
.await?;
|
|
|
|
let knock_room_state = services
|
|
.rooms
|
|
.state
|
|
.summary_stripped(&pdu, &body.room_id, &sender, true)
|
|
.await;
|
|
|
|
Ok(create_knock_event::v1::Response::new(knock_room_state))
|
|
}
|