Skip to main content

tuwunel_api/oidc/account/
session_end_confirm.rs

1use const_str::format as const_format;
2use ruma::UserId;
3use tuwunel_core::{Result, utils::html::escape as html_escape};
4
5use super::{ACCOUNT_HEAD, url_encode};
6
7/// Shows a POST confirmation form. The `login_token` is the original SSO-issued
8/// token, peeked (not consumed) by the GET handler and embedded here as the
9/// CSRF/auth token. It is consumed when the user submits this form.
10pub(super) async fn session_end_confirm_html(
11	user_id: &UserId,
12	device_id: &str,
13	login_token: &str,
14) -> Result<String> {
15	let uid = html_escape(user_id.as_str());
16	let did = html_escape(device_id);
17	let tok = html_escape(login_token);
18
19	// url_encode for use in the Cancel href query parameter.
20	let did_enc = url_encode(device_id);
21	let tok_enc = url_encode(login_token);
22
23	Ok(PAGE_HTML
24		.replace("{uid}", &uid)
25		.replace("{did}", &did)
26		.replace("{tok}", &tok)
27		.replace("{did_enc}", &did_enc)
28		.replace("{tok_enc}", &tok_enc))
29}
30
31static PAGE_HTML: &str = const_format!(
32	r#"
33<!DOCTYPE html>
34<html lang="en">
35	<head>
36		{ACCOUNT_HEAD}
37		<title>Sign Out Session</title>
38	</head>
39	<body>
40		<h1>Sign Out Session</h1>
41		<p>
42			Signed in as <strong>{{uid}}</strong>.
43		</p>
44		<p class="warn">
45			Sign out session <code>{{did}}</code>?
46			This will immediately invalidate its access token.
47		</p>
48		<form method="POST" action="/_tuwunel/oidc/account_callback">
49			<input type="hidden" name="action" value="org.matrix.session_end">
50			<input type="hidden" name="device_id" value="{{did}}">
51			<input type="hidden" name="loginToken" value="{{tok}}">
52			<button type="submit" class="danger">Sign out</button>
53			<a
54				class="cancel"
55				href="/_tuwunel/oidc/account_callback?action=org.matrix.session_view&device_id={{did_enc}}&loginToken={{tok_enc}}"
56			>
57				Cancel
58			</a>
59		</form>
60	</body>
61</html>"#
62);