diff --git a/backend/src/handlers/setup.rs b/backend/src/handlers/setup.rs index 55f6875..ae44d8c 100644 --- a/backend/src/handlers/setup.rs +++ b/backend/src/handlers/setup.rs @@ -6,6 +6,8 @@ use axum::{ }; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; +use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite}; +use time::Duration; #[derive(Deserialize, ToSchema)] pub struct SetupRequest { @@ -41,7 +43,7 @@ pub async fn get_setup_status_handler(State(state): State) -> impl Int path = "/api/setup", request_body = SetupRequest, responses( - (status = 200, description = "Setup completed"), + (status = 200, description = "Setup completed and logged in"), (status = 400, description = "Invalid request"), (status = 403, description = "Setup already completed"), (status = 500, description = "Internal server error") @@ -49,6 +51,7 @@ pub async fn get_setup_status_handler(State(state): State) -> impl Int )] pub async fn setup_handler( State(state): State, + jar: CookieJar, Json(payload): Json, ) -> impl IntoResponse { // 1. Check if setup is already completed (i.e., users exist) @@ -68,7 +71,6 @@ pub async fn setup_handler( // 3. Create User // Lower cost for faster login on low-power devices (MIPS routers etc.) - // Default is usually 12, which takes ~3s on slow CPUs. 6 should be much faster. let password_hash = match bcrypt::hash(&payload.password, 6) { Ok(h) => h, Err(e) => { @@ -82,5 +84,42 @@ pub async fn setup_handler( return (StatusCode::INTERNAL_SERVER_ERROR, "Failed to create user").into_response(); } - (StatusCode::OK, "Setup completed successfully").into_response() + // 4. Auto-Login (Create Session) + // Get the created user's ID + let user = match state.db.get_user_by_username(&payload.username).await { + Ok(Some(u)) => u, + Ok(None) => return (StatusCode::INTERNAL_SERVER_ERROR, "User created but not found").into_response(), + Err(e) => { + tracing::error!("DB error fetching new user: {}", e); + return (StatusCode::INTERNAL_SERVER_ERROR, "Database error").into_response(); + } + }; + let (user_id, _) = user; + + // Create session token + let token: String = (0..32).map(|_| { + use rand::{distributions::Alphanumeric, Rng}; + rand::thread_rng().sample(Alphanumeric) as char + }).collect(); + + // Default expiration: 1 day (since it's not "remember me") + let expires_in = 60 * 60 * 24; + let expires_at = time::OffsetDateTime::now_utc().unix_timestamp() + expires_in; + + if let Err(e) = state.db.create_session(user_id, &token, expires_at).await { + tracing::error!("Failed to create session for new user: {}", e); + // Even if session fails, setup is technically complete, but login failed. + // We return OK but user will have to login manually. + return (StatusCode::OK, "Setup completed, please login").into_response(); + } + + let mut cookie = Cookie::build(("auth_token", token)) + .path("/") + .http_only(true) + .same_site(SameSite::Lax) + .build(); + + cookie.set_max_age(Duration::seconds(expires_in)); + + (StatusCode::OK, jar.add(cookie), "Setup completed and logged in").into_response() } diff --git a/frontend/src/components/auth/setup.rs b/frontend/src/components/auth/setup.rs index b14df34..ac71c3a 100644 --- a/frontend/src/components/auth/setup.rs +++ b/frontend/src/components/auth/setup.rs @@ -48,8 +48,9 @@ pub fn Setup() -> impl IntoView { match client.send().await { Ok(resp) => { if resp.ok() { - // Redirect to login after setup (full reload to be safe) - let _ = window().location().set_href("/login"); + // Redirect to home after setup (auto-login handled by backend) + // Full reload to ensure auth state is refreshed + let _ = window().location().set_href("/"); } else { let text = resp.text().await.unwrap_or_default(); set_error.set(Some(format!("Hata: {}", text)));