use std::sync::Arc;
use axum::extract::{Path, Query, State};
use axum::Json;
use serde::Deserialize;
use serde_json::json;
use crate::error::AppError;
use crate::server::AppState;
#[derive(Debug, Deserialize)]
pub struct RangeQuery {
pub from_seq: Option<u64>,
pub to_seq: Option<u64>,
}
#[derive(Debug, Deserialize)]
pub struct ExportRequest {
pub from_seq: Option<u64>,
}
pub(crate) async fn handle_audit_entries(
State(state): State<Arc<AppState>>,
Query(params): Query<RangeQuery>,
) -> Result<Json<serde_json::Value>, AppError> {
let from_seq = params.from_seq.unwrap_or(0);
let to_seq = params.to_seq.unwrap_or(100);
let entries = state.kernel.security.query_audit(from_seq, to_seq);
let count = entries.len();
let entries_json: Vec<serde_json::Value> = entries
.into_iter()
.map(|e| serde_json::to_value(&e).unwrap_or(serde_json::Value::Null))
.collect();
Ok(Json(json!({
"entries": entries_json,
"count": count,
})))
}
pub(crate) async fn handle_audit_verify(
State(state): State<Arc<AppState>>,
) -> Result<Json<serde_json::Value>, AppError> {
let entry_count = state.kernel.security.audit_count();
match state.kernel.security.verify_chain() {
Ok(valid) => Ok(Json(json!({
"valid": valid,
"entry_count": entry_count,
}))),
Err(e) => {
let msg = e.to_string();
if let Some(seq) = msg.strip_prefix("chain broken at seq ") {
let parts: Vec<&str> = seq.split(" expected ").collect();
if parts.len() >= 2 {
let seq_num: u64 = parts[0].parse().unwrap_or(0);
let exp_found: Vec<&str> = parts[1].split(" found ").collect();
if exp_found.len() >= 2 {
return Ok(Json(json!({
"valid": false,
"entry_count": entry_count,
"broken_at_seq": seq_num,
"expected": exp_found[0],
"found": exp_found[1],
})));
}
}
}
if msg.contains("timestamp in the future") {
let seq = msg
.lines()
.find(|l| l.contains("seq"))
.and_then(|l| l.split(":").nth(1))
.map(|s| s.trim().parse::<u64>().unwrap_or(0))
.unwrap_or(0);
return Ok(Json(json!({
"valid": false,
"entry_count": entry_count,
"broken_at_seq": seq,
"expected": "valid timestamp",
"found": "timestamp in the future",
})));
}
Err(AppError::Internal(format!("audit verify failed: {}", msg)))
}
}
}
pub(crate) async fn handle_audit_by_agent(
State(state): State<Arc<AppState>>,
Path(agent_id): Path<String>,
) -> Result<Json<serde_json::Value>, AppError> {
let entries = state.kernel.security.query_audit_by_agent(&agent_id);
let count = entries.len();
let entries_json: Vec<serde_json::Value> = entries
.into_iter()
.map(|e| serde_json::to_value(&e).unwrap_or(serde_json::Value::Null))
.collect();
Ok(Json(json!({
"entries": entries_json,
"count": count,
})))
}
pub(crate) async fn handle_audit_export(
State(state): State<Arc<AppState>>,
Json(body): Json<ExportRequest>,
) -> Result<Json<serde_json::Value>, AppError> {
let from_seq = body.from_seq.unwrap_or(0);
let entries = state.kernel.security.query_audit(from_seq, u64::MAX);
let entry_count = entries.len();
let json = serde_json::to_string_pretty(&entries)
.map_err(|e| AppError::Internal(format!("failed to serialize entries: {}", e)))?;
Ok(Json(json!({
"json": json,
"entry_count": entry_count,
})))
}
pub(crate) async fn handle_audit_flush(
State(state): State<Arc<AppState>>,
) -> Result<Json<serde_json::Value>, AppError> {
let flushed = state.kernel.security.audit_count();
let _ = state.kernel.flush_audit();
Ok(Json(json!({
"flushed": flushed,
})))
}