fix optional config section related
split api/client well_known simplify well_known config access Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
5f1cab6850
commit
f30b08f015
9 changed files with 144 additions and 138 deletions
|
@ -37,6 +37,7 @@ pub(super) mod unstable;
|
||||||
pub(super) mod unversioned;
|
pub(super) mod unversioned;
|
||||||
pub(super) mod user_directory;
|
pub(super) mod user_directory;
|
||||||
pub(super) mod voip;
|
pub(super) mod voip;
|
||||||
|
pub(super) mod well_known;
|
||||||
|
|
||||||
pub use account::full_user_deactivate;
|
pub use account::full_user_deactivate;
|
||||||
pub(super) use account::*;
|
pub(super) use account::*;
|
||||||
|
@ -80,6 +81,7 @@ pub(super) use unstable::*;
|
||||||
pub(super) use unversioned::*;
|
pub(super) use unversioned::*;
|
||||||
pub(super) use user_directory::*;
|
pub(super) use user_directory::*;
|
||||||
pub(super) use voip::*;
|
pub(super) use voip::*;
|
||||||
|
pub(super) use well_known::*;
|
||||||
|
|
||||||
/// generated device ID length
|
/// generated device ID length
|
||||||
const DEVICE_ID_LENGTH: usize = 10;
|
const DEVICE_ID_LENGTH: usize = 10;
|
||||||
|
|
|
@ -198,8 +198,10 @@ pub(crate) async fn login_route(
|
||||||
|
|
||||||
// send client well-known if specified so the client knows to reconfigure itself
|
// send client well-known if specified so the client knows to reconfigure itself
|
||||||
let client_discovery_info: Option<DiscoveryInfo> = services
|
let client_discovery_info: Option<DiscoveryInfo> = services
|
||||||
.globals
|
.server
|
||||||
.well_known_client()
|
.config
|
||||||
|
.well_known
|
||||||
|
.client
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|server| DiscoveryInfo::new(HomeserverInfo::new(server.to_string())));
|
.map(|server| DiscoveryInfo::new(HomeserverInfo::new(server.to_string())));
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,9 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use axum::{extract::State, response::IntoResponse, Json};
|
use axum::{extract::State, response::IntoResponse, Json};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use ruma::api::client::{
|
use ruma::api::client::discovery::get_supported_versions;
|
||||||
discovery::{
|
|
||||||
discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo},
|
|
||||||
discover_support::{self, Contact},
|
|
||||||
get_supported_versions,
|
|
||||||
},
|
|
||||||
error::ErrorKind,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{Error, Result, Ruma};
|
use crate::{Result, Ruma};
|
||||||
|
|
||||||
/// # `GET /_matrix/client/versions`
|
/// # `GET /_matrix/client/versions`
|
||||||
///
|
///
|
||||||
|
@ -65,99 +58,6 @@ pub(crate) async fn get_supported_versions_route(
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # `GET /.well-known/matrix/client`
|
|
||||||
///
|
|
||||||
/// Returns the .well-known URL if it is configured, otherwise returns 404.
|
|
||||||
pub(crate) async fn well_known_client(
|
|
||||||
State(services): State<crate::State>, _body: Ruma<discover_homeserver::Request>,
|
|
||||||
) -> Result<discover_homeserver::Response> {
|
|
||||||
let client_url = match services.globals.well_known_client() {
|
|
||||||
Some(url) => url.to_string(),
|
|
||||||
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(discover_homeserver::Response {
|
|
||||||
homeserver: HomeserverInfo {
|
|
||||||
base_url: client_url.clone(),
|
|
||||||
},
|
|
||||||
identity_server: None,
|
|
||||||
sliding_sync_proxy: Some(SlidingSyncProxyInfo {
|
|
||||||
url: client_url,
|
|
||||||
}),
|
|
||||||
tile_server: None,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # `GET /.well-known/matrix/support`
|
|
||||||
///
|
|
||||||
/// Server support contact and support page of a homeserver's domain.
|
|
||||||
pub(crate) async fn well_known_support(
|
|
||||||
State(services): State<crate::State>, _body: Ruma<discover_support::Request>,
|
|
||||||
) -> Result<discover_support::Response> {
|
|
||||||
let support_page = services
|
|
||||||
.globals
|
|
||||||
.well_known_support_page()
|
|
||||||
.as_ref()
|
|
||||||
.map(ToString::to_string);
|
|
||||||
|
|
||||||
let role = services.globals.well_known_support_role().clone();
|
|
||||||
|
|
||||||
// support page or role must be either defined for this to be valid
|
|
||||||
if support_page.is_none() && role.is_none() {
|
|
||||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
|
||||||
}
|
|
||||||
|
|
||||||
let email_address = services.globals.well_known_support_email().clone();
|
|
||||||
let matrix_id = services.globals.well_known_support_mxid().clone();
|
|
||||||
|
|
||||||
// if a role is specified, an email address or matrix id is required
|
|
||||||
if role.is_some() && (email_address.is_none() && matrix_id.is_none()) {
|
|
||||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TOOD: support defining multiple contacts in the config
|
|
||||||
let mut contacts: Vec<Contact> = vec![];
|
|
||||||
|
|
||||||
if let Some(role) = role {
|
|
||||||
let contact = Contact {
|
|
||||||
role,
|
|
||||||
email_address,
|
|
||||||
matrix_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
contacts.push(contact);
|
|
||||||
}
|
|
||||||
|
|
||||||
// support page or role+contacts must be either defined for this to be valid
|
|
||||||
if contacts.is_empty() && support_page.is_none() {
|
|
||||||
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(discover_support::Response {
|
|
||||||
contacts,
|
|
||||||
support_page,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # `GET /client/server.json`
|
|
||||||
///
|
|
||||||
/// Endpoint provided by sliding sync proxy used by some clients such as Element
|
|
||||||
/// Web as a non-standard health check.
|
|
||||||
pub(crate) async fn syncv3_client_server_json(State(services): State<crate::State>) -> Result<impl IntoResponse> {
|
|
||||||
let server_url = match services.globals.well_known_client() {
|
|
||||||
Some(url) => url.to_string(),
|
|
||||||
None => match services.globals.well_known_server() {
|
|
||||||
Some(url) => url.to_string(),
|
|
||||||
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Json(serde_json::json!({
|
|
||||||
"server": server_url,
|
|
||||||
"version": conduit::version(),
|
|
||||||
})))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// # `GET /_conduwuit/server_version`
|
/// # `GET /_conduwuit/server_version`
|
||||||
///
|
///
|
||||||
/// Conduwuit-specific API to get the server version, results akin to
|
/// Conduwuit-specific API to get the server version, results akin to
|
||||||
|
|
105
src/api/client/well_known.rs
Normal file
105
src/api/client/well_known.rs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
use axum::{extract::State, response::IntoResponse, Json};
|
||||||
|
use ruma::api::client::{
|
||||||
|
discovery::{
|
||||||
|
discover_homeserver::{self, HomeserverInfo, SlidingSyncProxyInfo},
|
||||||
|
discover_support::{self, Contact},
|
||||||
|
},
|
||||||
|
error::ErrorKind,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{Error, Result, Ruma};
|
||||||
|
|
||||||
|
/// # `GET /.well-known/matrix/client`
|
||||||
|
///
|
||||||
|
/// Returns the .well-known URL if it is configured, otherwise returns 404.
|
||||||
|
pub(crate) async fn well_known_client(
|
||||||
|
State(services): State<crate::State>, _body: Ruma<discover_homeserver::Request>,
|
||||||
|
) -> Result<discover_homeserver::Response> {
|
||||||
|
let client_url = match services.server.config.well_known.client.as_ref() {
|
||||||
|
Some(url) => url.to_string(),
|
||||||
|
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(discover_homeserver::Response {
|
||||||
|
homeserver: HomeserverInfo {
|
||||||
|
base_url: client_url.clone(),
|
||||||
|
},
|
||||||
|
identity_server: None,
|
||||||
|
sliding_sync_proxy: Some(SlidingSyncProxyInfo {
|
||||||
|
url: client_url,
|
||||||
|
}),
|
||||||
|
tile_server: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # `GET /.well-known/matrix/support`
|
||||||
|
///
|
||||||
|
/// Server support contact and support page of a homeserver's domain.
|
||||||
|
pub(crate) async fn well_known_support(
|
||||||
|
State(services): State<crate::State>, _body: Ruma<discover_support::Request>,
|
||||||
|
) -> Result<discover_support::Response> {
|
||||||
|
let support_page = services
|
||||||
|
.server
|
||||||
|
.config
|
||||||
|
.well_known
|
||||||
|
.support_page
|
||||||
|
.as_ref()
|
||||||
|
.map(ToString::to_string);
|
||||||
|
|
||||||
|
let role = services.server.config.well_known.support_role.clone();
|
||||||
|
|
||||||
|
// support page or role must be either defined for this to be valid
|
||||||
|
if support_page.is_none() && role.is_none() {
|
||||||
|
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
let email_address = services.server.config.well_known.support_email.clone();
|
||||||
|
let matrix_id = services.server.config.well_known.support_mxid.clone();
|
||||||
|
|
||||||
|
// if a role is specified, an email address or matrix id is required
|
||||||
|
if role.is_some() && (email_address.is_none() && matrix_id.is_none()) {
|
||||||
|
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOOD: support defining multiple contacts in the config
|
||||||
|
let mut contacts: Vec<Contact> = vec![];
|
||||||
|
|
||||||
|
if let Some(role) = role {
|
||||||
|
let contact = Contact {
|
||||||
|
role,
|
||||||
|
email_address,
|
||||||
|
matrix_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
contacts.push(contact);
|
||||||
|
}
|
||||||
|
|
||||||
|
// support page or role+contacts must be either defined for this to be valid
|
||||||
|
if contacts.is_empty() && support_page.is_none() {
|
||||||
|
return Err(Error::BadRequest(ErrorKind::NotFound, "Not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(discover_support::Response {
|
||||||
|
contacts,
|
||||||
|
support_page,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # `GET /client/server.json`
|
||||||
|
///
|
||||||
|
/// Endpoint provided by sliding sync proxy used by some clients such as Element
|
||||||
|
/// Web as a non-standard health check.
|
||||||
|
pub(crate) async fn syncv3_client_server_json(State(services): State<crate::State>) -> Result<impl IntoResponse> {
|
||||||
|
let server_url = match services.server.config.well_known.client.as_ref() {
|
||||||
|
Some(url) => url.to_string(),
|
||||||
|
None => match services.server.config.well_known.server.as_ref() {
|
||||||
|
Some(url) => url.to_string(),
|
||||||
|
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Json(serde_json::json!({
|
||||||
|
"server": server_url,
|
||||||
|
"version": conduit::version(),
|
||||||
|
})))
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ pub(crate) async fn well_known_server(
|
||||||
State(services): State<crate::State>, _body: Ruma<discover_homeserver::Request>,
|
State(services): State<crate::State>, _body: Ruma<discover_homeserver::Request>,
|
||||||
) -> Result<discover_homeserver::Response> {
|
) -> Result<discover_homeserver::Response> {
|
||||||
Ok(discover_homeserver::Response {
|
Ok(discover_homeserver::Response {
|
||||||
server: match services.globals.well_known_server() {
|
server: match services.server.config.well_known.server.as_ref() {
|
||||||
Some(server_name) => server_name.to_owned(),
|
Some(server_name) => server_name.to_owned(),
|
||||||
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
None => return Err(Error::BadRequest(ErrorKind::NotFound, "Not found.")),
|
||||||
},
|
},
|
||||||
|
|
|
@ -87,7 +87,8 @@ pub struct Config {
|
||||||
port: ListeningPort,
|
port: ListeningPort,
|
||||||
|
|
||||||
// external structure; separate section
|
// external structure; separate section
|
||||||
pub tls: Option<TlsConfig>,
|
#[serde(default)]
|
||||||
|
pub tls: TlsConfig,
|
||||||
|
|
||||||
/// Uncomment unix_socket_path to listen on a UNIX socket at the specified
|
/// Uncomment unix_socket_path to listen on a UNIX socket at the specified
|
||||||
/// path. If listening on a UNIX socket, you MUST remove/comment the
|
/// path. If listening on a UNIX socket, you MUST remove/comment the
|
||||||
|
@ -1500,17 +1501,19 @@ pub struct Config {
|
||||||
catchall: BTreeMap<String, IgnoredAny>,
|
catchall: BTreeMap<String, IgnoredAny>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
#[config_example_generator(filename = "conduwuit-example.toml", section = "global.tls")]
|
#[config_example_generator(filename = "conduwuit-example.toml", section = "global.tls")]
|
||||||
pub struct TlsConfig {
|
pub struct TlsConfig {
|
||||||
/// Path to a valid TLS certificate file.
|
/// Path to a valid TLS certificate file.
|
||||||
///
|
///
|
||||||
/// example: "/path/to/my/certificate.crt"
|
/// example: "/path/to/my/certificate.crt"
|
||||||
pub certs: String,
|
pub certs: Option<String>,
|
||||||
|
|
||||||
/// Path to a valid TLS certificate private key.
|
/// Path to a valid TLS certificate private key.
|
||||||
///
|
///
|
||||||
/// example: "/path/to/my/certificate.key"
|
/// example: "/path/to/my/certificate.key"
|
||||||
pub key: String,
|
pub key: Option<String>,
|
||||||
|
|
||||||
/// Whether to listen and allow for HTTP and HTTPS connections (insecure!)
|
/// Whether to listen and allow for HTTP and HTTPS connections (insecure!)
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub dual_protocol: bool,
|
pub dual_protocol: bool,
|
||||||
|
@ -1520,20 +1523,25 @@ pub struct TlsConfig {
|
||||||
#[derive(Clone, Debug, Deserialize, Default)]
|
#[derive(Clone, Debug, Deserialize, Default)]
|
||||||
#[config_example_generator(filename = "conduwuit-example.toml", section = "global.well_known")]
|
#[config_example_generator(filename = "conduwuit-example.toml", section = "global.well_known")]
|
||||||
pub struct WellKnownConfig {
|
pub struct WellKnownConfig {
|
||||||
|
/// The server URL that the client well-known file will serve. This should
|
||||||
|
/// not contain a port, and should just be a valid HTTPS URL.
|
||||||
|
///
|
||||||
|
/// example: "https://matrix.example.com"
|
||||||
|
pub client: Option<Url>,
|
||||||
|
|
||||||
/// The server base domain of the URL with a specific port that the server
|
/// The server base domain of the URL with a specific port that the server
|
||||||
/// well-known file will serve. This should contain a port at the end, and
|
/// well-known file will serve. This should contain a port at the end, and
|
||||||
/// should not be a URL.
|
/// should not be a URL.
|
||||||
///
|
///
|
||||||
/// example: "matrix.example.com:443"
|
/// example: "matrix.example.com:443"
|
||||||
pub server: Option<OwnedServerName>,
|
pub server: Option<OwnedServerName>,
|
||||||
/// The server URL that the client well-known file will serve. This should
|
|
||||||
/// not contain a port, and should just be a valid HTTPS URL.
|
|
||||||
///
|
|
||||||
/// example: "https://matrix.example.com"
|
|
||||||
pub client: Option<Url>,
|
|
||||||
pub support_page: Option<Url>,
|
pub support_page: Option<Url>,
|
||||||
|
|
||||||
pub support_role: Option<ContactRole>,
|
pub support_role: Option<ContactRole>,
|
||||||
|
|
||||||
pub support_email: Option<String>,
|
pub support_email: Option<String>,
|
||||||
|
|
||||||
pub support_mxid: Option<OwnedUserId>,
|
pub support_mxid: Option<OwnedUserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ pub(super) async fn serve(
|
||||||
|
|
||||||
if cfg!(unix) && config.unix_socket_path.is_some() {
|
if cfg!(unix) && config.unix_socket_path.is_some() {
|
||||||
unix::serve(server, app, shutdown).await
|
unix::serve(server, app, shutdown).await
|
||||||
} else if config.tls.is_some() {
|
} else if config.tls.certs.is_some() {
|
||||||
#[cfg(feature = "direct_tls")]
|
#[cfg(feature = "direct_tls")]
|
||||||
return tls::serve(server, app, handle, addrs).await;
|
return tls::serve(server, app, handle, addrs).await;
|
||||||
|
|
||||||
|
|
|
@ -6,17 +6,20 @@ use axum_server_dual_protocol::{
|
||||||
axum_server::{bind_rustls, tls_rustls::RustlsConfig},
|
axum_server::{bind_rustls, tls_rustls::RustlsConfig},
|
||||||
ServerExt,
|
ServerExt,
|
||||||
};
|
};
|
||||||
use conduit::{Result, Server};
|
use conduit::{err, Result, Server};
|
||||||
use tokio::task::JoinSet;
|
use tokio::task::JoinSet;
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
pub(super) async fn serve(
|
pub(super) async fn serve(server: &Arc<Server>, app: Router, handle: ServerHandle, addrs: Vec<SocketAddr>) -> Result {
|
||||||
server: &Arc<Server>, app: Router, handle: ServerHandle, addrs: Vec<SocketAddr>,
|
let tls = &server.config.tls;
|
||||||
) -> Result<()> {
|
let certs = tls
|
||||||
let config = &server.config;
|
.certs
|
||||||
let tls = config.tls.as_ref().expect("TLS configuration");
|
.as_ref()
|
||||||
let certs = &tls.certs;
|
.ok_or(err!(Config("tls.certs", "Missing required value in tls config section")))?;
|
||||||
let key = &tls.key;
|
let key = tls
|
||||||
|
.key
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(err!(Config("tls.key", "Missing required value in tls config section")))?;
|
||||||
|
|
||||||
// we use ring for ruma and hashing state, but aws-lc-rs is the new default.
|
// we use ring for ruma and hashing state, but aws-lc-rs is the new default.
|
||||||
// without this, TLS mode will panic.
|
// without this, TLS mode will panic.
|
||||||
|
|
|
@ -12,11 +12,9 @@ use data::Data;
|
||||||
use ipaddress::IPAddress;
|
use ipaddress::IPAddress;
|
||||||
use regex::RegexSet;
|
use regex::RegexSet;
|
||||||
use ruma::{
|
use ruma::{
|
||||||
api::client::discovery::discover_support::ContactRole, OwnedEventId, OwnedRoomAliasId, OwnedServerName,
|
OwnedEventId, OwnedRoomAliasId, OwnedServerName, OwnedUserId, RoomAliasId, RoomVersionId, ServerName, UserId,
|
||||||
OwnedUserId, RoomAliasId, RoomVersionId, ServerName, UserId,
|
|
||||||
};
|
};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use url::Url;
|
|
||||||
|
|
||||||
use crate::service;
|
use crate::service;
|
||||||
|
|
||||||
|
@ -243,14 +241,6 @@ impl Service {
|
||||||
|
|
||||||
pub fn allow_outgoing_read_receipts(&self) -> bool { self.config.allow_outgoing_read_receipts }
|
pub fn allow_outgoing_read_receipts(&self) -> bool { self.config.allow_outgoing_read_receipts }
|
||||||
|
|
||||||
pub fn well_known_support_page(&self) -> &Option<Url> { &self.config.well_known.support_page }
|
|
||||||
|
|
||||||
pub fn well_known_support_role(&self) -> &Option<ContactRole> { &self.config.well_known.support_role }
|
|
||||||
|
|
||||||
pub fn well_known_support_email(&self) -> &Option<String> { &self.config.well_known.support_email }
|
|
||||||
|
|
||||||
pub fn well_known_support_mxid(&self) -> &Option<OwnedUserId> { &self.config.well_known.support_mxid }
|
|
||||||
|
|
||||||
pub fn block_non_admin_invites(&self) -> bool { self.config.block_non_admin_invites }
|
pub fn block_non_admin_invites(&self) -> bool { self.config.block_non_admin_invites }
|
||||||
|
|
||||||
pub fn supported_room_versions(&self) -> Vec<RoomVersionId> {
|
pub fn supported_room_versions(&self) -> Vec<RoomVersionId> {
|
||||||
|
@ -265,10 +255,6 @@ impl Service {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn well_known_client(&self) -> &Option<Url> { &self.config.well_known.client }
|
|
||||||
|
|
||||||
pub fn well_known_server(&self) -> &Option<OwnedServerName> { &self.config.well_known.server }
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn valid_cidr_range(&self, ip: &IPAddress) -> bool {
|
pub fn valid_cidr_range(&self, ip: &IPAddress) -> bool {
|
||||||
for cidr in &self.cidr_range_denylist {
|
for cidr in &self.cidr_range_denylist {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue