Skip to main content

Operator

Struct Operator 

Source
pub struct Operator {
    pub login_limiter: Limiter,
    pub step_up_limiter: Limiter,
    pub passkey_limiter: Limiter,
    pub ceremonies: Ceremonies,
    /* private fields */
}

Fields§

§login_limiter: Limiter

Wrong passwords per client address at login (kernel spec §3.2).

§step_up_limiter: Limiter

Wrong passwords per client address at step-up, a budget of its own (3b decision 10): a login flood from a shared address does not stop a signed-in owner stepping up, nor step-up guesses lock out login.

§passkey_limiter: Limiter

Passkey logins begun per client address (plan 3c decision 8): a budget of its own, untouched by wrong passwords.

§ceremonies: Ceremonies

The passkey ceremonies begun and not yet finished (plan 3c decision 5).

Implementations§

Source§

impl Operator

Source

pub fn open(path: &Path) -> Result<Self>

Open the kernel’s tables in hennery.db (shared with the host registry and the sessions store).

Source

pub fn open_in_memory() -> Result<Self>

Source

pub fn owner_id(&self) -> &str

The owner’s id. The owner exists from the first start, set up or not (is_set_up).

Source

pub fn is_set_up(&self) -> Result<bool>

Whether setup has run: the owner has a password and a public_url.

Source

pub fn ping(&self) -> Result<()>

Whether the database answers a query (/readyz).

Source

pub fn public_url(&self) -> Option<PublicUrl>

Source

pub fn issue_setup_token(&self, now: i64) -> Result<Option<String>>

A fresh setup token (64 hex characters), valid for SETUP_TOKEN_TTL_SECS, replacing any earlier one. None once there is an owner.

Source

pub fn announce_setup( &self, dir: &Path, base_url: &str, now: i64, ) -> Result<Option<SetupLink>>

Before setup: issue a fresh setup token and write its link, <base_url>/setup#<token>, to dir/setup-url (kernel spec §3.1). The file is created 0600 under a temporary name and renamed into place, so an existing setup-url (even a symlink) is replaced, never written through. Once set up: remove a stale setup-url and return None.

The setup link for the admin socket’s setup-url (kernel spec §4.2): the one last announced while its token is live, else a fresh one, announced as announce_setup does (the old token dies). None once set up.

Source

pub fn set_up( &self, token: &str, password: &str, public_url: &str, now: i64, ) -> Result<SetupOutcome>

Set the owner up with password and store public_url (kernel spec §3.1), if token is the live setup token, keeping the default hat’s name. See set_up_naming_hat.

Source

pub fn set_up_naming_hat( &self, token: &str, password: &str, public_url: &str, hat_name: Option<&str>, now: i64, ) -> Result<SetupOutcome>

Set the owner up with password and store public_url (kernel spec §3.1), if token is the live setup token, and name the default hat hat_name if one is given (plan 5a decision 1: the hat exists from the first start). The token is used up only once the owner is committed. Hashes the password: call it on a blocking thread. It takes no check_password slot: only the token’s holder gets as far as the hash, and the setup lock serialises it.

Source

pub fn verify_password(&self, password: &str) -> Result<Option<String>>

Whether password is the owner’s: the PHC string it verified against, or None. Before setup it is checked against a dummy hash, so the answer takes as long either way. A session opened on the strength of it passes the PHC to open_session, so a reset landing in between wins (3b-ii decision 11). Blocking: prefer check_password.

Source

pub async fn check_password( self: &Arc<Self>, password: String, ) -> Result<Option<String>>

verify_password on a blocking thread, at most MAX_CONCURRENT_HASHES at once; others wait their turn. The slot moves into the blocking closure: a caller that goes away (a client disconnect, a timeout) cannot free it while its verify still runs.

Source

pub fn verifications(&self) -> u64

How many password checks have run: every login attempt that is not rate limited runs exactly one (kernel spec §3.2’s constant-time failure path), which tests pin with this.

Source

pub async fn reset_password( self: &Arc<Self>, password: String, now: i64, ) -> Result<Reset>

Replace the owner’s password (the admin socket’s reset, kernel spec §4.2) and end every signed-in session, so their streams end too. The hash runs on a blocking thread and takes a check_password slot like any other, so a reset cannot add a third Argon2 run to a login flood. The limiters are cleared: the operator proved local access. It fails, changing nothing, unless it replaced exactly one password (3b-ii’s O9): an owner with none (a passkey-only owner, in 3c) has nothing to reset. Every passkey is removed and every passkey ceremony begun before it ends, a finish re-checking under the lock in any case (plan 3c decision 2, amended by its review’s A1): a passkey added with a stolen session must not survive the recovery. With no change-password route, every password change costs the passkeys.

Source

pub fn reset_public_url(&self, input: &str) -> Result<Reset>

Replace public_url (the admin socket’s recovery when the collector moved, 3b decision 4): the stored row and the origin every browser request is checked against, which is cached here. Every signed-in session ends: they were opened at the old origin, and the new one signs in afresh. Passkeys are bound to the host name, the RP id (kernel spec §3.2): when it changes they stop working, and are removed; a move to another port or scheme keeps them (plan 3c decision 9). Every passkey ceremony begun before it ends too, a finish re-checking under the lock in any case.

