diff --git a/Cargo.lock b/Cargo.lock index a6d9d3a5..1671aa08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2190,7 +2190,7 @@ dependencies = [ [[package]] name = "ruma" version = "0.12.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "assign", "js_int", @@ -2201,7 +2201,6 @@ dependencies = [ "ruma-events", "ruma-federation-api", "ruma-push-gateway-api", - "ruma-server-util", "ruma-signatures", "ruma-state-res", "web-time", @@ -2210,7 +2209,7 @@ dependencies = [ [[package]] name = "ruma-appservice-api" version = "0.12.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "js_int", "ruma-common", @@ -2222,7 +2221,7 @@ dependencies = [ [[package]] name = "ruma-client-api" version = "0.20.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "as_variant", "assign", @@ -2245,7 +2244,7 @@ dependencies = [ [[package]] name = "ruma-common" version = "0.15.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "as_variant", "base64 0.22.1", @@ -2276,7 +2275,7 @@ dependencies = [ [[package]] name = "ruma-events" version = "0.30.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "as_variant", "indexmap 2.2.6", @@ -2299,10 +2298,12 @@ dependencies = [ [[package]] name = "ruma-federation-api" version = "0.11.0" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "bytes", + "headers", "http 1.1.0", + "http-auth", "httparse", "js_int", "memchr", @@ -2312,12 +2313,14 @@ dependencies = [ "ruma-events", "serde", "serde_json", + "thiserror 2.0.11", + "tracing", ] [[package]] name = "ruma-identifiers-validation" version = "0.10.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "js_int", "thiserror 2.0.11", @@ -2326,7 +2329,7 @@ dependencies = [ [[package]] name = "ruma-macros" version = "0.15.1" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "cfg-if", "proc-macro-crate", @@ -2341,7 +2344,7 @@ dependencies = [ [[package]] name = "ruma-push-gateway-api" version = "0.11.0" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "js_int", "ruma-common", @@ -2350,23 +2353,10 @@ dependencies = [ "serde_json", ] -[[package]] -name = "ruma-server-util" -version = "0.5.0" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" -dependencies = [ - "headers", - "http 1.1.0", - "http-auth", - "ruma-common", - "thiserror 2.0.11", - "tracing", -] - [[package]] name = "ruma-signatures" version = "0.17.0" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "base64 0.22.1", "ed25519-dalek", @@ -2382,7 +2372,7 @@ dependencies = [ [[package]] name = "ruma-state-res" version = "0.13.0" -source = "git+https://github.com/ruma/ruma.git#9e6099161d4ed295e694fa0d5de2b28a23840a4f" +source = "git+https://github.com/ruma/ruma.git#7c03b554c0d3e8b0a27fc0fadba36a4d636935d3" dependencies = [ "js_int", "ruma-common", diff --git a/Cargo.toml b/Cargo.toml index e5fbd41a..345fba60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,7 +160,6 @@ features = [ "push-gateway-api-c", "rand", "ring-compat", - "server-util", "state-res", "unstable-msc2448", "unstable-msc3575", diff --git a/src/api/appservice_server.rs b/src/api/appservice_server.rs index 6af31d8f..641e9532 100644 --- a/src/api/appservice_server.rs +++ b/src/api/appservice_server.rs @@ -1,8 +1,6 @@ -use crate::{services, utils, Error, Result}; +use crate::{services, utils, Error, Result, MATRIX_VERSIONS}; use bytes::BytesMut; -use ruma::api::{ - appservice::Registration, IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken, -}; +use ruma::api::{appservice::Registration, IncomingResponse, OutgoingRequest, SendAccessToken}; use std::{fmt::Debug, mem, time::Duration}; use tracing::warn; @@ -30,7 +28,7 @@ where .try_into_http_request::( &destination, SendAccessToken::IfRequired(hs_token), - &[MatrixVersion::V1_0], + MATRIX_VERSIONS, ) .unwrap() .map(|body| body.freeze()); diff --git a/src/api/client_server/appservice.rs b/src/api/client_server/appservice.rs new file mode 100644 index 00000000..1b525f7c --- /dev/null +++ b/src/api/client_server/appservice.rs @@ -0,0 +1,80 @@ +use std::time::Instant; + +use ruma::api::{ + appservice::ping::send_ping, + client::{appservice::request_ping, error::ErrorKind}, +}; + +use crate::{api::appservice_server, Error, Result, Ruma}; + +/// # `POST /_matrix/client/v1/appservice/{appserviceId}/ping` +/// +/// Allows an appservice to check whether the server and +/// appservice can connect, and how fast their connection is +pub async fn ping_appservice_route( + body: Ruma, +) -> Result { + let Ruma:: { + appservice_info, + body, + .. + } = body; + + let registration = appservice_info + .expect("Only appservices can call this endpoint") + .registration; + + if registration.id != body.appservice_id { + return Err(Error::BadRequest( + ErrorKind::forbidden(), + "Appservice ID specified in path does not match the requesting access token", + )); + } + + if registration.url.is_some() { + let start = Instant::now(); + let response = appservice_server::send_request( + registration, + send_ping::v1::Request { + transaction_id: body.transaction_id, + }, + ) + .await; + let elapsed = start.elapsed(); + + if let Err(error) = response { + Err(match error { + Error::ReqwestError { source } => { + if source.is_timeout() { + Error::BadRequest( + ErrorKind::ConnectionTimeout, + "Connection to appservice timed-out", + ) + } else if let Some(status_code) = source.status() { + Error::BadRequest( + ErrorKind::BadStatus { + status: Some(status_code), + body: Some(source.to_string()), + }, + "Ping returned error status", + ) + } else { + Error::BadRequest(ErrorKind::ConnectionFailed, "Failed to ping appservice") + } + } + Error::BadServerResponse(_) => Error::BadRequest( + ErrorKind::ConnectionFailed, + "Recieved invalid response from appservice", + ), + e => e, + }) + } else { + Ok(request_ping::v1::Response::new(elapsed)) + } + } else { + Err(Error::BadRequest( + ErrorKind::UrlNotSet, + "Appservice doesn't have a URL configured", + )) + } +} diff --git a/src/api/client_server/mod.rs b/src/api/client_server/mod.rs index a35d7a98..e5d0a5d5 100644 --- a/src/api/client_server/mod.rs +++ b/src/api/client_server/mod.rs @@ -1,5 +1,6 @@ mod account; mod alias; +mod appservice; mod backup; mod capabilities; mod config; @@ -37,6 +38,7 @@ mod well_known; pub use account::*; pub use alias::*; +pub use appservice::*; pub use backup::*; pub use capabilities::*; pub use config::*; diff --git a/src/api/ruma_wrapper/axum.rs b/src/api/ruma_wrapper/axum.rs index 2c5da21b..dd755f64 100644 --- a/src/api/ruma_wrapper/axum.rs +++ b/src/api/ruma_wrapper/axum.rs @@ -15,8 +15,10 @@ use axum_extra::{ use bytes::{BufMut, BytesMut}; use http::{Request, StatusCode}; use ruma::{ - api::{client::error::ErrorKind, AuthScheme, IncomingRequest, OutgoingResponse}, - server_util::authorization::XMatrix, + api::{ + client::error::ErrorKind, federation::authentication::XMatrix, AuthScheme, IncomingRequest, + OutgoingResponse, + }, CanonicalJsonValue, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId, UserId, }; use serde::Deserialize; @@ -110,7 +112,10 @@ where )); } } - (AuthScheme::AccessToken, Token::Appservice(info)) => { + ( + AuthScheme::AccessToken | AuthScheme::AppserviceToken, + Token::Appservice(info), + ) => { let user_id = query_params .user_id .map_or_else( @@ -144,11 +149,11 @@ where } ( AuthScheme::None - | AuthScheme::AppserviceToken + | AuthScheme::AppserviceTokenOptional | AuthScheme::AccessTokenOptional, Token::Appservice(info), ) => (None, None, None, Some(*info)), - (AuthScheme::AccessToken, Token::None) => { + (AuthScheme::AppserviceToken | AuthScheme::AccessToken, Token::None) => { return Err(Error::BadRequest( ErrorKind::MissingToken, "Missing access token.", @@ -287,7 +292,7 @@ where } ( AuthScheme::None - | AuthScheme::AppserviceToken + | AuthScheme::AppserviceTokenOptional | AuthScheme::AccessTokenOptional, Token::None, ) => (None, None, None, None), @@ -297,7 +302,10 @@ where "Only server signatures should be used on this endpoint.", )); } - (AuthScheme::AppserviceToken, Token::User(_)) => { + ( + AuthScheme::AppserviceToken | AuthScheme::AppserviceTokenOptional, + Token::User(_), + ) => { return Err(Error::BadRequest( ErrorKind::Unauthorized, "Only appservice access tokens should be used on this endpoint.", diff --git a/src/api/server_server.rs b/src/api/server_server.rs index f8768a9a..9134a634 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -7,7 +7,7 @@ use crate::{ media::FileMeta, pdu::{gen_event_id_canonical_json, PduBuilder}, }, - services, utils, Error, PduEvent, Result, Ruma, + services, utils, Error, PduEvent, Result, Ruma, MATRIX_VERSIONS, }; use axum::{response::IntoResponse, Json}; use axum_extra::headers::{CacheControl, Header}; @@ -44,8 +44,7 @@ use ruma::{ send_transaction_message, }, }, - EndpointError, IncomingResponse, MatrixVersion, OutgoingRequest, OutgoingResponse, - SendAccessToken, + EndpointError, IncomingResponse, OutgoingRequest, OutgoingResponse, SendAccessToken, }, directory::{Filter, RoomNetwork}, events::{ @@ -215,7 +214,7 @@ where .try_into_http_request::>( &actual_destination_str, SendAccessToken::IfRequired(""), - &[MatrixVersion::V1_11], + MATRIX_VERSIONS, ) .map_err(|e| { warn!( diff --git a/src/lib.rs b/src/lib.rs index 5a89f805..141d880a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,10 +13,12 @@ use std::sync::RwLock; pub use api::ruma_wrapper::{Ruma, RumaResponse}; pub use config::Config; pub use database::KeyValueDatabase; +use ruma::api::MatrixVersion; pub use service::{pdu::PduEvent, Services}; pub use utils::error::{Error, Result}; pub static SERVICES: RwLock> = RwLock::new(None); +pub const MATRIX_VERSIONS: &[MatrixVersion] = &[MatrixVersion::V1_13]; pub fn services() -> &'static Services { SERVICES diff --git a/src/main.rs b/src/main.rs index 5669cc0a..48d082cc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -279,6 +279,7 @@ async fn unrecognized_method( fn routes(config: &Config) -> Router { let router = Router::new() + .ruma_route(client_server::ping_appservice_route) .ruma_route(client_server::get_supported_versions_route) .ruma_route(client_server::get_register_available_route) .ruma_route(client_server::register_route) diff --git a/src/service/pusher/mod.rs b/src/service/pusher/mod.rs index 3ef54b6c..dede74b0 100644 --- a/src/service/pusher/mod.rs +++ b/src/service/pusher/mod.rs @@ -2,7 +2,7 @@ mod data; pub use data::Data; use ruma::{events::AnySyncTimelineEvent, push::PushConditionPowerLevelsCtx}; -use crate::{services, Error, PduEvent, Result}; +use crate::{services, Error, PduEvent, Result, MATRIX_VERSIONS}; use bytes::BytesMut; use ruma::{ api::{ @@ -11,7 +11,7 @@ use ruma::{ self, v1::{Device, Notification, NotificationCounts, NotificationPriority}, }, - IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken, + IncomingResponse, OutgoingRequest, SendAccessToken, }, events::{room::power_levels::RoomPowerLevelsEventContent, StateEventType, TimelineEventType}, push::{Action, PushConditionRoomCtx, PushFormat, Ruleset, Tweak}, @@ -58,7 +58,7 @@ impl Service { .try_into_http_request::( &destination, SendAccessToken::IfRequired(""), - &[MatrixVersion::V1_0], + MATRIX_VERSIONS, ) .map_err(|e| { warn!("Failed to find destination {}: {}", destination, e); diff --git a/src/utils/error.rs b/src/utils/error.rs index 50afd6d0..406db205 100644 --- a/src/utils/error.rs +++ b/src/utils/error.rs @@ -122,6 +122,8 @@ impl Error { LimitExceeded { .. } => StatusCode::TOO_MANY_REQUESTS, UserDeactivated => StatusCode::FORBIDDEN, TooLarge => StatusCode::PAYLOAD_TOO_LARGE, + ConnectionTimeout => StatusCode::GATEWAY_TIMEOUT, + BadStatus { .. } | ConnectionFailed => StatusCode::BAD_GATEWAY, _ => StatusCode::BAD_REQUEST, }, ),