torrust_tracker/servers/apis/v1/context/auth_key/
resources.rs

1//! API resources for the [`auth_key`](crate::servers::apis::v1::context::auth_key) API context.
2
3use serde::{Deserialize, Serialize};
4use torrust_tracker_clock::conv::convert_from_iso_8601_to_timestamp;
5
6use crate::core::auth::{self, Key};
7
8/// A resource that represents an authentication key.
9#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
10pub struct AuthKey {
11    /// The authentication key.
12    pub key: String,
13    /// The timestamp when the key will expire.
14    #[deprecated(since = "3.0.0", note = "please use `expiry_time` instead")]
15    pub valid_until: Option<u64>, // todo: remove when the torrust-index-backend starts using the `expiry_time` attribute.
16    /// The ISO 8601 timestamp when the key will expire.
17    pub expiry_time: Option<String>,
18}
19
20impl From<AuthKey> for auth::PeerKey {
21    fn from(auth_key_resource: AuthKey) -> Self {
22        auth::PeerKey {
23            key: auth_key_resource.key.parse::<Key>().unwrap(),
24            valid_until: auth_key_resource
25                .expiry_time
26                .map(|expiry_time| convert_from_iso_8601_to_timestamp(&expiry_time)),
27        }
28    }
29}
30
31#[allow(deprecated)]
32impl From<auth::PeerKey> for AuthKey {
33    fn from(auth_key: auth::PeerKey) -> Self {
34        match (auth_key.valid_until, auth_key.expiry_time()) {
35            (Some(valid_until), Some(expiry_time)) => AuthKey {
36                key: auth_key.key.to_string(),
37                valid_until: Some(valid_until.as_secs()),
38                expiry_time: Some(expiry_time.to_string()),
39            },
40            _ => AuthKey {
41                key: auth_key.key.to_string(),
42                valid_until: None,
43                expiry_time: None,
44            },
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use std::time::Duration;
52
53    use torrust_tracker_clock::clock::stopped::Stopped as _;
54    use torrust_tracker_clock::clock::{self, Time};
55
56    use super::AuthKey;
57    use crate::core::auth::{self, Key};
58    use crate::CurrentClock;
59
60    struct TestTime {
61        pub timestamp: u64,
62        pub iso_8601_v1: String,
63        pub iso_8601_v2: String,
64    }
65
66    fn one_hour_after_unix_epoch() -> TestTime {
67        let timestamp = 60_u64;
68        let iso_8601_v1 = "1970-01-01T00:01:00.000Z".to_string();
69        let iso_8601_v2 = "1970-01-01 00:01:00 UTC".to_string();
70        TestTime {
71            timestamp,
72            iso_8601_v1,
73            iso_8601_v2,
74        }
75    }
76
77    #[test]
78    #[allow(deprecated)]
79    fn it_should_be_convertible_into_an_auth_key() {
80        clock::Stopped::local_set_to_unix_epoch();
81
82        let auth_key_resource = AuthKey {
83            key: "IaWDneuFNZi8IB4MPA3qW1CD0M30EZSM".to_string(), // cspell:disable-line
84            valid_until: Some(one_hour_after_unix_epoch().timestamp),
85            expiry_time: Some(one_hour_after_unix_epoch().iso_8601_v1),
86        };
87
88        assert_eq!(
89            auth::PeerKey::from(auth_key_resource),
90            auth::PeerKey {
91                key: "IaWDneuFNZi8IB4MPA3qW1CD0M30EZSM".parse::<Key>().unwrap(), // cspell:disable-line
92                valid_until: Some(CurrentClock::now_add(&Duration::new(one_hour_after_unix_epoch().timestamp, 0)).unwrap())
93            }
94        );
95    }
96
97    #[test]
98    #[allow(deprecated)]
99    fn it_should_be_convertible_from_an_auth_key() {
100        clock::Stopped::local_set_to_unix_epoch();
101
102        let auth_key = auth::PeerKey {
103            key: "IaWDneuFNZi8IB4MPA3qW1CD0M30EZSM".parse::<Key>().unwrap(), // cspell:disable-line
104            valid_until: Some(CurrentClock::now_add(&Duration::new(one_hour_after_unix_epoch().timestamp, 0)).unwrap()),
105        };
106
107        assert_eq!(
108            AuthKey::from(auth_key),
109            AuthKey {
110                key: "IaWDneuFNZi8IB4MPA3qW1CD0M30EZSM".to_string(), // cspell:disable-line
111                valid_until: Some(one_hour_after_unix_epoch().timestamp),
112                expiry_time: Some(one_hour_after_unix_epoch().iso_8601_v2),
113            }
114        );
115    }
116
117    #[test]
118    #[allow(deprecated)]
119    fn it_should_be_convertible_into_json() {
120        assert_eq!(
121            serde_json::to_string(&AuthKey {
122                key: "IaWDneuFNZi8IB4MPA3qW1CD0M30EZSM".to_string(), // cspell:disable-line
123                valid_until: Some(one_hour_after_unix_epoch().timestamp),
124                expiry_time: Some(one_hour_after_unix_epoch().iso_8601_v1),
125            })
126            .unwrap(),
127            "{\"key\":\"IaWDneuFNZi8IB4MPA3qW1CD0M30EZSM\",\"valid_until\":60,\"expiry_time\":\"1970-01-01T00:01:00.000Z\"}" // cspell:disable-line
128        );
129    }
130}