1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
7pub struct OAuth1Token {
8 pub oauth_token: String,
9 pub oauth_token_secret: String,
10 #[serde(skip_serializing_if = "Option::is_none")]
11 pub mfa_token: Option<String>,
12 #[serde(skip_serializing_if = "Option::is_none")]
13 pub mfa_expiration_timestamp: Option<DateTime<Utc>>,
14 #[serde(default = "default_domain")]
15 pub domain: String,
16}
17
18fn default_domain() -> String {
19 "garmin.com".to_string()
20}
21
22impl OAuth1Token {
23 pub fn new(oauth_token: String, oauth_token_secret: String) -> Self {
24 Self {
25 oauth_token,
26 oauth_token_secret,
27 mfa_token: None,
28 mfa_expiration_timestamp: None,
29 domain: default_domain(),
30 }
31 }
32
33 pub fn with_domain(mut self, domain: impl Into<String>) -> Self {
34 self.domain = domain.into();
35 self
36 }
37
38 pub fn with_mfa(mut self, mfa_token: String, expiration: Option<DateTime<Utc>>) -> Self {
39 self.mfa_token = Some(mfa_token);
40 self.mfa_expiration_timestamp = expiration;
41 self
42 }
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
48pub struct OAuth2Token {
49 pub scope: String,
50 pub jti: String,
51 pub token_type: String,
52 pub access_token: String,
53 pub refresh_token: String,
54 pub expires_in: i64,
55 #[serde(default)]
56 pub expires_at: i64,
57 pub refresh_token_expires_in: i64,
58 #[serde(default)]
59 pub refresh_token_expires_at: i64,
60}
61
62impl OAuth2Token {
63 pub fn is_expired(&self) -> bool {
65 let now = Utc::now().timestamp();
66 self.expires_at < now
67 }
68
69 pub fn is_refresh_expired(&self) -> bool {
71 let now = Utc::now().timestamp();
72 self.refresh_token_expires_at < now
73 }
74
75 pub fn authorization_header(&self) -> String {
77 format!("{} {}", self.token_type, self.access_token)
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn test_oauth1_token_new() {
87 let token = OAuth1Token::new(
88 "test_oauth_token".to_string(),
89 "test_oauth_secret".to_string(),
90 );
91
92 assert_eq!(token.oauth_token, "test_oauth_token");
93 assert_eq!(token.oauth_token_secret, "test_oauth_secret");
94 assert_eq!(token.domain, "garmin.com");
95 assert!(token.mfa_token.is_none());
96 assert!(token.mfa_expiration_timestamp.is_none());
97 }
98
99 #[test]
100 fn test_oauth1_token_with_domain() {
101 let token = OAuth1Token::new(
102 "test_oauth_token".to_string(),
103 "test_oauth_secret".to_string(),
104 )
105 .with_domain("garmin.cn");
106
107 assert_eq!(token.domain, "garmin.cn");
108 }
109
110 #[test]
111 fn test_oauth1_token_with_mfa() {
112 let expiration = Utc::now();
113 let token = OAuth1Token::new(
114 "test_oauth_token".to_string(),
115 "test_oauth_secret".to_string(),
116 )
117 .with_mfa("mfa_token_123".to_string(), Some(expiration));
118
119 assert_eq!(token.mfa_token, Some("mfa_token_123".to_string()));
120 assert_eq!(token.mfa_expiration_timestamp, Some(expiration));
121 }
122
123 #[test]
124 fn test_oauth1_token_serialization() {
125 let token = OAuth1Token::new(
126 "test_oauth_token".to_string(),
127 "test_oauth_secret".to_string(),
128 );
129
130 let json = serde_json::to_string(&token).unwrap();
131 let deserialized: OAuth1Token = serde_json::from_str(&json).unwrap();
132
133 assert_eq!(token, deserialized);
134 }
135
136 #[test]
137 fn test_oauth2_token_is_expired() {
138 let expired_token = OAuth2Token {
139 scope: "test".to_string(),
140 jti: "jti123".to_string(),
141 token_type: "Bearer".to_string(),
142 access_token: "access123".to_string(),
143 refresh_token: "refresh123".to_string(),
144 expires_in: 3600,
145 expires_at: 0, refresh_token_expires_in: 86400,
147 refresh_token_expires_at: Utc::now().timestamp() + 86400,
148 };
149
150 assert!(expired_token.is_expired());
151 }
152
153 #[test]
154 fn test_oauth2_token_not_expired() {
155 let valid_token = OAuth2Token {
156 scope: "test".to_string(),
157 jti: "jti123".to_string(),
158 token_type: "Bearer".to_string(),
159 access_token: "access123".to_string(),
160 refresh_token: "refresh123".to_string(),
161 expires_in: 3600,
162 expires_at: Utc::now().timestamp() + 3600, refresh_token_expires_in: 86400,
164 refresh_token_expires_at: Utc::now().timestamp() + 86400,
165 };
166
167 assert!(!valid_token.is_expired());
168 }
169
170 #[test]
171 fn test_oauth2_token_refresh_expired() {
172 let token = OAuth2Token {
173 scope: "test".to_string(),
174 jti: "jti123".to_string(),
175 token_type: "Bearer".to_string(),
176 access_token: "access123".to_string(),
177 refresh_token: "refresh123".to_string(),
178 expires_in: 3600,
179 expires_at: Utc::now().timestamp() + 3600,
180 refresh_token_expires_in: 86400,
181 refresh_token_expires_at: 0, };
183
184 assert!(token.is_refresh_expired());
185 }
186
187 #[test]
188 fn test_oauth2_token_authorization_header() {
189 let token = OAuth2Token {
190 scope: "test".to_string(),
191 jti: "jti123".to_string(),
192 token_type: "Bearer".to_string(),
193 access_token: "my_access_token".to_string(),
194 refresh_token: "refresh123".to_string(),
195 expires_in: 3600,
196 expires_at: Utc::now().timestamp() + 3600,
197 refresh_token_expires_in: 86400,
198 refresh_token_expires_at: Utc::now().timestamp() + 86400,
199 };
200
201 assert_eq!(token.authorization_header(), "Bearer my_access_token");
202 }
203
204 #[test]
205 fn test_oauth2_token_serialization() {
206 let token = OAuth2Token {
207 scope: "test".to_string(),
208 jti: "jti123".to_string(),
209 token_type: "Bearer".to_string(),
210 access_token: "access123".to_string(),
211 refresh_token: "refresh123".to_string(),
212 expires_in: 3600,
213 expires_at: 1700000000,
214 refresh_token_expires_in: 86400,
215 refresh_token_expires_at: 1700086400,
216 };
217
218 let json = serde_json::to_string(&token).unwrap();
219 let deserialized: OAuth2Token = serde_json::from_str(&json).unwrap();
220
221 assert_eq!(token, deserialized);
222 }
223}