Skip to main content

tuwunel_api/
router.rs

1mod args;
2mod auth;
3mod client_ip;
4mod handler;
5mod request;
6mod response;
7pub mod state;
8
9use axum::{
10	Router,
11	response::IntoResponse,
12	routing::{any, get, post},
13};
14pub use client_ip::{ConfiguredIpSource, TrustedPeerSubnets};
15use tuwunel_core::{Server, err};
16
17use self::handler::RouterExt;
18pub(super) use self::{
19	args::Args as Ruma, auth::auth_uiaa, client_ip::ClientIp, response::RumaResponse,
20	state::State,
21};
22use crate::{
23	client,
24	oidc::{self, native_get_route, native_submit_route},
25	server,
26};
27
28pub fn build(router: Router<State>, server: &Server) -> Router<State> {
29	let config = &server.config;
30	let router = register_client_auth_routes(router);
31	let router = register_mas_routes(router);
32	let router = register_client_profile_and_data_routes(router);
33	let router = register_client_keys_and_backup_routes(router);
34	let router = register_client_room_routes(router);
35	let router = register_client_state_and_sync_routes(router);
36	let router = register_client_media_and_device_routes(router);
37	let router = register_client_misc_routes(router);
38	let router = register_oidc_routes(router);
39	let router = register_server_misc_routes(router);
40	let router = register_federation_routes(router, config.allow_federation);
41
42	register_legacy_media_routes(router, config.allow_legacy_media)
43}
44
45fn register_client_auth_routes(router: Router<State>) -> Router<State> {
46	router
47		.ruma_route(&client::get_supported_versions_route)
48		.ruma_route(&client::get_register_available_route)
49		.ruma_route(&client::register_route)
50		.ruma_route(&client::get_login_types_route)
51		.ruma_route(&client::login_route)
52		.ruma_route(&client::login_token_route)
53		.ruma_route(&client::refresh_token_route)
54		.ruma_route(&client::sso_login_route)
55		.ruma_route(&client::sso_login_with_provider_route)
56		.ruma_route(&client::sso_callback_route)
57		.ruma_route(&client::sso_fallback_route)
58		.ruma_route(&client::whoami_route)
59		.ruma_route(&client::logout_route)
60		.ruma_route(&client::logout_all_route)
61		.ruma_route(&client::change_password_route)
62		.ruma_route(&client::deactivate_route)
63		.ruma_route(&client::third_party_route)
64		.ruma_route(&client::add_3pid_route)
65		.ruma_route(&client::delete_3pid_route)
66		.ruma_route(&client::request_3pid_management_token_via_email_route)
67		.ruma_route(&client::request_3pid_management_token_via_msisdn_route)
68		.ruma_route(&client::request_registration_token_via_email_route)
69		.ruma_route(&client::request_password_change_token_via_email_route)
70		.ruma_route(&client::check_registration_token_validity)
71		.ruma_route(&client::create_openid_token_route)
72		.ruma_route(&client::is_user_suspended_route)
73		.ruma_route(&client::suspend_user_route)
74		.ruma_route(&client::is_user_locked_route)
75		.ruma_route(&client::lock_user_route)
76		.ruma_route(&client::admin_register_nonce_route)
77		.ruma_route(&client::admin_register_route)
78}
79
80fn register_mas_routes(router: Router<State>) -> Router<State> {
81	router
82		.ruma_route(&client::mas::query_user_route)
83		.ruma_route(&client::mas::provision_user_route)
84		.ruma_route(&client::mas::is_localpart_available_route)
85		.ruma_route(&client::mas::delete_user_route)
86		.ruma_route(&client::mas::reactivate_user_route)
87		.ruma_route(&client::mas::set_displayname_route)
88		.ruma_route(&client::mas::unset_displayname_route)
89		.ruma_route(&client::mas::allow_cross_signing_reset_route)
90		.ruma_route(&client::mas::upsert_device_route)
91		.ruma_route(&client::mas::delete_device_route)
92		.ruma_route(&client::mas::update_device_display_name_route)
93		.ruma_route(&client::mas::sync_devices_route)
94}
95
96fn register_client_profile_and_data_routes(router: Router<State>) -> Router<State> {
97	router
98		.ruma_route(&client::get_profile_field_route)
99		.ruma_route(&client::set_profile_field_route)
100		.ruma_route(&client::delete_profile_field_route)
101		.ruma_route(&client::get_profile_route)
102		.ruma_route(&client::set_presence_route)
103		.ruma_route(&client::get_presence_route)
104		.ruma_route(&client::get_filter_route)
105		.ruma_route(&client::create_filter_route)
106		.ruma_route(&client::set_global_account_data_route)
107		.ruma_route(&client::set_room_account_data_route)
108		.ruma_route(&client::get_global_account_data_route)
109		.ruma_route(&client::get_room_account_data_route)
110		.ruma_route(&client::delete_global_account_data_route)
111		.ruma_route(&client::delete_room_account_data_route)
112		.ruma_route(&client::get_tags_route)
113		.ruma_route(&client::update_tag_route)
114		.ruma_route(&client::delete_tag_route)
115		.ruma_route(&client::get_pushrules_all_route)
116		.ruma_route(&client::get_pushrules_global_route)
117		.ruma_route(&client::set_pushrule_route)
118		.ruma_route(&client::get_pushrule_route)
119		.ruma_route(&client::set_pushrule_enabled_route)
120		.ruma_route(&client::get_pushrule_enabled_route)
121		.ruma_route(&client::get_pushrule_actions_route)
122		.ruma_route(&client::set_pushrule_actions_route)
123		.ruma_route(&client::delete_pushrule_route)
124		.ruma_route(&client::get_pushers_route)
125		.ruma_route(&client::set_pushers_route)
126		.ruma_route(&client::get_notifications_route)
127		.ruma_route(&client::get_capabilities_route)
128}
129
130fn register_client_keys_and_backup_routes(router: Router<State>) -> Router<State> {
131	router
132		.ruma_route(&client::upload_keys_route)
133		.ruma_route(&client::get_keys_route)
134		.ruma_route(&client::claim_keys_route)
135		.ruma_route(&client::upload_signing_keys_route)
136		.ruma_route(&client::upload_signatures_route)
137		.ruma_route(&client::get_key_changes_route)
138		.ruma_route(&client::create_backup_version_route)
139		.ruma_route(&client::update_backup_version_route)
140		.ruma_route(&client::delete_backup_version_route)
141		.ruma_route(&client::get_latest_backup_info_route)
142		.ruma_route(&client::get_backup_info_route)
143		.ruma_route(&client::add_backup_keys_route)
144		.ruma_route(&client::add_backup_keys_for_room_route)
145		.ruma_route(&client::add_backup_keys_for_session_route)
146		.ruma_route(&client::delete_backup_keys_for_room_route)
147		.ruma_route(&client::delete_backup_keys_for_session_route)
148		.ruma_route(&client::delete_backup_keys_route)
149		.ruma_route(&client::get_backup_keys_for_room_route)
150		.ruma_route(&client::get_backup_keys_for_session_route)
151		.ruma_route(&client::get_backup_keys_route)
152}
153
154fn register_client_room_routes(router: Router<State>) -> Router<State> {
155	router
156		.ruma_route(&client::appservice_ping)
157		.ruma_route(&client::set_read_marker_route)
158		.ruma_route(&client::create_receipt_route)
159		.ruma_route(&client::create_typing_event_route)
160		.ruma_route(&client::create_room_route)
161		.ruma_route(&client::redact_event_route)
162		.ruma_route(&client::report_event_route)
163		.ruma_route(&client::report_room_route)
164		.ruma_route(&client::report_user_route)
165		.ruma_route(&client::create_alias_route)
166		.ruma_route(&client::delete_alias_route)
167		.ruma_route(&client::get_alias_route)
168		.ruma_route(&client::join_room_by_id_route)
169		.ruma_route(&client::join_room_by_id_or_alias_route)
170		.ruma_route(&client::joined_members_route)
171		.ruma_route(&client::knock_room_route)
172		.ruma_route(&client::leave_room_route)
173		.ruma_route(&client::forget_room_route)
174		.ruma_route(&client::joined_rooms_route)
175		.ruma_route(&client::kick_user_route)
176		.ruma_route(&client::ban_user_route)
177		.ruma_route(&client::unban_user_route)
178		.ruma_route(&client::invite_user_route)
179		.ruma_route(&client::set_room_visibility_route)
180		.ruma_route(&client::get_room_visibility_route)
181		.ruma_route(&client::get_public_rooms_route)
182		.ruma_route(&client::get_public_rooms_filtered_route)
183		.ruma_route(&client::search_users_route)
184		.ruma_route(&client::get_member_events_route)
185		.ruma_route(&client::get_protocols_route)
186		.ruma_route(&client::upgrade_room_route)
187		.ruma_route(&client::get_mutual_rooms_route)
188		.ruma_route(&client::get_room_summary)
189		.route(
190			"/_matrix/client/unstable/im.nheko.summary/rooms/{room_id_or_alias}/summary",
191			get(client::get_room_summary_legacy),
192		)
193		.ruma_route(&client::room_initial_sync_route)
194		.ruma_route(&client::get_room_event_route)
195		.ruma_route(&client::get_room_aliases_route)
196}
197
198fn register_client_state_and_sync_routes(router: Router<State>) -> Router<State> {
199	router
200		.ruma_route(&client::send_message_event_route)
201		.ruma_route(&client::send_state_event_for_key_route)
202		.ruma_route(&client::get_state_events_route)
203		.ruma_route(&client::get_state_events_for_key_route)
204		// Ruma doesn't have support for multiple paths for a single endpoint yet, and these
205		// routes share one Ruma request / response type pair with
206		// {get,send}_state_event_for_key_route
207		.route(
208			"/_matrix/client/r0/rooms/{room_id}/state/{event_type}",
209			get(client::get_state_events_for_empty_key_route)
210				.put(client::send_state_event_for_empty_key_route),
211		)
212		.route(
213			"/_matrix/client/v3/rooms/{room_id}/state/{event_type}",
214			get(client::get_state_events_for_empty_key_route)
215				.put(client::send_state_event_for_empty_key_route),
216		)
217		// These two endpoints allow trailing slashes
218		.route(
219			"/_matrix/client/r0/rooms/{room_id}/state/{event_type}/",
220			get(client::get_state_events_for_empty_key_route)
221				.put(client::send_state_event_for_empty_key_route),
222		)
223		.route(
224			"/_matrix/client/v3/rooms/{room_id}/state/{event_type}/",
225			get(client::get_state_events_for_empty_key_route)
226				.put(client::send_state_event_for_empty_key_route),
227		)
228		.ruma_route(&client::events_route)
229		.ruma_route(&client::sync_events_route)
230		.ruma_route(&client::sync_events_v5_route)
231		.ruma_route(&client::get_context_route)
232		.ruma_route(&client::get_event_by_timestamp_route)
233		.ruma_route(&client::get_message_events_route)
234		.ruma_route(&client::search_events_route)
235		.ruma_route(&client::get_threads_route)
236		.ruma_route(&client::get_relating_events_with_rel_type_and_event_type_route)
237		.ruma_route(&client::get_relating_events_with_rel_type_route)
238		.ruma_route(&client::get_relating_events_route)
239		.ruma_route(&client::get_hierarchy_route)
240}
241
242fn register_client_media_and_device_routes(router: Router<State>) -> Router<State> {
243	router
244		.ruma_route(&client::create_content_route)
245		.ruma_route(&client::create_mxc_uri_route)
246		.ruma_route(&client::create_content_async_route)
247		.ruma_route(&client::get_content_thumbnail_route)
248		.ruma_route(&client::get_content_route)
249		.ruma_route(&client::get_content_as_filename_route)
250		.ruma_route(&client::get_media_preview_route)
251		.ruma_route(&client::get_media_config_route)
252		.ruma_route(&client::get_devices_route)
253		.ruma_route(&client::get_device_route)
254		.ruma_route(&client::update_device_route)
255		.ruma_route(&client::delete_device_route)
256		.ruma_route(&client::delete_devices_route)
257		.ruma_route(&client::put_dehydrated_device_route)
258		.ruma_route(&client::delete_dehydrated_device_route)
259		.ruma_route(&client::get_dehydrated_device_route)
260		.ruma_route(&client::get_dehydrated_events_route)
261		.ruma_route(&client::send_event_to_device_route)
262}
263
264fn register_client_misc_routes(router: Router<State>) -> Router<State> {
265	router
266		.ruma_route(&client::turn_server_route)
267		.ruma_route(&client::get_transports_route)
268		.ruma_route(&client::well_known_support)
269		.ruma_route(&client::well_known_client)
270		.ruma_route(&client::tuwunel_remote_version)
271		.route("/_tuwunel/server_version", get(client::tuwunel_server_version))
272		.route(
273			"/_tuwunel/3pid/email/validate",
274			get(client::get_email_validate_route).post(client::post_email_validate_route),
275		)
276}
277
278fn register_oidc_routes(router: Router<State>) -> Router<State> {
279	// OIDC server endpoints (next-gen auth, MSC2965/2964/2966/2967)
280	router
281		.route("/_tuwunel/oidc/registration", post(oidc::registration_route))
282		.route("/_tuwunel/oidc/authorize", get(oidc::authorize_route))
283		.route("/_tuwunel/oidc/_complete", get(oidc::complete_route))
284		.route("/_tuwunel/oidc/native", get(native_get_route).post(native_submit_route))
285		.route("/_tuwunel/oidc/token", post(oidc::token_route))
286		.route("/_tuwunel/oidc/device_authorization", post(oidc::device_authorization_route))
287		.route("/_tuwunel/oidc/device", get(oidc::get_device_route))
288		.route(
289			"/_tuwunel/oidc/device_callback",
290			get(oidc::get_device_callback_route).post(oidc::post_device_callback_route),
291		)
292		.route("/_tuwunel/oidc/revoke", post(oidc::revoke_route))
293		.route("/_tuwunel/oidc/jwks", get(oidc::jwks_route))
294		.route("/_tuwunel/oidc/userinfo", get(oidc::userinfo_route).post(oidc::userinfo_route))
295		.route("/_tuwunel/oidc/account.js", get(oidc::account_js_route))
296		.route("/_tuwunel/oidc/account.css", get(oidc::account_css_route))
297		.route(
298			"/_tuwunel/oidc/account_callback",
299			get(oidc::get_account_callback_route).post(oidc::post_account_callback_route),
300		)
301		.route("/_tuwunel/oidc/account", get(oidc::get_account_route))
302		.route("/_matrix/client/v1/auth_issuer", get(oidc::auth_issuer_route))
303		.route("/_matrix/client/v1/auth_metadata", get(oidc::openid_configuration_route))
304		.route(
305			"/_matrix/client/unstable/org.matrix.msc2965/auth_issuer",
306			get(oidc::auth_issuer_route),
307		)
308		.route(
309			"/_matrix/client/unstable/org.matrix.msc2965/auth_metadata",
310			get(oidc::openid_configuration_route),
311		)
312		.route("/.well-known/openid-configuration", get(oidc::openid_configuration_route))
313}
314
315fn register_server_misc_routes(router: Router<State>) -> Router<State> {
316	// SS endpoints not related to federation
317	router
318		.ruma_route(&server::well_known_server)
319		.ruma_route(&server::get_openid_userinfo_route)
320}
321
322fn register_federation_routes(router: Router<State>, allow_federation: bool) -> Router<State> {
323	if allow_federation {
324		router
325			.ruma_route(&server::get_server_version_route)
326			.route("/_matrix/key/v2/server", get(server::get_server_keys_route))
327			.ruma_route(&server::get_public_rooms_route)
328			.ruma_route(&server::get_public_rooms_filtered_route)
329			.ruma_route(&server::send_transaction_message_route)
330			.ruma_route(&server::get_event_route)
331			.ruma_route(&server::get_event_by_timestamp_route)
332			.ruma_route(&server::get_backfill_route)
333			.ruma_route(&server::get_missing_events_route)
334			.ruma_route(&server::get_event_authorization_route)
335			.ruma_route(&server::get_room_state_route)
336			.ruma_route(&server::get_room_state_ids_route)
337			.ruma_route(&server::create_leave_event_template_route)
338			.ruma_route(&server::create_knock_event_template_route)
339			.ruma_route(&server::create_leave_event_v2_route)
340			.ruma_route(&server::create_knock_event_v1_route)
341			.ruma_route(&server::create_join_event_template_route)
342			.ruma_route(&server::create_join_event_v2_route)
343			.ruma_route(&server::create_invite_route)
344			.ruma_route(&server::get_devices_route)
345			.ruma_route(&server::get_room_information_route)
346			.ruma_route(&server::get_profile_information_route)
347			.ruma_route(&server::get_keys_route)
348			.ruma_route(&server::claim_keys_route)
349			.ruma_route(&server::get_hierarchy_route)
350			.ruma_route(&server::get_content_route)
351			.ruma_route(&server::get_content_thumbnail_route)
352			.route("/_matrix/federation/v1/query/edutypes", get(server::get_edu_types_route))
353			.route("/_tuwunel/local_user_count", get(client::tuwunel_local_user_count))
354	} else {
355		router
356			.route("/_matrix/federation/{*path}", any(federation_disabled))
357			.route("/_matrix/key/{*path}", any(federation_disabled))
358			.route("/_tuwunel/local_user_count", any(federation_disabled))
359	}
360}
361
362fn register_legacy_media_routes(
363	router: Router<State>,
364	allow_legacy_media: bool,
365) -> Router<State> {
366	if allow_legacy_media {
367		router
368			.ruma_route(&client::get_media_config_legacy_route)
369			.ruma_route(&client::get_media_preview_legacy_route)
370			.route(
371				"/_matrix/media/r0/download/{server_name}/{media_id}",
372				get(client::get_content_legacy_route),
373			)
374			.route(
375				"/_matrix/media/v3/download/{server_name}/{media_id}",
376				get(client::get_content_legacy_route),
377			)
378			.route(
379				"/_matrix/media/r0/download/{server_name}/{media_id}/{filename}",
380				get(client::get_content_as_filename_legacy_route),
381			)
382			.route(
383				"/_matrix/media/v3/download/{server_name}/{media_id}/{filename}",
384				get(client::get_content_as_filename_legacy_route),
385			)
386			.route(
387				"/_matrix/media/r0/thumbnail/{server_name}/{media_id}",
388				get(client::get_content_thumbnail_legacy_route),
389			)
390			.route(
391				"/_matrix/media/v3/thumbnail/{server_name}/{media_id}",
392				get(client::get_content_thumbnail_legacy_route),
393			)
394	} else {
395		router
396			.route("/_matrix/media/v3/config", any(legacy_media_disabled))
397			.route("/_matrix/media/v3/download/{*path}", any(legacy_media_disabled))
398			.route("/_matrix/media/v3/thumbnail/{*path}", any(legacy_media_disabled))
399			.route("/_matrix/media/v3/preview_url", any(legacy_media_disabled))
400	}
401}
402
403async fn legacy_media_disabled() -> impl IntoResponse {
404	err!(Request(Forbidden("Unauthenticated media is disabled.")))
405}
406
407async fn federation_disabled() -> impl IntoResponse {
408	err!(Request(Forbidden("Federation is disabled.")))
409}