4
4
//! Tracker keys are tokens used to authenticate the tracker clients when the tracker runs
5
5
//! in `private` or `private_listed` modes.
6
6
//!
7
- //! There are services to [`generate `] and [`verify `] authentication keys.
7
+ //! There are services to [`generate_key `] and [`verify_key `] authentication keys.
8
8
//!
9
9
//! Authentication keys are used only by [`HTTP`](crate::servers::http) trackers. All keys have an expiration time, that means
10
10
//! they are only valid during a period of time. After that time the expiring key will no longer be valid.
19
19
//! /// Random 32-char string. For example: `YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ`
20
20
//! pub key: Key,
21
21
//! /// Timestamp, the key will be no longer valid after this timestamp
22
- //! pub valid_until: DurationSinceUnixEpoch,
22
+ //! pub valid_until: Option< DurationSinceUnixEpoch> ,
23
23
//! }
24
24
//! ```
25
25
//!
29
29
//! use torrust_tracker::core::auth;
30
30
//! use std::time::Duration;
31
31
//!
32
- //! let expiring_key = auth::generate( Duration::new(9999, 0));
32
+ //! let expiring_key = auth::generate_key(Some( Duration::new(9999, 0) ));
33
33
//!
34
34
//! // And you can later verify it with:
35
35
//!
36
- //! assert!(auth::verify (&expiring_key).is_ok());
36
+ //! assert!(auth::verify_key (&expiring_key).is_ok());
37
37
//! ```
38
38
39
39
use std:: panic:: Location ;
@@ -55,63 +55,96 @@ use tracing::debug;
55
55
use crate :: shared:: bit_torrent:: common:: AUTH_KEY_LENGTH ;
56
56
use crate :: CurrentClock ;
57
57
58
+ /// It generates a new permanent random key [`PeerKey`].
58
59
#[ must_use]
59
- /// It generates a new random 32-char authentication [`ExpiringKey`]
60
+ pub fn generate_permanent_key ( ) -> PeerKey {
61
+ generate_key ( None )
62
+ }
63
+
64
+ /// It generates a new random 32-char authentication [`PeerKey`].
65
+ ///
66
+ /// It can be an expiring or permanent key.
60
67
///
61
68
/// # Panics
62
69
///
63
70
/// It would panic if the `lifetime: Duration` + Duration is more than `Duration::MAX`.
64
- pub fn generate ( lifetime : Duration ) -> ExpiringKey {
71
+ ///
72
+ /// # Arguments
73
+ ///
74
+ /// * `lifetime`: if `None` the key will be permanent.
75
+ #[ must_use]
76
+ pub fn generate_key ( lifetime : Option < Duration > ) -> PeerKey {
65
77
let random_id: String = thread_rng ( )
66
78
. sample_iter ( & Alphanumeric )
67
79
. take ( AUTH_KEY_LENGTH )
68
80
. map ( char:: from)
69
81
. collect ( ) ;
70
82
71
- debug ! ( "Generated key: {}, valid for: {:?} seconds" , random_id, lifetime) ;
83
+ if let Some ( lifetime) = lifetime {
84
+ debug ! ( "Generated key: {}, valid for: {:?} seconds" , random_id, lifetime) ;
85
+
86
+ PeerKey {
87
+ key : random_id. parse :: < Key > ( ) . unwrap ( ) ,
88
+ valid_until : Some ( CurrentClock :: now_add ( & lifetime) . unwrap ( ) ) ,
89
+ }
90
+ } else {
91
+ debug ! ( "Generated key: {}, permanent" , random_id) ;
72
92
73
- ExpiringKey {
74
- key : random_id. parse :: < Key > ( ) . unwrap ( ) ,
75
- valid_until : CurrentClock :: now_add ( & lifetime) . unwrap ( ) ,
93
+ PeerKey {
94
+ key : random_id. parse :: < Key > ( ) . unwrap ( ) ,
95
+ valid_until : None ,
96
+ }
76
97
}
77
98
}
78
99
79
- /// It verifies an [`ExpiringKey`]. It checks if the expiration date has passed.
100
+ /// It verifies an [`PeerKey`]. It checks if the expiration date has passed.
101
+ /// Permanent keys without duration (`None`) do not expire.
80
102
///
81
103
/// # Errors
82
104
///
83
- /// Will return `Error::KeyExpired` if `auth_key.valid_until` is past the `current_time`.
105
+ /// Will return:
84
106
///
85
- /// Will return `Error::KeyInvalid` if `auth_key.valid_until` is past the `None`.
86
- pub fn verify ( auth_key : & ExpiringKey ) -> Result < ( ) , Error > {
107
+ /// - `Error::KeyExpired` if `auth_key.valid_until` is past the `current_time`.
108
+ /// - `Error::KeyInvalid` if `auth_key.valid_until` is past the `None`.
109
+ pub fn verify_key ( auth_key : & PeerKey ) -> Result < ( ) , Error > {
87
110
let current_time: DurationSinceUnixEpoch = CurrentClock :: now ( ) ;
88
111
89
- if auth_key. valid_until < current_time {
90
- Err ( Error :: KeyExpired {
91
- location : Location :: caller ( ) ,
92
- } )
93
- } else {
94
- Ok ( ( ) )
112
+ match auth_key. valid_until {
113
+ Some ( valid_until) => {
114
+ if valid_until < current_time {
115
+ Err ( Error :: KeyExpired {
116
+ location : Location :: caller ( ) ,
117
+ } )
118
+ } else {
119
+ Ok ( ( ) )
120
+ }
121
+ }
122
+ None => Ok ( ( ) ) , // Permanent key
95
123
}
96
124
}
97
125
98
- /// An authentication key which has an expiration time.
126
+ /// An authentication key which can potentially have an expiration time.
99
127
/// After that time is will automatically become invalid.
100
128
#[ derive( Serialize , Deserialize , Debug , Eq , PartialEq , Clone ) ]
101
- pub struct ExpiringKey {
129
+ pub struct PeerKey {
102
130
/// Random 32-char string. For example: `YZSl4lMZupRuOpSRC3krIKR5BPB14nrJ`
103
131
pub key : Key ,
104
- /// Timestamp, the key will be no longer valid after this timestamp
105
- pub valid_until : DurationSinceUnixEpoch ,
132
+
133
+ /// Timestamp, the key will be no longer valid after this timestamp.
134
+ /// If `None` the keys will not expire (permanent key).
135
+ pub valid_until : Option < DurationSinceUnixEpoch > ,
106
136
}
107
137
108
- impl std:: fmt:: Display for ExpiringKey {
138
+ impl std:: fmt:: Display for PeerKey {
109
139
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
110
- write ! ( f, "key: `{}`, valid until `{}`" , self . key, self . expiry_time( ) )
140
+ match self . expiry_time ( ) {
141
+ Some ( expire_time) => write ! ( f, "key: `{}`, valid until `{}`" , self . key, expire_time) ,
142
+ None => write ! ( f, "key: `{}`, permanent" , self . key) ,
143
+ }
111
144
}
112
145
}
113
146
114
- impl ExpiringKey {
147
+ impl PeerKey {
115
148
#[ must_use]
116
149
pub fn key ( & self ) -> Key {
117
150
self . key . clone ( )
@@ -126,8 +159,8 @@ impl ExpiringKey {
126
159
/// Will panic when the key timestamp overflows the internal i64 type.
127
160
/// (this will naturally happen in 292.5 billion years)
128
161
#[ must_use]
129
- pub fn expiry_time ( & self ) -> chrono:: DateTime < chrono:: Utc > {
130
- convert_from_timestamp_to_datetime_utc ( self . valid_until )
162
+ pub fn expiry_time ( & self ) -> Option < chrono:: DateTime < chrono:: Utc > > {
163
+ self . valid_until . map ( convert_from_timestamp_to_datetime_utc )
131
164
}
132
165
}
133
166
@@ -194,8 +227,8 @@ impl FromStr for Key {
194
227
}
195
228
}
196
229
197
- /// Verification error. Error returned when an [`ExpiringKey `] cannot be
198
- /// verified with the [`verify(...)`]( crate::core::auth::verify ) function.
230
+ /// Verification error. Error returned when an [`PeerKey `] cannot be
231
+ /// verified with the (` crate::core::auth::verify_key` ) function.
199
232
#[ derive( Debug , Error ) ]
200
233
#[ allow( dead_code) ]
201
234
pub enum Error {
@@ -277,7 +310,7 @@ mod tests {
277
310
// Set the time to the current time.
278
311
clock:: Stopped :: local_set_to_unix_epoch ( ) ;
279
312
280
- let expiring_key = auth:: generate ( Duration :: from_secs ( 0 ) ) ;
313
+ let expiring_key = auth:: generate_key ( Some ( Duration :: from_secs ( 0 ) ) ) ;
281
314
282
315
assert_eq ! (
283
316
expiring_key. to_string( ) ,
@@ -287,9 +320,9 @@ mod tests {
287
320
288
321
#[ test]
289
322
fn should_be_generated_with_a_expiration_time ( ) {
290
- let expiring_key = auth:: generate ( Duration :: new ( 9999 , 0 ) ) ;
323
+ let expiring_key = auth:: generate_key ( Some ( Duration :: new ( 9999 , 0 ) ) ) ;
291
324
292
- assert ! ( auth:: verify ( & expiring_key) . is_ok( ) ) ;
325
+ assert ! ( auth:: verify_key ( & expiring_key) . is_ok( ) ) ;
293
326
}
294
327
295
328
#[ test]
@@ -298,17 +331,17 @@ mod tests {
298
331
clock:: Stopped :: local_set_to_system_time_now ( ) ;
299
332
300
333
// Make key that is valid for 19 seconds.
301
- let expiring_key = auth:: generate ( Duration :: from_secs ( 19 ) ) ;
334
+ let expiring_key = auth:: generate_key ( Some ( Duration :: from_secs ( 19 ) ) ) ;
302
335
303
336
// Mock the time has passed 10 sec.
304
337
clock:: Stopped :: local_add ( & Duration :: from_secs ( 10 ) ) . unwrap ( ) ;
305
338
306
- assert ! ( auth:: verify ( & expiring_key) . is_ok( ) ) ;
339
+ assert ! ( auth:: verify_key ( & expiring_key) . is_ok( ) ) ;
307
340
308
341
// Mock the time has passed another 10 sec.
309
342
clock:: Stopped :: local_add ( & Duration :: from_secs ( 10 ) ) . unwrap ( ) ;
310
343
311
- assert ! ( auth:: verify ( & expiring_key) . is_err( ) ) ;
344
+ assert ! ( auth:: verify_key ( & expiring_key) . is_err( ) ) ;
312
345
}
313
346
}
314
347
}
0 commit comments