feat(auth): admin role with cookie-only RequireAdmin extractor (0.37.0)
Adds an `is_admin` flag on users plus the substrate every later PR in the admin feature builds on: - migration 0018 adds the column with default false - `repo::user::bootstrap_admin` creates or promotes the user named by `ADMIN_USERNAME` at startup, hashing `ADMIN_PASSWORD` only when the row is new — never overwriting an existing hash, so an operator can rotate the admin password via the UI without env-var conflict - `CurrentSessionUser` extractor accepts only the session cookie; `RequireAdmin` composes over it and additionally requires `user.is_admin`. Bearer tokens are intentionally excluded so an admin's bot token never inherits admin authority (privilege-escalation surface that bites every "API keys reuse user perms" auth design) - demotion is instant: `RequireAdmin` re-reads the user row each request `/api/v1/auth/me` now exposes `is_admin`; no other response embeds `User`, so no privacy fanout to audit.
This commit is contained in:
@@ -60,6 +60,13 @@ pub async fn build(config: Config) -> anyhow::Result<AppHandle> {
|
||||
.await?;
|
||||
sqlx::migrate!("./migrations").run(&db).await?;
|
||||
|
||||
if let Some((username, password)) = config.admin_bootstrap.as_ref() {
|
||||
repo::user::bootstrap_admin(&db, username, password)
|
||||
.await
|
||||
.context("bootstrap_admin from ADMIN_USERNAME/ADMIN_PASSWORD env")?;
|
||||
tracing::info!(admin_username = %username, "admin bootstrap ensured");
|
||||
}
|
||||
|
||||
let storage: Arc<dyn Storage> = Arc::new(LocalStorage::new(config.storage_dir.clone()));
|
||||
|
||||
let daemon = if config.crawler.daemon_enabled {
|
||||
|
||||
Reference in New Issue
Block a user