acme_proxy_admin/webadmin/handlers/
misc.rs1use axum::Json;
8use axum::extract::State;
9use serde::Deserialize;
10use serde_json::{Value, json};
11use std::time::Duration;
12
13use crate::admin;
14use crate::webadmin::AdminState;
15use crate::webadmin::error::AdminError;
16use crate::webadmin::handlers::Caller;
17use crate::webadmin::session::{Authenticated, AuthenticatedWrite};
18use acme_proxy_store::nonce::Nonce;
19
20#[derive(Debug, Deserialize, Default)]
22pub struct CleanupRequest {
23 #[serde(rename = "ttlSeconds")]
25 pub ttl_seconds: Option<u64>,
26}
27
28pub async fn get_nonces(
33 State(state): State<AdminState>,
34 _auth: Authenticated,
35) -> Result<Json<Value>, AdminError> {
36 let count = Nonce::count(&state.database).await?;
37 Ok(Json(admin::render_nonce_stats_json(
38 count,
39 state.config.nonce.ttl_seconds,
40 )))
41}
42
43pub async fn cleanup_nonces(
45 State(state): State<AdminState>,
46 AuthenticatedWrite(auth): AuthenticatedWrite,
47 request_context: acme_proxy_core::audit::RequestContext,
48 body: Option<Json<CleanupRequest>>,
49) -> Result<Json<Value>, AdminError> {
50 let seconds = body
51 .and_then(|Json(body)| body.ttl_seconds)
52 .unwrap_or(state.config.nonce.ttl_seconds);
53
54 let removed =
55 apply_cleanup_nonces(&state, &Caller::api(&auth, &request_context), seconds).await?;
56 Ok(Json(json!({ "removed": removed })))
57}
58
59pub(crate) async fn apply_cleanup_nonces(
61 state: &AdminState,
62 caller: &Caller<'_>,
63 seconds: u64,
64) -> Result<u64, AdminError> {
65 let removed =
66 admin::cleanup_nonces(Duration::from_secs(seconds), state.database.clone()).await?;
67 if removed > 0 {
70 state
71 .record_admin_action(caller.request, caller.username(), |actor, client| {
72 acme_proxy_jobs::auditor::admin::nonce_cleanup_completed(actor, client, removed)
73 })
74 .await;
75 }
76 tracing::info!(event = "admin_nonces_cleaned",
77 outcome = "success",
78 surface = caller.surface,
79 rows_removed = removed,
80 ttl_seconds = seconds,
81 username = %caller.username());
82 Ok(removed)
83}
84
85pub async fn list_profiles(State(state): State<AdminState>, _auth: Authenticated) -> Json<Value> {
91 Json(Value::Array(profile_rows(&state)))
92}
93
94pub(crate) fn profile_rows(state: &AdminState) -> Vec<Value> {
100 let mut names: Vec<&String> = state.profiles.keys().collect();
101 names.sort();
102
103 names
104 .into_iter()
105 .filter_map(|name| state.profiles.get(name))
106 .map(|profile| profile_row(profile))
107 .collect()
108}
109
110pub(crate) fn profile_row(profile: &acme_proxy_protocol::profile::Profile) -> Value {
122 admin::render_profile_json(&admin::ProfileSummary::mounted(profile))
123}