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