use super::AppState;
use axum::{
extract::State,
http::StatusCode,
response::{IntoResponse, Json},
};
use serde_json::{json, Value};
const SECRET_POINTERS: &[&str] = &[
"/web/auth_token",
"/remote/telegram/token",
"/remote/whatsapp/account_sid",
"/remote/whatsapp/auth_token",
"/remote/whatsapp/signing_secret",
];
pub(super) async fn get_config(State(s): State<AppState>) -> impl IntoResponse {
let Some(cfg) = s.config.as_ref() else {
return (
StatusCode::OK,
Json(json!({ "config": null, "source": "none" })),
)
.into_response();
};
match serde_json::to_value(cfg.as_ref()) {
Ok(mut value) => {
redact(&mut value);
(
StatusCode::OK,
Json(json!({ "config": value, "source": "file" })),
)
.into_response()
}
Err(e) => {
tracing::warn!("config serialize failed: {e}");
(
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({ "error": "failed to serialize config" })),
)
.into_response()
}
}
}
pub(super) async fn get_version(State(s): State<AppState>) -> impl IntoResponse {
Json(json!({
"service": "lopi",
"version": env!("CARGO_PKG_VERSION"),
"uptime_secs": s.pool.stats().uptime_secs,
}))
}
fn redact(value: &mut Value) {
for ptr in SECRET_POINTERS {
if let Some(field) = value.pointer_mut(ptr) {
if !field.is_null() {
*field = Value::String("***".to_string());
}
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
mod tests {
use super::*;
#[test]
fn redact_blanks_present_secrets_only() {
let mut v = json!({
"web": { "auth_token": "supersecret", "port": 3000 },
"remote": {
"telegram": { "token": "tg-token", "chat_id": 42 },
"whatsapp": { "auth_token": null, "from": "whatsapp:+1" }
}
});
redact(&mut v);
assert_eq!(v["web"]["auth_token"], "***");
assert_eq!(v["web"]["port"], 3000);
assert_eq!(v["remote"]["telegram"]["token"], "***");
assert_eq!(v["remote"]["telegram"]["chat_id"], 42);
assert!(v["remote"]["whatsapp"]["auth_token"].is_null());
assert_eq!(v["remote"]["whatsapp"]["from"], "whatsapp:+1");
}
#[test]
fn redact_is_noop_when_fields_absent() {
let mut v = json!({ "web": { "port": 8080 } });
redact(&mut v);
assert_eq!(v["web"]["port"], 8080);
}
}