Source

pub fn change_public_url( &self, input: &str, contact: Option<Option<&str>>, caller: Option<(&str, i64)>, ) -> Result<PublicUrlChange>

What reset_public_url does, the one way public_url changes after setup: the admin socket’s reset and PATCH /api/settings (plan 4d-B4 decision 1) both call it.

  • With contact, the push contact is set too (Some(None) clears it), in the same transaction: a body that names both changes both or neither. Both are checked before anything is written; either one refused is Invalid, nothing changed.
  • With caller, the session that asked and the time it asked: the transaction’s first statement re-checks that session, live and stepped up, as a passkey registration’s write does (plan 3c A2; 4d-B4’s review, A1). One ended or stepped down since the request’s checks (a password reset, a revoke, a slow body) changes nothing.
Source

pub fn contact(&self) -> Result<Option<String>>

The owner’s push contact (kernel spec §6): an e-mail address, or None when they gave none and the VAPID token names public_url.

Source

pub fn set_contact(&self, contact: Option<&str>) -> Result<Result<(), String>>

Set the owner’s push contact, or clear it with None (plan 10a decision 7). Err with the reason, and nothing stored, for one that is not a plain e-mail address.

Source§

impl Operator

Source

pub fn open_session( &self, user_agent: &str, verified: &str, now: i64, ) -> Result<Option<String>>

Open a session for the owner and return its token, the cookie’s value. Only the token’s hash is stored. The password was just checked, so the session starts stepped up. verified is the PHC string that check verified against (verify_password): the session is opened only while it is still the owner’s, so a login whose check raced a password reset gets no session (None), like one before setup, when the owner has no password.

Source

pub fn authenticate( &self, token: &str, now: i64, ) -> Result<Option<Authenticated>>

The live session token names, if any. Its expiry slides to SESSION_TTL_SECS from now, at most every SESSION_SLIDE_SECS.

Source

pub fn step_up(&self, session_id: &str, now: i64) -> Result<bool>

Record a fresh password check on a session (kernel spec §3.4). Whether the session still exists.

Source

pub fn sessions(&self, now: i64) -> Result<Vec<AuthSession>>

Every live session, most recently used first.

Source

pub fn revoke_session(&self, session_id: &str, now: i64) -> Result<bool>

End a live session, and the push subscriptions it made (plan 10a decision 4): a device signed out, or revoked as lost, gets no more notifications. Whether there was one: an expired session is not listed by sessions, so it is not there to revoke either.

Source

pub fn session_ends(&self) -> Receiver<u64>

Changes whenever a session ends (revoke_session, and so logout, and the resets).

Source

pub fn session_expires_at( &self, session_id: &str, now: i64, ) -> Result<Option<i64>>

When the live session session_id expires, without sliding it; None once it is gone or expired.

Source

pub fn authenticate_cookies( &self, headers: &HeaderMap, now: i64, ) -> Result<Option<(String, Authenticated)>>

The first of the request’s session cookies (session_tokens) that authenticates, with its token; None when none does. Like authenticate, it slides the session it finds.

Source§

impl Operator

Source

pub fn start_passkey_registration( &self, session_id: &str, label: &str, now: i64, ) -> Result<Start>

Begin registering a passkey labelled label for the signed-in session session_id (decision 7: the route requires step-up). The owner’s passkeys are excluded, so an authenticator that holds one says so rather than making a second.

Source

pub fn finish_passkey_registration( &self, session_id: &str, ceremony_id: &str, credential: &Value, now: i64, ) -> Result<Result<PasskeyRecord, Refused>>

Finish the registration ceremony_id names, begun by session_id, with the browser’s credential (RegisterPublicKeyCredential as JSON), and store the passkey.

Source

pub fn passkeys(&self) -> Result<Vec<PasskeyRecord>>

The owner’s passkeys, oldest first.

Source

pub fn remove_passkey(&self, id: &str) -> Result<bool>

Remove the passkey id (the route requires step-up, kernel spec §3.4). Whether there was one. The password stays, so a login method always remains (decision 2).

Source

pub fn start_passkey_login(&self, now: i64) -> Result<Start>

Begin signing in with a passkey (decision 8).

Source

pub fn finish_passkey_login( &self, ceremony_id: &str, credential: &Value, user_agent: &str, now: i64, ) -> Result<Result<String, Refused>>

Finish the login ceremony_id names with the browser’s credential (PublicKeyCredential as JSON), and open a session: its token, the cookie’s value. The session starts stepped up, as a password login’s does. The passkey’s counter moves on and the session opens in one transaction, and only while the passkey is still stored: one removed since the ceremony began opens nothing.

Source

pub fn start_passkey_step_up(&self, session_id: &str, now: i64) -> Result<Start>

Begin stepping the session session_id up with a passkey (kernel spec §3.4, decision 8).

Source

pub fn finish_passkey_step_up( &self, session_id: &str, ceremony_id: &str, credential: &Value, now: i64, ) -> Result<Result<bool, Refused>>

Finish the step-up ceremony_id names, begun by session_id, and record it on the session, in one transaction with the passkey’s counter. Ok(false) when the session has ended meanwhile.

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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 = !

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

fn try_from(value: U) -> Result<T, !>

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