feat: support hosting .well-known from Conduit

Co-authored-by: Matthias Ahouansou <matthias@ahouansou.cz>
This commit is contained in:
Jakub Kubík 2024-05-02 09:26:43 +01:00 committed by Matthias Ahouansou
parent b4a60c3f9a
commit c1f695653b
No known key found for this signature in database
10 changed files with 101 additions and 23 deletions

3
Cargo.lock generated
View file

@ -432,6 +432,8 @@ dependencies = [
"tracing-flame", "tracing-flame",
"tracing-opentelemetry", "tracing-opentelemetry",
"tracing-subscriber", "tracing-subscriber",
"trust-dns-resolver",
"url",
] ]
[[package]] [[package]]
@ -3124,6 +3126,7 @@ dependencies = [
"form_urlencoded", "form_urlencoded",
"idna 0.5.0", "idna 0.5.0",
"percent-encoding", "percent-encoding",
"serde",
] ]
[[package]] [[package]]

View file

@ -107,6 +107,9 @@ futures-util = { version = "0.3.28", default-features = false }
# Used for reading the configuration from conduit.toml & environment variables # Used for reading the configuration from conduit.toml & environment variables
figment = { version = "0.10.8", features = ["env", "toml"] } 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 } tikv-jemallocator = { version = "0.5.0", features = ["unprefixed_malloc_on_supported_platforms"], optional = true }
async-trait = "0.1.68" async-trait = "0.1.68"

View file

@ -17,7 +17,7 @@
# https://matrix.org/docs/spec/client_server/latest#get-well-known-matrix-client # https://matrix.org/docs/spec/client_server/latest#get-well-known-matrix-client
# and # and
# https://matrix.org/docs/spec/server_server/r0.1.4#get-well-known-matrix-server # 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 # YOU NEED TO EDIT THIS
#server_name = "your.server.name" #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 = "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. #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

View file

@ -32,6 +32,7 @@ mod typing;
mod unversioned; mod unversioned;
mod user_directory; mod user_directory;
mod voip; mod voip;
mod well_known;
pub use account::*; pub use account::*;
pub use alias::*; pub use alias::*;
@ -67,6 +68,7 @@ pub use typing::*;
pub use unversioned::*; pub use unversioned::*;
pub use user_directory::*; pub use user_directory::*;
pub use voip::*; pub use voip::*;
pub use well_known::*;
pub const DEVICE_ID_LENGTH: usize = 10; pub const DEVICE_ID_LENGTH: usize = 10;
pub const TOKEN_LENGTH: usize = 32; pub const TOKEN_LENGTH: usize = 32;

View file

@ -1,9 +1,8 @@
use std::{collections::BTreeMap, iter::FromIterator}; use std::{collections::BTreeMap, iter::FromIterator};
use axum::{response::IntoResponse, Json}; use ruma::api::client::discovery::get_supported_versions;
use ruma::api::client::{discovery::get_supported_versions, error::ErrorKind};
use crate::{services, Error, Result, Ruma}; use crate::{Result, Ruma};
/// # `GET /_matrix/client/versions` /// # `GET /_matrix/client/versions`
/// ///
@ -33,18 +32,3 @@ pub async fn get_supported_versions_route(
Ok(resp) Ok(resp)
} }
/// # `GET /.well-known/matrix/client`
pub async fn well_known_client_route(
_body: Ruma<get_supported_versions::Request>,
) -> Result<impl IntoResponse> {
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}
})))
}

View file

@ -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<discover_homeserver::Request>,
) -> Result<discover_homeserver::Response> {
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 }),
})
}

View file

