#![forbid(unsafe_code)]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(
test,
allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing
)
)]
pub mod account;
pub mod audit;
mod config;
pub mod error;
pub mod flow;
pub mod http;
mod ids;
pub mod limits;
pub mod mail;
#[cfg(feature = "passkeys")]
#[cfg_attr(docsrs, doc(cfg(feature = "passkeys")))]
pub mod passkey;
pub mod password;
pub mod recovery;
pub mod seal;
pub mod session;
pub mod token;
pub mod totp;
pub use account::{Account, Email, Factors, Lockout, LockoutPolicy, PasswordOnly, Role};
pub use config::{Config, ConfigBuilder};
pub use error::Error;
pub use flow::step_up::StepUpFailures;
pub use ids::{CeremonyId, PasskeyId, SessionId, UserId};
pub use rand_core::CryptoRng;
#[cfg(test)]
mod proptests;
#[cfg(doctest)]
#[doc = include_str!("../README.md")]
struct ReadmeDoctests;
#[cfg(feature = "os-rng")]
#[cfg_attr(docsrs, doc(cfg(feature = "os-rng")))]
pub fn os_rng() -> Result<impl CryptoRng + Send + Sync + 'static, Error> {
use rand::SeedableRng;
rand::rngs::StdRng::try_from_rng(&mut rand::rngs::SysRng).map_err(|_| Error::Rng)
}
pub(crate) fn hex(bytes: &[u8]) -> String {
use std::fmt::Write;
bytes
.iter()
.fold(String::with_capacity(bytes.len() * 2), |mut out, b| {
let _ = write!(out, "{b:02x}");
out
})
}
#[cfg(test)]
pub(crate) fn test_rng() -> rand::rngs::StdRng {
use rand::SeedableRng;
use std::sync::atomic::{AtomicU64, Ordering};
static SEED: AtomicU64 = AtomicU64::new(1);
rand::rngs::StdRng::seed_from_u64(SEED.fetch_add(1, Ordering::Relaxed))
}
#[cfg(feature = "_fuzzing")]
#[doc(hidden)]
pub mod fuzzing {
use time::OffsetDateTime;
pub fn untrusted_inputs(data: &[u8]) {
let text = String::from_utf8_lossy(data);
let now = OffsetDateTime::UNIX_EPOCH;
let _ = crate::token::TokenHash::of(&text);
let _ = crate::token::TokenHash::of_foreign(&text);
let _ = crate::flow::email_link::EmailCodeHash::of(&text, &text);
let _ = crate::flow::email_link::EmailCodeHash::of(
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
&text,
);
let _ = crate::recovery::RecoveryCodeHash::of(&text);
if let Ok(secret) = crate::totp::TotpSecret::from_bytes(vec![0; 20]) {
let _ = crate::totp::verify(
&secret,
&text,
None,
now,
crate::totp::TotpParams::default(),
);
}
let _ = crate::totp::TotpSecret::from_base32(&text);
let _ = crate::password::PasswordHash::from_legacy_argon2(&text);
let _ = crate::account::Email::parse(&text);
let _ = crate::account::AccountKey::from_login(&text);
let _ = crate::password::check_policy(&text, crate::password::PasswordLength::default());
let _ = crate::http::find_cookie([text.as_ref()], "__Host-latchkey");
let _ = crate::http::client_ip(None, [text.as_ref()], true);
let _ = crate::http::CookieName::new(&text);
let _ = text.parse::<crate::session::SignInMethod>();
let _ = crate::flow::invite::optional_name(Some(text.to_string()), 100);
let key = crate::seal::DataKey::new(&[3; 32]);
let aad = crate::seal::Aad::app("fuzz");
let _ = key.open_bytes(&aad, data);
let _ = key.open_text(&aad, &text);
let _ = crate::password::PasswordHash::try_from(text.as_ref());
}
}