security(dashboard): enforce admin authentication on all sensitive endpoints
This commit adds the missing auth::require_admin check to all analytics, system info, and configuration list endpoints. It also improves error logging in the usage summary handler to aid in troubleshooting 'Failed to load statistics' errors.
This commit is contained in:
+46
-2
@@ -71,8 +71,14 @@ impl UsagePeriodFilter {
|
||||
|
||||
pub(super) async fn handle_usage_summary(
|
||||
State(state): State<DashboardState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(filter): Query<UsagePeriodFilter>,
|
||||
) -> Json<ApiResponse<serde_json::Value>> {
|
||||
let (_session, _) = match super::auth::require_admin(&state, &headers).await {
|
||||
Ok((session, new_token)) => (session, new_token),
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let pool = &state.app_state.db_pool;
|
||||
let (period_clause, period_binds) = filter.to_sql();
|
||||
|
||||
@@ -133,7 +139,9 @@ pub(super) async fn handle_usage_summary(
|
||||
)
|
||||
.fetch_one(pool);
|
||||
|
||||
match tokio::join!(total_stats, today_stats, error_stats, avg_response) {
|
||||
let results = tokio::join!(total_stats, today_stats, error_stats, avg_response);
|
||||
|
||||
match results {
|
||||
(Ok(t), Ok(d), Ok(e), Ok(a)) => {
|
||||
let total_requests: i64 = t.get("total_requests");
|
||||
let total_tokens: i64 = t.get("total_tokens");
|
||||
@@ -168,14 +176,26 @@ pub(super) async fn handle_usage_summary(
|
||||
"total_cache_write_tokens": total_cache_write,
|
||||
})))
|
||||
}
|
||||
_ => Json(ApiResponse::error("Failed to fetch usage statistics".to_string())),
|
||||
(t_res, d_res, e_res, a_res) => {
|
||||
if let Err(e) = t_res { warn!("Total stats query failed: {}", e); }
|
||||
if let Err(e) = d_res { warn!("Today stats query failed: {}", e); }
|
||||
if let Err(e) = e_res { warn!("Error stats query failed: {}", e); }
|
||||
if let Err(e) = a_res { warn!("Avg response query failed: {}", e); }
|
||||
Json(ApiResponse::error("Failed to fetch usage statistics".to_string()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) async fn handle_time_series(
|
||||
State(state): State<DashboardState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(filter): Query<UsagePeriodFilter>,
|
||||
) -> Json<ApiResponse<serde_json::Value>> {
|
||||
let (_session, _) = match super::auth::require_admin(&state, &headers).await {
|
||||
Ok((session, new_token)) => (session, new_token),
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let pool = &state.app_state.db_pool;
|
||||
let (period_clause, period_binds) = filter.to_sql();
|
||||
let granularity = filter.granularity();
|
||||
@@ -248,8 +268,14 @@ pub(super) async fn handle_time_series(
|
||||
|
||||
pub(super) async fn handle_clients_usage(
|
||||
State(state): State<DashboardState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(filter): Query<UsagePeriodFilter>,
|
||||
) -> Json<ApiResponse<serde_json::Value>> {
|
||||
let (_session, _) = match super::auth::require_admin(&state, &headers).await {
|
||||
Ok((session, new_token)) => (session, new_token),
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let pool = &state.app_state.db_pool;
|
||||
let (period_clause, period_binds) = filter.to_sql();
|
||||
|
||||
@@ -308,8 +334,14 @@ pub(super) async fn handle_clients_usage(
|
||||
|
||||
pub(super) async fn handle_providers_usage(
|
||||
State(state): State<DashboardState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(filter): Query<UsagePeriodFilter>,
|
||||
) -> Json<ApiResponse<serde_json::Value>> {
|
||||
let (_session, _) = match super::auth::require_admin(&state, &headers).await {
|
||||
Ok((session, new_token)) => (session, new_token),
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let pool = &state.app_state.db_pool;
|
||||
let (period_clause, period_binds) = filter.to_sql();
|
||||
|
||||
@@ -370,8 +402,14 @@ pub(super) async fn handle_providers_usage(
|
||||
|
||||
pub(super) async fn handle_detailed_usage(
|
||||
State(state): State<DashboardState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(filter): Query<UsagePeriodFilter>,
|
||||
) -> Json<ApiResponse<serde_json::Value>> {
|
||||
let (_session, _) = match super::auth::require_admin(&state, &headers).await {
|
||||
Ok((session, new_token)) => (session, new_token),
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let pool = &state.app_state.db_pool;
|
||||
let (period_clause, period_binds) = filter.to_sql();
|
||||
|
||||
@@ -433,8 +471,14 @@ pub(super) async fn handle_detailed_usage(
|
||||
|
||||
pub(super) async fn handle_analytics_breakdown(
|
||||
State(state): State<DashboardState>,
|
||||
headers: axum::http::HeaderMap,
|
||||
Query(filter): Query<UsagePeriodFilter>,
|
||||
) -> Json<ApiResponse<serde_json::Value>> {
|
||||
let (_session, _) = match super::auth::require_admin(&state, &headers).await {
|
||||
Ok((session, new_token)) => (session, new_token),
|
||||
Err(e) => return e,
|
||||
};
|
||||
|
||||
let pool = &state.app_state.db_pool;
|
||||
let (period_clause, period_binds) = filter.to_sql();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user