cloudreve_api/api/v3/
session.rs

1//! Session and authentication management for Cloudreve API v3
2
3use crate::Error;
4use crate::api::v3::ApiV3Client;
5use crate::api::v3::models::*;
6use log::debug;
7
8impl ApiV3Client {
9    /// Login with email and password
10    pub async fn login(&mut self, request: &LoginRequest<'_>) -> Result<User, Error> {
11        let url = self.get_url("/user/session");
12        let mut http_request = self.http_client.post(&url).json(request);
13
14        if let Some(cookie) = &self.session_cookie {
15            http_request = http_request.header("Cookie", format!("cloudreve-session={}", cookie));
16        }
17
18        let response = http_request.send().await?;
19
20        // Extract session cookie from Set-Cookie headers
21        // V3 uses Set-Cookie headers to set the session cookie
22        let cookie_headers = response.headers().get_all("Set-Cookie");
23        for cookie_header in cookie_headers {
24            if let Ok(cookie_str) = cookie_header.to_str() {
25                // Check if this Set-Cookie header contains cloudreve-session
26                if cookie_str.contains("cloudreve-session=") {
27                    // Parse the cookie value
28                    // Format: "cloudreve-session=VALUE; Path=/; HttpOnly" etc.
29                    for part in cookie_str.split(';') {
30                        let part = part.trim();
31                        if part.starts_with("cloudreve-session=") {
32                            let session_value = part.trim_start_matches("cloudreve-session=");
33                            self.session_cookie = Some(session_value.to_string());
34                            debug!(
35                                "Extracted V3 session cookie: {}...",
36                                &session_value[..session_value.len().min(20)]
37                            );
38                            break;
39                        }
40                    }
41                }
42            }
43        }
44
45        debug!("V3 session_cookie after login: {:?}", self.session_cookie);
46
47        let _status = response.status();
48        let api_response: ApiResponse<User> = response.json().await?;
49
50        match api_response.data {
51            Some(user) => Ok(user),
52            None => Err(Error::Api {
53                code: api_response.code,
54                message: api_response.msg,
55            }),
56        }
57    }
58
59    /// Login with OTP (Two-Factor Authentication)
60    pub async fn login_2fa(&mut self, request: &OtpLoginRequest) -> Result<User, Error> {
61        let url = self.get_url("/user/2fa");
62        let mut http_request = self.http_client.post(&url).json(request);
63
64        if let Some(cookie) = &self.session_cookie {
65            http_request = http_request.header("Cookie", format!("cloudreve-session={}", cookie));
66        }
67
68        let response = http_request.send().await?;
69
70        // Extract session cookie from Set-Cookie headers
71        let cookie_headers = response.headers().get_all("Set-Cookie");
72        for cookie_header in cookie_headers {
73            if let Ok(cookie_str) = cookie_header.to_str()
74                && cookie_str.contains("cloudreve-session=")
75            {
76                for part in cookie_str.split(';') {
77                    let part = part.trim();
78                    if part.starts_with("cloudreve-session=") {
79                        let session_value = part.trim_start_matches("cloudreve-session=");
80                        self.session_cookie = Some(session_value.to_string());
81                        debug!(
82                            "Extracted V3 session cookie (2FA): {}...",
83                            &session_value[..session_value.len().min(20)]
84                        );
85                        break;
86                    }
87                }
88            }
89        }
90
91        let _status = response.status();
92        let api_response: ApiResponse<User> = response.json().await?;
93
94        match api_response.data {
95            Some(user) => Ok(user),
96            None => Err(Error::Api {
97                code: api_response.code,
98                message: api_response.msg,
99            }),
100        }
101    }
102
103    /// Logout from current session
104    pub async fn logout(&self) -> Result<(), Error> {
105        let response: ApiResponse<()> = self.delete("/user/session").await?;
106        if response.code == 0 {
107            Ok(())
108        } else {
109            Err(Error::Api {
110                code: response.code,
111                message: response.msg,
112            })
113        }
114    }
115}