summaryrefslogtreecommitdiff
path: root/crates/chat-server/src/maintenance.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
commitc3b361c45ac8dd898d5c83a161abed5fc138b6c0 (patch)
tree3eeabb31508f98a6753a2492238581f888769b4a /crates/chat-server/src/maintenance.rs
parent3034705b6679bff1802c4180b7b4711b94fed7f9 (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/maintenance.rs')
-rw-r--r--crates/chat-server/src/maintenance.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/crates/chat-server/src/maintenance.rs b/crates/chat-server/src/maintenance.rs
new file mode 100644
index 0000000..eac689d
--- /dev/null
+++ b/crates/chat-server/src/maintenance.rs
@@ -0,0 +1,61 @@
+// Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai>
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+use crate::store::Store;
+use anyhow::{Context, Result, ensure};
+use std::fs::{File, OpenOptions};
+use std::io::Write;
+use std::net::{SocketAddr, TcpListener};
+use std::os::unix::fs::OpenOptionsExt;
+use std::path::Path;
+
+pub(crate) fn lock(directory: &Path) -> Result<File> {
+ let file = OpenOptions::new()
+ .read(true)
+ .write(true)
+ .create(true)
+ .truncate(false)
+ .mode(0o600)
+ .open(directory.join("server.lock"))?;
+ file.try_lock().context(
+ "Chat is already running. Stop it before starting another server or resetting the owner.",
+ )?;
+ Ok(file)
+}
+
+pub(crate) fn fingerprint(store: &Store) -> Result<()> {
+ let certificate = store.owner()?.context("No owner identity is registered")?;
+ writeln!(
+ std::io::stdout().lock(),
+ "{}",
+ stack_chat_crypto::public_identity(&certificate)?
+ )?;
+ Ok(())
+}
+
+pub(crate) fn reset(store: &mut Store, expected: &str, address: SocketAddr) -> Result<()> {
+ ensure!(
+ address.ip().is_loopback(),
+ "Reset must use the local chat address"
+ );
+ let _port =
+ TcpListener::bind(address).context("Stop the chat server before resetting its owner")?;
+ store.reset_owner(expected)?;
+ writeln!(
+ std::io::stdout().lock(),
+ "Owner registration and chat history cleared. Restart chat and use OWNER SETUP to create a new owner file. Existing backup archives were not changed."
+ )?;
+ Ok(())
+}