pub struct Db { /* private fields */ }Expand description
Handle to the allowthem database.
Wraps a SqlitePool and guarantees that migrations have been applied.
All query code receives a &Db and calls db.pool() to access the pool.
Implementations§
Source§impl Db
impl Db
Sourcepub async fn create_api_token(
&self,
user_id: UserId,
name: &str,
expires_at: Option<DateTime<Utc>>,
) -> Result<(String, ApiTokenInfo), AuthError>
pub async fn create_api_token( &self, user_id: UserId, name: &str, expires_at: Option<DateTime<Utc>>, ) -> Result<(String, ApiTokenInfo), AuthError>
Generate and store a new API token for the user.
Returns the raw token string (shown once, never stored) and
ApiTokenInfo metadata. The caller must present the raw token to the
user — it cannot be retrieved again.
Sourcepub async fn validate_api_token(
&self,
raw_token: &str,
) -> Result<Option<UserId>, AuthError>
pub async fn validate_api_token( &self, raw_token: &str, ) -> Result<Option<UserId>, AuthError>
Validate a raw bearer token.
Hashes the token and queries by hash. Tokens with a past expires_at
are excluded. Returns Some(UserId) if valid, None otherwise.
Sourcepub async fn list_api_tokens(
&self,
user_id: UserId,
) -> Result<Vec<ApiTokenInfo>, AuthError>
pub async fn list_api_tokens( &self, user_id: UserId, ) -> Result<Vec<ApiTokenInfo>, AuthError>
List all API tokens for a user (metadata only, no hashes).
Sourcepub async fn delete_api_token(&self, id: ApiTokenId) -> Result<bool, AuthError>
pub async fn delete_api_token(&self, id: ApiTokenId) -> Result<bool, AuthError>
Delete a single API token by ID.
Returns true if a token was found and deleted.
Source§impl Db
impl Db
Sourcepub async fn log_audit(
&self,
event_type: AuditEvent,
user_id: Option<&UserId>,
target_id: Option<&str>,
ip_address: Option<&str>,
user_agent: Option<&str>,
detail: Option<&str>,
) -> Result<(), AuthError>
pub async fn log_audit( &self, event_type: AuditEvent, user_id: Option<&UserId>, target_id: Option<&str>, ip_address: Option<&str>, user_agent: Option<&str>, detail: Option<&str>, ) -> Result<(), AuthError>
Record an audit event.
user_id may be None for events where no authenticated user is
involved (e.g. a failed login attempt against an unknown email).
Sourcepub async fn get_audit_log(
&self,
user_id: Option<&UserId>,
limit: u32,
offset: u32,
) -> Result<Vec<AuditEntry>, AuthError>
pub async fn get_audit_log( &self, user_id: Option<&UserId>, limit: u32, offset: u32, ) -> Result<Vec<AuditEntry>, AuthError>
Retrieve audit log entries, optionally filtered by user.
Results are ordered by created_at descending (newest first).
Sourcepub async fn get_audit_log_by_event(
&self,
event_type: AuditEvent,
limit: u32,
offset: u32,
) -> Result<Vec<AuditEntry>, AuthError>
pub async fn get_audit_log_by_event( &self, event_type: AuditEvent, limit: u32, offset: u32, ) -> Result<Vec<AuditEntry>, AuthError>
Retrieve audit log entries filtered by event type.
Results are ordered by created_at descending (newest first).
Source§impl Db
impl Db
Sourcepub async fn new(pool: SqlitePool) -> Result<Self, AuthError>
pub async fn new(pool: SqlitePool) -> Result<Self, AuthError>
Create a Db from an integrator-provided pool and run migrations.
This is the embedded-mode constructor. The caller is responsible for
configuring PRAGMA foreign_keys = ON on their pool’s
SqliteConnectOptions — this constructor cannot set per-connection
pragmas on a pool it did not create.
Migrations are idempotent: safe to call on a pool that has already
been migrated. SQLx tracks applied migrations in _sqlx_migrations
and CREATE TABLE IF NOT EXISTS in the SQL is a no-op on existing tables.
ignore_missing is set so that migrations from the integrating application
already recorded in _sqlx_migrations do not cause an error — those are
the integrator’s own migrations, not allowthem’s.
Sourcepub async fn connect(url: &str) -> Result<Self, AuthError>
pub async fn connect(url: &str) -> Result<Self, AuthError>
Create a pool from a URL, apply pragmas, run migrations, and return a Db.
Configures the pool with:
PRAGMA foreign_keys = ON— FK constraint enforcementPRAGMA journal_mode = WAL— concurrent reads (silently ignored for:memory:)PRAGMA busy_timeout = 5000— wait under contention instead of immediate SQLITE_BUSY
Sourcepub fn pool(&self) -> &SqlitePool
pub fn pool(&self) -> &SqlitePool
Return a reference to the underlying connection pool.
Source§impl Db
impl Db
Sourcepub async fn create_oauth_state(
&self,
provider: &str,
redirect_uri: &str,
pkce_verifier: &str,
post_login_redirect: Option<&str>,
linking_user_id: Option<UserId>,
) -> Result<String, AuthError>
pub async fn create_oauth_state( &self, provider: &str, redirect_uri: &str, pkce_verifier: &str, post_login_redirect: Option<&str>, linking_user_id: Option<UserId>, ) -> Result<String, AuthError>
Create an OAuth state record. Returns the raw state value (for the authorize URL).
linking_user_id is Some when initiating the account-linking flow (the user is
already authenticated and wants to add a provider). It is None for the standard
login/register flow.
Sourcepub async fn validate_oauth_state(
&self,
raw_state: &str,
) -> Result<Option<OAuthStateInfo>, AuthError>
pub async fn validate_oauth_state( &self, raw_state: &str, ) -> Result<Option<OAuthStateInfo>, AuthError>
Validate and consume an OAuth state. Returns the stored info or None if invalid/expired. Atomically deletes to prevent reuse.
Sourcepub async fn create_oauth_user(
&self,
email: Email,
provider: &str,
provider_user_id: &str,
) -> Result<User, AuthError>
pub async fn create_oauth_user( &self, email: Email, provider: &str, provider_user_id: &str, ) -> Result<User, AuthError>
Create a user via OAuth – no password.
Creates the user (password_hash = NULL) and the oauth_accounts row in a single transaction. Returns the created User.
Sourcepub async fn link_oauth_account(
&self,
user_id: UserId,
provider: &str,
provider_user_id: &str,
email: &str,
) -> Result<(), AuthError>
pub async fn link_oauth_account( &self, user_id: UserId, provider: &str, provider_user_id: &str, email: &str, ) -> Result<(), AuthError>
Link an OAuth identity to an existing user.
Sourcepub async fn find_user_by_oauth(
&self,
provider: &str,
provider_user_id: &str,
) -> Result<Option<User>, AuthError>
pub async fn find_user_by_oauth( &self, provider: &str, provider_user_id: &str, ) -> Result<Option<User>, AuthError>
Find an allowthem user by provider + provider_user_id.
Sourcepub async fn get_user_oauth_accounts(
&self,
user_id: UserId,
) -> Result<Vec<OAuthAccountInfo>, AuthError>
pub async fn get_user_oauth_accounts( &self, user_id: UserId, ) -> Result<Vec<OAuthAccountInfo>, AuthError>
List all OAuth accounts linked to a user.
Source§impl Db
impl Db
Sourcepub async fn create_password_reset(
&self,
email: &Email,
) -> Result<Option<String>, AuthError>
pub async fn create_password_reset( &self, email: &Email, ) -> Result<Option<String>, AuthError>
Create a password reset token for the user with the given email.
Looks up the user by email. If found, inserts a new reset token record
(hashed) and returns the raw token for inclusion in the reset URL.
Returns None if no user exists for that email (caller should not
reveal this to prevent email enumeration).
Sourcepub async fn validate_reset_token(
&self,
raw_token: &str,
) -> Result<Option<(ResetTokenId, UserId)>, AuthError>
pub async fn validate_reset_token( &self, raw_token: &str, ) -> Result<Option<(ResetTokenId, UserId)>, AuthError>
Validate a raw reset token.
Hashes the token and looks it up in the database. Returns the associated
UserId and token record ID if the token exists, has not expired, and has
not been used. Returns None if the token is invalid or expired.
Sourcepub async fn execute_reset(
&self,
raw_token: &str,
new_password: &str,
) -> Result<bool, AuthError>
pub async fn execute_reset( &self, raw_token: &str, new_password: &str, ) -> Result<bool, AuthError>
Execute a password reset: update the password and mark the token used.
Runs atomically in a transaction:
- Validate the token (not expired, not used).
- Mark the token as used (
used_at = now). - Hash the new password.
- Update the user’s
password_hashandupdated_at.
Returns Ok(true) on success, Ok(false) if the token was invalid.
Sourcepub async fn send_password_reset(
&self,
email: &Email,
base_url: &str,
sender: &dyn EmailSender,
) -> Result<(), AuthError>
pub async fn send_password_reset( &self, email: &Email, base_url: &str, sender: &dyn EmailSender, ) -> Result<(), AuthError>
Send a password reset email for the given address.
Calls create_password_reset to generate a token. If the email exists,
constructs a reset URL using base_url and delivers it via sender.
If the email does not exist, returns Ok(()) silently (no enumeration).
Source§impl Db
impl Db
Sourcepub async fn create_permission(
&self,
name: &PermissionName,
description: Option<&str>,
) -> Result<Permission, AuthError>
pub async fn create_permission( &self, name: &PermissionName, description: Option<&str>, ) -> Result<Permission, AuthError>
Create a permission with a unique name and optional description.
Sourcepub async fn get_permission(
&self,
id: &PermissionId,
) -> Result<Option<Permission>, AuthError>
pub async fn get_permission( &self, id: &PermissionId, ) -> Result<Option<Permission>, AuthError>
Get a permission by ID. Returns None if not found.
Sourcepub async fn get_permission_by_name(
&self,
name: &PermissionName,
) -> Result<Option<Permission>, AuthError>
pub async fn get_permission_by_name( &self, name: &PermissionName, ) -> Result<Option<Permission>, AuthError>
Get a permission by name. Returns None if not found.
Sourcepub async fn list_permissions(&self) -> Result<Vec<Permission>, AuthError>
pub async fn list_permissions(&self) -> Result<Vec<Permission>, AuthError>
List all permissions, ordered by creation time.
Sourcepub async fn delete_permission(
&self,
id: &PermissionId,
) -> Result<bool, AuthError>
pub async fn delete_permission( &self, id: &PermissionId, ) -> Result<bool, AuthError>
Delete a permission by ID. Returns true if a row was deleted, false if not found.
Cascades to allowthem_role_permissions and allowthem_user_permissions.
Sourcepub async fn assign_permission_to_role(
&self,
role_id: &RoleId,
permission_id: &PermissionId,
) -> Result<(), AuthError>
pub async fn assign_permission_to_role( &self, role_id: &RoleId, permission_id: &PermissionId, ) -> Result<(), AuthError>
Assign a permission to a role. Idempotent — silently succeeds if already assigned.
Sourcepub async fn assign_permission_to_user(
&self,
user_id: &UserId,
permission_id: &PermissionId,
) -> Result<(), AuthError>
pub async fn assign_permission_to_user( &self, user_id: &UserId, permission_id: &PermissionId, ) -> Result<(), AuthError>
Assign a permission directly to a user. Idempotent — silently succeeds if already assigned.
Sourcepub async fn unassign_permission_from_role(
&self,
role_id: &RoleId,
permission_id: &PermissionId,
) -> Result<bool, AuthError>
pub async fn unassign_permission_from_role( &self, role_id: &RoleId, permission_id: &PermissionId, ) -> Result<bool, AuthError>
Unassign a permission from a role. Returns true if removed, false if not found.
Sourcepub async fn unassign_permission_from_user(
&self,
user_id: &UserId,
permission_id: &PermissionId,
) -> Result<bool, AuthError>
pub async fn unassign_permission_from_user( &self, user_id: &UserId, permission_id: &PermissionId, ) -> Result<bool, AuthError>
Unassign a permission from a user. Returns true if removed, false if not found.
Sourcepub async fn has_permission(
&self,
user_id: &UserId,
perm_name: &PermissionName,
) -> Result<bool, AuthError>
pub async fn has_permission( &self, user_id: &UserId, perm_name: &PermissionName, ) -> Result<bool, AuthError>
Check whether a user has a permission by name via either path: direct user assignment or any of the user’s roles.
Sourcepub async fn get_user_permissions(
&self,
user_id: &UserId,
) -> Result<Vec<Permission>, AuthError>
pub async fn get_user_permissions( &self, user_id: &UserId, ) -> Result<Vec<Permission>, AuthError>
Return all permissions for a user — both directly assigned and via roles — deduplicated and ordered by name.
Source§impl Db
impl Db
Sourcepub async fn create_role(
&self,
name: &RoleName,
description: Option<&str>,
) -> Result<Role, AuthError>
pub async fn create_role( &self, name: &RoleName, description: Option<&str>, ) -> Result<Role, AuthError>
Create a role with a unique name and optional description.
Sourcepub async fn get_role(&self, id: &RoleId) -> Result<Option<Role>, AuthError>
pub async fn get_role(&self, id: &RoleId) -> Result<Option<Role>, AuthError>
Get a role by ID. Returns None if not found.
Sourcepub async fn get_role_by_name(
&self,
name: &RoleName,
) -> Result<Option<Role>, AuthError>
pub async fn get_role_by_name( &self, name: &RoleName, ) -> Result<Option<Role>, AuthError>
Get a role by name. Returns None if not found.
Sourcepub async fn list_roles(&self) -> Result<Vec<Role>, AuthError>
pub async fn list_roles(&self) -> Result<Vec<Role>, AuthError>
List all roles, ordered by creation time.
Sourcepub async fn delete_role(&self, id: &RoleId) -> Result<bool, AuthError>
pub async fn delete_role(&self, id: &RoleId) -> Result<bool, AuthError>
Delete a role by ID. Returns true if a row was deleted, false if not found.
Cascades to allowthem_user_roles and allowthem_role_permissions.
Sourcepub async fn assign_role(
&self,
user_id: &UserId,
role_id: &RoleId,
) -> Result<(), AuthError>
pub async fn assign_role( &self, user_id: &UserId, role_id: &RoleId, ) -> Result<(), AuthError>
Assign a role to a user. Silently succeeds if already assigned (idempotent).
Sourcepub async fn unassign_role(
&self,
user_id: &UserId,
role_id: &RoleId,
) -> Result<bool, AuthError>
pub async fn unassign_role( &self, user_id: &UserId, role_id: &RoleId, ) -> Result<bool, AuthError>
Unassign a role from a user. Returns true if removed, false if the assignment
did not exist.
Source§impl Db
impl Db
Sourcepub async fn create_session(
&self,
user_id: UserId,
token_hash: TokenHash,
ip_address: Option<&str>,
user_agent: Option<&str>,
expires_at: DateTime<Utc>,
) -> Result<Session, AuthError>
pub async fn create_session( &self, user_id: UserId, token_hash: TokenHash, ip_address: Option<&str>, user_agent: Option<&str>, expires_at: DateTime<Utc>, ) -> Result<Session, AuthError>
Insert a new session record and return it.
The caller is responsible for hashing the token before calling this function
via hash_token(). The raw token must never be passed here.
Sourcepub async fn lookup_session(
&self,
token: &SessionToken,
) -> Result<Option<Session>, AuthError>
pub async fn lookup_session( &self, token: &SessionToken, ) -> Result<Option<Session>, AuthError>
Look up a session by raw token.
Hashes the token internally and queries by hash. Expired sessions
(where expires_at is in the past) are excluded. Returns None
when no matching active session is found.
Sourcepub async fn validate_session(
&self,
token: &SessionToken,
ttl: Duration,
) -> Result<Option<Session>, AuthError>
pub async fn validate_session( &self, token: &SessionToken, ttl: Duration, ) -> Result<Option<Session>, AuthError>
Validate a session token and optionally extend it.
Fetches the active session by token hash. If the session is past the
halfway point of its TTL (now > expires_at - ttl/2), it is renewed
by setting expires_at = now + ttl. Returns the session with the
updated expiry, or None if no active session was found.
Sourcepub async fn delete_session(
&self,
token: &SessionToken,
) -> Result<bool, AuthError>
pub async fn delete_session( &self, token: &SessionToken, ) -> Result<bool, AuthError>
Delete a single session by raw token.
Returns true if a session was found and deleted, false if no
matching session existed.
Source§impl Db
impl Db
Sourcepub async fn create_mfa_secret(
&self,
user_id: UserId,
mfa_key: &[u8; 32],
) -> Result<String, AuthError>
pub async fn create_mfa_secret( &self, user_id: UserId, mfa_key: &[u8; 32], ) -> Result<String, AuthError>
Generate a new TOTP secret for a user and store it (encrypted, not yet enabled).
Returns the plaintext base32-encoded secret for display to the user
during the setup flow. The caller must present this secret (or a QR code
derived from it) and require the user to confirm with a valid code
before calling enable_mfa.
Fails with MfaAlreadyEnabled if the user already has an enabled MFA secret.
If a non-enabled secret exists (abandoned setup attempt), it is replaced.
Sourcepub async fn enable_mfa(
&self,
user_id: UserId,
code: &str,
mfa_key: &[u8; 32],
) -> Result<Vec<String>, AuthError>
pub async fn enable_mfa( &self, user_id: UserId, code: &str, mfa_key: &[u8; 32], ) -> Result<Vec<String>, AuthError>
Enable MFA for a user after verifying a TOTP code.
Decrypts the stored secret, validates the provided code against it,
and if valid, sets enabled = 1 and inserts 10 hashed recovery codes.
Returns the plaintext recovery codes (this is the only time they are visible).
Runs in a transaction to ensure MFA is never enabled without recovery codes.
Sourcepub async fn verify_totp(
&self,
user_id: UserId,
code: &str,
mfa_key: &[u8; 32],
) -> Result<bool, AuthError>
pub async fn verify_totp( &self, user_id: UserId, code: &str, mfa_key: &[u8; 32], ) -> Result<bool, AuthError>
Validate a TOTP code against a user’s enabled MFA secret.
Returns Ok(true) if the code is valid, Ok(false) if invalid.
Returns Err(MfaNotEnabled) if the user has no enabled MFA.
Sourcepub async fn has_mfa_enabled(&self, user_id: UserId) -> Result<bool, AuthError>
pub async fn has_mfa_enabled(&self, user_id: UserId) -> Result<bool, AuthError>
Check whether a user has MFA enabled.
Sourcepub async fn disable_mfa(&self, user_id: UserId) -> Result<(), AuthError>
pub async fn disable_mfa(&self, user_id: UserId) -> Result<(), AuthError>
Disable MFA for a user. Deletes the secret and all recovery codes.
Uses a transaction to ensure both deletes are atomic.
Sourcepub async fn verify_recovery_code(
&self,
user_id: UserId,
code: &str,
) -> Result<bool, AuthError>
pub async fn verify_recovery_code( &self, user_id: UserId, code: &str, ) -> Result<bool, AuthError>
Verify a recovery code. If valid, marks it as used (one-time use).
Uses atomic UPDATE ... RETURNING to prevent race conditions.
Returns Ok(true) if the code was valid and consumed,
Ok(false) if no matching unused code was found.
Sourcepub async fn remaining_recovery_codes(
&self,
user_id: UserId,
) -> Result<i64, AuthError>
pub async fn remaining_recovery_codes( &self, user_id: UserId, ) -> Result<i64, AuthError>
Count remaining unused recovery codes for a user.
Sourcepub async fn regenerate_recovery_codes(
&self,
user_id: UserId,
) -> Result<Vec<String>, AuthError>
pub async fn regenerate_recovery_codes( &self, user_id: UserId, ) -> Result<Vec<String>, AuthError>
Replace all recovery codes with a fresh set of 10.
Deletes all existing codes (used and unused) and inserts 10 new ones. Returns the plaintext codes. Runs in a transaction.
Sourcepub async fn create_mfa_challenge(
&self,
user_id: UserId,
) -> Result<String, AuthError>
pub async fn create_mfa_challenge( &self, user_id: UserId, ) -> Result<String, AuthError>
Create a short-lived MFA challenge token after password verification.
The integrator calls this when a user with MFA enabled passes password verification. Returns the raw token string to send to the client. The client presents this token along with a TOTP code to complete login. Challenge tokens expire after 5 minutes.
Sourcepub async fn validate_mfa_challenge(
&self,
raw_token: &str,
) -> Result<Option<UserId>, AuthError>
pub async fn validate_mfa_challenge( &self, raw_token: &str, ) -> Result<Option<UserId>, AuthError>
Validate an MFA challenge token without consuming it.
Returns Some(user_id) if the token is valid and not expired,
None otherwise. Does not consume the token so the user can retry
if they mistype the TOTP code.
Source§impl Db
impl Db
Sourcepub async fn create_user(
&self,
email: Email,
password: &str,
username: Option<Username>,
) -> Result<User, AuthError>
pub async fn create_user( &self, email: Email, password: &str, username: Option<Username>, ) -> Result<User, AuthError>
Create a user with email, plaintext password, and optional username.
Hashes the password with Argon2id (via password::hash_password).
Returns the created User (without password_hash in the returned struct).
Sourcepub async fn get_user(&self, id: UserId) -> Result<User, AuthError>
pub async fn get_user(&self, id: UserId) -> Result<User, AuthError>
Look up a user by ID. Returns User with password_hash = None.
Sourcepub async fn get_user_by_email(&self, email: &Email) -> Result<User, AuthError>
pub async fn get_user_by_email(&self, email: &Email) -> Result<User, AuthError>
Look up a user by email. Returns User with password_hash = None.
Sourcepub async fn get_user_by_username(
&self,
username: &Username,
) -> Result<User, AuthError>
pub async fn get_user_by_username( &self, username: &Username, ) -> Result<User, AuthError>
Look up a user by username. Returns User with password_hash = None.
Sourcepub async fn find_for_login(&self, identifier: &str) -> Result<User, AuthError>
pub async fn find_for_login(&self, identifier: &str) -> Result<User, AuthError>
Look up a user by email OR username for login.
Returns User WITH password_hash populated. The caller is responsible
for calling verify_password() to check the password.
Sourcepub async fn update_user_email(
&self,
id: UserId,
email: Email,
) -> Result<(), AuthError>
pub async fn update_user_email( &self, id: UserId, email: Email, ) -> Result<(), AuthError>
Update a user’s email. Also updates updated_at.
Sourcepub async fn update_user_username(
&self,
id: UserId,
username: Option<Username>,
) -> Result<(), AuthError>
pub async fn update_user_username( &self, id: UserId, username: Option<Username>, ) -> Result<(), AuthError>
Update a user’s username (set or clear). Also updates updated_at.
Sourcepub async fn update_user_active(
&self,
id: UserId,
is_active: bool,
) -> Result<(), AuthError>
pub async fn update_user_active( &self, id: UserId, is_active: bool, ) -> Result<(), AuthError>
Update a user’s is_active flag. Also updates updated_at.
Sourcepub async fn delete_user(&self, id: UserId) -> Result<(), AuthError>
pub async fn delete_user(&self, id: UserId) -> Result<(), AuthError>
Delete a user by ID. Cascades to sessions, user_roles, user_permissions.
Auto Trait Implementations§
impl Freeze for Db
impl !RefUnwindSafe for Db
impl Send for Db
impl Sync for Db
impl Unpin for Db
impl UnsafeUnpin for Db
impl !UnwindSafe for Db
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more