Development Documentation (main branch) - For stable release docs, see docs.rs/eidetica
Skip to main content

eidetica/user/
types.rs

1//! Core data types for the user system
2
3use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7use crate::{
8    auth::{
9        SigKey,
10        crypto::{PrivateKey, PublicKey},
11    },
12    entry::ID,
13};
14
15/// Credentials for unlocking a user's root signing key.
16///
17/// For password-protected users, contains the salt (for Argon2id key derivation)
18/// and the encrypted root key (AES-256-GCM). Decryption failure IS password
19/// verification — no separate password hash is needed.
20/// For passwordless users, contains the unencrypted root key directly.
21#[derive(Clone, Debug, Serialize, Deserialize)]
22pub struct UserCredentials {
23    /// Public key (available without decryption)
24    pub root_key_id: PublicKey,
25
26    /// Encrypted or unencrypted root private key
27    pub root_key: KeyStorage,
28
29    /// Salt for Argon2id key derivation (None for passwordless)
30    pub password_salt: Option<String>,
31}
32
33/// User information stored in _users database
34///
35/// Users are stored in a Table with auto-generated UUID primary keys.
36/// The username field is used for login and must be unique.
37#[derive(Clone, Debug, Serialize, Deserialize)]
38pub struct UserInfo {
39    /// Unique username (login identifier)
40    pub username: String,
41
42    /// ID of the user's private database
43    pub user_database_id: ID,
44
45    /// Credentials containing the user's root signing key
46    pub credentials: UserCredentials,
47
48    /// User account creation timestamp (Unix timestamp)
49    pub created_at: i64,
50
51    /// Account status
52    pub status: UserStatus,
53}
54
55/// User account status
56#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
57pub enum UserStatus {
58    Active,
59    Disabled,
60    Locked,
61}
62
63/// User profile stored in user's private database
64#[derive(Clone, Debug, Serialize, Deserialize)]
65pub struct UserProfile {
66    /// Username
67    pub username: String,
68
69    /// Display name
70    pub display_name: Option<String>,
71
72    /// Email or other contact info
73    pub contact_info: Option<String>,
74
75    /// User preferences
76    pub preferences: UserPreferences,
77}
78
79/// User-specific preferences
80#[derive(Clone, Debug, Serialize, Deserialize, Default)]
81pub struct UserPreferences {
82    /// Default sync tracked databases
83    pub default_sync_enabled: bool,
84
85    /// Other user-specific settings
86    pub properties: HashMap<String, String>,
87}
88
89/// How a user's private key is stored
90///
91/// Encrypted keys store AES-256-GCM ciphertext of a prefixed-string-encoded `PrivateKey`.
92/// Unencrypted keys store the `PrivateKey` directly (passwordless users only).
93#[derive(Clone, Debug, Serialize, Deserialize)]
94#[serde(tag = "type", rename_all = "lowercase")]
95pub enum KeyStorage {
96    /// Key is encrypted with a password-derived key (AES-256-GCM)
97    Encrypted {
98        /// Encryption algorithm identifier
99        algorithm: String,
100        /// Encrypted prefixed-string-encoded PrivateKey
101        ciphertext: Vec<u8>,
102        /// Encryption nonce/IV (12 bytes for AES-GCM)
103        nonce: Vec<u8>,
104    },
105    /// Key is stored unencrypted (passwordless users only)
106    Unencrypted {
107        /// PrivateKey stored directly — serde carries the signing algorithm tag
108        key: PrivateKey,
109    },
110}
111
112/// User's private key with database mappings
113///
114/// Keys can be either encrypted (for password-protected users) or
115/// unencrypted (for passwordless single-user mode).
116#[derive(Clone, Debug, Serialize, Deserialize)]
117pub struct UserKey {
118    /// Key identifier (the public key)
119    pub key_id: PublicKey,
120
121    /// Key storage (encrypted ciphertext or plaintext PrivateKey)
122    pub storage: KeyStorage,
123
124    /// Display name for this key
125    pub display_name: Option<String>,
126
127    /// When this key was created (Unix timestamp)
128    pub created_at: i64,
129
130    /// Last time this key was used (Unix timestamp)
131    pub last_used: Option<i64>,
132
133    /// Whether this is the user's default key, which has admin access on the user's DB
134    /// Only one key should be marked as default at a time
135    pub is_default: bool,
136
137    /// Database-specific SigKey mappings
138    /// Maps: Database ID → SigKey identity for that database
139    ///
140    /// `None` = default identity (pubkey derived from this key's `key_id`)
141    /// `Some(sigkey)` = non-default identity (global wildcard, name-based, delegation)
142    pub database_sigkeys: HashMap<ID, Option<SigKey>>,
143}
144
145/// A database tracked by a user.
146///
147/// Stored in the user's private database "databases" Table.
148/// Records which databases the user has added to their list, along with
149/// which key to use and sync preferences.
150#[derive(Clone, Debug, Serialize, Deserialize)]
151pub struct TrackedDatabase {
152    /// Database ID
153    pub database_id: ID,
154
155    /// Which user key to use for this database
156    pub key_id: PublicKey,
157
158    /// Sync preferences for this database
159    pub sync_settings: SyncSettings,
160}
161
162/// Synchronization settings for a database
163///
164/// Per-user-per-database sync configuration.
165/// Different users may have different sync preferences for the same database.
166///
167/// # Construction
168///
169/// Use factory methods for common configurations:
170/// - `SyncSettings::disabled()` — sync disabled (this is the `Default`)
171/// - `SyncSettings::enabled()` — sync enabled, no sync on commit
172/// - `SyncSettings::on_commit()` — sync enabled with sync on commit on every transaction
173///
174/// Chain `.with_interval()` to override the periodic sync interval:
175/// ```
176/// # use eidetica::user::types::SyncSettings;
177/// let settings = SyncSettings::enabled().with_interval(60);
178/// ```
179#[derive(Clone, Debug, Serialize, Deserialize)]
180pub struct SyncSettings {
181    /// Whether user wants to sync this database
182    pub sync_enabled: bool,
183
184    /// Sync on commit
185    /// Whether to sync after every commit
186    pub sync_on_commit: bool,
187
188    /// Sync interval in seconds (for periodic sync).
189    /// `None` uses the background sync default interval.
190    pub interval_seconds: Option<u64>,
191
192    /// Additional sync configuration
193    pub properties: HashMap<String, String>,
194}
195
196impl Default for SyncSettings {
197    fn default() -> Self {
198        Self::disabled()
199    }
200}
201
202impl SyncSettings {
203    /// Sync disabled. This is the `Default`.
204    pub fn disabled() -> Self {
205        Self {
206            sync_enabled: false,
207            sync_on_commit: false,
208            interval_seconds: None,
209            properties: HashMap::new(),
210        }
211    }
212
213    /// Sync enabled, no sync on commit.
214    pub fn enabled() -> Self {
215        Self {
216            sync_enabled: true,
217            ..Self::disabled()
218        }
219    }
220
221    /// Sync enabled with sync on commit on every transaction.
222    pub fn on_commit() -> Self {
223        Self {
224            sync_enabled: true,
225            sync_on_commit: true,
226            ..Self::disabled()
227        }
228    }
229
230    /// Set periodic sync interval in seconds.
231    pub fn with_interval(mut self, seconds: u64) -> Self {
232        self.interval_seconds = Some(seconds);
233        self
234    }
235}
236
237/// Database tracking information in _databases table
238#[derive(Clone, Debug, Serialize, Deserialize)]
239pub struct DatabaseTracking {
240    /// Database ID
241    pub database_id: ID,
242
243    /// Cached database name (for quick lookup)
244    pub name: Option<String>,
245
246    /// User UUIDs who have this database in their preferences
247    /// (stores internal UUIDs, not usernames)
248    pub users: Vec<String>,
249
250    /// Database creation time (Unix timestamp)
251    pub created_at: i64,
252
253    /// Last modification time (Unix timestamp)
254    pub last_modified: i64,
255
256    /// Additional metadata
257    pub metadata: HashMap<String, String>,
258}