Skip to main content

AuthStore

Struct AuthStore 

Source
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

Source

pub fn from_pool(pool: SqlitePool) -> Self

Create an AuthStore from a shared pool.

The pool should already have migrations applied (via CoreDb).

Source

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).

Source

pub async fn get_user(&self, id: &str) -> Result<Option<User>>

Get a user by ID.

Source

pub async fn list_users(&self) -> Result<Vec<User>>

List all users.

Source

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.

Source

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.

Source

pub async fn activate_user(&self, id: &str) -> Result<()>

Reactivate a previously deactivated user. Sets is_active = true.

Source

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).

Source

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).

Source

pub async fn authenticate_api_key(&self, key: &str) -> Result<Option<User>>

Authenticate a request by API key. Returns the user if valid.

Source

pub async fn list_api_keys(&self, user_id: &str) -> Result<Vec<ApiKeyMeta>>

List API keys for a user (metadata only, no hashes).

Source

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.

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.

Source

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.

Unlink a Telegram account.

Source

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:

  1. Look up by telegram_id (exact match).
  2. If no match and username is provided, look up by username.
  3. If matched by username and the link has no telegram_id yet, the numeric ID is back-filled so subsequent lookups succeed by ID alone.

Returns None if the user is not linked or is deactivated.

Get the Telegram link for a specific user.

Unlink a Telegram account by user ID.

List all Telegram links.

Source

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).

Source

pub async fn recent_audit(&self, limit: usize) -> Result<Vec<AuditEntry>>

Get recent audit log entries, most recent first.

Source

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).

Source

pub async fn has_users(&self) -> Result<bool>

Check if any users exist in the database.

Used by the gateway to decide whether to enforce authentication: when false (fresh install), all requests are allowed.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more