Skip to main content

tuwunel_api/client/admin/tokens/
mod.rs

1//! Synapse admin API: registration-token endpoints.
2
3mod create;
4mod delete;
5mod get;
6mod list;
7mod update;
8
9use std::time::Duration;
10
11use ruma::{MilliSecondsSinceUnixEpoch, UInt, uint};
12use synapse_admin_api::registration_tokens::RegistrationToken;
13use tuwunel_core::{Result, utils::time::timepoint_from_epoch};
14use tuwunel_service::registration_tokens::{DatabaseTokenInfo, TokenExpires, TokenInfo};
15
16pub(crate) use self::{
17	create::admin_create_token_route, delete::admin_delete_token_route,
18	get::admin_get_token_route, list::admin_list_tokens_route, update::admin_update_token_route,
19};
20
21/// Map a validated token into the admin API wire shape. Config-file tokens
22/// carry no usage state, so they read as unlimited, never expiring, and unused.
23fn token_response(token: String, info: TokenInfo) -> RegistrationToken {
24	match info {
25		| TokenInfo::Config => RegistrationToken::new(token),
26		| TokenInfo::Database(info) => database_token_response(token, &info),
27	}
28}
29
30/// Map a token and its stored metadata into the admin API wire shape.
31/// `pending` is always zero: tuwunel consumes uses in a single step with no
32/// two-phase registration model.
33fn database_token_response(token: String, info: &DatabaseTokenInfo) -> RegistrationToken {
34	RegistrationToken {
35		token,
36		uses_allowed: info
37			.expires
38			.max_uses
39			.and_then(|n| UInt::try_from(n).ok()),
40		pending: uint!(0),
41		completed: UInt::try_from(info.uses).unwrap_or(UInt::MAX),
42		expiry_time: info
43			.expires
44			.max_age
45			.and_then(MilliSecondsSinceUnixEpoch::from_system_time),
46	}
47}
48
49fn token_expires(
50	uses_allowed: Option<UInt>,
51	expiry_time: Option<MilliSecondsSinceUnixEpoch>,
52) -> Result<TokenExpires> {
53	let max_age = expiry_time
54		.map(|ms| timepoint_from_epoch(Duration::from_millis(ms.0.into())))
55		.transpose()?;
56
57	Ok(TokenExpires {
58		max_uses: uses_allowed.map(Into::into),
59		max_age,
60	})
61}
62
63#[cfg(test)]
64mod tests {
65	use ruma::{MilliSecondsSinceUnixEpoch, uint};
66	use tuwunel_service::registration_tokens::{DatabaseTokenInfo, TokenExpires};
67
68	use super::database_token_response;
69
70	#[test]
71	fn unlimited_token_maps_to_null_cap_and_expiry() {
72		let info = DatabaseTokenInfo {
73			uses: 3,
74			expires: TokenExpires { max_uses: None, max_age: None },
75		};
76
77		let token = database_token_response("abc".to_owned(), &info);
78
79		assert_eq!(token.token, "abc");
80		assert_eq!(token.completed, uint!(3));
81		assert_eq!(token.pending, uint!(0));
82		assert!(token.uses_allowed.is_none());
83		assert!(token.expiry_time.is_none());
84	}
85
86	#[test]
87	fn capped_token_maps_cap_and_expiry() {
88		let expiry = MilliSecondsSinceUnixEpoch(
89			1_595_376_300_000_u64
90				.try_into()
91				.expect("fits UInt"),
92		);
93
94		let expires_at = expiry.to_system_time().expect("valid timepoint");
95
96		let info = DatabaseTokenInfo {
97			uses: 10,
98			expires: TokenExpires {
99				max_uses: Some(100),
100				max_age: Some(expires_at),
101			},
102		};
103
104		let token = database_token_response("abc".to_owned(), &info);
105
106		assert_eq!(token.uses_allowed, Some(uint!(100)));
107		assert_eq!(token.completed, uint!(10));
108		assert_eq!(token.expiry_time, Some(expiry));
109	}
110}