Skip to main content

AdminUser

Struct AdminUser 

Source
pub struct AdminUser {
    pub id: String,
    pub username: String,
    pub password_hash: String,
    pub status: String,
    pub totp_secret: Option<Vec<u8>>,
    pub totp_pending_secret: Option<Vec<u8>>,
    pub totp_last_step: Option<i64>,
    pub created_at: i64,
    pub updated_at: i64,
    pub last_login_at: Option<i64>,
}
Expand description

An operator of the web admin interface.

Not an ACME concept and never joined to one: an AdminUser is a person with a password, an accounts row is a client key. There is no profile column – an admin user sees every endpoint this process serves.

§Methods

  • create: persist a new operator, active
  • find_by_id / find_by_username: lookup (the latter is the login path)
  • list_all: every operator, oldest first
  • set_password_hash / set_status / mark_logged_in: in-place updates
  • set_totp_pending / confirm_totp / clear_totp / claim_totp_step: the second factor’s lifecycle, and RFC 6238 §5.2’s replay guard
  • delete: remove, cascading to the operator’s sessions and recovery codes
  • to_json: admin-facing rendering (never the password hash, never a secret)

Fields§

§id: String§username: String

Always lowercase: AdminUser::create normalizes before writing, so Alice and alice cannot become two logins that read as one.

§password_hash: String

The encoded KDF output – see crate::admin::password. Never rendered.

§status: String§totp_secret: Option<Vec<u8>>

Set once the owner has proven a code against a pending enrolment. None means no second factor is configured.

§totp_pending_secret: Option<Vec<u8>>

An enrolment begun but not yet confirmed. Not a usable second factor.

§totp_last_step: Option<i64>

The last TOTP time step accepted, so a code cannot be replayed inside its own window.

§created_at: i64§updated_at: i64§last_login_at: Option<i64>

Implementations§

Source§

impl AdminUser

Source

pub async fn create( username: &str, password_hash: &str, database: &Database, ) -> Result<AdminUser, Error>

Persists a new operator, active. username is lowercased and trimmed here rather than at the call sites, so every path – the CLI, a future API – stores the same thing.

password_hash is already encoded by crate::admin::password: this layer never sees a plaintext password and cannot hash one.

A duplicate username surfaces as the UNIQUE violation it is; the caller (admin::users::create_user) checks first and reports it in words.

Source

pub async fn find_by_id( id: &str, database: &Database, ) -> Result<Option<AdminUser>, Error>

Source

pub async fn find_by_username( username: &str, database: &Database, ) -> Result<Option<AdminUser>, Error>

The login path. Lowercases the argument for the same reason AdminUser::create does – a login typed Alice must find alice.

Source

pub async fn list_all(database: &Database) -> Result<Vec<AdminUser>, Error>

Every operator, oldest first – admin user list.

Source

pub async fn set_password_hash( &mut self, password_hash: &str, database: &Database, ) -> Result<(), Error>

Replaces the stored hash. Callers are responsible for invalidating the owner’s sessions – admin::users::set_password does, and a password change that left them alive would be a change in name only.

Source

pub async fn set_status( &mut self, status: &str, database: &Database, ) -> Result<(), Error>

Moves between active and disabled. A disabled operator cannot log in, and an existing session of theirs is refused on its next use – the session rows are left for the reaper rather than deleted here, so re-enabling is a single UPDATE either way.

Source

pub async fn set_totp_pending( &mut self, secret: &[u8], database: &Database, ) -> Result<(), Error>

Stores an enrolment the owner has not yet proven a code against.

Not a usable second factor: AdminUser::has_totp stays false until AdminUser::confirm_totp moves it across, which is what stops an abandoned enrolment from locking its own owner out.

Source

pub async fn confirm_totp(&mut self, database: &Database) -> Result<(), Error>

Promotes the pending secret to the real one.

One statement, deliberately: a half-applied enrolment would leave the operator believing they have a factor that nothing checks, or holding a pending secret alongside a live one. totp_last_step is cleared with them – the replay guard belongs to the secret it was recorded against.

A no-op when nothing is pending, so a double-submit cannot clear a live factor.

Source

pub async fn clear_totp(&mut self, database: &Database) -> Result<(), Error>

Removes the factor, any half-finished enrolment and the replay guard together. Callers drop the recovery codes too – a code that recovers access to a factor that no longer exists is a second password.

Source

pub async fn claim_totp_step( &mut self, step: i64, database: &Database, ) -> Result<bool, Error>

Records step as accepted, refusing one that is not strictly newer than the stored value – RFC 6238 §5.2’s replay guard.

The comparison lives in the WHERE clause rather than in Rust: a code observed in flight and resubmitted inside its own 30-second window must not be accepted twice, and with two requests racing it is rows_affected that decides which one was first. Same primitive as Nonce::verify.

Source

pub async fn mark_logged_in(&mut self, database: &Database) -> Result<(), Error>

Stamps last_login_at. Advisory only – nothing authorises on it.

Called when a login completes, which for an operator with a second factor is one request later than the password being accepted.

Source

pub async fn delete(id: &str, database: &Database) -> Result<bool, Error>

Removes the operator. Their sessions go with them via the schema’s ON DELETE CASCADE, which needs foreign_keys on – Database::connect and connect_in_memory both pin it. Returns whether a row existed.

Source

pub fn is_active(&self) -> bool

Whether this operator may log in and hold a session.

Source

pub fn has_totp(&self) -> bool

Whether a confirmed second factor is configured. A pending enrolment does not count – it has never been proven against a code.

Source

pub fn has_pending_totp(&self) -> bool

Whether an enrolment is half-finished: a secret was generated and shown, and no code has proven it yet.

Deliberately not folded into AdminUser::has_totp and deliberately not in AdminUser::to_json: the login path must treat this operator as having no factor, and the only surface that cares is the enrolment page deciding whether to offer “start over”.

Source

pub fn to_json(&self) -> Value

The admin-facing rendering. Never includes password_hash, nor either TOTP secret – only whether one is configured.

Trait Implementations§

Source§

impl Clone for AdminUser

Source§

fn clone(&self) -> AdminUser

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for AdminUser

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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<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