diff options
| author | Doan Luu Duc Tai <doan@luuduct.ai> | 2026-10-30 22:12:54 -0500 |
|---|---|---|
| committer | Doan Luu Duc Tai <doan@luuduct.ai> | 2026-10-30 22:12:54 -0500 |
| commit | be16d00a8a4750028073e018ab2c58d54af192c4 (patch) | |
| tree | 3eeabb31508f98a6753a2492238581f888769b4a /crates/chat-server/src/main.rs | |
| parent | b7374fe09306c495131cf3673addb76a1dcf017d (diff) | |
Refine chat controls and add explicit owner recovery reset
Simplify the ASCII interface, expose owner setup, and load any selected number of messages using bounded history batches. Add backend-only owner reset with a matching public fingerprint and stopped-service guards, and document the loss of old history and key continuity.
Diffstat (limited to 'crates/chat-server/src/main.rs')
| -rw-r--r-- | crates/chat-server/src/main.rs | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/crates/chat-server/src/main.rs b/crates/chat-server/src/main.rs index 6c7f4e1..c17a7f6 100644 --- a/crates/chat-server/src/main.rs +++ b/crates/chat-server/src/main.rs @@ -16,6 +16,7 @@ #![doc = "Local experimental chat server with ciphertext-only durable storage."] mod http; +mod maintenance; mod service; mod store; @@ -33,8 +34,16 @@ struct Arguments { root: PathBuf, #[arg(long, default_value = "127.0.0.1:9080")] bind: SocketAddr, - #[arg(long)] + #[arg(long, conflicts_with_all = ["reset_owner", "owner_fingerprint", "snapshot"])] init: bool, + #[arg(long, value_name = "FINGERPRINT", conflicts_with_all = ["owner_fingerprint", "snapshot"], help = "Permanently clear the matching owner registration and all chat history after key loss")] + reset_owner: Option<String>, + #[arg( + long, + conflicts_with = "snapshot", + help = "Print the registered owner's public fingerprint" + )] + owner_fingerprint: bool, #[arg(long)] snapshot: Option<PathBuf>, } @@ -76,11 +85,22 @@ async fn run(arguments: Arguments) -> Result<()> { std::fs::create_dir_all(&data)?; std::fs::set_permissions(&data, std::os::unix::fs::PermissionsExt::from_mode(0o700))?; let database = data.join("chat.sqlite"); - let store = store::Store::open(&database)?; + let _server_lock = if arguments.snapshot.is_none() && !arguments.owner_fingerprint { + Some(maintenance::lock(&data)?) + } else { + None + }; + let mut store = store::Store::open(&database)?; std::fs::set_permissions( &database, std::os::unix::fs::PermissionsExt::from_mode(0o600), )?; + if arguments.owner_fingerprint { + return maintenance::fingerprint(&store); + } + if let Some(expected) = arguments.reset_owner { + return maintenance::reset(&mut store, &expected, arguments.bind); + } if let Some(destination) = arguments.snapshot { store.snapshot(&destination)?; std::fs::set_permissions( |
