Skip to main content

tuwunel_api/client/session/
appservice.rs

1use ruma::{
2	OwnedUserId, UserId,
3	api::client::{
4		session::login::v3::{ApplicationService, Request},
5		uiaa,
6	},
7};
8use tuwunel_core::{Err, Result, err, extract};
9use tuwunel_service::Services;
10
11use crate::Ruma;
12
13pub(super) fn handle_login(
14	services: &Services,
15	body: &Ruma<Request>,
16	info: &ApplicationService,
17) -> Result<OwnedUserId> {
18	#[expect(deprecated)]
19	let ApplicationService { identifier, user } = info;
20
21	let Some(ref info) = body.appservice_info else {
22		return Err!(Request(MissingToken("Missing appservice token.")));
23	};
24
25	// MSC4190: an appservice managing its own devices does not use appservice
26	// login; it creates devices directly via PUT /devices/{deviceId}.
27	if info.registration.device_management {
28		return Err!(Request(AppserviceLoginUnsupported(
29			"Appservice has MSC4190 device management enabled; appservice login is unsupported."
30		)));
31	}
32
33	let user_id = extract!(
34		identifier,
35		x in Some(uiaa::UserIdentifier::Matrix(uiaa::MatrixUserIdentifier { user: x, .. }))
36	)
37	.or(user.as_ref())
38	.ok_or_else(|| {
39		err!(Request(Unknown(debug_warn!(
40			?body.login_info,
41			"Valid identifier or username was not provided (invalid or unsupported login type?)"
42		))))
43	})?;
44
45	let user_id = UserId::parse_with_server_name(user_id, &services.config.server_name)
46		.map_err(|e| err!(Request(InvalidUsername(warn!("Username is invalid: {e}")))))?;
47
48	if !services.globals.user_is_local(&user_id) {
49		return Err!(Request(Unknown("User ID does not belong to this homeserver")));
50	}
51
52	let emergency_mode_enabled = services.config.emergency_password.is_some();
53
54	if !info.is_user_match(&user_id) && !emergency_mode_enabled {
55		return Err!(Request(Exclusive("Username is not in an appservice namespace.")));
56	}
57
58	Ok(user_id)
59}