summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDoan Luu Duc Tai <doan@luuduct.ai>2026-10-31 10:12:51 -0500
committerDoan Luu Duc Tai <doan@luuduct.ai>2026-10-31 10:12:51 -0500
commitef61fc5aca6eca613a055c507a060b70bd537a37 (patch)
tree09a382d4af80dc0f504a6b4b6662fcc93c5a30f4
parentb7b163a4d34f486663e72950625ad03fbf022f73 (diff)
Remove retired chat placeholder and stale deployment documentation
-rw-r--r--README.txt2
-rw-r--r--docs/CHAT-APPLICATION.txt9
-rw-r--r--docs/CHAT-DESIGN.txt123
-rw-r--r--docs/CHAT-OPENSSL-MIGRATION.txt2
-rw-r--r--docs/CHAT-PRODUCTION.txt2
-rw-r--r--docs/GIT-HISTORY.txt7
-rw-r--r--docs/OPERATIONS.txt16
-rw-r--r--infra/Caddyfile2
-rw-r--r--infra/Caddyfile.local2
-rw-r--r--src/images.rs2
-rw-r--r--src/render.rs18
-rw-r--r--web/message/index.html53
12 files changed, 30 insertions, 208 deletions
diff --git a/README.txt b/README.txt
index 811ddc8..2ff1cf6 100644
--- a/README.txt
+++ b/README.txt
@@ -61,7 +61,7 @@ DEVELOPMENT AND PRODUCTION
Build and test on the development machine. Deploy prebuilt release
archives. The production host needs Podman, Git, and GnuPG, but no Rust
- toolchain, Cargo, Compose, or Docker daemon.
+ toolchain or Cargo.
CHECKS AND LICENSES
diff --git a/docs/CHAT-APPLICATION.txt b/docs/CHAT-APPLICATION.txt
index 28c576b..27ab61f 100644
--- a/docs/CHAT-APPLICATION.txt
+++ b/docs/CHAT-APPLICATION.txt
@@ -342,9 +342,8 @@ BACKUP, EXPORT, AND RESTORE
INTERFACE AND SITE STYLE
- The interface follows web/styles.css and the previous www/message.html and
- www/form.css from the parent of e373f15, the commit that removed the original
- Message Me form. It reuses the red ASCII logo, 80-column desktop width,
+ The interface follows web/styles.css, using the red ASCII logo,
+ 80-column desktop width,
black/white light and dark themes, blue links, green prompts/actions, ASCII
form frames, and bracketed controls. Licensing links retain the main site's
amber and muted green accents. The LibreJS badge stays yellow with its
@@ -439,5 +438,5 @@ LICENSES, SOURCE, AND VERIFICATION
curl, restrictive export permissions, and full encrypted recovery with saved
images and no build directories inside the recovered installation.
Native tests cover authorization, challenge reuse, expiry, locked sessions,
- quotas, idempotency, and SQLite snapshot recovery. See CHAT-DESIGN.txt and
- CHAT-OPENSSL-MIGRATION.txt for the design and historical backend review.
+ quotas, idempotency, and SQLite snapshot recovery. The implemented design and
+ limits are documented here. CHAT-OPENSSL-MIGRATION.txt records the backend review.
diff --git a/docs/CHAT-DESIGN.txt b/docs/CHAT-DESIGN.txt
deleted file mode 100644
index fa2ad1b..0000000
--- a/docs/CHAT-DESIGN.txt
+++ /dev/null
@@ -1,123 +0,0 @@
-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/>.
-
-
-PRIVATE CHAT DESIGN AND LIMITATIONS
-
- Status: experimental implementation on feature/private-chat.
- CHAT-APPLICATION.txt records the implemented formats, behavior, commands,
- tests, and current limitations. This document preserves the original design.
- CHAT-PRODUCTION.txt records the later packaged deployment path.
-
-USER EXPERIENCE
-
- Entry offers CREATE NEW CHAT and OPEN CHAT FILE. Creation asks for a display
- name and password, generates a dedicated identity locally, and downloads one
- protected file. The user must reopen that file before sending a first message.
- Returning users select the file locally and unlock it with its password.
- Usernames are labels; cryptographic identities determine access.
-
- Show authenticated total, sent, and received message counts. Let the user
- select N recent messages, including zero, and page backwards for older ones.
- Sending never requires an updated identity file. Scope is text only between
- each visitor and Doan, with no public directory, attachments, or group chats.
-
- Intended host: https://chat.doan.luuduct.ai/ with API under /api/ on the same
- origin. It is not configured or deployed yet. The feature branch adds Message
- Me links below the name in the home-page box and after Services in navigation.
-
-CRYPTOGRAPHY AND FILES
-
- Fixed encryption: RFC 9980 ML-KEM-1024 + X448 with OpenPGP v6 keys.
- Test signing profile: ML-DSA-87 + Ed448. Dedicated application identities must
- remain separate from Doan's canonical RSA identity. Advise users not to reuse
- chat identities elsewhere; exported keys cannot be technically restricted to
- this application alone. Future authentication signatures must bind to the
- application, origin, conversation, operation, fresh nonce, and expiry.
-
- The intended chat file contains versioned recovery and identity data, server
- identity, and a pinned owner public-key fingerprint. Its exact protected file
- format is not finalized. The compatibility probe protects OpenPGP secret-key
- material; it does not implement the proposed complete chat-file envelope.
- Private keys and passwords must never be uploaded to the server or placed
- in a URL, log, analytics event, crash report, or application browser storage.
-
- Both participants need access to their own stored conversation. The browser
- signs and encrypts each message for both participants. The plaintext payload
- binds the conversation, sender, unique message ID, and protocol version.
- Display names can travel inside encrypted conversation details.
-
-STATE AND LIMITS
-
- No intentional persistent browser chat state: no cookies, localStorage,
- sessionStorage, IndexedDB, service workers, analytics, or third-party requests.
- Keep keys, passwords, session credentials, and loaded history in memory only.
- Serve chat content with Cache-Control: no-store. Reload, close, and leave
- require the file and password again. Clear references and zero mutable secret
- buffers where possible; JavaScript strings and browser/OS copies are not
- reliably erasable. Test page restoration and back/forward navigation.
-
- The downloaded identity file is the intentional persistent client artifact.
- Browsers and operating systems may retain memory, swap, crash dumps, download
- records, or restored pages. The application cannot promise literally zero
- traces. The current browser probe checks only its own limited test behavior.
-
- The VPS necessarily retains ciphertext, public-key associations, message IDs,
- ordering, counts, and authentication state. Connection addresses, timing, and
- ciphertext sizes are visible while serving requests. Avoid retaining these
- in application/access logs. Storage and encrypted backups require consistent
- database snapshots and a tested recovery procedure before actual chat use.
-
- The private file is a credential. A lost file/password has no username-based
- recovery. A copied unlocked identity enables impersonation and historical
- decryption. Rotation can protect future use but cannot undo historical
- ciphertext or key copies. Static OpenPGP does not automatically provide
- forward secrecy. Compromise of a shared owner key can affect every
- conversation encrypted to that key.
-
- The browser trusts served code, including WASM and generated JavaScript.
- A compromised server, dependency, extension, browser, or OS may expose keys
- or plaintext. A pinned key does not defeat a malicious application update
- or solve first-visit trust. A separate origin limits ordinary cross-origin
- access, not shared-host compromise or every cross-site attack.
-
-LIBREJS AND LICENSING
-
- First-party code is AGPL-3.0-or-later. Third-party licenses and notices remain
- accurate. Required legal comments are the exception to the no-comments rule.
- Supply machine-readable JS licensing and corresponding Rust/WASM/JS source.
- Test actual LibreJS recognition, generated bindings, workers, and WASM before
- displaying GNU LibreJS-compliant. The compatibility harness makes no such
- claim and is not a public chat application.
-
- Intended badge: yellow, GNU LibreJS-compliant, linked to
- https://www.gnu.org/software/librejs/ . Hover and keyboard focus explain:
-
- LibreJS compliance concerns software freedom, not a guarantee of privacy
- or security. Review the source code, dependencies, and scripts delivered
- to your browser. Server-delivered code can change between visits; free
- software can still track users or behave maliciously.
-
-REMAINING RELIABILITY WORK
-
- The OpenSSL compatibility experiment is in CHAT-OPENSSL-MIGRATION.txt.
- It supersedes the original backend gate, not the remaining application review.
- Implement and
- test file creation/import, recovery confirmation, signed one-use challenges,
- authorization, encrypted sends/replies, replay rejection, N=0 and pagination,
- authenticated counters, quotas, rate limits, hostile file and packet limits,
- plaintext-only display, session expiry, explicit lock, reload/restoration,
- no network leakage, no persistent application storage, and complete backup
- restoration. No application is ready merely because its crypto test passes.
diff --git a/docs/CHAT-OPENSSL-MIGRATION.txt b/docs/CHAT-OPENSSL-MIGRATION.txt
index 9e63730..d2901c4 100644
--- a/docs/CHAT-OPENSSL-MIGRATION.txt
+++ b/docs/CHAT-OPENSSL-MIGRATION.txt
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
OPENSSL BACKEND MIGRATION RECORD
- Date: 2026-10-30. Branch: feature/private-chat.
+ Date: 2026-10-30. Historical backend migration record.
Scope at this checkpoint: a compatibility and dependency-security experiment.
The later messenger and packaged deployment are described separately in
CHAT-APPLICATION.txt and CHAT-PRODUCTION.txt. Tests use disposable identities.
diff --git a/docs/CHAT-PRODUCTION.txt b/docs/CHAT-PRODUCTION.txt
index c1a2402..8830920 100644
--- a/docs/CHAT-PRODUCTION.txt
+++ b/docs/CHAT-PRODUCTION.txt
@@ -16,7 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
PRODUCTION CHAT INTEGRATION
- Implemented on main after merging the original feature/private-chat branch.
+ Implemented on main.
Building and testing a release does not activate the VPS. This is experimental software without an
independent cryptographic or application security audit. Read the limitations
in CHAT-APPLICATION.txt before using it for private conversations.
diff --git a/docs/GIT-HISTORY.txt b/docs/GIT-HISTORY.txt
index 2dfc335..410b53b 100644
--- a/docs/GIT-HISTORY.txt
+++ b/docs/GIT-HISTORY.txt
@@ -20,15 +20,15 @@ GIT IDENTITY AND SIGNATURE REWRITE
RSA-2048 key 3346AA3150F8F16828BB0D14F8C66DF77AFECEA6.
Ten historical author identities and their corresponding committer identities
- were corrected. All 27 commits reachable from main and feature/private-chat
+ were corrected. All 27 commits reachable from the two published branches
at the time of the rewrite were recreated and signed because rewritten
parents change descendant commit IDs. Every new signature was verified.
Every corresponding tree, message, original author timestamp/time zone, and
original committer timestamp/time zone was preserved. Merge topology was
preserved. Signature creation times reflect the new signing operation.
- main's file tree is unchanged. Configuration/chat development stays on
- feature/private-chat; rewriting metadata does not deploy that code to main.
+ At the time, main's file tree was unchanged and chat development was separate.
+ Chat has since been merged into main; the temporary feature branch was deleted.
Remote updates use an atomic push and exact force-with-lease expectations
for both branches, preventing overwrite of an unexpected remote update.
@@ -48,7 +48,6 @@ EXISTING CLONES
git switch main
git reset --keep origin/main
- For a feature checkout, use feature/private-chat in the final two commands.
--keep refuses updates that would overwrite conflicting working changes.
Do not blindly reset a clone with independent local work; use the mapping
below to identify the corresponding rewritten base before rebasing that work.
diff --git a/docs/OPERATIONS.txt b/docs/OPERATIONS.txt
index 5b1da25..c646a99 100644
--- a/docs/OPERATIONS.txt
+++ b/docs/OPERATIONS.txt
@@ -217,7 +217,7 @@ SET UP A NEW PRODUCTION HOST
Allow inbound 22/tcp, 80/tcp, 443/tcp, and 443/udp through the host/provider
firewall, for IPv4 and IPv6 as applicable. Backend container ports must not
be published. Preserve your SSH access and verify the address before DNS
- changes. There is no need to restore Docker's old generated firewall rules.
+ changes.
Point public A records to the new IPv4 address, and AAAA records only to a
working new IPv6 address. Remove stale AAAA records. Public hostnames are
@@ -333,10 +333,7 @@ RECOVERY LIMITS AND SECRET ROTATION
For one export, use --recipient FULL_FINGERPRINT --key /path/public-key.asc.
Keep old secret keys while any retained export still depends on them.
- Legacy format-1 exports made before the Rust migration use their embedded
- historical Python recovery helper. Keep that helper with those exports.
- The current command intentionally accepts only its verified format-2
- archives. Fresh format-2 production backups replace the normal workflow.
+ The restore command accepts verified format-2 application archives.
CENTRAL THIRD-PARTY LICENSE PAGE
@@ -345,7 +342,8 @@ CENTRAL THIRD-PARTY LICENSE PAGE
configured SITE_HOST for other deployments. Website and chat license links
use that same canonical page. Local previews use the local main-site origin.
- cgit no longer has a custom license renderer, Lua filter, or license About
- tab. The generated file remains accessible through its normal Source and Raw
- views in the repository. The old chat /THIRD-PARTY-LICENSES.html URL redirects
- to the canonical site page. Source exports retain license texts for offline use.
+ The generated file is accessible through cgit's normal Source and Raw views.
+ Chat's /THIRD-PARTY-LICENSES.html URL redirects to the canonical site page.
+ Source exports retain license texts for offline use.
+
+ Homepage /message and /message/ URLs redirect to the current chat origin.
diff --git a/infra/Caddyfile b/infra/Caddyfile
index 7975f68..140101d 100644
--- a/infra/Caddyfile
+++ b/infra/Caddyfile
@@ -42,6 +42,8 @@ https://www.{{BASE_DOMAIN}}:{{HTTPS_PORT}} {
https://{{SITE_HOST}}:{{HTTPS_PORT}} {
import https_security
+ redir /message {{CHAT_PUBLIC_ORIGIN}}/ permanent
+ redir /message/ {{CHAT_PUBLIC_ORIGIN}}/ permanent
root * /srv
file_server
diff --git a/infra/Caddyfile.local b/infra/Caddyfile.local
index 6f81a0a..94114f9 100644
--- a/infra/Caddyfile.local
+++ b/infra/Caddyfile.local
@@ -14,6 +14,8 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
:80 {
+ redir /message {{CHAT_PUBLIC_ORIGIN}}/ permanent
+ redir /message/ {{CHAT_PUBLIC_ORIGIN}}/ permanent
redir /git /git/?{query} permanent
redir /search /search/?{query} permanent
@git path /git /git/* /cgit.js /cgit.png
diff --git a/src/images.rs b/src/images.rs
index 11daaea..30019ca 100644
--- a/src/images.rs
+++ b/src/images.rs
@@ -48,7 +48,7 @@ fn inspect(project: &Project, name: &str) -> Result<Value> {
records
.into_iter()
.next()
- .context("Docker returned no image")
+ .context("Podman returned no image")
}
pub(crate) fn save(project: &Project, containers: &[Value], destination: &Path) -> Result<()> {
diff --git a/src/render.rs b/src/render.rs
index dea7e28..a552643 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -37,16 +37,14 @@ pub(crate) fn prepare(project: &Project, settings: &Settings) -> Result<()> {
fs::remove_dir_all(&web)?;
}
files::copy_tree(&project.root.join("web"), &web)?;
- for name in ["index.html", "message/index.html"] {
- let file = web.join(name);
- files::write(
- &file,
- config
- .render(&fs::read_to_string(&file)?, local)?
- .as_bytes(),
- 0o644,
- )?;
- }
+ let file = web.join("index.html");
+ files::write(
+ &file,
+ config
+ .render(&fs::read_to_string(&file)?, local)?
+ .as_bytes(),
+ 0o644,
+ )?;
let template = project.root.join(if settings.mode == Mode::Local {
"infra/Caddyfile.local"
} else {
diff --git a/web/message/index.html b/web/message/index.html
deleted file mode 100644
index cc64787..0000000
--- a/web/message/index.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!doctype html>
-<!--
-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/>.
--->
-<html lang="en">
-<head>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width,initial-scale=1">
- <title>Message Me — Doan Luu Duc Tai</title>
- <link rel="stylesheet" href="/styles.css?v=ef54dd8d9908ae8682c273d84377d322935874c3d491d9cc656f4485c5e795a1">
-</head>
-<body>
- <div id="page">
- <div class="badge">[ JS-free ]</div>
- <div id="content">
- <pre>
-<a href="/">Home</a> <a href="/#services">Services</a> Message Me
-
-+------------------------------------------------------------------------------+
-| |
-| MESSAGE ME |
-| |
-| UNDER CONSTRUCTION |
-| |
-| Private messaging is being built and tested. |
-| Nothing to send here yet. |
-| |
-+------------------------------------------------------------------------------+
-
-For now, you can reach me by <a href="mailto:doan@luuduct.ai">email</a> or use the SimpleX link on <a href="/">my homepage</a>.
- </pre>
- <nav class="source-footer" aria-label="Licensing and source">
- <a class="project-license" href="https://www.gnu.org/licenses/agpl-3.0.html">[ LICENSE ]</a>
- <a class="dependency-licenses" href="{{SITE_ORIGIN}}/THIRD-PARTY-LICENSES.html">[ THIRD PARTY LICENSES ]</a>
- <a href="{{GIT_ORIGIN}}/stack/tree/web/message/index.html">[ SOURCE CODE ]</a>
- </nav>
- </div>
- </div>
-</body>
-</html>