tuwunel_api/oidc/account/
session_view.rs1use const_str::format as const_format;
2use ruma::{OwnedDeviceId, UserId};
3use tuwunel_core::{Err, Result, err, utils::html::escape as html_escape};
4use tuwunel_service::Services;
5
6use super::{ACCOUNT_HEAD, ACCOUNT_JS_INCLUDE, ts_cell, url_encode};
7
8pub(super) async fn session_view_html(
9 services: &Services,
10 user_id: &UserId,
11 device_id: &str,
12 login_token: &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 let device = services
20 .users
21 .get_device_metadata(user_id, &device_id_owned)
22 .await
23 .map_err(|_| err!(Request(NotFound("Session not found"))))?;
24
25 let device_display_name = device
26 .display_name
27 .as_deref()
28 .unwrap_or("Unknown device");
29
30 let name = html_escape(device_display_name);
31 let tok = html_escape(login_token);
32 let ip = html_escape(device.last_seen_ip.as_deref().unwrap_or("—"));
33 let id = html_escape(device.device_id.as_str());
34 let id_enc = url_encode(device.device_id.as_str());
35
36 let ts_cell = device
37 .last_seen_ts
38 .map(|t| u64::from(t.as_secs()))
39 .map(ts_cell)
40 .unwrap_or_default();
41
42 Ok(PAGE_HTML
45 .replace("{name}", &name)
46 .replace("{tok}", &tok)
47 .replace("{ip}", &ip)
48 .replace("{id}", &id)
49 .replace("{id_enc}", &id_enc)
50 .replace("{ts_cell}", &ts_cell)
51 .replace("{uid}", &html_escape(user_id.as_str())))
52}
53
54static PAGE_HTML: &str = const_format!(
55 r#"
56<!DOCTYPE html>
57<html lang="en">
58 <head>
59 {ACCOUNT_HEAD}
60 <title>Session: {{name}}</title>
61 </head>
62 <body>
63 <h1>Session Details</h1>
64 <p>
65 Signed in as <strong>{{uid}}</strong>.
66 </p>
67 <dl>
68 <dt>Name</dt><dd>{{name}}</dd>
69 <dt>Device ID</dt><dd><code>{{id}}</code></dd>
70 <dt>Last seen IP</dt><dd>{{ip}}</dd>
71 <dt>Last seen</dt><dd>{{ts_cell}}</dd>
72 </dl>
73 <div class="actions">
74 <a href="/_tuwunel/oidc/account?action=org.matrix.sessions_list">
75 Back to sessions
76 </a>
77 <a
78 href="/_tuwunel/oidc/account_callback?action=org.matrix.session_end&device_id={{id_enc}}&loginToken={{tok}}"
79 class="err"
80 >
81 Sign out this session
82 </a>
83 </div>
84 {ACCOUNT_JS_INCLUDE}
85 </body>
86</html>
87"#
88);