Skip to main content

tuwunel_api/oidc/account/
session_end_execute.rs

1use const_str::format as const_format;
2use ruma::{OwnedDeviceId, UserId};
3use tuwunel_core::{Err, Result, info, utils::html::escape as html_escape};
4use tuwunel_service::Services;
5
6use super::ACCOUNT_HEAD;
7
8/// Executes the actual session deletion. Called only from the POST handler.
9pub(super) async fn session_end_execute_html(
10	services: &Services,
11	user_id: &UserId,
12	device_id: &str,
13) -> Result<String> {
14	if device_id.is_empty() {
15		return Err!(Request(InvalidParam("device_id is required")));
16	}
17
18	let device_id_owned: OwnedDeviceId = device_id.into();
19	if !services
20		.users
21		.device_exists(user_id, &device_id_owned)
22		.await
23	{
24		return Err!(Request(NotFound("Session not found")));
25	}
26
27	services
28		.users
29		.remove_device(user_id, &device_id_owned)
30		.await;
31
32	info!(?user_id, ?device_id_owned, "Session signed out via account management page");
33
34	Ok(PAGE_HTML
35		.replace("{did}", &html_escape(device_id_owned.as_str()))
36		.replace("{uid}", &html_escape(user_id.as_str())))
37}
38
39static PAGE_HTML: &str = const_format!(
40	r#"
41<!DOCTYPE html>
42<html lang="en">
43	<head>
44		{ACCOUNT_HEAD}
45		<title>Session Signed Out</title>
46	</head>
47	<body>
48		<h1 class="ok">Session Signed Out</h1>
49		<p>
50			Session <code>{{did}}</code> for <strong>{{uid}}</strong> has been signed out.
51		</p>
52		<div class="nav">
53			<a href="/_tuwunel/oidc/account?action=org.matrix.sessions_list">
54				Back to sessions
55			</a>
56		</div>
57	</body>
58</html>"#
59);