tuwunel_api/oidc/account/
session_end_execute.rs1use 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
8pub(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);