eidetica/instance/new_user.rs
1//! Inputs for creating a user.
2//!
3//! [`NewUser`] is the request shape for "create a user with these settings",
4//! used in two places:
5//!
6//! - [`Instance::create_backend`](super::Instance::create_backend) and
7//! [`Instance::connect_or_create`](super::Instance::connect_or_create) — the
8//! initial user who bootstraps a fresh instance, automatically granted
9//! Admin on the system databases by virtue of being the first user.
10//! - [`InstanceAdmin::create_user`](crate::user::InstanceAdmin::create_user) —
11//! every subsequent user created by an existing admin.
12//!
13//! There is no separate "initial user" concept: the entity that creates the
14//! instance is just the first `NewUser`, and from that point on additional
15//! users are created through the admin path. This eliminates the prior
16//! hardcoded `admin/admin` bootstrap.
17
18/// Inputs needed to create a user account.
19///
20/// Use the [`passwordless`](Self::passwordless) constructor for embedded or
21/// single-user applications where login latency matters and the surrounding
22/// process is already trusted; use [`with_password`](Self::with_password) for
23/// multi-user deployments where the root key must be encrypted at rest.
24///
25/// The struct is marked `#[non_exhaustive]` so we can add fields
26/// (key algorithm, locale, initial roles, etc.) without a breaking API
27/// change. Construct it through the provided helpers rather than struct
28/// literal syntax.
29#[derive(Debug, Clone)]
30#[non_exhaustive]
31pub struct NewUser {
32 /// Login identifier for the user. Must be unique within the instance.
33 pub username: String,
34 /// Optional password. `None` produces a passwordless user whose root key
35 /// is stored unencrypted (fine for embedded apps where the host process
36 /// is the trust boundary); `Some(_)` produces an Argon2id-derived
37 /// encryption key under which the root signing key is AES-256-GCM
38 /// encrypted at rest.
39 pub password: Option<String>,
40}
41
42impl NewUser {
43 /// Create a passwordless user. The root signing key will be stored
44 /// unencrypted in the user's credentials.
45 pub fn passwordless(name: impl Into<String>) -> Self {
46 Self {
47 username: name.into(),
48 password: None,
49 }
50 }
51
52 /// Create a password-protected user. The root signing key will be
53 /// encrypted with an Argon2id-derived key at rest; the password is
54 /// required for every login.
55 pub fn with_password(name: impl Into<String>, password: impl Into<String>) -> Self {
56 Self {
57 username: name.into(),
58 password: Some(password.into()),
59 }
60 }
61}