Skip to main content

tuwunel_api/server/
key.rs

1use std::{
2	mem::take,
3	time::{Duration, SystemTime},
4};
5
6use axum::{Json, extract::State, response::IntoResponse};
7use ruma::{
8	MilliSecondsSinceUnixEpoch, Signatures,
9	api::{
10		OutgoingResponse,
11		federation::discovery::{OldVerifyKey, ServerSigningKeys, get_server_keys},
12	},
13	serde::Raw,
14};
15use tuwunel_core::{Result, utils::timepoint_from_now};
16
17/// # `GET /_matrix/key/v2/server`
18///
19/// Gets the public signing keys of this server.
20///
21/// - Matrix does not support invalidating public keys, so the key returned by
22///   this will be valid forever.
23// Response type for this endpoint is Json because we need to calculate a
24// signature for the response
25pub(crate) async fn get_server_keys_route(
26	State(services): State<crate::State>,
27) -> Result<impl IntoResponse> {
28	let server_name = services.globals.server_name();
29	let active_key_id = services.server_keys.active_key_id();
30	let mut all_keys = services
31		.server_keys
32		.verify_keys_for(server_name)
33		.await;
34
35	let verify_keys = all_keys
36		.remove_entry(active_key_id)
37		.expect("active verify_key is missing");
38
39	let old_verify_keys = all_keys
40		.into_iter()
41		.map(|(id, key)| (id, OldVerifyKey::new(expires_ts(), key.key)))
42		.collect();
43
44	let server_key = ServerSigningKeys {
45		verify_keys: [verify_keys].into(),
46		old_verify_keys,
47		server_name: server_name.to_owned(),
48		valid_until_ts: valid_until_ts(),
49		signatures: Signatures::new(),
50	};
51
52	let server_key = Raw::new(&server_key)?;
53	let mut response = get_server_keys::v2::Response::new(server_key)
54		.try_into_http_response::<Vec<u8>>()
55		.map(|mut response| take(response.body_mut()))
56		.and_then(|body| serde_json::from_slice(&body).map_err(Into::into))?;
57
58	services.server_keys.sign_json(&mut response)?;
59
60	Ok(Json(response))
61}
62
63fn valid_until_ts() -> MilliSecondsSinceUnixEpoch {
64	let dur = Duration::from_hours(168);
65	let timepoint = timepoint_from_now(dur).expect("SystemTime should not overflow");
66	MilliSecondsSinceUnixEpoch::from_system_time(timepoint).expect("UInt should not overflow")
67}
68
69fn expires_ts() -> MilliSecondsSinceUnixEpoch {
70	let timepoint = SystemTime::now();
71	MilliSecondsSinceUnixEpoch::from_system_time(timepoint).expect("UInt should not overflow")
72}
73
74/// # `GET /_matrix/key/v2/server/{keyId}`
75///
76/// Gets the public signing keys of this server.
77///
78/// - Matrix does not support invalidating public keys, so the key returned by
79///   this will be valid forever.
80pub(crate) async fn get_server_keys_deprecated_route(
81	State(services): State<crate::State>,
82) -> impl IntoResponse {
83	get_server_keys_route(State(services)).await
84}