#[cfg(feature = "server")] use axum::{ extract::{Path, State}, http::StatusCode, response::IntoResponse, Json, }; use serde_json::{json, Value}; use std::sync::Arc; use super::ApiResponse; use crate::core::VaultCore; /// GET /v1/* - Read a secret from any mounted engine #[cfg(feature = "server")] pub async fn read_secret( State(vault): State>, Path(path): Path, ) -> impl IntoResponse { let full_path = path; match vault.split_path(&full_path) { Some((_mount_path, relative_path)) => match vault.route_to_engine(&full_path) { Some(engine) => match engine.read(&relative_path).await { Ok(Some(data)) => { let response = ApiResponse::success(data); (StatusCode::OK, Json(response)).into_response() } Ok(None) => { let response = ApiResponse::::error("Secret not found"); (StatusCode::NOT_FOUND, Json(response)).into_response() } Err(e) => { let response = ApiResponse::::error(format!("Failed to read: {}", e)); (StatusCode::INTERNAL_SERVER_ERROR, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("No engine mounted at this path"); (StatusCode::NOT_FOUND, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("Path not found"); (StatusCode::NOT_FOUND, Json(response)).into_response() } } } /// POST /v1/* - Write a secret to any mounted engine #[cfg(feature = "server")] pub async fn write_secret( State(vault): State>, Path(path): Path, Json(payload): Json, ) -> impl IntoResponse { let full_path = path; match vault.split_path(&full_path) { Some((_mount_path, relative_path)) => match vault.route_to_engine(&full_path) { Some(engine) => match engine.write(&relative_path, &payload).await { Ok(()) => { let response = ApiResponse::success(json!({"path": full_path})); (StatusCode::OK, Json(response)).into_response() } Err(e) => { let response = ApiResponse::::error(format!("Failed to write: {}", e)); (StatusCode::BAD_REQUEST, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("No engine mounted at this path"); (StatusCode::NOT_FOUND, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("Path not found"); (StatusCode::NOT_FOUND, Json(response)).into_response() } } } /// PUT /v1/* - Update a secret in any mounted engine #[cfg(feature = "server")] pub async fn update_secret( State(vault): State>, Path(path): Path, Json(payload): Json, ) -> impl IntoResponse { let full_path = path; match vault.split_path(&full_path) { Some((_mount_path, relative_path)) => match vault.route_to_engine(&full_path) { Some(engine) => match engine.write(&relative_path, &payload).await { Ok(()) => { let response = ApiResponse::success(json!({"path": full_path})); (StatusCode::OK, Json(response)).into_response() } Err(e) => { let response = ApiResponse::::error(format!("Failed to update: {}", e)); (StatusCode::BAD_REQUEST, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("No engine mounted at this path"); (StatusCode::NOT_FOUND, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("Path not found"); (StatusCode::NOT_FOUND, Json(response)).into_response() } } } /// DELETE /v1/* - Delete a secret from any mounted engine #[cfg(feature = "server")] pub async fn delete_secret( State(vault): State>, Path(path): Path, ) -> impl IntoResponse { let full_path = path; match vault.split_path(&full_path) { Some((_mount_path, relative_path)) => match vault.route_to_engine(&full_path) { Some(engine) => match engine.delete(&relative_path).await { Ok(()) => { let response: ApiResponse = ApiResponse::success(json!({})); (StatusCode::NO_CONTENT, Json(response)).into_response() } Err(e) => { let response = ApiResponse::::error(format!("Failed to delete: {}", e)); (StatusCode::BAD_REQUEST, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("No engine mounted at this path"); (StatusCode::NOT_FOUND, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("Path not found"); (StatusCode::NOT_FOUND, Json(response)).into_response() } } } /// LIST /v1/* - List secrets at a path prefix #[cfg(feature = "server")] pub async fn list_secrets( State(vault): State>, Path(path): Path, ) -> impl IntoResponse { let full_path = path; match vault.split_path(&full_path) { Some((_mount_path, relative_path)) => match vault.route_to_engine(&full_path) { Some(engine) => match engine.list(&relative_path).await { Ok(items) => { let response = ApiResponse::success(json!({"keys": items})); (StatusCode::OK, Json(response)).into_response() } Err(e) => { let response = ApiResponse::::error(format!("Failed to list: {}", e)); (StatusCode::BAD_REQUEST, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("No engine mounted at this path"); (StatusCode::NOT_FOUND, Json(response)).into_response() } }, None => { let response = ApiResponse::::error("Path not found"); (StatusCode::NOT_FOUND, Json(response)).into_response() } } }