1
use uuid::Uuid;
2
use web::token::{
3
    TokenClaims, TokenDetails, generate_jwt_token, generate_jwt_token_with_uuid, verify_jwt_token,
4
};
5

            
6
const TEST_PRIVATE_KEY_B64: &str = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRREptUmdUU1pEY3QySGsKQys5L2xNa1poQWNQL09zQWpQU1B5LytoYzZYNHhkMzFUT0RrS1lzeGhqQXE1RkFmQzJjZTk4VmY3ZmhWYlgyMwpwYU91WVp2ZTY1UUEyRW81VlM1SFFKWUsxUXNSWTVUVzFDQ05MZVJmV3pWSWY4c01YMlNuN09XYStWakZaVW0rCkhPd3pBL0xIUW84QzFzUWZsYUJVWVVIUEJkMTE5a25TU0pIYlNhdTFsZ1ZsUVlvY1FndWVnZ29MVktjcnlZMTgKYitNSXlTRWJCT1lUUDk1YlNKbjlPK3lhcHZPamhhQ3VuSlQzakVjOVhVRytiakJBam9CVTZpV3NncTVtTnljYQpPbHd3N253S0ZoaEhjUEZhRWY4bHZ3WFoxVkxHTDNlQ0FMR0VrakhteFdBWEdVUnNMMWxIOTYvN2JvQjhBUXBDCkxPaXIwb0s5QWdNQkFBRUNnZ0VBQkVoZWtOQlVCY0JXa2Nub0gxbDVrVE56RS9XZlIyNTNKcFBpblJzd0dESVoKNWtOcEZxZkVSM3ZPaTZhNGhnUlB2MEpydkw4NU1wVm1JWS9oQTR3YXk5aE0xMXpBN09sZ2w0NXBjWmIzaW5uSApXRzMrdUFrVXpDckxuYnZyUkJyRnNHU1J0eUpiYnF3WmJqSyttTkhaWno3RWUzNjFBV2ZFRlc3UWYxV2tVQVJ1Ci9zTXVqUzdVem5RZFBwNnhzWnJzbGRrRmlJSStWVXA4UitzUDhVTFJuZlhKRnliZXNuQXRDRUZiM053U0EzVWQKSnhjcGlNUzlHOHhGY2VKK3kxNlNnc3FpZG55dGtZdm1UUVZ3N0NEZmtHZHZFT0lXdkdNNTFVNjdNbVpyZW15OApnZ1p2ZkcyUlgyaG4yNVdPTlFaY1hrRDJmZ2UwWXZvMjVKRnQzZ3lhY1FLQmdRRHh4ajl0UUtDankrd3d5Yk9iCmw5bFp4Uzh1aUM0YTY1OExOU3VoNGZYbkRJTE83VmRBbW9lY2hNeXMwaXZxSnhxWTBva2QvVzAwUVg0RWx5Ui8KRG9QWHM5N01DaHRMc1dTZUJpN3VsZWhtbTJab1F6d09xSkR6Ynd2TmZGTWVJYlNVTG5nTEFYT1lyQUZNVGhjWQpHMmFxRFRCRjBUUkRNd3hoMGhLL1NYRS9VUUtCZ1FEVmRhOXlPV2wxUkJrNDZoU1AveFB3ZEUrR0RRR0dycDNKCkNzRXRYeUovMVBrajVKZ25HTTZ4dWdHTHhuaGs2YW1TN0czUS95QzBwalZXOVkrSUg5RUpNRUdYcTNyUjlKWkEKcFdZNkQ5SnM1K2dCT3h4Y3ZxaCtDQ1VWZnk2b0pRUGpJK3VxUXNEYjQ0TVRHUGJQckhxbU10dUE5M3pkQ2ZXOQpOYlZvOW9ycHJRS0JnRUs3am53d1QyYUdmYTNGcm41dXZqNUo3OGp2SzVLZ29HaHVoNW1LRGQ1MUZKSGE3cTlWCk44TWE0SWQvQjBIOUF4bFZXeVZjOHN4dW0wTFhHT3E4N2VVV3I1TXY0dkxVaHNvYk9NNy9yNExLdDh4bGFtazkKVzZ6bFpLT1dBamNaNUliV0FLcEEvMUFQZ2RnMjRhYjB3VFNFcVdOTDZCbjRPQjJ6NXhySFFhdlJBb0dBRFRVZAo2T3hpZVE0QW5ZUG1SODZabGp3c0czZzhpdS9NOVg2RDIySFNpYVJNMGdxMzIxdHVscEtTdStwSTByMmViMmZQCmw2bmhoU3Z2aXZUZ3I2U0FVNWczeHNHbWRNMDBhc1dSSUxDUDdZc2YwTXV1Z3BLTmJGYm1ySURWQ3pSWEhEdkIKdmlRcE9MSElEMnR4QWdLRENEdUhWMkI0eWxodWF3bWlzdDdtVTNVQ2dZQitFVlJGUlVjQnhYSm8xaXg2bXZlQQo1blgwa2s2L1F3YVZWWUhlLzFlYm1ISDNZYUZWQzhvYTJYQWpmNDRuRkN6cHFGWjlsTnZYMHR0eFo3VzlzV1E3CjFjOXU1VTQxekdDZzkreVVwcUdYNTZXdG4zUWJkL0dUdGJlTXd5c2o3V0NlSFltU0xUcklaU001aE0zNDBaeHkKNzZZRTV0SGRKazhHUGVzNzNwR29lUT09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K";
7

            
8
const TEST_PUBLIC_KEY_B64: &str = "LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUF5WmtZRTBtUTNMZGg1QXZ2ZjVUSgpHWVFIRC96ckFJejBqOHYvb1hPbCtNWGQ5VXpnNUNtTE1ZWXdLdVJRSHd0bkh2ZkZYKzM0VlcxOXQ2V2pybUdiCjN1dVVBTmhLT1ZVdVIwQ1dDdFVMRVdPVTF0UWdqUzNrWDFzMVNIL0xERjlrcCt6bG12bFl4V1ZKdmh6c013UHkKeDBLUEF0YkVINVdnVkdGQnp3WGRkZlpKMGtpUjIwbXJ0WllGWlVHS0hFSUxub0lLQzFTbks4bU5mRy9qQ01raApHd1RtRXovZVcwaVovVHZzbXFiem80V2dycHlVOTR4SFBWMUJ2bTR3UUk2QVZPb2xySUt1WmpjbkdqcGNNTzU4CkNoWVlSM0R4V2hIL0piOEYyZFZTeGk5M2dnQ3hoSkl4NXNWZ0Z4bEViQzlaUi9ldisyNkFmQUVLUWl6b3E5S0MKdlFJREFRQUIKLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg==";
9

            
10
#[test]
11
1
fn test_token_details_creation() {
12
1
    let user_id = Uuid::new_v4();
13
1
    let token_uuid = Uuid::new_v4();
14

            
15
1
    let token_details = TokenDetails {
16
1
        token: Some("test_token".to_string()),
17
1
        token_uuid,
18
1
        user_id,
19
1
        expires_in: Some(1234567890),
20
1
    };
21

            
22
1
    assert_eq!(token_details.user_id, user_id);
23
1
    assert_eq!(token_details.token_uuid, token_uuid);
24
1
    assert_eq!(token_details.token, Some("test_token".to_string()));
25
1
    assert_eq!(token_details.expires_in, Some(1234567890));
26
1
}
27

            
28
#[test]
29
1
fn test_token_claims_creation() {
30
1
    let user_id = Uuid::new_v4();
31
1
    let token_uuid = Uuid::new_v4();
32

            
33
1
    let claims = TokenClaims {
34
1
        sub: user_id.to_string(),
35
1
        token_uuid: token_uuid.to_string(),
36
1
        exp: 1234567890,
37
1
        iat: 1234567000,
38
1
        nbf: 1234567000,
39
1
    };
40

            
41
1
    assert_eq!(claims.sub, user_id.to_string());
42
1
    assert_eq!(claims.token_uuid, token_uuid.to_string());
43
1
    assert_eq!(claims.exp, 1234567890);
44
1
    assert_eq!(claims.iat, 1234567000);
45
1
    assert_eq!(claims.nbf, 1234567000);
46
1
}
47

            
48
#[test]
49
1
fn test_generate_jwt_token_round_trip() {
50
1
    let user_id = Uuid::new_v4();
51
1
    let details = generate_jwt_token(user_id, 15, TEST_PRIVATE_KEY_B64).expect("encode");
52
1
    let token = details.token.as_deref().expect("token");
53

            
54
1
    let verified = verify_jwt_token(TEST_PUBLIC_KEY_B64, token).expect("verify");
55

            
56
1
    assert_eq!(verified.user_id, user_id);
57
1
    assert_eq!(verified.token_uuid, details.token_uuid);
58
1
}
59

            
60
#[test]
61
1
fn test_generate_jwt_token_with_uuid_preserves_uuid() {
62
1
    let user_id = Uuid::new_v4();
63
1
    let fixed_uuid = Uuid::new_v4();
64

            
65
1
    let details = generate_jwt_token_with_uuid(user_id, fixed_uuid, 15, TEST_PRIVATE_KEY_B64)
66
1
        .expect("encode");
67

            
68
1
    assert_eq!(details.token_uuid, fixed_uuid);
69

            
70
1
    let verified =
71
1
        verify_jwt_token(TEST_PUBLIC_KEY_B64, details.token.as_deref().unwrap()).expect("verify");
72
1
    assert_eq!(verified.token_uuid, fixed_uuid);
73
1
    assert_eq!(verified.user_id, user_id);
74
1
}
75

            
76
#[test]
77
1
fn test_remint_with_same_uuid_extends_expiry() {
78
1
    let user_id = Uuid::new_v4();
79
1
    let shared_uuid = Uuid::new_v4();
80

            
81
1
    let first = generate_jwt_token_with_uuid(user_id, shared_uuid, 15, TEST_PRIVATE_KEY_B64)
82
1
        .expect("first");
83

            
84
1
    std::thread::sleep(std::time::Duration::from_secs(1));
85

            
86
1
    let second = generate_jwt_token_with_uuid(user_id, shared_uuid, 60, TEST_PRIVATE_KEY_B64)
87
1
        .expect("second");
88

            
89
1
    assert_eq!(first.token_uuid, second.token_uuid);
90
1
    assert!(
91
1
        second.expires_in.unwrap() > first.expires_in.unwrap(),
92
        "re-mint must push exp forward: first={:?}, second={:?}",
93
        first.expires_in,
94
        second.expires_in,
95
    );
96
1
    assert_ne!(
97
        first.token, second.token,
98
        "JWT string must differ (different iat/exp claims)"
99
    );
100

            
101
1
    let verified_first =
102
1
        verify_jwt_token(TEST_PUBLIC_KEY_B64, first.token.as_deref().unwrap()).expect("v1");
103
1
    let verified_second =
104
1
        verify_jwt_token(TEST_PUBLIC_KEY_B64, second.token.as_deref().unwrap()).expect("v2");
105
1
    assert_eq!(verified_first.token_uuid, verified_second.token_uuid);
106
1
}
107

            
108
#[test]
109
1
fn test_generate_jwt_token_unique_uuid_per_call() {
110
1
    let user_id = Uuid::new_v4();
111

            
112
1
    let a = generate_jwt_token(user_id, 15, TEST_PRIVATE_KEY_B64).expect("a");
113
1
    let b = generate_jwt_token(user_id, 15, TEST_PRIVATE_KEY_B64).expect("b");
114

            
115
1
    assert_ne!(
116
        a.token_uuid, b.token_uuid,
117
        "generate_jwt_token must mint fresh uuid each call"
118
    );
119
1
}