pub struct AuthStore { /* private fields */ }Expand description
Database-backed authentication store.
Wraps a SQLite connection pool and provides methods for user management, API key authentication, Telegram linking, and audit logging.
Thread-safe: can be wrapped in Arc and shared across async tasks.
Implementations§
Source§impl AuthStore
impl AuthStore
Sourcepub fn from_pool(pool: SqlitePool) -> Self
pub fn from_pool(pool: SqlitePool) -> Self
Create an AuthStore from a shared pool.
The pool should already have migrations applied (via CoreDb).
Sourcepub async fn create_user(
&self,
email: Option<&str>,
display_name: Option<&str>,
role: Role,
) -> Result<User>
pub async fn create_user( &self, email: Option<&str>, display_name: Option<&str>, role: Role, ) -> Result<User>
Create a new user with a random UUID.
Both email and display_name are optional. If email is provided,
it must be unique across all users (enforced by the database).
Sourcepub async fn list_users(&self) -> Result<Vec<User>>
pub async fn list_users(&self) -> Result<Vec<User>>
List all users.
Sourcepub async fn update_user(
&self,
id: &str,
email: Option<&str>,
display_name: Option<&str>,
role: Option<Role>,
filesystem_enabled: Option<bool>,
) -> Result<()>
pub async fn update_user( &self, id: &str, email: Option<&str>, display_name: Option<&str>, role: Option<Role>, filesystem_enabled: Option<bool>, ) -> Result<()>
Update a user’s fields. Only non-None values are applied (COALESCE).
Pass role: Some(Role::Admin) to promote a user, or role: None to
leave the role unchanged.
Sourcepub async fn deactivate_user(&self, id: &str) -> Result<()>
pub async fn deactivate_user(&self, id: &str) -> Result<()>
Deactivate a user (soft-delete). Sets is_active = false.
Deactivated users cannot authenticate via API keys or Telegram. Their data is preserved — use this instead of hard-deleting.
Sourcepub async fn activate_user(&self, id: &str) -> Result<()>
pub async fn activate_user(&self, id: &str) -> Result<()>
Reactivate a previously deactivated user. Sets is_active = true.
Sourcepub async fn create_api_key(
&self,
user_id: &str,
label: Option<&str>,
) -> Result<ApiKeyCreated>
pub async fn create_api_key( &self, user_id: &str, label: Option<&str>, ) -> Result<ApiKeyCreated>
Create a new API key for a user. Returns the full key (shown only once).
Sourcepub async fn import_api_key(
&self,
user_id: &str,
plaintext_key: &str,
label: Option<&str>,
) -> Result<ApiKeyMeta>
pub async fn import_api_key( &self, user_id: &str, plaintext_key: &str, label: Option<&str>, ) -> Result<ApiKeyMeta>
Import an existing plaintext key as a user’s API key (for backward-compat bootstrap).
Sourcepub async fn authenticate_api_key(&self, key: &str) -> Result<Option<User>>
pub async fn authenticate_api_key(&self, key: &str) -> Result<Option<User>>
Authenticate a request by API key. Returns the user if valid.
Sourcepub async fn list_api_keys(&self, user_id: &str) -> Result<Vec<ApiKeyMeta>>
pub async fn list_api_keys(&self, user_id: &str) -> Result<Vec<ApiKeyMeta>>
List API keys for a user (metadata only, no hashes).
Sourcepub async fn revoke_api_key(&self, key_id: &str) -> Result<()>
pub async fn revoke_api_key(&self, key_id: &str) -> Result<()>
Revoke an API key by its database ID.
Revoked keys immediately fail authentication. The key record is preserved for audit purposes.
Sourcepub async fn link_telegram(
&self,
user_id: &str,
telegram_id: Option<i64>,
username: Option<&str>,
) -> Result<TelegramLink>
pub async fn link_telegram( &self, user_id: &str, telegram_id: Option<i64>, username: Option<&str>, ) -> Result<TelegramLink>
Link a Telegram account to a user.
Accepts either a telegram_id, a username, or both. At least one
must be provided. When only a username is given, the telegram_id is
back-filled automatically when the user first messages the bot (see
authenticate_telegram).
Each user can have at most one Telegram link. Calling this method
replaces any existing link for the same user_id, telegram_id, or
username to maintain uniqueness across all three dimensions.
Sourcepub async fn backfill_telegram_id(
&self,
username: &str,
telegram_id: i64,
) -> Result<()>
pub async fn backfill_telegram_id( &self, username: &str, telegram_id: i64, ) -> Result<()>
Back-fill the telegram_id on an existing username-only link.
Called by the bot when a user with a matching username sends their first message and the link was created without a numeric ID.
Sourcepub async fn unlink_telegram(&self, telegram_id: i64) -> Result<()>
pub async fn unlink_telegram(&self, telegram_id: i64) -> Result<()>
Unlink a Telegram account.
Sourcepub async fn authenticate_telegram(
&self,
telegram_id: i64,
username: Option<&str>,
) -> Result<Option<User>>
pub async fn authenticate_telegram( &self, telegram_id: i64, username: Option<&str>, ) -> Result<Option<User>>
Authenticate a Telegram user by their numeric ID, falling back to username.
Resolution order:
- Look up by
telegram_id(exact match). - If no match and
usernameis provided, look up byusername. - If matched by username and the link has no
telegram_idyet, the numeric ID is back-filled so subsequent lookups succeed by ID alone.
Returns None if the user is not linked or is deactivated.
Sourcepub async fn get_telegram_link_for_user(
&self,
user_id: &str,
) -> Result<Option<TelegramLink>>
pub async fn get_telegram_link_for_user( &self, user_id: &str, ) -> Result<Option<TelegramLink>>
Get the Telegram link for a specific user.
Sourcepub async fn unlink_telegram_by_user(&self, user_id: &str) -> Result<()>
pub async fn unlink_telegram_by_user(&self, user_id: &str) -> Result<()>
Unlink a Telegram account by user ID.
Sourcepub async fn list_telegram_links(&self) -> Result<Vec<TelegramLink>>
pub async fn list_telegram_links(&self) -> Result<Vec<TelegramLink>>
List all Telegram links.
Sourcepub async fn log_event(
&self,
user_id: Option<&str>,
event_type: &str,
detail: Option<&str>,
ip_address: Option<&str>,
) -> Result<()>
pub async fn log_event( &self, user_id: Option<&str>, event_type: &str, detail: Option<&str>, ip_address: Option<&str>, ) -> Result<()>
Log an authentication event to the audit table.
Use user_id: None when the user could not be identified (e.g. a
failed auth attempt with an unknown key).
Sourcepub async fn recent_audit(&self, limit: usize) -> Result<Vec<AuditEntry>>
pub async fn recent_audit(&self, limit: usize) -> Result<Vec<AuditEntry>>
Get recent audit log entries, most recent first.
Sourcepub async fn bootstrap_admin(
&self,
existing_api_key: Option<&str>,
) -> Result<Option<(User, String)>>
pub async fn bootstrap_admin( &self, existing_api_key: Option<&str>, ) -> Result<Option<(User, String)>>
Bootstrap the admin user on first startup.
If no users exist, creates an admin user. If existing_api_key is provided,
imports it as the admin’s key (backward compat). Otherwise generates a new key.
Returns the admin user and the API key (plaintext, for logging).
Auto Trait Implementations§
impl Freeze for AuthStore
impl !RefUnwindSafe for AuthStore
impl Send for AuthStore
impl Sync for AuthStore
impl Unpin for AuthStore
impl UnsafeUnpin for AuthStore
impl !UnwindSafe for AuthStore
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