Skip to main content

tuwunel_api/client/
capabilities.rs

1use std::collections::BTreeMap;
2
3use axum::extract::State;
4#[allow(deprecated)]
5use ruma::api::client::discovery::get_capabilities::v3::{
6	SetAvatarUrlCapability, SetDisplayNameCapability,
7};
8use ruma::{
9	RoomVersionId,
10	api::client::discovery::{
11		get_capabilities,
12		get_capabilities::v3::{
13			AccountModerationCapability, Capabilities, ChangePasswordCapability,
14			GetLoginTokenCapability, ProfileFieldsCapability, RoomVersionStability,
15			RoomVersionsCapability, ThirdPartyIdChangesCapability,
16		},
17	},
18};
19use serde_json::json;
20use tuwunel_core::Result;
21
22use crate::Ruma;
23
24/// # `GET /_matrix/client/v3/capabilities`
25///
26/// Get information on the supported feature set and other relevant capabilities
27/// of this server.
28#[allow(deprecated)]
29pub(crate) async fn get_capabilities_route(
30	State(services): State<crate::State>,
31	body: Ruma<get_capabilities::v3::Request>,
32) -> Result<get_capabilities::v3::Response> {
33	let available: BTreeMap<RoomVersionId, RoomVersionStability> = services
34		.config
35		.supported_room_versions()
36		.collect();
37
38	let mut capabilities = Capabilities::default();
39	capabilities.room_versions = RoomVersionsCapability {
40		available,
41		default: services
42			.server
43			.config
44			.default_room_version
45			.clone(),
46	};
47
48	// MSC3283: deprecated displayname/avatar capabilities for pre-1.16 clients.
49	capabilities.set_displayname = SetDisplayNameCapability::new(true);
50	capabilities.set_avatar_url = SetAvatarUrlCapability::new(true);
51
52	// we do not implement 3PID stuff
53	capabilities.thirdparty_id_changes = ThirdPartyIdChangesCapability { enabled: false };
54
55	capabilities.get_login_token = GetLoginTokenCapability {
56		enabled: services.server.config.login_via_existing_session,
57	};
58
59	capabilities.profile_fields = ProfileFieldsCapability::new(true).into();
60
61	capabilities.change_password = ChangePasswordCapability {
62		enabled: services.server.config.login_with_password,
63	};
64
65	capabilities.set(
66		"org.matrix.msc4267.forget_forced_upon_leave",
67		json!({"enabled": services.config.forget_forced_upon_leave}),
68	)?;
69
70	// MSC4452: enabled mirrors the per-URL gate; empty allowlists 403 every URL.
71	let preview_url_enabled = !services
72		.config
73		.url_preview_domain_contains_allowlist
74		.is_empty()
75		|| !services
76			.config
77			.url_preview_domain_explicit_allowlist
78			.is_empty()
79		|| !services
80			.config
81			.url_preview_url_contains_allowlist
82			.is_empty();
83
84	capabilities
85		.set("io.element.msc4452.preview_url", json!({"enabled": preview_url_enabled}))?;
86
87	// MSC4323: advertise admin moderation only to admins; absence implies
88	// neither suspend nor lock is available to the caller.
89	if services
90		.admin
91		.user_is_admin(body.sender_user())
92		.await
93	{
94		capabilities.account_moderation = AccountModerationCapability::new(true, true);
95	}
96
97	Ok(get_capabilities::v3::Response { capabilities })
98}