use axum::{extract::State, http::StatusCode, Json}; use serde_json::{json, Value}; use crate::{auth::encode_jwt, models::user::LoginRequest, state::AppState}; pub async fn login( State(state): State, Json(body): Json, ) -> Result, StatusCode> { let user = sqlx::query_as::<_, crate::models::user::User>( "SELECT id, username, password_hash, permissions_mask, created_at FROM users WHERE username = $1", ) .bind(&body.username) .fetch_optional(&state.pool) .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)? .ok_or(StatusCode::UNAUTHORIZED)?; let valid = bcrypt::verify(&body.password, &user.password_hash) .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; if !valid { return Err(StatusCode::UNAUTHORIZED); } let mask: u128 = user.permissions_mask.parse().unwrap_or(0); let token = encode_jwt( &user.username, mask, &state.config.jwt_secret, state.config.jwt_expiry_secs, ) .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; Ok(Json(json!({ "token": token }))) }