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 http::{HeaderValue, header};
16use tower_http::set_header::SetResponseHeaderLayer;
17use tuwunel_core::{Server, err};
18
19use self::handler::RouterExt;
20pub(super) use self::{
21	args::Args as Ruma, auth::auth_uiaa, client_ip::ClientIp, response::RumaResponse,
22	state::State,
23};
24use crate::{client, oidc, server};
25
26pub fn build(router: Router<State>, server: &Server) -> Router<State> {
27	let config = &server.config;
28	let mas_active = client::mas_active(config);
29	let router = register_client_auth_routes(router);
30	let router = register_mas_routes(router);
31	let router = register_client_profile_and_data_routes(router);
32	let router = register_client_keys_and_backup_routes(router);
33	let router = register_client_room_routes(router);
34	let router = register_client_state_and_sync_routes(router);
35	let router = register_client_media_and_device_routes(router);
36	let router = register_client_misc_routes(router);
37	let router = register_synapse_admin_users_routes(router, mas_active);
38	let router = register_synapse_admin_devices_routes(router, mas_active);
39	let router = register_synapse_admin_rooms_routes(router);
40	let router = register_synapse_admin_media_routes(router);
41	let router = register_synapse_admin_federation_routes(router);
42	let router = register_synapse_admin_misc_routes(router);
43	let router = register_oidc_routes(router);
44	let router = register_rendezvous_routes(router);
45	let router = register_server_misc_routes(router);
46	let router = register_federation_routes(router, config.allow_federation);
47
48	register_legacy_media_routes(router, config.allow_legacy_media)
49}
50
51fn register_client_auth_routes(router: Router<State>) -> Router<State> {
52	router
53		.ruma_route(&client::get_supported_versions_route)
54		.ruma_route(&client::get_register_available_route)
55		.ruma_route(&client::register_route)
56		.ruma_route(&client::get_login_types_route)
57		.ruma_route(&client::login_route)
58		.ruma_route(&client::login_token_route)
59		.ruma_route(&client::refresh_token_route)
60		.ruma_route(&client::sso_login_route)
61		.ruma_route(&client::sso_login_with_provider_route)
62		.ruma_route(&client::sso_callback_route)
63		.ruma_route(&client::sso_fallback_route)
64		.ruma_route(&client::whoami_route)
65		.ruma_route(&client::logout_route)
66		.ruma_route(&client::logout_all_route)
67		.ruma_route(&client::change_password_route)
68		.ruma_route(&client::deactivate_route)
69		.ruma_route(&client::third_party_route)
70		.ruma_route(&client::add_3pid_route)
71		.ruma_route(&client::delete_3pid_route)
72		.ruma_route(&client::request_3pid_management_token_via_email_route)
73		.ruma_route(&client::request_3pid_management_token_via_msisdn_route)
74		.ruma_route(&client::request_registration_token_via_email_route)
75		.ruma_route(&client::request_password_change_token_via_email_route)
76		.ruma_route(&client::check_registration_token_validity)
77		.ruma_route(&client::create_openid_token_route)
78		.ruma_route(&client::is_user_suspended_route)
79		.ruma_route(&client::suspend_user_route)
80		.ruma_route(&client::is_user_locked_route)
81		.ruma_route(&client::lock_user_route)
82		.route("/_tuwunel/sso/complete.js", get(client::sso_complete_js_route))
83		.route("/_tuwunel/sso/sso.css", get(client::sso_css_route))
84}
85
86fn register_mas_routes(router: Router<State>) -> Router<State> {
87	router
88		.ruma_route(&client::mas::query_user_route)
89		.ruma_route(&client::mas::provision_user_route)
90		.ruma_route(&client::mas::is_localpart_available_route)
91		.ruma_route(&client::mas::delete_user_route)
92		.ruma_route(&client::mas::reactivate_user_route)
93		.ruma_route(&client::mas::set_displayname_route)
94		.ruma_route(&client::mas::unset_displayname_route)
95		.ruma_route(&client::mas::allow_cross_signing_reset_route)
96		.ruma_route(&client::mas::upsert_device_route)
97		.ruma_route(&client::mas::delete_device_route)
98		.ruma_route(&client::mas::update_device_display_name_route)
99		.ruma_route(&client::mas::sync_devices_route)
100}
101
102fn register_synapse_admin_users_routes(router: Router<State>, mas_active: bool) -> Router<State> {
103	let router = router
104		.ruma_route(&client::users::admin_list_users_v2_route)
105		.ruma_route(&client::users::admin_list_users_v3_route)
106		.ruma_route(&client::users::admin_get_details_route)
107		.ruma_route(&client::users::admin_create_or_modify_route)
108		.ruma_route(&client::users::admin_deactivate_account_route)
109		.ruma_route(&client::users::admin_list_joined_rooms_route)
110		.ruma_route(&client::users::admin_memberships_route)
111		.ruma_route(&client::users::admin_pushers_route)
112		.ruma_route(&client::users::admin_account_data_route)
113		.ruma_route(&client::users::admin_suspend_route)
114		.ruma_route(&client::users::admin_username_available_route)
115		.ruma_route(&client::users::admin_lookup_threepid_route)
116		.ruma_route(&client::users::admin_allow_cross_signing_replacement_route)
117		.ruma_route(&client::users::admin_redact_user_route)
118		.ruma_route(&client::users::admin_redact_status_route)
119		// whois is served at the /_synapse admin path and the client-server admin
120		// aliases where Synapse also mounts it.
121		.route("/_synapse/admin/v1/whois/{user_id}", get(client::users::admin_whois_route))
122		.route("/_matrix/client/v3/admin/whois/{user_id}", get(client::users::admin_whois_route))
123		.route("/_matrix/client/r0/admin/whois/{user_id}", get(client::users::admin_whois_route))
124		.route(
125			"/_matrix/client/unstable/admin/whois/{user_id}",
126			get(client::users::admin_whois_route),
127		);
128
129	// The Synapse user-provisioning routes MAS owns (register pair, password
130	// reset, admin flag) are de-registered under MAS delegation, mirroring
131	// Synapse.
132	if mas_active {
133		router
134	} else {
135		router
136			.ruma_route(&client::admin_register_nonce_route)
137			.ruma_route(&client::admin_register_route)
138			.ruma_route(&client::users::admin_reset_password_route)
139			.ruma_route(&client::users::admin_is_user_admin_route)
140			.ruma_route(&client::users::admin_login_as_route)
141	}
142}
143
144fn register_synapse_admin_devices_routes(
145	router: Router<State>,
146	mas_active: bool,
147) -> Router<State> {
148	let router = router
149		.ruma_route(&client::devices::admin_list_devices_route)
150		.ruma_route(&client::devices::admin_create_device_route)
151		.ruma_route(&client::devices::admin_get_device_route)
152		.ruma_route(&client::devices::admin_update_device_route)
153		.ruma_route(&client::devices::admin_delete_device_route)
154		.ruma_route(&client::devices::admin_delete_devices_route);
155
156	// Registration-token administration is de-registered under MAS, mirroring
157	// Synapse.
158	if mas_active {
159		router
160	} else {
161		router
162			.ruma_route(&client::tokens::admin_list_tokens_route)
163			.ruma_route(&client::tokens::admin_create_token_route)
164			.ruma_route(&client::tokens::admin_get_token_route)
165			.ruma_route(&client::tokens::admin_update_token_route)
166			.ruma_route(&client::tokens::admin_delete_token_route)
167	}
168}
169
170fn register_synapse_admin_rooms_routes(router: Router<State>) -> Router<State> {
171	router
172		.ruma_route(&client::rooms::admin_list_rooms_route)
173		.ruma_route(&client::rooms::admin_room_details_route)
174		.ruma_route(&client::rooms::admin_room_members_route)
175		.ruma_route(&client::rooms::admin_join_room_route)
176		.ruma_route(&client::rooms::admin_get_room_block_route)
177		.ruma_route(&client::rooms::admin_set_room_block_route)
178		.ruma_route(&client::rooms::admin_make_room_admin_route)
179		.ruma_route(&client::rooms::admin_delete_room_v1_route)
180		.ruma_route(&client::rooms::admin_delete_room_v2_route)
181		.ruma_route(&client::rooms::admin_delete_status_by_id_route)
182		.ruma_route(&client::rooms::admin_delete_status_by_room_route)
183		.ruma_route(&client::rooms::admin_get_forward_extremities_route)
184		.ruma_route(&client::rooms::admin_delete_forward_extremities_route)
185		.ruma_route(&client::rooms::admin_purge_history_route)
186		.ruma_route(&client::rooms::admin_purge_history_by_event_route)
187		.ruma_route(&client::rooms::admin_purge_history_status_route)
188		.ruma_route(&client::rooms::admin_room_state_route)
189		.ruma_route(&client::rooms::admin_room_messages_route)
190		.ruma_route(&client::rooms::admin_room_context_route)
191		.ruma_route(&client::rooms::admin_room_timestamp_to_event_route)
192		.ruma_route(&client::rooms::admin_room_hierarchy_route)
193}
194
195fn register_synapse_admin_media_routes(router: Router<State>) -> Router<State> {
196	router
197		.ruma_route(&client::admin::media::admin_query_media_route)
198		.ruma_route(&client::admin::media::admin_delete_media_route)
199		.ruma_route(&client::admin::media::admin_list_user_media_route)
200		.ruma_route(&client::admin::media::admin_list_room_media_route)
201		.ruma_route(&client::admin::media::admin_delete_user_media_route)
202		.ruma_route(&client::admin::media::admin_purge_media_cache_route)
203		.ruma_route(&client::admin::media::admin_user_media_statistics_route)
204		.route(
205			"/_synapse/admin/v1/media/delete",
206			post(client::admin::media::admin_delete_media_by_date_size_route),
207		)
208		// Synapse's deprecated per-server alias for the same date/size purge.
209		.route(
210			"/_synapse/admin/v1/media/{server_name}/delete",
211			post(client::admin::media::admin_delete_media_by_date_size_route),
212		)
213}
214
215fn register_synapse_admin_federation_routes(router: Router<State>) -> Router<State> {
216	router
217		.ruma_route(&client::admin::federation::admin_list_destinations_route)
218		.ruma_route(&client::admin::federation::admin_destination_details_route)
219		.ruma_route(&client::admin::federation::admin_destination_rooms_route)
220		.ruma_route(&client::admin::federation::admin_reset_connection_route)
221}
222
223fn register_synapse_admin_misc_routes(router: Router<State>) -> Router<State> {
224	router
225		.ruma_route(&client::misc::admin_server_version_route)
226		.ruma_route(&client::misc::admin_fetch_event_route)
227		.ruma_route(&client::misc::admin_scheduled_tasks_route)
228		.ruma_route(&client::misc::admin_send_server_notice_route)
229		.ruma_route(&client::misc::admin_send_server_notice_txn_route)
230}
231
232fn register_client_profile_and_data_routes(router: Router<State>) -> Router<State> {
233	router
234		.ruma_route(&client::get_profile_field_route)
235		.ruma_route(&client::set_profile_field_route)
236		.ruma_route(&client::delete_profile_field_route)
237		.ruma_route(&client::get_profile_route)
238		.ruma_route(&client::set_presence_route)
239		.ruma_route(&client::get_presence_route)
240		.ruma_route(&client::get_filter_route)
241		.ruma_route(&client::create_filter_route)
242		.ruma_route(&client::set_global_account_data_route)
243		.ruma_route(&client::set_room_account_data_route)
244		.ruma_route(&client::get_global_account_data_route)
245		.ruma_route(&client::get_room_account_data_route)
246		.ruma_route(&client::delete_global_account_data_route)
247		.ruma_route(&client::delete_room_account_data_route)
248		.ruma_route(&client::get_tags_route)
249		.ruma_route(&client::update_tag_route)
250		.ruma_route(&client::delete_tag_route)
251		.ruma_route(&client::get_pushrules_all_route)
252		.ruma_route(&client::get_pushrules_global_route)
253		.ruma_route(&client::set_pushrule_route)
254		.ruma_route(&client::get_pushrule_route)
255		.ruma_route(&client::set_pushrule_enabled_route)
256		.ruma_route(&client::get_pushrule_enabled_route)
257		.ruma_route(&client::get_pushrule_actions_route)
258		.ruma_route(&client::set_pushrule_actions_route)
259		.ruma_route(&client::delete_pushrule_route)
260		.ruma_route(&client::get_pushers_route)
261		.ruma_route(&client::set_pushers_route)
262		.ruma_route(&client::get_notifications_route)
263		.ruma_route(&client::get_capabilities_route)
264}
265
266fn register_client_keys_and_backup_routes(router: Router<State>) -> Router<State> {
267	router
268		.ruma_route(&client::upload_keys_route)
269		.ruma_route(&client::get_keys_route)
270		.ruma_route(&client::claim_keys_route)
271		.ruma_route(&client::upload_signing_keys_route)
272		.ruma_route(&client::upload_signatures_route)
273		.ruma_route(&client::get_key_changes_route)
274		.ruma_route(&client::create_backup_version_route)
275		.ruma_route(&client::update_backup_version_route)
276		.ruma_route(&client::delete_backup_version_route)
277		.ruma_route(&client::get_latest_backup_info_route)
278		.ruma_route(&client::get_backup_info_route)
279		.ruma_route(&client::add_backup_keys_route)
280		.ruma_route(&client::add_backup_keys_for_room_route)
281		.ruma_route(&client::add_backup_keys_for_session_route)
282		.ruma_route(&client::delete_backup_keys_for_room_route)
283		.ruma_route(&client::delete_backup_keys_for_session_route)
284		.ruma_route(&client::delete_backup_keys_route)
285		.ruma_route(&client::get_backup_keys_for_room_route)
286		.ruma_route(&client::get_backup_keys_for_session_route)
287		.ruma_route(&client::get_backup_keys_route)
288}
289
290fn register_client_room_routes(router: Router<State>) -> Router<State> {
291	router
292		.ruma_route(&client::appservice_ping)
293		.ruma_route(&client::set_read_marker_route)
294		.ruma_route(&client::create_receipt_route)
295		.ruma_route(&client::create_typing_event_route)
296		.ruma_route(&client::create_room_route)
297		.ruma_route(&client::redact_event_route)
298		.ruma_route(&client::report_event_route)
299		.ruma_route(&client::report_room_route)
300		.ruma_route(&client::report_user_route)
301		.ruma_route(&client::create_alias_route)
302		.ruma_route(&client::delete_alias_route)
303		.ruma_route(&client::get_alias_route)
304		.ruma_route(&client::join_room_by_id_route)
305		.ruma_route(&client::join_room_by_id_or_alias_route)
306		.ruma_route(&client::joined_members_route)
307		.ruma_route(&client::knock_room_route)
308		.ruma_route(&client::leave_room_route)
309		.ruma_route(&client::forget_room_route)
310		.ruma_route(&client::joined_rooms_route)
311		.ruma_route(&client::kick_user_route)
312		.ruma_route(&client::ban_user_route)
313		.ruma_route(&client::unban_user_route)
314		.ruma_route(&client::invite_user_route)
315		.ruma_route(&client::set_room_visibility_route)
316		.ruma_route(&client::get_room_visibility_route)
317		.ruma_route(&client::get_public_rooms_route)
318		.ruma_route(&client::get_public_rooms_filtered_route)
319		.ruma_route(&client::search_users_route)
320		.ruma_route(&client::get_member_events_route)
321		.ruma_route(&client::get_protocols_route)
322		.ruma_route(&client::get_protocol_route)
323		.ruma_route(&client::get_user_for_protocol_route)
324		.ruma_route(&client::get_location_for_protocol_route)
325		.ruma_route(&client::get_user_for_user_id_route)
326		.ruma_route(&client::get_location_for_room_alias_route)
327		.ruma_route(&client::upgrade_room_route)
328		.ruma_route(&client::get_mutual_rooms_route)
329		.ruma_route(&client::get_room_summary)
330		.route(
331			"/_matrix/client/unstable/im.nheko.summary/rooms/{room_id_or_alias}/summary",
332			get(client::get_room_summary_legacy),
333		)
334		.ruma_route(&client::room_initial_sync_route)
335		.ruma_route(&client::get_room_event_route)
336		.ruma_route(&client::get_room_aliases_route)
337}
338
339fn register_client_state_and_sync_routes(router: Router<State>) -> Router<State> {
340	router
341		.ruma_route(&client::send_message_event_route)
342		.ruma_route(&client::send_state_event_for_key_route)
343		.ruma_route(&client::get_state_events_route)
344		.ruma_route(&client::get_state_events_for_key_route)
345		// Ruma doesn't have support for multiple paths for a single endpoint yet, and these
346		// routes share one Ruma request / response type pair with
347		// {get,send}_state_event_for_key_route
348		.route(
349			"/_matrix/client/r0/rooms/{room_id}/state/{event_type}",
350			get(client::get_state_events_for_empty_key_route)
351				.put(client::send_state_event_for_empty_key_route),
352		)
353		.route(
354			"/_matrix/client/v3/rooms/{room_id}/state/{event_type}",
355			get(client::get_state_events_for_empty_key_route)
356				.put(client::send_state_event_for_empty_key_route),
357		)
358		// These two endpoints allow trailing slashes
359		.route(
360			"/_matrix/client/r0/rooms/{room_id}/state/{event_type}/",
361			get(client::get_state_events_for_empty_key_route)
362				.put(client::send_state_event_for_empty_key_route),
363		)
364		.route(
365			"/_matrix/client/v3/rooms/{room_id}/state/{event_type}/",
366			get(client::get_state_events_for_empty_key_route)
367				.put(client::send_state_event_for_empty_key_route),
368		)
369		.ruma_route(&client::events_route)
370		.ruma_route(&client::sync_events_route)
371		.ruma_route(&client::sync_events_v5_route)
372		.ruma_route(&client::get_context_route)
373		.ruma_route(&client::get_event_by_timestamp_route)
374		.ruma_route(&client::get_message_events_route)
375		.ruma_route(&client::search_events_route)
376		.ruma_route(&client::get_threads_route)
377		.ruma_route(&client::get_relating_events_with_rel_type_and_event_type_route)
378		.ruma_route(&client::get_relating_events_with_rel_type_route)
379		.ruma_route(&client::get_relating_events_route)
380		.ruma_route(&client::get_hierarchy_route)
381}
382
383fn register_client_media_and_device_routes(router: Router<State>) -> Router<State> {
384	let media_content_router = Router::new()
385		.ruma_route(&client::get_content_thumbnail_route)
386		.ruma_route(&client::get_content_route)
387		.ruma_route(&client::get_content_as_filename_route);
388
389	let media_content_router = media_content_headers(media_content_router);
390
391	router
392		.ruma_route(&client::create_content_route)
393		.ruma_route(&client::create_mxc_uri_route)
394		.ruma_route(&client::create_content_async_route)
395		.ruma_route(&client::get_media_preview_route)
396		.ruma_route(&client::get_media_config_route)
397		.ruma_route(&client::get_devices_route)
398		.ruma_route(&client::get_device_route)
399		.ruma_route(&client::update_device_route)
400		.ruma_route(&client::delete_device_route)
401		.ruma_route(&client::delete_devices_route)
402		.ruma_route(&client::put_dehydrated_device_route)
403		.ruma_route(&client::delete_dehydrated_device_route)
404		.ruma_route(&client::get_dehydrated_device_route)
405		.ruma_route(&client::get_dehydrated_events_route)
406		.ruma_route(&client::send_event_to_device_route)
407		.merge(media_content_router)
408}
409
410fn register_client_misc_routes(router: Router<State>) -> Router<State> {
411	router
412		.ruma_route(&client::turn_server_route)
413		.ruma_route(&client::get_transports_route)
414		.ruma_route(&client::well_known_support)
415		.ruma_route(&client::well_known_client)
416		.ruma_route(&client::tuwunel_remote_version)
417		.route("/_tuwunel/server_version", get(client::tuwunel_server_version))
418		.route(
419			"/_tuwunel/3pid/email/validate",
420			get(client::get_email_validate_route).post(client::post_email_validate_route),
421		)
422}
423
424fn register_oidc_routes(router: Router<State>) -> Router<State> {
425	// OIDC server endpoints (next-gen auth, MSC2965/2964/2966/2967)
426	router
427		.route("/_tuwunel/oidc/registration", post(oidc::registration_route))
428		.route("/_tuwunel/oidc/authorize", get(oidc::authorize_route))
429		.route("/_tuwunel/oidc/_complete", get(oidc::complete_route))
430		.route(
431			"/_tuwunel/oidc/native",
432			get(oidc::native_get_route).post(oidc::native_submit_route),
433		)
434		.route("/_tuwunel/oidc/token", post(oidc::token_route))
435		.route("/_tuwunel/oidc/device_authorization", post(oidc::device_authorization_route))
436		.route("/_tuwunel/oidc/device", get(oidc::get_device_route))
437		.route(
438			"/_tuwunel/oidc/device_callback",
439			get(oidc::get_device_callback_route).post(oidc::post_device_callback_route),
440		)
441		.route("/_tuwunel/oidc/revoke", post(oidc::revoke_route))
442		.route("/_tuwunel/oidc/jwks", get(oidc::jwks_route))
443		.route("/_tuwunel/oidc/userinfo", get(oidc::userinfo_route).post(oidc::userinfo_route))
444		.route("/_tuwunel/oidc/account.js", get(oidc::account_js_route))
445		.route("/_tuwunel/oidc/account.css", get(oidc::account_css_route))
446		.route(
447			"/_tuwunel/oidc/account_callback",
448			get(oidc::get_account_callback_route).post(oidc::post_account_callback_route),
449		)
450		.route("/_tuwunel/oidc/account", get(oidc::get_account_route))
451		.route("/_matrix/client/v1/auth_issuer", get(oidc::auth_issuer_route))
452		.route("/_matrix/client/v1/auth_metadata", get(oidc::openid_configuration_route))
453		.route(
454			"/_matrix/client/unstable/org.matrix.msc2965/auth_issuer",
455			get(oidc::auth_issuer_route),
456		)
457		.route(
458			"/_matrix/client/unstable/org.matrix.msc2965/auth_metadata",
459			get(oidc::openid_configuration_route),
460		)
461		.route("/.well-known/openid-configuration", get(oidc::openid_configuration_route))
462}
463
464fn register_rendezvous_routes(router: Router<State>) -> Router<State> {
465	let router = router
466		.ruma_route(&client::discover_msc4388_route)
467		.ruma_route(&client::create_msc4388_route)
468		.ruma_route(&client::get_msc4388_route)
469		.ruma_route(&client::put_msc4388_route)
470		.ruma_route(&client::delete_msc4388_route);
471
472	let session_routes = get(client::get_rendezvous_route)
473		.put(client::put_rendezvous_route)
474		.delete(client::delete_rendezvous_route);
475
476	router
477		.route(
478			"/_matrix/client/unstable/org.matrix.msc4108/rendezvous",
479			post(client::create_rendezvous_route),
480		)
481		.route("/_matrix/client/unstable/org.matrix.msc4108/rendezvous/{id}", session_routes)
482}
483
484fn register_server_misc_routes(router: Router<State>) -> Router<State> {
485	// SS endpoints not related to federation
486	router
487		.ruma_route(&server::well_known_server)
488		.ruma_route(&server::get_openid_userinfo_route)
489}
490
491fn register_federation_routes(router: Router<State>, allow_federation: bool) -> Router<State> {
492	if allow_federation {
493		router
494			.ruma_route(&server::get_server_version_route)
495			.route("/_matrix/key/v2/server", get(server::get_server_keys_route))
496			.ruma_route(&server::get_public_rooms_route)
497			.ruma_route(&server::get_public_rooms_filtered_route)
498			.ruma_route(&server::send_transaction_message_route)
499			.ruma_route(&server::get_event_route)
500			.ruma_route(&server::get_event_by_timestamp_route)
501			.ruma_route(&server::get_backfill_route)
502			.ruma_route(&server::get_missing_events_route)
503			.ruma_route(&server::get_event_authorization_route)
504			.ruma_route(&server::get_room_state_route)
505			.ruma_route(&server::get_room_state_ids_route)
506			.ruma_route(&server::create_leave_event_template_route)
507			.ruma_route(&server::create_knock_event_template_route)
508			.ruma_route(&server::create_leave_event_v2_route)
509			.ruma_route(&server::create_knock_event_v1_route)
510			.ruma_route(&server::create_join_event_template_route)
511			.ruma_route(&server::create_join_event_v2_route)
512			.ruma_route(&server::create_invite_route)
513			.ruma_route(&server::get_devices_route)
514			.ruma_route(&server::get_room_information_route)
515			.ruma_route(&server::get_profile_information_route)
516			.ruma_route(&server::get_keys_route)
517			.ruma_route(&server::claim_keys_route)
518			.ruma_route(&server::get_hierarchy_route)
519			.ruma_route(&server::get_content_route)
520			.ruma_route(&server::get_content_thumbnail_route)
521			.route("/_tuwunel/local_user_count", get(client::tuwunel_local_user_count))
522	} else {
523		router
524			.route("/_matrix/federation/{*path}", any(federation_disabled))
525			.route("/_matrix/key/{*path}", any(federation_disabled))
526			.route("/_tuwunel/local_user_count", any(federation_disabled))
527	}
528}
529
530fn register_legacy_media_routes(
531	router: Router<State>,
532	allow_legacy_media: bool,
533) -> Router<State> {
534	if allow_legacy_media {
535		let media_content_router = Router::new()
536			.route(
537				"/_matrix/media/r0/download/{server_name}/{media_id}",
538				get(client::get_content_legacy_route),
539			)
540			.route(
541				"/_matrix/media/v3/download/{server_name}/{media_id}",
542				get(client::get_content_legacy_route),
543			)
544			.route(
545				"/_matrix/media/r0/download/{server_name}/{media_id}/{filename}",
546				get(client::get_content_as_filename_legacy_route),
547			)
548			.route(
549				"/_matrix/media/v3/download/{server_name}/{media_id}/{filename}",
550				get(client::get_content_as_filename_legacy_route),
551			)
552			.route(
553				"/_matrix/media/r0/thumbnail/{server_name}/{media_id}",
554				get(client::get_content_thumbnail_legacy_route),
555			)
556			.route(
557				"/_matrix/media/v3/thumbnail/{server_name}/{media_id}",
558				get(client::get_content_thumbnail_legacy_route),
559			);
560
561		let media_content_router = media_content_headers(media_content_router);
562
563		router
564			.ruma_route(&client::get_media_config_legacy_route)
565			.ruma_route(&client::get_media_preview_legacy_route)
566			.merge(media_content_router)
567	} else {
568		router
569			.route("/_matrix/media/v3/config", any(legacy_media_disabled))
570			.route("/_matrix/media/v3/download/{*path}", any(legacy_media_disabled))
571			.route("/_matrix/media/v3/thumbnail/{*path}", any(legacy_media_disabled))
572			.route("/_matrix/media/v3/preview_url", any(legacy_media_disabled))
573	}
574}
575
576fn media_content_headers(router: Router<State>) -> Router<State> {
577	const MEDIA_CSP: &[&str] = &[
578		"sandbox",
579		"default-src 'none'",
580		"script-src 'none'",
581		"plugin-types application/pdf",
582		"style-src 'unsafe-inline'",
583		"object-src 'self'",
584	];
585
586	router.route_layer(SetResponseHeaderLayer::overriding(
587		header::CONTENT_SECURITY_POLICY,
588		HeaderValue::from_static(const_str::join!(MEDIA_CSP, ";")),
589	))
590}
591
592async fn legacy_media_disabled() -> impl IntoResponse {
593	err!(Request(Forbidden("Unauthenticated media is disabled.")))
594}
595
596async fn federation_disabled() -> impl IntoResponse {
597	err!(Request(Forbidden("Federation is disabled.")))
598}