lastfm_edit/
session.rs

1use serde::{Deserialize, Serialize};
2
3/// Serializable client session state that can be persisted and restored.
4///
5/// This contains all the authentication state needed to resume a Last.fm session
6/// without requiring the user to log in again.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct LastFmEditSession {
9    /// The authenticated username
10    pub username: String,
11    /// Session cookies required for authenticated requests
12    pub cookies: Vec<String>,
13    /// CSRF token for form submissions
14    pub csrf_token: Option<String>,
15    /// Base URL for the Last.fm instance
16    pub base_url: String,
17}
18
19impl LastFmEditSession {
20    /// Create a new client session with the provided state
21    pub fn new(
22        username: String,
23        session_cookies: Vec<String>,
24        csrf_token: Option<String>,
25        base_url: String,
26    ) -> Self {
27        Self {
28            username,
29            cookies: session_cookies,
30            csrf_token,
31            base_url,
32        }
33    }
34
35    /// Check if this session appears to be valid
36    ///
37    /// This performs basic validation but doesn't guarantee the session
38    /// is still active on the server.
39    pub fn is_valid(&self) -> bool {
40        !self.username.is_empty()
41            && !self.cookies.is_empty()
42            && self.csrf_token.is_some()
43            && self
44                .cookies
45                .iter()
46                .any(|cookie| cookie.starts_with("sessionid=") && cookie.len() > 50)
47    }
48
49    /// Serialize session to JSON string
50    pub fn to_json(&self) -> Result<String, serde_json::Error> {
51        serde_json::to_string(self)
52    }
53
54    /// Deserialize session from JSON string
55    pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
56        serde_json::from_str(json)
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_session_validity() {
66        let valid_session = LastFmEditSession::new(
67            "testuser".to_string(),
68            vec!["sessionid=.eJy1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890".to_string()],
69            Some("csrf_token_123".to_string()),
70            "https://www.last.fm".to_string(),
71        );
72        assert!(valid_session.is_valid());
73
74        let invalid_session = LastFmEditSession::new(
75            "".to_string(),
76            vec![],
77            None,
78            "https://www.last.fm".to_string(),
79        );
80        assert!(!invalid_session.is_valid());
81    }
82
83    #[test]
84    fn test_session_serialization() {
85        let session = LastFmEditSession::new(
86            "testuser".to_string(),
87            vec![
88                "sessionid=.test123".to_string(),
89                "csrftoken=abc".to_string(),
90            ],
91            Some("csrf_token_123".to_string()),
92            "https://www.last.fm".to_string(),
93        );
94
95        let json = session.to_json().unwrap();
96        let restored_session = LastFmEditSession::from_json(&json).unwrap();
97
98        assert_eq!(session.username, restored_session.username);
99        assert_eq!(session.cookies, restored_session.cookies);
100        assert_eq!(session.csrf_token, restored_session.csrf_token);
101        assert_eq!(session.base_url, restored_session.base_url);
102    }
103}