pub mod ceremony;
pub mod error;
pub mod session;
pub mod verify;
pub use ceremony::{
authentication_options_json, generate_challenge, registration_options_json,
verify_authentication, verify_registration, RegistrationOutcome,
};
pub use error::PasskeyError;
pub use session::{open_challenge, seal_challenge};
use crate::sql::{Auto, Pool};
use crate::Model;
#[derive(Model, Debug, Clone)]
#[rustango(table = "rustango_webauthn_credentials", managed = false)]
#[allow(dead_code)]
pub struct WebauthnCredential {
#[rustango(primary_key)]
pub id: Auto<i64>,
#[rustango(index)]
pub user_id: i64,
#[rustango(max_length = 255, unique)]
pub credential_id: String,
pub public_key: Vec<u8>,
#[rustango(default = "0")]
pub sign_count: i64,
#[rustango(max_length = 64, default = "''")]
pub label: String,
#[rustango(default = "now()")]
pub created_at: chrono::DateTime<chrono::Utc>,
}
pub async fn ensure_table(pool: &Pool) -> Result<(), sqlx::Error> {
use crate::core::Model as _;
let snapshot =
crate::migrate::SchemaSnapshot::from_models_forced(&[WebauthnCredential::SCHEMA]);
crate::migrate::apply_idempotent(pool, &snapshot).await?;
Ok(())
}
pub async fn for_user(
pool: &Pool,
user_id: i64,
) -> Result<Vec<WebauthnCredential>, crate::sql::ExecError> {
use crate::sql::FetcherPool as _;
WebauthnCredential::objects()
.filter("user_id", user_id)
.fetch(pool)
.await
}
pub async fn by_credential_id(
pool: &Pool,
credential_id: &str,
) -> Result<Option<WebauthnCredential>, crate::sql::ExecError> {
use crate::sql::FetcherPool as _;
Ok(WebauthnCredential::objects()
.filter("credential_id", credential_id.to_owned())
.fetch(pool)
.await?
.into_iter()
.next())
}
pub async fn register(
pool: &Pool,
user_id: i64,
credential_id: &str,
public_key: Vec<u8>,
sign_count: i64,
label: &str,
) -> Result<(), crate::sql::ExecError> {
let mut row = WebauthnCredential {
id: Auto::Unset,
user_id,
credential_id: credential_id.to_owned(),
public_key,
sign_count,
label: label.to_owned(),
created_at: chrono::Utc::now(),
};
row.insert_pool(pool).await?;
Ok(())
}
pub async fn update_sign_count(
pool: &Pool,
credential_id: &str,
new_count: i64,
) -> Result<(), crate::sql::ExecError> {
use crate::sql::UpdaterPool as _;
WebauthnCredential::objects()
.filter("credential_id", credential_id.to_owned())
.update()
.set("sign_count", new_count)
.execute_pool(pool)
.await?;
Ok(())
}