Skip to main content

arminius_server_client/handlers/
thirdparty.rs

1// SPDX-FileCopyrightText: 2025 BWI GmbH
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Implements APIs for third-party networks over application service bridges.
6//! Currently, no third-party protocols are supported.
7
8#![allow(
9	clippy::allow_attributes,
10	reason = "This source file contains enums which allow `clippy::missing_docs_in_private_items`. But an exception to this lint will mistakenly report that it's unfulfilled when used with expect, even though it is not."
11)]
12
13mod tests;
14
15use std::collections::BTreeMap;
16
17use arminius_lib_component::{
18	Component, ServerState,
19	error::{InternalServerError, MatrixApiError, ResultExt as _},
20	ruma_requests::ArminiusResponse,
21};
22use arminius_lib_db::DefaultDb;
23use arminius_lib_db_user::UserQueries as _;
24use axum::{Router, extract::State, http::StatusCode, routing::get};
25use ruma::api::{client::thirdparty, error::ErrorKind};
26
27use crate::client_request::AuthenticatedClientRequest;
28
29#[allow(
30	missing_docs,
31	clippy::missing_docs_in_private_items,
32	reason = "TODO(#2003): This exception predates us enabling `clippy::allow_attributes_without_reason`, so we don't know why it was enabled"
33)]
34#[derive(Debug, thiserror::Error, MatrixApiError)]
35enum ThirdPartyError {
36	#[error(transparent)]
37	InternalServerError(#[from] InternalServerError),
38
39	/// The request's user does not exist.
40	#[error("User not found")]
41	#[matrix_api_error(status_code = StatusCode::NOT_FOUND, error_kind = ErrorKind::NotFound)]
42	UserNotFound,
43
44	/// The request's room does not exist.
45	#[error("Room not found")]
46	#[matrix_api_error(status_code = StatusCode::NOT_FOUND, error_kind = ErrorKind::NotFound)]
47	RoomNotFound,
48
49	/// The requested protocol does not exist.
50	#[error("Unknown protocol")]
51	#[matrix_api_error(status_code = StatusCode::NOT_FOUND, error_kind = ErrorKind::NotFound)]
52	UnknownProtocol,
53}
54
55/// Handler for `GET /_matrix/client/v3/thirdparty/location` (See
56/// <https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3thirdpartylocation>).
57///
58/// Endpoint used to retrieve an array of third-party network locations from a
59/// Matrix room alias.
60///
61/// NOTE: For now, this always return `404 - Not Found`
62/// because room aliases are not implemented.
63async fn get_location_for_room_alias_handler(
64	AuthenticatedClientRequest(_claims, _request): AuthenticatedClientRequest<
65		thirdparty::get_location_for_room_alias::v3::Request,
66	>,
67) -> Result<ArminiusResponse<thirdparty::get_location_for_room_alias::v3::Response>, ThirdPartyError>
68{
69	// TODO: return empty response for valid room aliases when room aliases are
70	// implemented
71	Err(ThirdPartyError::RoomNotFound)
72}
73
74/// Handler for `GET /_matrix/client/v3/thirdparty/location/{protocol}` (See
75/// <https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3thirdpartylocationprotocol>).
76///
77/// Requesting this endpoint with a valid protocol name would return the
78/// locations.
79///
80/// NOTE: For now, there are no supported third-parties, so it always return
81/// `404 - Not Found`.
82async fn get_location_for_protocol_handler(
83	AuthenticatedClientRequest(_claims, _request): AuthenticatedClientRequest<
84		thirdparty::get_location_for_protocol::v3::Request,
85	>,
86) -> Result<ArminiusResponse<thirdparty::get_location_for_protocol::v3::Response>, ThirdPartyError>
87{
88	Err(ThirdPartyError::UnknownProtocol)
89}
90
91/// Handler for `GET /_matrix/client/v3/thirdparty/protocol/{protocol}` (See
92/// <https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3thirdpartyprotocolprotocol>).
93///
94/// Fetches the metadata from the homeserver about a particular third-party
95/// protocol.
96///
97/// NOTE: For now, there are no supported third-parties, so this always returns
98/// `404 - Not Found`.
99async fn get_protocol_handler(
100	AuthenticatedClientRequest(_claims, _request): AuthenticatedClientRequest<
101		thirdparty::get_protocol::v3::Request,
102	>,
103) -> Result<ArminiusResponse<thirdparty::get_protocol::v3::Response>, ThirdPartyError> {
104	Err(ThirdPartyError::UnknownProtocol)
105}
106
107/// Handler for `GET /_matrix/client/v3/thirdparty/protocols` (See
108/// <https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3thirdpartyprotocols>).
109///
110/// Fetches the overall metadata about protocols supported by the homeserver.
111///
112/// NOTE: For now, there are no supported third-parties, so this always returns
113/// an empty map.
114async fn get_protocols_handler(
115	AuthenticatedClientRequest(_claims, _request): AuthenticatedClientRequest<
116		thirdparty::get_protocols::v3::Request,
117	>,
118) -> Result<ArminiusResponse<thirdparty::get_protocols::v3::Response>, ThirdPartyError> {
119	Ok(thirdparty::get_protocols::v3::Response::new(BTreeMap::default()).into())
120}
121
122/// Handler for `GET /_matrix/client/v3/thirdparty/user` (See
123/// <https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3thirdpartyuser>).
124///
125/// Retrieve the always empty array of third-party users from a Matrix User ID.
126///
127///	If the user does not exist, a `404 - Not Found` is returned. Otherwise,
128/// returns an empty array since there are no supported third-parties for now.
129async fn get_user_for_user_id_handler(
130	mut database: State<DefaultDb>,
131	AuthenticatedClientRequest(_claims, request): AuthenticatedClientRequest<
132		thirdparty::get_user_for_user_id::v3::Request,
133	>,
134) -> Result<ArminiusResponse<thirdparty::get_user_for_user_id::v3::Response>, ThirdPartyError> {
135	database
136		.fetch_user(&request.userid)
137		.await
138		.unrecoverable_error("Querying user")?
139		.ok_or(ThirdPartyError::UserNotFound)?;
140
141	Ok(thirdparty::get_user_for_user_id::v3::Response::new(vec![]).into())
142}
143
144/// Handler for `GET /_matrix/client/v3/thirdparty/user/{protocol}` (See
145/// <https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3thirdpartyuserprotocol>).
146///
147/// Retrieve a Matrix User ID linked to a user on the third-party service/.
148///
149/// NOTE: For now, there are no supported third-party, so this always returns
150/// `404 - Not Found`.
151async fn get_user_for_protocol_handler(
152	AuthenticatedClientRequest(_claims, _request): AuthenticatedClientRequest<
153		thirdparty::get_user_for_protocol::v3::Request,
154	>,
155) -> Result<ArminiusResponse<thirdparty::get_user_for_protocol::v3::Response>, ThirdPartyError> {
156	Err(ThirdPartyError::UnknownProtocol)
157}
158
159/// Component implementing endpoints for account management
160#[derive(Debug)]
161pub struct ThirdpartyComponent;
162
163impl Component for ThirdpartyComponent {
164	fn router() -> Router<ServerState> {
165		Router::new()
166			.route(
167				"/_matrix/client/v3/thirdparty/location",
168				get(get_location_for_room_alias_handler),
169			)
170			.route(
171				"/_matrix/client/v3/thirdparty/location/{protocol}",
172				get(get_location_for_protocol_handler),
173			)
174			.route("/_matrix/client/v3/thirdparty/protocol/{protocol}", get(get_protocol_handler))
175			.route("/_matrix/client/v3/thirdparty/protocols", get(get_protocols_handler))
176			.route("/_matrix/client/v3/thirdparty/user", get(get_user_for_user_id_handler))
177			.route(
178				"/_matrix/client/v3/thirdparty/user/{protocol}",
179				get(get_user_for_protocol_handler),
180			)
181	}
182}