• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Xevion / Pac-Man / 17862749257

19 Sep 2025 03:28PM UTC coverage: 66.315% (+0.4%) from 65.884%
17862749257

push

github

Xevion
ci: adjust timeouts for nextest given docker requirements

2514 of 3791 relevant lines covered (66.31%)

21873.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

52.46
/pacman-server/src/session.rs
1
use std::time::{SystemTime, UNIX_EPOCH};
2

3
use axum_cookie::{cookie::Cookie, prelude::SameSite, CookieManager};
4
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
5

6
use crate::auth::provider::AuthUser;
7
use tracing::{trace, warn};
8

9
pub const SESSION_COOKIE_NAME: &str = "session";
10
pub const JWT_TTL_SECS: u64 = 60 * 60; // 1 hour
11

12
#[derive(Debug, serde::Serialize, serde::Deserialize)]
13
pub struct Claims {
14
    pub sub: String, // format: "{provider}:{provider_user_id}"
15
    pub name: Option<String>,
16
    pub iat: usize,
17
    pub exp: usize,
18
    // PKCE flow fields - only present during OAuth flow
19
    #[serde(rename = "ver", skip_serializing_if = "Option::is_none")]
20
    pub pkce_verifier: Option<String>,
21
    #[serde(rename = "st", skip_serializing_if = "Option::is_none")]
22
    pub csrf_state: Option<String>,
23
}
24

25
pub fn create_jwt_for_user(provider: &str, user: &AuthUser, encoding_key: &EncodingKey) -> String {
×
26
    let now = SystemTime::now()
×
27
        .duration_since(UNIX_EPOCH)
×
28
        .expect("time went backwards")
×
29
        .as_secs() as usize;
×
30
    let claims = Claims {
×
31
        sub: format!("{}:{}", provider, user.id),
×
32
        name: user.name.clone(),
×
33
        iat: now,
×
34
        exp: now + JWT_TTL_SECS as usize,
×
35
        pkce_verifier: None,
×
36
        csrf_state: None,
×
37
    };
×
38
    let token = encode(&Header::new(Algorithm::HS256), &claims, encoding_key).expect("jwt sign");
×
39
    trace!(sub = %claims.sub, exp = claims.exp, "Created session JWT");
×
40
    token
×
41
}
×
42

43
/// Creates a temporary session for PKCE flow with verifier and CSRF state
44
pub fn create_pkce_session(pkce_verifier: &str, csrf_state: &str, encoding_key: &EncodingKey) -> String {
2✔
45
    let now = SystemTime::now()
2✔
46
        .duration_since(UNIX_EPOCH)
2✔
47
        .expect("time went backwards")
2✔
48
        .as_secs() as usize;
2✔
49
    let claims = Claims {
2✔
50
        sub: "pkce_flow".to_string(), // Special marker for PKCE flow
2✔
51
        name: None,
2✔
52
        iat: now,
2✔
53
        exp: now + JWT_TTL_SECS as usize,
2✔
54
        pkce_verifier: Some(pkce_verifier.to_string()),
2✔
55
        csrf_state: Some(csrf_state.to_string()),
2✔
56
    };
2✔
57
    let token = encode(&Header::new(Algorithm::HS256), &claims, encoding_key).expect("jwt sign");
2✔
58
    trace!(csrf_state = %csrf_state, "Created PKCE session JWT");
2✔
59
    token
2✔
60
}
2✔
61

62
/// Checks if a session is a PKCE flow session
63
pub fn is_pkce_session(claims: &Claims) -> bool {
×
64
    claims.sub == "pkce_flow" && claims.pkce_verifier.is_some() && claims.csrf_state.is_some()
×
65
}
×
66

67
pub fn decode_jwt(token: &str, decoding_key: &DecodingKey) -> Option<Claims> {
×
68
    let mut validation = Validation::new(Algorithm::HS256);
×
69
    validation.leeway = 30;
×
70
    match decode::<Claims>(token, decoding_key, &validation) {
×
71
        Ok(data) => Some(data.claims),
×
72
        Err(e) => {
×
73
            warn!(error = %e, "Session JWT verification failed");
×
74
            None
×
75
        }
76
    }
77
}
×
78

79
pub fn set_session_cookie(cookie: &CookieManager, token: &str) {
2✔
80
    cookie.add(
2✔
81
        Cookie::builder(SESSION_COOKIE_NAME, token.to_string())
2✔
82
            .http_only(true)
2✔
83
            .secure(!cfg!(debug_assertions))
2✔
84
            .path("/")
2✔
85
            .same_site(SameSite::Lax)
2✔
86
            .build(),
2✔
87
    );
88
}
2✔
89

90
pub fn clear_session_cookie(cookie: &CookieManager) {
1✔
91
    cookie.remove(SESSION_COOKIE_NAME);
1✔
92
}
1✔
93

94
pub fn get_session_token(cookie: &CookieManager) -> Option<String> {
2✔
95
    cookie.get(SESSION_COOKIE_NAME).map(|c| c.value().to_string())
2✔
96
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc