use serde::{Deserialize, Serialize}; use time::{Duration, OffsetDateTime}; use crate::cli::client::{ApiClient, Session, check_response}; use crate::cli::output; #[derive(Serialize)] struct LoginRequest { username: String, password: String, } #[derive(Deserialize)] struct LoginResponse { success: bool, username: String, } #[derive(Deserialize)] struct SessionResponse { authenticated: bool, username: String, } /// Login and save session pub async fn login( mut client: ApiClient, username: &str, password: &str, ) -> Result<(), Box> { let request = LoginRequest { username: username.to_string(), password: password.to_string(), }; let response = client.post("/api/login", &request).await?; // Extract session cookie from response headers let session_token = response .headers() .get_all("set-cookie") .iter() .find_map(|v| { let s = v.to_str().ok()?; if s.starts_with("admin_session=") { // Extract just the token value let token = s.strip_prefix("admin_session=")?.split(';').next()?; Some(token.to_string()) } else { None } }); let response = check_response(response).await?; let login_response: LoginResponse = response.json().await?; if !login_response.success { output::error("Login failed"); return Ok(()); } let session_token = session_token.ok_or("No session cookie received")?; let session = Session { api_url: client.api_url.clone(), session_token, username: login_response.username.clone(), created_at: OffsetDateTime::now_utc(), expires_at: OffsetDateTime::now_utc() + Duration::days(7), }; client.save_session(session)?; output::success(&format!("Logged in as {}", login_response.username)); Ok(()) } /// Clear saved session pub async fn logout(mut client: ApiClient) -> Result<(), Box> { // Try to call logout endpoint if we have a session if client.is_authenticated() { let _ = client.post("/api/logout", &()).await; } client.clear_session()?; output::success("Logged out"); Ok(()) } /// Check current session status pub async fn session(client: ApiClient, json: bool) -> Result<(), Box> { // First check local session if let Some(session) = client.session() { // Verify with server let response = client.get("/api/session").await?; let response = check_response(response).await?; let session_response: SessionResponse = response.json().await?; if json { println!( "{}", serde_json::json!({ "authenticated": session_response.authenticated, "username": session_response.username, "api_url": session.api_url, "expires_at": session.expires_at.format(&time::format_description::well_known::Rfc3339).unwrap(), }) ); } else if session_response.authenticated { output::print_session(&session_response.username, &session.api_url); } else { output::error("Session expired or invalid"); } } else if json { println!( "{}", serde_json::json!({ "authenticated": false, }) ); } else { output::info("Not logged in"); } Ok(()) }