diff --git a/Cargo.lock b/Cargo.lock index b2a47390..c5f2fa2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -432,6 +432,8 @@ dependencies = [ "tracing-flame", "tracing-opentelemetry", "tracing-subscriber", + "trust-dns-resolver", + "url", ] [[package]] @@ -3124,6 +3126,7 @@ dependencies = [ "form_urlencoded", "idna 0.5.0", "percent-encoding", + "serde", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 88383391..eb7463ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,6 +107,9 @@ futures-util = { version = "0.3.28", default-features = false } # Used for reading the configuration from conduit.toml & environment variables figment = { version = "0.10.8", features = ["env", "toml"] } +# Validating urls in config +url = { version = "2", features = ["serde"] } + tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_supported_platforms"], optional = true } async-trait = "0.1.68" diff --git a/conduit-example.toml b/conduit-example.toml index c83bce74..ef7bd182 100644 --- a/conduit-example.toml +++ b/conduit-example.toml @@ -17,7 +17,7 @@ # https://matrix.org/docs/spec/client_server/latest#get-well-known-matrix-client # and # https://matrix.org/docs/spec/server_server/r0.1.4#get-well-known-matrix-server -# for more information +# for more information, or continue below to see how conduit can do this for you. # YOU NEED TO EDIT THIS #server_name = "your.server.name" @@ -65,3 +65,10 @@ trusted_servers = ["matrix.org"] address = "127.0.0.1" # This makes sure Conduit can only be reached using the reverse proxy #address = "0.0.0.0" # If Conduit is running in a container, make sure the reverse proxy (ie. Traefik) can reach it. + +[global.well_known] +# Conduit handles the /.well-known/matrix/* endpoints, making both clients and servers try to access conduit with the host +# server_name and port 443 by default. +# If you want to override these defaults, uncomment and edit the following lines accordingly: +#server = your.server.name:443 +#client = https://your.server.name diff --git a/src/api/client_server/mod.rs b/src/api/client_server/mod.rs index 54c99aa0..afe5181e 100644 --- a/src/api/client_server/mod.rs +++ b/src/api/client_server/mod.rs @@ -32,6 +32,7 @@ mod typing; mod unversioned; mod user_directory; mod voip; +mod well_known; pub use account::*; pub use alias::*; @@ -67,6 +68,7 @@ pub use typing::*; pub use unversioned::*; pub use user_directory::*; pub use voip::*; +pub use well_known::*; pub const DEVICE_ID_LENGTH: usize = 10; pub const TOKEN_LENGTH: usize = 32; diff --git a/src/api/client_server/unversioned.rs b/src/api/client_server/unversioned.rs index 70e260ec..7706afee 100644 --- a/src/api/client_server/unversioned.rs +++ b/src/api/client_server/unversioned.rs @@ -1,9 +1,8 @@ use std::{collections::BTreeMap, iter::FromIterator}; -use axum::{response::IntoResponse, Json}; -use ruma::api::client::{discovery::get_supported_versions, error::ErrorKind}; +use ruma::api::client::discovery::get_supported_versions; -use crate::{services, Error, Result, Ruma}; +use crate::{Result, Ruma}; /// # `GET /_matrix/client/versions` /// @@ -33,18 +32,3 @@ pub async fn get_supported_versions_route( Ok(resp) } - -/// # `GET /.well-known/matrix/client` -pub async fn well_known_client_route( - _body: Ruma, -) -> Result { - let client_url = match services().globals.well_known_client() { - Some(url) => url.clone(), - None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")), - }; - - Ok(Json(serde_json::json!({ - "m.homeserver": {"base_url": client_url}, - "org.matrix.msc3575.proxy": {"url": client_url} - }))) -} diff --git a/src/api/client_server/well_known.rs b/src/api/client_server/well_known.rs new file mode 100644 index 00000000..e7bc2a4a --- /dev/null +++ b/src/api/client_server/well_known.rs @@ -0,0 +1,22 @@ +use ruma::api::client::discovery::discover_homeserver::{ + self, HomeserverInfo, SlidingSyncProxyInfo, +}; + +use crate::{services, Result, Ruma}; + +/// # `GET /.well-known/matrix/client` +/// +/// Returns the client server discovery information. +pub async fn well_known_client( + _body: Ruma, +) -> Result { + let client_url = services().globals.well_known_client(); + + Ok(discover_homeserver::Response { + homeserver: HomeserverInfo { + base_url: client_url.clone(), + }, + identity_server: None, + sliding_sync_proxy: Some(SlidingSyncProxyInfo { url: client_url }), + }) +} diff --git a/src/api/server_server.rs b/src/api/server_server.rs index b25b1313..6b86aca4 100644 --- a/src/api/server_server.rs +++ b/src/api/server_server.rs @@ -17,7 +17,10 @@ use ruma::{ backfill::get_backfill, device::get_devices::{self, v1::UserDevice}, directory::{get_public_rooms, get_public_rooms_filtered}, - discovery::{get_server_keys, get_server_version, ServerSigningKeys, VerifyKey}, + discovery::{ + discover_homeserver, get_server_keys, get_server_version, ServerSigningKeys, + VerifyKey, + }, event::{get_event, get_missing_events, get_room_state, get_room_state_ids}, keys::{claim_keys, get_keys}, membership::{create_invite, create_join_event, prepare_join_event}, @@ -1910,6 +1913,17 @@ pub async fn claim_keys_route( }) } +/// # `GET /.well-known/matrix/server` +/// +/// Returns the federation server discovery information. +pub async fn well_known_server( + _body: Ruma, +) -> Result { + Ok(discover_homeserver::Response { + server: services().globals.well_known_server(), + }) +} + #[cfg(test)] mod tests { use super::{add_port_to_hostname, get_ip_with_port, FedDest}; diff --git a/src/config/mod.rs b/src/config/mod.rs index fb1e2f31..652b3a4c 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -7,6 +7,7 @@ use std::{ use ruma::{OwnedServerName, RoomVersionId}; use serde::{de::IgnoredAny, Deserialize}; use tracing::warn; +use url::Url; mod proxy; @@ -56,7 +57,8 @@ pub struct Config { pub allow_unstable_room_versions: bool, #[serde(default = "default_default_room_version")] pub default_room_version: RoomVersionId, - pub well_known_client: Option, + #[serde(default)] + pub well_known: WellKnownConfig, #[serde(default = "false_fn")] pub allow_jaeger: bool, #[serde(default = "false_fn")] @@ -91,6 +93,12 @@ pub struct TlsConfig { pub key: String, } +#[derive(Clone, Debug, Deserialize, Default)] +pub struct WellKnownConfig { + pub client: Option, + pub server: Option, +} + const DEPRECATED_KEYS: &[&str] = &["cache_capacity"]; impl Config { @@ -111,9 +119,35 @@ impl Config { } } +impl Config { + pub fn well_known_client(&self) -> String { + if let Some(url) = &self.well_known.client { + url.to_string() + } else { + format!("https://{}", self.server_name) + } + } + + pub fn well_known_server(&self) -> OwnedServerName { + match &self.well_known.server { + Some(server_name) => server_name.to_owned(), + None => { + if self.server_name.port().is_some() { + self.server_name.to_owned() + } else { + format!("{}:443", self.server_name.host()) + .try_into() + .expect("Host from valid hostname + :443 must be valid") + } + } + } + } +} + impl fmt::Display for Config { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Prepare a list of config values to show + let well_known_server = self.well_known_server(); let lines = [ ("Server name", self.server_name.host()), ("Database backend", &self.database_backend), @@ -194,6 +228,8 @@ impl fmt::Display for Config { } &lst.join(", ") }), + ("Well-known server name", well_known_server.as_str()), + ("Well-known client URL", &self.well_known_client()), ]; let mut msg: String = "Active config values:\n\n".to_owned(); diff --git a/src/main.rs b/src/main.rs index 7beeb8ba..84467543 100644 --- a/src/main.rs +++ b/src/main.rs @@ -390,6 +390,7 @@ fn routes(config: &Config) -> Router { .ruma_route(client_server::get_relating_events_with_rel_type_route) .ruma_route(client_server::get_relating_events_route) .ruma_route(client_server::get_hierarchy_route) + .ruma_route(client_server::well_known_client) .route( "/_matrix/client/r0/rooms/:room_id/initialSync", get(initial_sync), @@ -430,10 +431,12 @@ fn routes(config: &Config) -> Router { .ruma_route(server_server::get_profile_information_route) .ruma_route(server_server::get_keys_route) .ruma_route(server_server::claim_keys_route) + .ruma_route(server_server::well_known_server) } else { router .route("/_matrix/federation/*path", any(federation_disabled)) .route("/_matrix/key/*path", any(federation_disabled)) + .route("/.well-known/matrix/server", any(federation_disabled)) } } diff --git a/src/service/globals/mod.rs b/src/service/globals/mod.rs index ab66ed45..263463d7 100644 --- a/src/service/globals/mod.rs +++ b/src/service/globals/mod.rs @@ -417,8 +417,12 @@ impl Service { r } - pub fn well_known_client(&self) -> &Option { - &self.config.well_known_client + pub fn well_known_server(&self) -> OwnedServerName { + self.config.well_known_server() + } + + pub fn well_known_client(&self) -> String { + self.config.well_known_client() } pub fn shutdown(&self) {