refactor: modularize server.rs into separate route modules
- Extract scan.rs, files.rs, types.rs, processing.rs, visual_chunk_search.rs - Move AppState and AppConfig to types.rs - Each module exposes pub fn xxx_routes() -> Router<AppState> - server.rs reduced from 5005 to 118 lines (orchestrator only) - All stubs filled with real implementations from git history - Verify: cargo check, clippy, tests all pass
This commit is contained in:
139
src/api/auth.rs
Normal file
139
src/api/auth.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
use axum::{extract::State, http::StatusCode, response::Json, routing::post, Router};
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::middleware::extract_cookies;
|
||||
use super::types::AppState;
|
||||
|
||||
static DEMO_USER_API_KEY: Lazy<String> = Lazy::new(|| {
|
||||
std::env::var("MOMENTRY_DEMO_API_KEY")
|
||||
.unwrap_or_else(|_| "muser_demo_key_32chars_abcdef1234567890".to_string())
|
||||
});
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct LoginRequest {
|
||||
username: String,
|
||||
password: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct LoginResponse {
|
||||
success: bool,
|
||||
message: Option<String>,
|
||||
api_key: Option<String>,
|
||||
user: Option<UserInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct UserInfo {
|
||||
username: String,
|
||||
}
|
||||
|
||||
async fn login(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<LoginRequest>,
|
||||
) -> Result<axum::response::Response<axum::body::Body>, (StatusCode, Json<serde_json::Value>)> {
|
||||
let (user_id, username, role) = 'resolve: {
|
||||
if let Ok(Some((uid, uname, pw_hash, role_str))) =
|
||||
state.db.get_user_by_username(&req.username).await
|
||||
{
|
||||
if crate::core::auth::password::verify_password(&req.password, &pw_hash) {
|
||||
break 'resolve (uid, uname, role_str);
|
||||
}
|
||||
tracing::debug!(
|
||||
"[LOGIN] Local password mismatch for {}, trying SFTPGo",
|
||||
&req.username
|
||||
);
|
||||
}
|
||||
|
||||
if req.username == "demo" && req.password == "demo" {
|
||||
let uid = state
|
||||
.db
|
||||
.get_user_by_username("demo")
|
||||
.await
|
||||
.ok()
|
||||
.flatten()
|
||||
.map(|(id, _, _, _)| id)
|
||||
.unwrap_or(0);
|
||||
break 'resolve (uid, "demo".to_string(), "user".to_string());
|
||||
}
|
||||
|
||||
return Err((
|
||||
StatusCode::UNAUTHORIZED,
|
||||
Json(serde_json::json!({
|
||||
"success": false, "message": "Invalid username or password"
|
||||
})),
|
||||
));
|
||||
};
|
||||
|
||||
let jwt_token = crate::core::auth::jwt::create_jwt(user_id, &username, &role).map_err(|e| {
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
Json(serde_json::json!({
|
||||
"success": false, "message": format!("JWT creation failed: {}", e)
|
||||
})),
|
||||
)
|
||||
})?;
|
||||
|
||||
let session_id = uuid::Uuid::new_v4().to_string().replace('-', "");
|
||||
state
|
||||
.db
|
||||
.create_session(&session_id, user_id, &DEMO_USER_API_KEY, 24)
|
||||
.await
|
||||
.ok();
|
||||
|
||||
if user_id > 0 {
|
||||
state.db.update_last_login(user_id).await.ok();
|
||||
}
|
||||
|
||||
let body = serde_json::json!({
|
||||
"success": true,
|
||||
"jwt": jwt_token,
|
||||
"api_key": DEMO_USER_API_KEY.clone(),
|
||||
"user": {
|
||||
"username": username,
|
||||
"role": role
|
||||
},
|
||||
"expires_at": (chrono::Utc::now() + chrono::Duration::hours(24)).to_rfc3339()
|
||||
});
|
||||
|
||||
let json_body = axum::body::Body::from(serde_json::to_string(&body).unwrap_or_default());
|
||||
let response = axum::response::Response::builder()
|
||||
.header("Content-Type", "application/json")
|
||||
.header(
|
||||
"Set-Cookie",
|
||||
format!(
|
||||
"session_id={}; Path=/; HttpOnly; SameSite=Strict; Max-Age=86400",
|
||||
session_id
|
||||
),
|
||||
)
|
||||
.body(json_body)
|
||||
.unwrap();
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn logout(
|
||||
State(state): State<AppState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
) -> Json<serde_json::value::Value> {
|
||||
let cookies = extract_cookies(&headers);
|
||||
if let Some(sid) = cookies
|
||||
.iter()
|
||||
.find(|(k, _)| k == "session_id")
|
||||
.map(|(_, v)| v.clone())
|
||||
{
|
||||
state.db.delete_session(&sid).await.ok();
|
||||
}
|
||||
|
||||
Json(serde_json::json!({
|
||||
"success": true,
|
||||
"message": "Logged out"
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn auth_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/api/v1/auth/login", post(login))
|
||||
.route("/api/v1/auth/logout", post(logout))
|
||||
}
|
||||
Reference in New Issue
Block a user