1use async_trait::async_trait;
62use chrono::{Duration, Utc};
63use serde::{Deserialize, Serialize, de::DeserializeOwned};
64use std::collections::HashMap;
65use std::sync::{Arc, RwLock};
66
67use crate::error::{Error, Result, StorageError, TokenError};
68use crate::random::{generate_random_base64_url, generate_random_hex};
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
104pub struct RefreshToken {
105 pub token: String,
107
108 pub token_id: String,
110
111 pub user_id: String,
113
114 pub family_id: String,
116
117 pub created_at: i64,
119
120 pub expires_at: i64,
122
123 pub used: bool,
125
126 pub used_at: Option<i64>,
128
129 pub replaced_by: Option<String>,
131
132 pub device_info: Option<String>,
134
135 pub ip_address: Option<String>,
137
138 pub metadata: serde_json::Value,
140}
141
142impl RefreshToken {
143 fn new(user_id: impl Into<String>, family_id: String, expires_in: Duration) -> Result<Self> {
145 let now = Utc::now().timestamp();
146 let token = generate_random_base64_url(48)?;
147 let token_id = generate_random_hex(16)?;
148
149 Ok(Self {
150 token,
151 token_id,
152 user_id: user_id.into(),
153 family_id,
154 created_at: now,
155 expires_at: now + expires_in.num_seconds(),
156 used: false,
157 used_at: None,
158 replaced_by: None,
159 device_info: None,
160 ip_address: None,
161 metadata: serde_json::Value::Object(serde_json::Map::new()),
162 })
163 }
164
165 #[inline]
167 pub fn is_expired(&self) -> bool {
168 Utc::now().timestamp() > self.expires_at
169 }
170
171 #[inline]
173 pub fn is_valid(&self) -> bool {
174 !self.is_expired() && !self.used
175 }
176
177 pub fn time_to_live(&self) -> i64 {
181 (self.expires_at - Utc::now().timestamp()).max(0)
182 }
183
184 fn mark_as_used(&mut self, replaced_by: Option<String>) {
186 self.used = true;
187 self.used_at = Some(Utc::now().timestamp());
188 self.replaced_by = replaced_by;
189 }
190
191 pub fn set_metadata<T: Serialize>(&mut self, key: impl Into<String>, value: T) {
213 if let Ok(json_value) = serde_json::to_value(value)
214 && let Some(obj) = self.metadata.as_object_mut()
215 {
216 obj.insert(key.into(), json_value);
217 }
218 }
219
220 pub fn get_metadata<T: DeserializeOwned>(&self, key: &str) -> Option<T> {
239 self.metadata
240 .get(key)
241 .and_then(|v| serde_json::from_value(v.clone()).ok())
242 }
243
244 pub fn get_metadata_raw(&self, key: &str) -> Option<&serde_json::Value> {
246 self.metadata.get(key)
247 }
248
249 pub fn has_metadata(&self, key: &str) -> bool {
251 self.metadata.get(key).is_some()
252 }
253
254 pub fn remove_metadata(&mut self, key: &str) -> Option<serde_json::Value> {
258 self.metadata
259 .as_object_mut()
260 .and_then(|obj| obj.remove(key))
261 }
262
263 pub fn clear_metadata(&mut self) {
265 self.metadata = serde_json::Value::Object(serde_json::Map::new());
266 }
267
268 pub fn metadata_keys(&self) -> Vec<&str> {
270 self.metadata
271 .as_object()
272 .map(|obj| obj.keys().map(|k| k.as_str()).collect())
273 .unwrap_or_default()
274 }
275}
276
277#[derive(Debug, Clone)]
283pub struct RefreshConfig {
284 pub expiration: Duration,
286
287 pub rotation_enabled: bool,
289
290 pub reuse_detection: bool,
292
293 pub max_tokens_per_family: usize,
295
296 pub max_families_per_user: usize,
298
299 pub grace_period: Duration,
301}
302
303impl Default for RefreshConfig {
304 fn default() -> Self {
305 Self {
306 expiration: Duration::days(30),
307 rotation_enabled: true,
308 reuse_detection: true,
309 max_tokens_per_family: 5,
310 max_families_per_user: 5,
311 grace_period: Duration::seconds(0),
312 }
313 }
314}
315
316impl RefreshConfig {
317 pub fn new() -> Self {
319 Self::default()
320 }
321
322 pub fn with_expiration(mut self, duration: Duration) -> Self {
324 self.expiration = duration;
325 self
326 }
327
328 pub fn with_rotation(mut self, enabled: bool) -> Self {
330 self.rotation_enabled = enabled;
331 self
332 }
333
334 pub fn with_reuse_detection(mut self, enabled: bool) -> Self {
336 self.reuse_detection = enabled;
337 self
338 }
339
340 pub fn with_max_families_per_user(mut self, max: usize) -> Self {
342 self.max_families_per_user = max;
343 self
344 }
345
346 pub fn with_grace_period(mut self, duration: Duration) -> Self {
348 self.grace_period = duration;
349 self
350 }
351
352 pub fn high_security() -> Self {
359 Self {
360 expiration: Duration::days(7),
361 rotation_enabled: true,
362 reuse_detection: true,
363 max_tokens_per_family: 3,
364 max_families_per_user: 3,
365 grace_period: Duration::seconds(0),
366 }
367 }
368
369 pub fn relaxed() -> Self {
375 Self {
376 expiration: Duration::days(90),
377 rotation_enabled: false,
378 reuse_detection: false,
379 max_tokens_per_family: 10,
380 max_families_per_user: 10,
381 grace_period: Duration::seconds(60),
382 }
383 }
384}
385
386#[async_trait]
423pub trait RefreshTokenStore: Send + Sync {
424 async fn save(&self, token: &RefreshToken) -> Result<()>;
426
427 async fn get_by_token(&self, token: &str) -> Result<Option<RefreshToken>>;
429
430 async fn get_by_id(&self, token_id: &str) -> Result<Option<RefreshToken>>;
432
433 async fn update(&self, token: &RefreshToken) -> Result<()>;
435
436 async fn delete(&self, token_id: &str) -> Result<()>;
438
439 async fn get_by_user(&self, user_id: &str) -> Result<Vec<RefreshToken>>;
441
442 async fn get_by_family(&self, family_id: &str) -> Result<Vec<RefreshToken>>;
444
445 async fn delete_family(&self, family_id: &str) -> Result<usize>;
449
450 async fn delete_by_user(&self, user_id: &str) -> Result<usize>;
454
455 async fn cleanup_expired(&self) -> Result<usize>;
459
460 async fn count(&self) -> Result<usize>;
462}
463
464#[derive(Debug, Default)]
478pub struct InMemoryRefreshTokenStore {
479 tokens: RwLock<HashMap<String, RefreshToken>>,
480 token_index: RwLock<HashMap<String, String>>, }
482
483impl InMemoryRefreshTokenStore {
484 pub fn new() -> Self {
486 Self::default()
487 }
488}
489
490#[async_trait]
491impl RefreshTokenStore for InMemoryRefreshTokenStore {
492 async fn save(&self, token: &RefreshToken) -> Result<()> {
493 let mut tokens = self
494 .tokens
495 .write()
496 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
497 let mut index = self
498 .token_index
499 .write()
500 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
501
502 index.insert(token.token.clone(), token.token_id.clone());
503 tokens.insert(token.token_id.clone(), token.clone());
504 Ok(())
505 }
506
507 async fn get_by_token(&self, token: &str) -> Result<Option<RefreshToken>> {
508 let index = self
509 .token_index
510 .read()
511 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
512 let tokens = self
513 .tokens
514 .read()
515 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
516
517 if let Some(token_id) = index.get(token) {
518 Ok(tokens.get(token_id).cloned())
519 } else {
520 Ok(None)
521 }
522 }
523
524 async fn get_by_id(&self, token_id: &str) -> Result<Option<RefreshToken>> {
525 let tokens = self
526 .tokens
527 .read()
528 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
529 Ok(tokens.get(token_id).cloned())
530 }
531
532 async fn update(&self, token: &RefreshToken) -> Result<()> {
533 let mut tokens = self
534 .tokens
535 .write()
536 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
537
538 if tokens.contains_key(&token.token_id) {
539 tokens.insert(token.token_id.clone(), token.clone());
540 Ok(())
541 } else {
542 Err(Error::Storage(StorageError::NotFound(
543 "token not found".into(),
544 )))
545 }
546 }
547
548 async fn delete(&self, token_id: &str) -> Result<()> {
549 let mut tokens = self
550 .tokens
551 .write()
552 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
553 let mut index = self
554 .token_index
555 .write()
556 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
557
558 if let Some(token) = tokens.remove(token_id) {
559 index.remove(&token.token);
560 }
561 Ok(())
562 }
563
564 async fn get_by_user(&self, user_id: &str) -> Result<Vec<RefreshToken>> {
565 let tokens = self
566 .tokens
567 .read()
568 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
569
570 Ok(tokens
571 .values()
572 .filter(|t| t.user_id == user_id)
573 .cloned()
574 .collect())
575 }
576
577 async fn get_by_family(&self, family_id: &str) -> Result<Vec<RefreshToken>> {
578 let tokens = self
579 .tokens
580 .read()
581 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
582
583 Ok(tokens
584 .values()
585 .filter(|t| t.family_id == family_id)
586 .cloned()
587 .collect())
588 }
589
590 async fn delete_family(&self, family_id: &str) -> Result<usize> {
591 let mut tokens = self
592 .tokens
593 .write()
594 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
595 let mut index = self
596 .token_index
597 .write()
598 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
599
600 let to_delete: Vec<_> = tokens
601 .iter()
602 .filter(|(_, t)| t.family_id == family_id)
603 .map(|(id, t)| (id.clone(), t.token.clone()))
604 .collect();
605
606 let count = to_delete.len();
607 for (token_id, token) in to_delete {
608 tokens.remove(&token_id);
609 index.remove(&token);
610 }
611
612 Ok(count)
613 }
614
615 async fn delete_by_user(&self, user_id: &str) -> Result<usize> {
616 let mut tokens = self
617 .tokens
618 .write()
619 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
620 let mut index = self
621 .token_index
622 .write()
623 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
624
625 let to_delete: Vec<_> = tokens
626 .iter()
627 .filter(|(_, t)| t.user_id == user_id)
628 .map(|(id, t)| (id.clone(), t.token.clone()))
629 .collect();
630
631 let count = to_delete.len();
632 for (token_id, token) in to_delete {
633 tokens.remove(&token_id);
634 index.remove(&token);
635 }
636
637 Ok(count)
638 }
639
640 async fn cleanup_expired(&self) -> Result<usize> {
641 let mut tokens = self
642 .tokens
643 .write()
644 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
645 let mut index = self
646 .token_index
647 .write()
648 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
649
650 let now = Utc::now().timestamp();
651 let to_delete: Vec<_> = tokens
652 .iter()
653 .filter(|(_, t)| t.expires_at < now)
654 .map(|(id, t)| (id.clone(), t.token.clone()))
655 .collect();
656
657 let count = to_delete.len();
658 for (token_id, token) in to_delete {
659 tokens.remove(&token_id);
660 index.remove(&token);
661 }
662
663 Ok(count)
664 }
665
666 async fn count(&self) -> Result<usize> {
667 let tokens = self
668 .tokens
669 .read()
670 .map_err(|_| Error::Storage(StorageError::OperationFailed("lock poisoned".into())))?;
671 Ok(tokens.len())
672 }
673}
674
675#[derive(Debug, Clone)]
681pub struct TokenUseResult {
682 pub new_token: Option<RefreshToken>,
684
685 pub user_id: String,
687
688 pub family_id: String,
690
691 pub was_in_grace_period: bool,
693}
694
695pub struct RefreshTokenManager {
734 store: Arc<dyn RefreshTokenStore>,
735 config: RefreshConfig,
736}
737
738impl RefreshTokenManager {
739 pub fn new(config: RefreshConfig) -> Self {
741 Self {
742 store: Arc::new(InMemoryRefreshTokenStore::new()),
743 config,
744 }
745 }
746
747 pub fn with_store(config: RefreshConfig, store: Arc<dyn RefreshTokenStore>) -> Self {
749 Self { store, config }
750 }
751
752 pub async fn generate(&self, user_id: impl Into<String>) -> Result<RefreshToken> {
762 let user_id = user_id.into();
763 self.enforce_max_families(&user_id).await?;
764
765 let family_id = generate_random_hex(16)?;
766 let token = RefreshToken::new(&user_id, family_id, self.config.expiration)?;
767 self.store.save(&token).await?;
768
769 Ok(token)
770 }
771
772 pub async fn generate_with_options(
776 &self,
777 user_id: impl Into<String>,
778 options: GenerateOptions,
779 ) -> Result<RefreshToken> {
780 let user_id = user_id.into();
781 self.enforce_max_families(&user_id).await?;
782
783 let family_id = options
784 .family_id
785 .unwrap_or_else(|| generate_random_hex(16).unwrap_or_default());
786 let mut token = RefreshToken::new(&user_id, family_id, self.config.expiration)?;
787
788 token.device_info = options.device_info;
789 token.ip_address = options.ip_address;
790
791 if let Some(metadata) = options.metadata {
792 token.metadata = metadata;
793 }
794
795 self.store.save(&token).await?;
796 Ok(token)
797 }
798
799 pub async fn use_token(&self, token: &str) -> Result<TokenUseResult> {
812 let mut stored_token = self
813 .store
814 .get_by_token(token)
815 .await?
816 .ok_or_else(|| Error::Token(TokenError::InvalidFormat("token not found".into())))?;
817
818 if stored_token.is_expired() {
820 self.store.delete(&stored_token.token_id).await?;
821 return Err(Error::Token(TokenError::Expired));
822 }
823
824 if stored_token.used {
826 if self.config.reuse_detection {
827 let grace_period_secs = self.config.grace_period.num_seconds();
829 let used_at = stored_token.used_at.unwrap_or(0);
830 let now = Utc::now().timestamp();
831
832 if grace_period_secs == 0 || now > used_at + grace_period_secs {
834 self.store.delete_family(&stored_token.family_id).await?;
836 return Err(Error::Token(TokenError::InvalidFormat(
837 "token reuse detected, family revoked".into(),
838 )));
839 }
840
841 return Ok(TokenUseResult {
843 new_token: None,
844 user_id: stored_token.user_id.clone(),
845 family_id: stored_token.family_id.clone(),
846 was_in_grace_period: true,
847 });
848 } else {
849 return Err(Error::Token(TokenError::InvalidFormat(
850 "token already used".into(),
851 )));
852 }
853 }
854
855 let new_token = if self.config.rotation_enabled {
857 let mut new = RefreshToken::new(
859 &stored_token.user_id,
860 stored_token.family_id.clone(),
861 self.config.expiration,
862 )?;
863
864 new.device_info = stored_token.device_info.clone();
866 new.ip_address = stored_token.ip_address.clone();
867 new.metadata = stored_token.metadata.clone();
868
869 stored_token.mark_as_used(Some(new.token_id.clone()));
871 self.store.update(&stored_token).await?;
872
873 self.store.save(&new).await?;
875
876 self.enforce_max_tokens_per_family(&stored_token.family_id)
878 .await?;
879
880 Some(new)
881 } else {
882 stored_token.mark_as_used(None);
884 self.store.update(&stored_token).await?;
885 None
886 };
887
888 Ok(TokenUseResult {
889 new_token,
890 user_id: stored_token.user_id,
891 family_id: stored_token.family_id,
892 was_in_grace_period: false,
893 })
894 }
895
896 pub async fn validate(&self, token: &str) -> Result<RefreshToken> {
900 let stored_token = self
901 .store
902 .get_by_token(token)
903 .await?
904 .ok_or_else(|| Error::Token(TokenError::InvalidFormat("token not found".into())))?;
905
906 if stored_token.is_expired() {
907 return Err(Error::Token(TokenError::Expired));
908 }
909
910 if stored_token.used && self.config.reuse_detection {
911 return Err(Error::Token(TokenError::InvalidFormat(
912 "token already used".into(),
913 )));
914 }
915
916 Ok(stored_token)
917 }
918
919 pub async fn revoke(&self, token: &str) -> Result<()> {
921 if let Some(stored) = self.store.get_by_token(token).await? {
922 self.store.delete(&stored.token_id).await?;
923 }
924 Ok(())
925 }
926
927 pub async fn revoke_family(&self, family_id: &str) -> Result<usize> {
929 self.store.delete_family(family_id).await
930 }
931
932 pub async fn revoke_all_for_user(&self, user_id: &str) -> Result<usize> {
934 self.store.delete_by_user(user_id).await
935 }
936
937 pub async fn get_user_tokens(&self, user_id: &str) -> Result<Vec<RefreshToken>> {
939 self.store.get_by_user(user_id).await
940 }
941
942 pub async fn get_family_tokens(&self, family_id: &str) -> Result<Vec<RefreshToken>> {
944 self.store.get_by_family(family_id).await
945 }
946
947 pub async fn cleanup(&self) -> Result<usize> {
949 self.store.cleanup_expired().await
950 }
951
952 pub async fn count(&self) -> Result<usize> {
954 self.store.count().await
955 }
956
957 pub fn config(&self) -> &RefreshConfig {
959 &self.config
960 }
961
962 async fn enforce_max_families(&self, user_id: &str) -> Result<()> {
968 if self.config.max_families_per_user == 0 {
969 return Ok(());
970 }
971
972 let tokens = self.store.get_by_user(user_id).await?;
973
974 let mut families: HashMap<String, i64> = HashMap::new();
976 for token in tokens {
977 families
978 .entry(token.family_id.clone())
979 .or_insert(token.created_at);
980 }
981
982 if families.len() >= self.config.max_families_per_user
985 && let Some((oldest_family, _)) =
986 families
987 .iter()
988 .min_by(|(id_a, created_a), (id_b, created_b)| {
989 created_a.cmp(created_b).then_with(|| id_a.cmp(id_b))
990 })
991 {
992 self.store.delete_family(oldest_family).await?;
993 }
994
995 Ok(())
996 }
997
998 async fn enforce_max_tokens_per_family(&self, family_id: &str) -> Result<()> {
1000 if self.config.max_tokens_per_family == 0 {
1001 return Ok(());
1002 }
1003
1004 let mut tokens = self.store.get_by_family(family_id).await?;
1005
1006 tokens.sort_by_key(|t| t.created_at);
1008
1009 while tokens.len() > self.config.max_tokens_per_family {
1011 if let Some(oldest) = tokens.first() {
1012 self.store.delete(&oldest.token_id).await?;
1013 tokens.remove(0);
1014 }
1015 }
1016
1017 Ok(())
1018 }
1019}
1020
1021#[derive(Debug, Clone, Default)]
1027pub struct GenerateOptions {
1028 pub device_info: Option<String>,
1030
1031 pub ip_address: Option<String>,
1033
1034 pub metadata: Option<serde_json::Value>,
1036
1037 pub family_id: Option<String>,
1039}
1040
1041impl GenerateOptions {
1042 pub fn new() -> Self {
1044 Self::default()
1045 }
1046
1047 pub fn with_device_info(mut self, info: impl Into<String>) -> Self {
1049 self.device_info = Some(info.into());
1050 self
1051 }
1052
1053 pub fn with_ip_address(mut self, ip: impl Into<String>) -> Self {
1055 self.ip_address = Some(ip.into());
1056 self
1057 }
1058
1059 pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
1061 self.metadata = Some(metadata);
1062 self
1063 }
1064
1065 pub fn with_metadata_from<T: Serialize>(mut self, data: T) -> Self {
1067 self.metadata = serde_json::to_value(data).ok();
1068 self
1069 }
1070
1071 pub fn with_family_id(mut self, family_id: impl Into<String>) -> Self {
1073 self.family_id = Some(family_id.into());
1074 self
1075 }
1076}
1077
1078#[cfg(test)]
1083mod tests {
1084 use super::*;
1085
1086 #[test]
1087 fn test_refresh_token_creation() {
1088 let token =
1089 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1090
1091 assert!(!token.token.is_empty());
1092 assert!(!token.token_id.is_empty());
1093 assert_eq!(token.user_id, "user123");
1094 assert_eq!(token.family_id, "family1");
1095 assert!(!token.used);
1096 assert!(!token.is_expired());
1097 assert!(token.is_valid());
1098 }
1099
1100 #[test]
1101 fn test_refresh_token_expiration() {
1102 let mut token =
1103 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1104 assert!(!token.is_expired());
1105
1106 token.expires_at = Utc::now().timestamp() - 1;
1108 assert!(token.is_expired());
1109 assert!(!token.is_valid());
1110 }
1111
1112 #[test]
1113 fn test_refresh_token_mark_as_used() {
1114 let mut token =
1115 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1116 assert!(token.is_valid());
1117
1118 token.mark_as_used(Some("new_token_id".to_string()));
1119
1120 assert!(token.used);
1121 assert!(token.used_at.is_some());
1122 assert_eq!(token.replaced_by, Some("new_token_id".to_string()));
1123 assert!(!token.is_valid());
1124 }
1125
1126 #[test]
1127 fn test_refresh_token_metadata() {
1128 let mut token =
1129 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1130
1131 token.set_metadata("device", "iPhone");
1133 token.set_metadata("count", 42);
1134 token.set_metadata("tags", vec!["a", "b"]);
1135
1136 let device: Option<String> = token.get_metadata("device");
1138 assert_eq!(device, Some("iPhone".to_string()));
1139
1140 let count: Option<i32> = token.get_metadata("count");
1141 assert_eq!(count, Some(42));
1142
1143 assert!(token.has_metadata("device"));
1145 assert!(!token.has_metadata("nonexistent"));
1146
1147 token.remove_metadata("device");
1149 assert!(!token.has_metadata("device"));
1150 }
1151
1152 #[tokio::test]
1153 async fn test_manager_generate() {
1154 let manager = RefreshTokenManager::new(RefreshConfig::default());
1155 let token = manager.generate("user123").await.unwrap();
1156
1157 assert_eq!(token.user_id, "user123");
1158 assert!(!token.token.is_empty());
1159 }
1160
1161 #[tokio::test]
1162 async fn test_manager_use_token_with_rotation() {
1163 let config = RefreshConfig::default().with_rotation(true);
1164 let manager = RefreshTokenManager::new(config);
1165
1166 let token = manager.generate("user123").await.unwrap();
1167 let result = manager.use_token(&token.token).await.unwrap();
1168
1169 assert!(result.new_token.is_some());
1170 assert_eq!(result.user_id, "user123");
1171
1172 assert!(manager.validate(&token.token).await.is_err());
1174 }
1175
1176 #[tokio::test]
1177 async fn test_manager_use_token_without_rotation() {
1178 let config = RefreshConfig::default().with_rotation(false);
1179 let manager = RefreshTokenManager::new(config);
1180
1181 let token = manager.generate("user123").await.unwrap();
1182 let result = manager.use_token(&token.token).await.unwrap();
1183
1184 assert!(result.new_token.is_none());
1185 }
1186
1187 #[tokio::test]
1188 async fn test_manager_reuse_detection() {
1189 let config = RefreshConfig::default()
1190 .with_rotation(true)
1191 .with_reuse_detection(true)
1192 .with_grace_period(Duration::seconds(0));
1193 let manager = RefreshTokenManager::new(config);
1194
1195 let token = manager.generate("user123").await.unwrap();
1196 let token_str = token.token.clone();
1197 let family_id = token.family_id.clone();
1198
1199 let result = manager.use_token(&token_str).await.unwrap();
1201 assert!(result.new_token.is_some());
1202 let new_token = result.new_token.unwrap();
1203
1204 let reuse_result = manager.use_token(&token_str).await;
1206 assert!(reuse_result.is_err());
1207
1208 assert!(manager.validate(&new_token.token).await.is_err());
1210 assert_eq!(
1211 manager.get_family_tokens(&family_id).await.unwrap().len(),
1212 0
1213 );
1214 }
1215
1216 #[tokio::test]
1217 async fn test_manager_revoke() {
1218 let manager = RefreshTokenManager::new(RefreshConfig::default());
1219 let token = manager.generate("user123").await.unwrap();
1220
1221 manager.revoke(&token.token).await.unwrap();
1222 assert!(manager.validate(&token.token).await.is_err());
1223 }
1224
1225 #[tokio::test]
1226 async fn test_manager_revoke_all_for_user() {
1227 let config = RefreshConfig::default().with_max_families_per_user(0);
1228 let manager = RefreshTokenManager::new(config);
1229
1230 manager.generate("user123").await.unwrap();
1231 manager.generate("user123").await.unwrap();
1232 manager.generate("user456").await.unwrap();
1233
1234 let count = manager.revoke_all_for_user("user123").await.unwrap();
1235 assert_eq!(count, 2);
1236
1237 assert_eq!(manager.get_user_tokens("user123").await.unwrap().len(), 0);
1238 assert_eq!(manager.get_user_tokens("user456").await.unwrap().len(), 1);
1239 }
1240
1241 #[tokio::test]
1242 async fn test_manager_max_families() {
1243 let config = RefreshConfig::default().with_max_families_per_user(2);
1244 let manager = RefreshTokenManager::new(config);
1245
1246 let t1 = manager.generate("user123").await.unwrap();
1247 let t2 = manager.generate("user123").await.unwrap();
1248 let t3 = manager.generate("user123").await.unwrap();
1249
1250 let tokens = manager.get_user_tokens("user123").await.unwrap();
1253 let families: std::collections::HashSet<_> =
1254 tokens.iter().map(|t| t.family_id.clone()).collect();
1255 assert_eq!(families.len(), 2);
1256
1257 let mut valid_count = 0;
1259 for t in [&t1.token, &t2.token, &t3.token] {
1260 if manager.validate(t).await.is_ok() {
1261 valid_count += 1;
1262 }
1263 }
1264 assert_eq!(valid_count, 2);
1265
1266 assert!(manager.validate(&t3.token).await.is_ok());
1268 }
1269
1270 #[tokio::test]
1271 async fn test_manager_validate() {
1272 let manager = RefreshTokenManager::new(RefreshConfig::default());
1273 let token = manager.generate("user123").await.unwrap();
1274
1275 let validated = manager.validate(&token.token).await.unwrap();
1276 assert_eq!(validated.user_id, "user123");
1277 }
1278
1279 #[tokio::test]
1280 async fn test_manager_cleanup() {
1281 let manager = RefreshTokenManager::new(RefreshConfig::default());
1282
1283 let mut token =
1285 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1286 token.expires_at = Utc::now().timestamp() - 100;
1287 manager.store.save(&token).await.unwrap();
1288
1289 manager.generate("user456").await.unwrap();
1291
1292 let cleaned = manager.cleanup().await.unwrap();
1293 assert_eq!(cleaned, 1);
1294 assert_eq!(manager.count().await.unwrap(), 1);
1295 }
1296
1297 #[test]
1298 fn test_config_presets() {
1299 let high_security = RefreshConfig::high_security();
1300 assert!(high_security.rotation_enabled);
1301 assert!(high_security.reuse_detection);
1302 assert_eq!(high_security.expiration.num_days(), 7);
1303
1304 let relaxed = RefreshConfig::relaxed();
1305 assert!(!relaxed.rotation_enabled);
1306 assert!(!relaxed.reuse_detection);
1307 }
1308
1309 #[tokio::test]
1310 async fn test_generate_with_options() {
1311 let manager = RefreshTokenManager::new(RefreshConfig::default());
1312
1313 let options = GenerateOptions::new()
1314 .with_device_info("iPhone 15")
1315 .with_ip_address("192.168.1.1");
1316
1317 let token = manager
1318 .generate_with_options("user123", options)
1319 .await
1320 .unwrap();
1321
1322 assert_eq!(token.device_info, Some("iPhone 15".to_string()));
1323 assert_eq!(token.ip_address, Some("192.168.1.1".to_string()));
1324 }
1325
1326 #[test]
1327 fn test_token_time_to_live() {
1328 let token =
1329 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1330 let ttl = token.time_to_live();
1331 assert!(ttl > 3500 && ttl <= 3600);
1332 }
1333
1334 #[tokio::test]
1335 async fn test_in_memory_store() {
1336 let store = InMemoryRefreshTokenStore::new();
1337
1338 let token =
1339 RefreshToken::new("user123", "family1".to_string(), Duration::hours(1)).unwrap();
1340 store.save(&token).await.unwrap();
1341
1342 let retrieved = store.get_by_token(&token.token).await.unwrap();
1343 assert!(retrieved.is_some());
1344 assert_eq!(retrieved.unwrap().user_id, "user123");
1345
1346 let by_id = store.get_by_id(&token.token_id).await.unwrap();
1347 assert!(by_id.is_some());
1348
1349 store.delete(&token.token_id).await.unwrap();
1350 assert!(store.get_by_token(&token.token).await.unwrap().is_none());
1351 }
1352
1353 #[tokio::test]
1354 async fn test_token_rotation_inherits_metadata() {
1355 let manager = RefreshTokenManager::new(RefreshConfig::default().with_rotation(true));
1356
1357 let mut token = manager.generate("user123").await.unwrap();
1358 token.set_metadata("custom_key", "custom_value");
1359 token.device_info = Some("TestDevice".to_string());
1360 manager.store.update(&token).await.unwrap();
1361
1362 let result = manager.use_token(&token.token).await.unwrap();
1363 let new_token = result.new_token.unwrap();
1364
1365 assert_eq!(new_token.device_info, Some("TestDevice".to_string()));
1367 let value: Option<String> = new_token.get_metadata("custom_key");
1368 assert_eq!(value, Some("custom_value".to_string()));
1369 }
1370}