Release: NX9-Auth v0.3.0

This commit is contained in:
thakares committed 2026-07-22 19:36:22 +05:30
1 parent 6a04d7f793
commit d93f2cef95
92 files changed
+2418 -1143

No files matched your search

+2 -2
View File
@@ -6,8 +6,8 @@ use serde::{Deserialize, Serialize};
use serde_json::{Value, json};
use crate::{
db::models::AuditLog,
db::repository::audit::{self as audit_repo, AuditFilter},
db::models::{AuditFilter, AuditLog},
db::repository::audit as audit_repo,
error::{AppError, Result},
middleware::{auth::AuthUser, permissions::require},
state::AppState,
+4 -1
View File
@@ -112,7 +112,10 @@ pub async fn login(
return Err(AppError::InvalidCredentials);
}
let user = final_user.expect("authenticated user");
let user = match final_user {
Some(u) => u,
None => return Err(AppError::InvalidCredentials),
};
// Clear rate limit on success
if let Some(ip_str) = &ctx.ip_address {
+2 -2
View File
@@ -84,7 +84,7 @@ pub async fn dashboard(State(state): State<AppState>, auth: AuthUser) -> Result<
let recent_personal = state
.provider
.audit()
.list_filtered(&crate::db::repository::audit::AuditFilter {
.list_filtered(&crate::db::models::AuditFilter {
actor_user_id: Some(auth.user.id.clone()),
limit: 10,
..Default::default()
@@ -175,7 +175,7 @@ pub async fn dashboard(State(state): State<AppState>, auth: AuthUser) -> Result<
let recent_logins = state
.provider
.audit()
.list_filtered(&crate::db::repository::audit::AuditFilter {
.list_filtered(&crate::db::models::AuditFilter {
action: Some("login_success".into()),
limit: 10,
..Default::default()
+21 -2
View File
@@ -1,7 +1,26 @@
use axum::Json;
use axum::extract::State;
use serde_json::{Value, json};
use crate::state::AppState;
/// GET /health
pub async fn health() -> Json<Value> {
Json(json!({ "status": "ok" }))
pub async fn health(State(state): State<AppState>) -> Json<Value> {
let backend = state
.config
.database
.resolved_url()
.map(|(_, b)| b.to_string())
.unwrap_or_else(|_| "unknown".to_string());
let db_status = match state.provider.tenants().list().await {
Ok(_) => "connected",
Err(_) => "error",
};
Json(json!({
"status": if db_status == "connected" { "ok" } else { "degraded" },
"db_backend": backend,
"database_status": db_status
}))
}
+22
View File
@@ -62,6 +62,28 @@ pub async fn serve_ui(uri: Uri) -> Response {
return StatusCode::NOT_FOUND.into_response();
}
// Security Hardening: Reject & sanitize any GET request containing credentials in query string.
if let Some(query) = uri.query() {
let q_lower = query.to_ascii_lowercase();
if q_lower.contains("password=")
|| q_lower.contains("username=")
|| q_lower.contains("secret=")
{
tracing::warn!(path = %uri.path(), "rejected credential query parameters in GET request");
let clean_path = if uri.path().is_empty() {
"/"
} else {
uri.path()
};
return Response::builder()
.status(StatusCode::SEE_OTHER)
.header(header::LOCATION, clean_path)
.header(header::CACHE_CONTROL, "no-store")
.body(Body::empty())
.unwrap_or_else(|_| StatusCode::BAD_REQUEST.into_response());
}
}
// Normalize and reject path traversal
if path.contains("..") {
return StatusCode::BAD_REQUEST.into_response();
+13 -2
View File
@@ -1,15 +1,26 @@
use axum::Json;
use axum::extract::State;
use serde_json::{Value, json};
use crate::state::AppState;
/// GET /version
///
/// Returns build metadata baked in at compile time via `build.rs`.
pub async fn version() -> Json<Value> {
/// Returns build metadata baked in at compile time via `build.rs` and active db_backend.
pub async fn version(State(state): State<AppState>) -> Json<Value> {
let backend = state
.config
.database
.resolved_url()
.map(|(_, b)| b.to_string())
.unwrap_or_else(|_| "unknown".to_string());
Json(json!({
"name": env!("CARGO_PKG_NAME"),
"version": env!("CARGO_PKG_VERSION"),
"git_commit": env!("GIT_COMMIT"),
"build_date": env!("BUILD_DATE"),
"rust_version": env!("RUST_VERSION"),
"db_backend": backend,
}))
}