pub mod middleware;
pub mod password;
pub mod routes;
use std::sync::{Arc, OnceLock};
use koan_core::auth::{Claims, Role};
use koan_core::db::pool::Pool;
use koan_core::db::queries::auth as auth_queries;
pub(crate) type Keypair = (Arc<Vec<u8>>, Arc<Vec<u8>>);
static SIGNING: OnceLock<Keypair> = OnceLock::new();
pub(crate) fn set_signing_keys(private: Arc<Vec<u8>>, public: Arc<Vec<u8>>) {
let _ = SIGNING.set((private, public));
}
pub(crate) fn signing_keys() -> Result<&'static Keypair, koan_core::auth::AuthError> {
if let Some(keys) = SIGNING.get() {
return Ok(keys);
}
let (private, public) = koan_core::auth::load_or_generate_keypair()?;
Ok(SIGNING.get_or_init(|| (Arc::new(private), Arc::new(public))))
}
#[derive(Debug, Clone)]
pub struct AuthUser {
pub user_id: i64,
pub username: String,
pub role: Role,
}
pub(crate) async fn current_user(pool: &Arc<Pool>, claims: Claims) -> Option<AuthUser> {
let pool = pool.clone();
tokio::task::spawn_blocking(move || {
let db = pool.get().ok()?;
let user = auth_queries::get_user_by_id(&db.conn, claims.sub).ok()??;
(user.username == claims.username).then_some(AuthUser {
user_id: user.id,
username: user.username,
role: user.role,
})
})
.await
.ok()
.flatten()
}
impl AuthUser {
pub fn anonymous_admin() -> Self {
Self {
user_id: 0,
username: koan_core::auth::ANONYMOUS.into(),
role: Role::Admin,
}
}
}