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-opentelemetry",
"tracing-subscriber",
"trust-dns-resolver",
"url",
]
[[package]]
@ -3124,6 +3126,7 @@ dependencies = [
"form_urlencoded",
"idna 0.5.0",
"percent-encoding",
"serde",
]
[[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
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"

View file

@ -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

View file

@ -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;

View file

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

View file

@ -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<String>,
#[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<Url>,
pub server: Option<OwnedServerName>,
}
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();

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_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))
}
}

View file

@ -417,8 +417,12 @@ impl Service {
r
}
pub fn well_known_client(&self) -> &Option<String> {
&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) {