@ -17,7 +17,10 @@ use ruma::{
backfill::get_backfill, backfill::get_backfill,
device::get_devices::{self, v1::UserDevice}, device::get_devices::{self, v1::UserDevice},
directory::{get_public_rooms, get_public_rooms_filtered}, 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}, event::{get_event, get_missing_events, get_room_state, get_room_state_ids},
keys::{claim_keys, get_keys}, keys::{claim_keys, get_keys},
membership::{create_invite, create_join_event, prepare_join_event}, 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<discover_homeserver::Request>,
) -> Result<discover_homeserver::Response> {
Ok(discover_homeserver::Response {
server: services().globals.well_known_server(),
})
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{add_port_to_hostname, get_ip_with_port, FedDest}; use super::{add_port_to_hostname, get_ip_with_port, FedDest};

View file

@ -7,6 +7,7 @@ use std::{
use ruma::{OwnedServerName, RoomVersionId}; use ruma::{OwnedServerName, RoomVersionId};
use serde::{de::IgnoredAny, Deserialize}; use serde::{de::IgnoredAny, Deserialize};
use tracing::warn; use tracing::warn;
use url::Url;
mod proxy; mod proxy;
@ -56,7 +57,8 @@ pub struct Config {
pub allow_unstable_room_versions: bool, pub allow_unstable_room_versions: bool,
#[serde(default = "default_default_room_version")] #[serde(default = "default_default_room_version")]
pub default_room_version: RoomVersionId, pub default_room_version: RoomVersionId,
pub well_known_client: Option<String>, #[serde(default)]
pub well_known: WellKnownConfig,
#[serde(default = "false_fn")] #[serde(default = "false_fn")]
pub allow_jaeger: bool, pub allow_jaeger: bool,
#[serde(default = "false_fn")] #[serde(default = "false_fn")]
@ -91,6 +93,12 @@ pub struct TlsConfig {
pub key: String, pub key: String,
} }
#[derive(Clone, Debug, Deserialize, Default)]
pub struct WellKnownConfig {
pub client: Option<Url>,
pub server: Option<OwnedServerName>,
}
const DEPRECATED_KEYS: &[&str] = &["cache_capacity"]; const DEPRECATED_KEYS: &[&str] = &["cache_capacity"];
impl Config { 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 { impl fmt::Display for Config {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Prepare a list of config values to show // Prepare a list of config values to show
let well_known_server = self.well_known_server();
let lines = [ let lines = [
("Server name", self.server_name.host()), ("Server name", self.server_name.host()),
("Database backend", &self.database_backend), ("Database backend", &self.database_backend),
@ -194,6 +228,8 @@ impl fmt::Display for Config {
} }
&lst.join(", ") &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(); let mut msg: String = "Active config values:\n\n".to_owned();

View file

@ -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_with_rel_type_route)
.ruma_route(client_server::get_relating_events_route) .ruma_route(client_server::get_relating_events_route)
.ruma_route(client_server::get_hierarchy_route) .ruma_route(client_server::get_hierarchy_route)
.ruma_route(client_server::well_known_client)
.route( .route(
"/_matrix/client/r0/rooms/:room_id/initialSync", "/_matrix/client/r0/rooms/:room_id/initialSync",
get(initial_sync), 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_profile_information_route)
.ruma_route(server_server::get_keys_route) .ruma_route(server_server::get_keys_route)
.ruma_route(server_server::claim_keys_route) .ruma_route(server_server::claim_keys_route)
.ruma_route(server_server::well_known_server)
} else { } else {
router router
.route("/_matrix/federation/*path", any(federation_disabled)) .route("/_matrix/federation/*path", any(federation_disabled))
.route("/_matrix/key/*path", any(federation_disabled)) .route("/_matrix/key/*path", any(federation_disabled))
.route("/.well-known/matrix/server", any(federation_disabled))
} }
} }

View file

@ -417,8 +417,12 @@ impl Service {
r r
} }
pub fn well_known_client(&self) -> &Option<String> { pub fn well_known_server(&self) -> OwnedServerName {
&self.config.well_known_client self.config.well_known_server()
}
pub fn well_known_client(&self) -> String {
self.config.well_known_client()
} }
pub fn shutdown(&self) { pub fn shutdown(&self) {