Something went wrong. Try again.
A lexicon-driven AppView for ATProto.
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465use axum::extract::FromRequestParts;use axum::http::request::Parts;
use crate::AppState;use crate::auth::middleware::Claims;use crate::error::AppError;
/// Axum extractor for admin auth. Validates the Bearer token via AIP OAuth/// (same as `Claims`), then checks if the returned DID exists in the `admins`/// table. If no admins exist yet, the first authenticated user is/// auto-bootstrapped as the initial admin.pub struct AdminAuth;
impl FromRequestParts<AppState> for AdminAuth { type Rejection = AppError;
async fn from_request_parts( parts: &mut Parts, state: &AppState, ) -> Result<Self, Self::Rejection> { // Validate the Bearer token via AIP userinfo (reuse Claims extractor). let claims = Claims::from_request_parts(parts, state).await?; let did = claims.did().to_string();
// Check whether the admins table is empty (auto-bootstrap case). let count: (i64,) = sqlx::query_as("SELECT COUNT(*) FROM admins") .fetch_one(&state.db) .await .map_err(|e| AppError::Internal(format!("admin count query failed: {e}")))?;
if count.0 == 0 { // First authenticated user becomes the initial admin. sqlx::query("INSERT INTO admins (did) VALUES ($1) ON CONFLICT DO NOTHING") .bind(&did) .execute(&state.db) .await .map_err(|e| AppError::Internal(format!("auto-bootstrap admin failed: {e}")))?;
tracing::info!(did = %did, "auto-bootstrapped first admin"); }
// Look up the DID in the admins table. let found: Option<(String,)> = sqlx::query_as("SELECT id::text FROM admins WHERE did = $1") .bind(&did) .fetch_optional(&state.db) .await .map_err(|e| AppError::Internal(format!("admin auth query failed: {e}")))?;
let Some((admin_id,)) = found else { return Err(AppError::Forbidden("not an admin".into())); };
// Update last_used_at in the background. let db = state.db.clone(); tokio::spawn(async move { let _ = sqlx::query("UPDATE admins SET last_used_at = NOW() WHERE id::text = $1") .bind(&admin_id) .execute(&db) .await; });
Ok(AdminAuth) }}