tuwunel_api/server/
key.rs1use 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
17pub(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
74pub(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}