mod http;
pub mod validation;
pub mod errors;
pub mod types;
pub use errors::StackureError;
pub use types::{MagicLinkResponse, User, VerifyError, VerifyResult};
pub async fn send_magic_link(
email: &str,
app_id: Option<&str>,
) -> Result<MagicLinkResponse, StackureError> {
http::send_magic_link(email, app_id).await
}
pub async fn logout(cookies: Option<&str>) -> Result<(), StackureError> {
http::logout(cookies).await
}
pub async fn verify(app_id: &str, cookies: Option<&str>, roles: Option<&[&str]>) -> VerifyResult {
match http::validate_session(app_id, cookies).await {
Ok(session) => {
if !session.authenticated || session.user.is_none() {
return VerifyResult {
authenticated: false,
user: None,
error: Some(VerifyError {
code: 401,
message: "Valid authentication required".into(),
sign_in_url: session.sign_in_url,
}),
};
}
let user = session.user.unwrap();
if let Some(required) = roles {
if !required.is_empty()
&& !required
.iter()
.any(|r| user.user_roles.iter().any(|ur| ur == r))
{
let role_list = required.join(", ");
return VerifyResult {
authenticated: false,
user: Some(user),
error: Some(VerifyError {
code: 403,
message: format!("Requires one of: {role_list}"),
sign_in_url: None,
}),
};
}
}
VerifyResult {
authenticated: true,
user: Some(user),
error: None,
}
}
Err(e) => {
eprintln!("stackure: verification error: {e}");
VerifyResult {
authenticated: false,
user: None,
error: Some(VerifyError {
code: 500,
message: "Authentication verification failed".into(),
sign_in_url: None,
}),
}
}
}
}