Skip to main content

arminius_server_client/handlers/
discovery.rs

1// SPDX-FileCopyrightText: 2025 BWI GmbH
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! API endpoint for server discovery by the client.
6
7mod tests;
8
9use arminius_lib_component::{
10	ArminiusConfig, Component, ServerState, ruma_requests::ArminiusResponse,
11};
12use axum::{Router, extract::State, routing::get};
13use ruma::api::{
14	FeatureFlag, MatrixVersion,
15	client::discovery::{discover_homeserver, get_capabilities, get_supported_versions},
16};
17
18use crate::client_request::{
19	AuthenticatedClientRequest, OptionallyAuthenticatedClientRequest, UnauthenticatedClientRequest,
20};
21
22/// Handler for `GET /_matrix/client/versions` (See
23/// <https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientversions>).
24///
25/// Gets the versions of the specification supported by the server.
26async fn get_supported_versions_handler(
27	OptionallyAuthenticatedClientRequest(_, _): OptionallyAuthenticatedClientRequest<
28		get_supported_versions::Request,
29	>,
30) -> ArminiusResponse<get_supported_versions::Response> {
31	#[expect(
32		clippy::expect_used,
33		reason = "Calling `MatrixVersion::as_str()` returns `None` only for its `V1_0` variant"
34	)]
35	let mut response = get_supported_versions::Response::new(vec![
36		MatrixVersion::V1_9.as_str().expect("Only `MatrixVersion::V1_0` returns `None`").to_owned(),
37		MatrixVersion::V1_10
38			.as_str()
39			.expect("Only `MatrixVersion::V1_0` returns `None`")
40			.to_owned(),
41		MatrixVersion::V1_11
42			.as_str()
43			.expect("Only `MatrixVersion::V1_0` returns `None`")
44			.to_owned(),
45	]);
46
47	response.unstable_features.insert(FeatureFlag::Msc4186.to_string(), true);
48
49	response.into()
50}
51
52/// Handler for `GET /.well-known/matrix/client` (See
53/// <https://spec.matrix.org/v1.18/client-server-api/#getwell-knownmatrixclient>).
54///
55/// Gets discovery information about the domain.
56async fn discover_homeserver_handler(
57	config: State<ArminiusConfig>,
58	UnauthenticatedClientRequest(_): UnauthenticatedClientRequest<discover_homeserver::Request>,
59) -> ArminiusResponse<discover_homeserver::Response> {
60	discover_homeserver::Response::new(discover_homeserver::HomeserverInfo::new(
61		config.client_base_url.to_string(),
62	))
63	.into()
64}
65
66/// Handler for `GET /_matrix/client/v3/capabilities` (See
67/// <https://spec.matrix.org/v1.18/client-server-api/#get_matrixclientv3capabilities>).
68///
69/// Gets information about the server’s supported feature set and other relevant
70/// capabilities.
71async fn get_capabilities_handler(
72	AuthenticatedClientRequest(_, _): AuthenticatedClientRequest<get_capabilities::v3::Request>,
73) -> ArminiusResponse<get_capabilities::v3::Response> {
74	let mut capabilities = get_capabilities::v3::Capabilities::new();
75	capabilities.change_password = get_capabilities::v3::ChangePasswordCapability::new(false);
76
77	capabilities.room_versions = get_capabilities::v3::RoomVersionsCapability::new(
78		arminius_lib_events::KnownRoomVersionId::default().into(),
79		arminius_lib_events::SUPPORTED_ROOM_VERSIONS
80			.into_iter()
81			.map(|version| (version.into(), get_capabilities::v3::RoomVersionStability::Stable))
82			.collect(),
83	);
84
85	capabilities.profile_fields = Some(get_capabilities::v3::ProfileFieldsCapability::new(false));
86	capabilities.thirdparty_id_changes =
87		get_capabilities::v3::ThirdPartyIdChangesCapability::new(false);
88	capabilities.get_login_token = get_capabilities::v3::GetLoginTokenCapability::new(false);
89
90	let response = get_capabilities::v3::Response::new(capabilities);
91	response.into()
92}
93
94/// Component for client discovery endpoints
95#[derive(Debug)]
96pub struct DiscoveryComponent;
97
98impl Component for DiscoveryComponent {
99	fn router() -> Router<ServerState> {
100		Router::new()
101			.route("/_matrix/client/versions", get(get_supported_versions_handler))
102			.route("/_matrix/client/v3/capabilities", get(get_capabilities_handler))
103			.route("/.well-known/matrix/client", get(discover_homeserver_handler))
104	}
105}