aboutsummaryrefslogtreecommitdiff
path: root/crates/chat-server/src/main.rs
diff options
context:
space:
mode:
authorDoan Luu Duc Tai <doan@luuduct.ai>2026-10-30 22:12:54 -0500
committerDoan Luu Duc Tai <doan@luuduct.ai>2026-10-30 22:12:54 -0500
commitbe16d00a8a4750028073e018ab2c58d54af192c4 (patch)
tree3eeabb31508f98a6753a2492238581f888769b4a /crates/chat-server/src/main.rs
parentb7374fe09306c495131cf3673addb76a1dcf017d (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.rs24
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(