eidetica/instance/new_account.rs
1//! Inputs for creating a user.
2//!
3//! [`NewAccount`] 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_account`](crate::account::InstanceAdmin::create_account) —
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 `NewAccount`, 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/// All accounts store an authenticated encrypted credential bundle. Passwords
21/// may be any string, including empty, with no length or complexity restrictions.
22/// [`passwordless`](Self::passwordless) is sugar for an empty password, not a
23/// different storage mode. Empty-string wrapping provides no meaningful
24/// confidentiality against a bundle holder.
25///
26/// The struct is marked `#[non_exhaustive]` so we can add fields
27/// (key algorithm, locale, initial roles, etc.) without a breaking API
28/// change. Construct it through the provided helpers rather than struct
29/// literal syntax.
30#[derive(Debug, Clone)]
31#[non_exhaustive]
32pub struct NewAccount {
33 /// Login identifier for the user. Must be unique within the instance.
34 pub username: String,
35 /// Password used to encrypt the local credential bundle. Every string,
36 /// including empty, uses the same Argon2id and AES-256-GCM path.
37 pub password: String,
38}
39
40impl NewAccount {
41 /// Create an empty-password account using the ordinary encrypted format.
42 /// This provides no meaningful confidentiality against a bundle holder.
43 pub fn passwordless(name: impl Into<String>) -> Self {
44 Self::with_password(name, "")
45 }
46
47 /// Create an account with any password string, including empty.
48 /// The password is required for login; signing uses already unlocked keys.
49 pub fn with_password(name: impl Into<String>, password: impl Into<String>) -> Self {
50 Self {
51 username: name.into(),
52 password: password.into(),
53 }
54 }
55}