diff options
| -rw-r--r-- | README.txt | 108 | ||||
| -rw-r--r-- | crates/README.txt | 11 | ||||
| -rw-r--r-- | crates/chat-crypto/README.txt | 52 | ||||
| -rw-r--r-- | crates/chat-server/README.txt | 12 | ||||
| -rw-r--r-- | crates/config/README.txt | 7 | ||||
| -rw-r--r-- | docs/CHAT-APPLICATION.txt | 298 | ||||
| -rw-r--r-- | docs/CHAT-OPENSSL-MIGRATION.txt | 198 | ||||
| -rw-r--r-- | docs/CHAT-PRODUCTION.txt | 183 | ||||
| -rw-r--r-- | docs/CHAT-SECURITY-REVIEW.txt | 123 | ||||
| -rw-r--r-- | docs/CONFIGURATION.txt | 156 | ||||
| -rw-r--r-- | docs/GIT-HISTORY.txt | 84 | ||||
| -rw-r--r-- | docs/LINTING.txt | 243 | ||||
| -rw-r--r-- | docs/MAP.txt | 175 | ||||
| -rw-r--r-- | docs/OPERATIONS.txt | 354 | ||||
| -rw-r--r-- | docs/POLICY.txt | 141 | ||||
| -rw-r--r-- | docs/TYPESCRIPT.txt | 153 |
16 files changed, 1002 insertions, 1296 deletions
@@ -15,85 +15,63 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. STACK - Personal web services, developed and managed through a root Cargo workspace. - Copyright (C) 2026 Doan Luu Duc Tai <doan@luuduct.ai> - GNU Affero General Public License, version 3 or later. See LICENSE. + Four services: Caddy, cgit, SearXNG, Rust private chat. + Rust management CLI; strict TypeScript browser code; GNU LibreJS checks. + SearXNG and cgit's upstream supervisor use third-party Python. No first-party Python. + License: GNU Affero General Public License, version 3 or later. See LICENSE. -GETTING STARTED +START LOCAL - Install Rust through rustup, Podman, Git, and GnuPG on a Linux development - machine, plus Node >=22.18.0 and npm for the TypeScript browser build. - Chat builds also need a GCC-compatible C compiler, Linux UAPI - headers, libclang, pkg-config, make, Perl, curl, tar, and OpenSSL 3.5+ - development libraries for native workspace checks. The pinned toolchain - includes rustfmt, Clippy, and the static x86_64 Linux target. - See docs/CHAT-PRODUCTION.txt for the native/WASI release build. - - From this directory: + Linux tools: rustup, Podman, Git, GnuPG, Node >=22.18.0, npm. + Native chat checks: GCC-compatible C compiler, Linux UAPI headers, libclang, + pkg-config, make, Perl, curl, tar, OpenSSL >=3.5 development libraries. + Pinned Rust includes rustfmt, Clippy, static x86_64 Linux target. + Native/WASI release builds: docs/CHAT-PRODUCTION.txt. cargo stack dev cargo stack status cargo stack down - Browse http://localhost:8080, /git/, /search/, and http://chat.localhost:8080/. - A fresh checkout generates a private .env automatically. - Local mode binds only loopback and does not request public certificates. - -DEVELOPMENT AND PRODUCTION - - src/main.rs forwards to the private Rust management implementation in - src/app.rs and src/app/. Future Rust application backends - belong in crates/. Add each crate to the root workspace explicitly and - inherit its strict workspace lints. - - infra/ holds service definitions, proxy configuration, container sources, - and the production user service. web/ holds the public website and WKD. - docs/ contains plaintext operations and policy documentation. + Open http://localhost:8080, /git/, /search/, http://chat.localhost:8080/. + Fresh checkout creates private .env. Local mode: loopback only, no public TLS. - The single root .env holds deployment settings and configured secrets. - The commented .env.example documents hostnames, ports, upstreams, chat, - backup recipients, and secret-setting names. See docs/CONFIGURATION.txt. - var/ contains private persistent data, container storage, temporary work, - and exports. Generated TLS private keys are runtime data under var/. - .env, var/, .tools/, target/, bin/, dist/, and node_modules/ are excluded - from Git. Browser code and tests are TypeScript; see docs/TYPESCRIPT.txt. +FILES AND STATE - The four services are Caddy, cgit, SearXNG, and the Rust chat server. The management - command is Rust. SearXNG and the cgit container's upstream supervisor retain - their third-party Python implementation. No first-party Python is needed. + Full file tree and uses: docs/MAP.txt. Rules: docs/POLICY.txt. + CLI: src/main.rs, src/app.rs, src/app/. Backends: crates/. + Add crates explicitly to root workspace; inherit strict workspace lints. + infra/: services, proxy, containers, user service. web/: site and WKD. + docs/: .txt guides. Browser code/tests: TypeScript; docs/TYPESCRIPT.txt. - Build and test on the development machine. Deploy prebuilt release - archives. The production host needs Podman, Git, and GnuPG, but no Rust - toolchain, Cargo, Node, npm, or TypeScript. + Exactly one root .env: settings and configured secrets. + One public .env.example: hosts, ports, upstreams, chat, backup keys/placeholders. + Generated databases and TLS keys: var/data. More: docs/CONFIGURATION.txt. + Git ignores .env, var/, .tools/, target/, bin/, dist/, node_modules/. -CHECKS AND LICENSES +CHECK AND RELEASE cargo install --locked --version 0.20.2 cargo-deny --root .tools cargo install --locked --version 0.9.3 --features cli cargo-about --root .tools cargo stack check cargo stack release - Check builds and checks TypeScript, then runs Rust formatting, Clippy, tests, - rustdoc, cargo-deny, and cargo-about. npm development dependencies are pinned - in package-lock.json. Typed ESLint, both compiler checks, and npm audit are - included. See docs/LINTING.txt for policy choices and tested exceptions. - THIRD-PARTY-LICENSES.html is generated from Cargo.lock and about.hbs. - Human-readable license headings use GNU's names. SPDX identifiers and - original third-party legal texts retain their exact spelling. - - Detailed manual backup, recovery, deployment, and host setup instructions - are in docs/OPERATIONS.txt. Read docs/POLICY.txt before changing conventions. - -EXPERIMENTAL CHAT - - main includes the experimental Rust/WASI chat application. Start with - docs/CHAT-APPLICATION.txt for setup, protected files, tests, backup/restore, - source licensing, and security limitations. cargo stack chat --init appends - chat configuration to the existing single root .env; cargo stack chat runs - the direct local service. docs/CHAT-PRODUCTION.txt describes its packaged - HTTPS gateway, release deployment, production owner setup, and recovery. - Building a release does not activate production. - - SQLite snapshots use the bundled SQLite C library. Release scripts build - static OpenSSL against hash-verified musl headers and the Rust musl target. - Runtime binaries remain static; no compiler is required on the VPS. + Check: TypeScript build, both compilers, typed ESLint, npm audit; Rust fmt, + Clippy, tests, private rustdoc, cargo-deny, cargo-about. npm lock: package-lock.json. + Policy and tested exceptions: docs/LINTING.txt. + Cargo.lock + about.hbs generate THIRD-PARTY-LICENSES.html. + Display GNU license names; preserve exact SPDX identifiers and upstream legal text. + + Build/test locally. Deploy prebuilt archives. VPS needs Podman, Git, GnuPG; + no Rust/Cargo/Node/npm/TypeScript. Backup, restore, host setup, deployment: + docs/OPERATIONS.txt. Building a release does not activate production. + +CHAT — EXPERIMENTAL + + cargo stack chat --init + cargo stack chat + + --init adds settings to existing root .env; chat starts direct local service. + Setup, protected files, tests, recovery, licensing, limits: docs/CHAT-APPLICATION.txt. + Packaged HTTPS, owner setup, recovery: docs/CHAT-PRODUCTION.txt. + SQLite snapshots use bundled SQLite C library. Static releases use OpenSSL, + hash-verified musl headers, Rust musl target. VPS needs no compiler. diff --git a/crates/README.txt b/crates/README.txt index 296f1a9..f724a28 100644 --- a/crates/README.txt +++ b/crates/README.txt @@ -15,10 +15,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. RUST BACKENDS - New first-party web backends belong in subdirectories here. Add their - paths to the workspace members in the root Cargo.toml. Use edition 2024, - AGPL-3.0-or-later, and workspace lints. Keep configured secrets in the one - root .env and pass only the required keys to each service. - - The current stack has no blog or comment backend. This directory reserves - a place for those features without adding an unused service or database. + New web backends belong here. Add paths to root Cargo.toml workspace members. + Use edition 2024, AGPL-3.0-or-later, workspace lints. + Keep configured secrets in one root .env. Pass each service only required keys. + No blog/comment backend or unused service/database exists. diff --git a/crates/chat-crypto/README.txt b/crates/chat-crypto/README.txt index 114544d..0fb26e7 100644 --- a/crates/chat-crypto/README.txt +++ b/crates/chat-crypto/README.txt @@ -13,34 +13,27 @@ 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 CRYPTOGRAPHY Fixed encryption: RFC 9980 ML-KEM-1024 + X448, OpenPGP v6. Signing: ML-DSA-87 + Ed448, OpenPGP v6. - Backend: Sequoia 2.4.2 with OpenSSL 3.6.5. No algorithm substitution or - vulnerability-advisory exception was used. The original RustCrypto backend - is historical and no longer selected. - - This crate implements purpose-specific identity creation, Argon2id/AES-256-GCM - protected files, detached authentication proofs, signed two-recipient messages, - bounded verified history batches, and the original compatibility probe. - Native Rust and browser WASI share the implementation. The standalone command - accepts one JSON request on stdin; empty input runs the compatibility probe. - Its browser WASI host grants no filesystem or network access. Private request - data must remain in local memory and must never be submitted to the server. - - See ../../docs/CHAT-APPLICATION.txt for implemented formats, local setup, - tests, backups, and limitations. See ../../docs/CHAT-PRODUCTION.txt for - packaged HTTPS integration. Work remains experimental; - compatibility tests are not an application security audit. - - ../../docs/CHAT-OPENSSL-MIGRATION.txt records the complete backend decision, - pinned source hashes, build flags, FFI/capability limitations, and reviewed - dependency-policy exceptions. ../../docs/CHAT-SECURITY-REVIEW.txt records - the superseded RustCrypto findings without advisory ignores. - -CHECKS FROM THE WORKSPACE ROOT + Sequoia 2.4.2 + OpenSSL 3.6.5. No algorithm substitution or advisory exception. + Superseded RustCrypto backend is not selected. + + Provides purpose-specific identities, Argon2id/AES-256-GCM protected files, + detached authentication proofs, signed two-recipient messages, bounded + verified history batches, compatibility probe. Native Rust and browser WASI + share code. Standalone CLI: one JSON request on stdin; empty stdin runs probe. + Browser WASI has no filesystem/network access. Private requests stay in local + memory; never send them to server. + + ../../docs/CHAT-APPLICATION.txt: formats, setup, tests, backups, limits. + ../../docs/CHAT-PRODUCTION.txt: packaged HTTPS. + ../../docs/CHAT-OPENSSL-MIGRATION.txt: backend decision, source hashes, + build flags, FFI/capability limits, reviewed dependency exceptions. + Experimental. Compatibility tests are not an application security audit. + +CHECK FROM WORKSPACE ROOT cargo test --locked -p stack-chat-crypto cargo run --locked -p stack-chat-crypto @@ -48,9 +41,8 @@ CHECKS FROM THE WORKSPACE ROOT PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:crypto cargo stack check - Native builds require OpenSSL >=3.5 development files and libclang. - The cross-build script supports an x86_64 GNU/Linux development host. - Installed browser tooling is excluded from source archives and releases. - The TypeScript tests and locked toolchain declarations are public. - The probe uses public fixture credentials and creates temporary identities - in memory. It does not open the root .env or use the canonical RSA key. + Native build: OpenSSL >=3.5 development files, libclang. + Cross-build host: x86_64 GNU/Linux. Browser tooling excluded from archives + and releases; TypeScript tests and locked toolchain declarations remain public. + Probe uses public fixture credentials and temporary in-memory identities. + It never opens root .env or uses canonical RSA key. diff --git a/crates/chat-server/README.txt b/crates/chat-server/README.txt index 0562385..1cd97d5 100644 --- a/crates/chat-server/README.txt +++ b/crates/chat-server/README.txt @@ -13,11 +13,11 @@ 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 SERVER — EXPERIMENTAL -EXPERIMENTAL PRIVATE CHAT SERVER + cargo stack chat --init + cargo stack chat - See docs/CHAT-APPLICATION.txt at the workspace root for local setup, - file formats, API/security limits, backups, recovery, source licensing, - and tests. Start with cargo stack chat --init, then cargo stack chat. - See docs/CHAT-PRODUCTION.txt for the prebuilt Podman/HTTPS deployment, - production owner setup, and full encrypted export/recovery procedure. + From workspace root: local setup, formats, API/security limits, backup, + recovery, licensing, tests: docs/CHAT-APPLICATION.txt. + Prebuilt Podman/HTTPS, production owner, encrypted export: docs/CHAT-PRODUCTION.txt. diff --git a/crates/config/README.txt b/crates/config/README.txt index 8648852..dccfbf4 100644 --- a/crates/config/README.txt +++ b/crates/config/README.txt @@ -13,8 +13,7 @@ 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/>. -SHARED STACK CONFIGURATION +SHARED CONFIGURATION - Public defaults are documented in the root .env.example. Each installation - overrides them in the single root .env alongside private settings. Rendering - uses an explicit public allowlist. See docs/CONFIGURATION.txt for details. + Root .env.example: public defaults. Single root .env: overrides and secrets. + Rendering uses explicit public allowlist. See docs/CONFIGURATION.txt at root. diff --git a/docs/CHAT-APPLICATION.txt b/docs/CHAT-APPLICATION.txt index 7ebac77..388c677 100644 --- a/docs/CHAT-APPLICATION.txt +++ b/docs/CHAT-APPLICATION.txt @@ -16,34 +16,28 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. EXPERIMENTAL PRIVATE CHAT - Available on main. Direct development and a prebuilt Podman/HTTPS - deployment path are implemented. See CHAT-PRODUCTION.txt for the release, - production setup, and recovery procedure; feature work does not itself merge - main or activate the VPS. - This is working experimental software, not an independently audited messenger. + Available on main: direct development and prebuilt Podman/HTTPS deployment. + See CHAT-PRODUCTION.txt for release, setup, and recovery. Feature work does + not merge main or activate the VPS. Experimental; no independent messenger audit. WHAT EXISTS - A Rust HTTP server and a Rust cryptographic command compiled to WASI. - Strict TypeScript implements the browser interface and a capability-limited - WASI host, compiled to small, readable, free JavaScript classic scripts. - Build configuration and source licensing are documented in TYPESCRIPT.txt. Text is displayed through textContent. - SearXNG and the other existing services are unchanged. - - Startup shows an ASCII download bar, percentage, and received/total MiB - while fetching the cryptographic module. If its size is unavailable, it shows - received MiB. A 45-second gap without download progress aborts with a reload - instruction; slow transfers continue while bytes arrive. After download, - a separate status identifies the connection to chat. No browser cache or - storage was added. - - Visitors choose CREATE NEW CHAT or OPEN CHAT FILE. Creation generates a - purpose-specific identity locally and downloads its protected file. Reopening - the exact downloaded file and entering its password is required before the - first authentication or message. No username/password account is created. - Returning users select their file and password again. The stable file does - not need updating as messages arrive. The owner has a separate chat identity - and inbox; the canonical RSA OpenPGP key is not used for chat encryption. + Rust HTTP server and Rust/WASI cryptography. Strict TypeScript compiles the + interface and capability-limited WASI host to small, readable, free classic + JavaScript. See TYPESCRIPT.txt for build/licensing. Text uses textContent. + Existing services, including SearXNG, are unchanged. + + Crypto download shows an ASCII bar, percentage, and received/total MiB; + unknown totals show received MiB. A 45-second stall aborts with reload + instructions; slow transfers continue while bytes arrive. Chat connection has + a separate status. No browser cache or storage was added. + + CREATE NEW CHAT generates a purpose-specific identity locally and downloads + its protected file. Reopen that exact file with its password before first + authentication/message. OPEN CHAT FILE restores access on later visits. + No username/password account; messages never require updating the stable file. + The owner has a separate identity/inbox. The canonical RSA OpenPGP key does + not encrypt chat. History defaults to zero messages. Authenticated counters show total, sent, and received messages. Choose 0 to N recent messages, where N is the current @@ -58,12 +52,10 @@ WHAT EXISTS LOCAL PREREQUISITES AND COMMANDS - Start in the root of the stack repository on main. Native - development needs Rust, libclang, OpenSSL 3.5 or newer development libraries, - a C compiler, pkg-config, make, Perl, curl, and tar. The checked configuration - uses OpenSSL 3.6.5. The WASI build script currently targets an x86_64 GNU/Linux - development host and downloads the hash-verified WASI SDK 34.0 and OpenSSL - source. General-purpose toolchains remain development tools, not VPS tools. + Start at the repository root on main. Native development needs Rust, libclang, + OpenSSL >=3.5 development libraries, C compiler, pkg-config, make, Perl, curl, + and tar. Checked OpenSSL: 3.6.5. WASI builds target x86_64 GNU/Linux and download + hash-verified WASI SDK 34.0/OpenSSL sources. Toolchains stay off the VPS. Build and initialize once: @@ -72,63 +64,54 @@ LOCAL PREREQUISITES AND COMMANDS sh infra/chat/build-source.sh cargo stack chat --init - Initialization appends CHAT_SETUP_TOKEN and CHAT_ORIGIN to the single root - .env, creating it privately if necessary. It refuses to overwrite an existing - setup token. The root .env.example lists both settings. Never commit .env. - Existing SearXNG settings stay in the same file. No crate has its own .env. - CHAT_BIND and public navigation now use the shared root configuration loader; - see CONFIGURATION.txt for the documented deployment keys. + Initialization privately creates/appends CHAT_SETUP_TOKEN and CHAT_ORIGIN + in the single root .env, preserving an existing token and SearXNG settings. + Root .env.example lists both; never commit .env or create crate-specific files. + CHAT_BIND and public navigation use the shared loader; see CONFIGURATION.txt. - For subsequent Rust-only edits, sh infra/chat/build-browser.sh reuses the - previously built, hash-verified OpenSSL/SDK inputs. Rebuild OpenSSL itself - after changing its source, version, configuration, or build flags. The WASI - module has a 256 MiB maximum linear-memory limit. + For Rust-only edits, sh infra/chat/build-browser.sh reuses verified OpenSSL/SDK + inputs. Source/version/configuration/flag changes require an OpenSSL rebuild. + WASI linear memory is capped at 256 MiB. Start: cargo stack chat - Open http://127.0.0.1:9080/ and choose OWNER SETUP, labeled for the owner - only. The direct http://127.0.0.1:9080/#setup link also works. - - Read CHAT_SETUP_TOKEN from your root .env locally and paste it into the owner - setup form. Choose an owner display name and a strong unique password. Save - the downloaded file, reopen it, and unlock it. That establishes the owner - public identity. The setup token stops authorizing setup once an owner exists. - It does not become an owner login or a key recovery mechanism. OWNER SETUP - stays visible; once an owner exists, it explains how to open the existing - owner file or reset after loss instead of silently replacing the key. Never publish - the owner private file or its password. Keep both in your private KeePassXC - database, along with a separately protected backup of that database. - - Open another browser window at http://127.0.0.1:9080/ to create a visitor chat. - Every page holds its own identity in memory; there is no shared browser login. - Stop the development server with Control-C. A server restart invalidates all - sessions but preserves identities, conversations, counts, and ciphertext. - - The direct development server refuses a non-loopback bind or an origin that - does not exactly match its development bind address. Packaged production uses - a private container listener behind Caddy HTTPS, with an explicit external - CHAT_HOST/HTTPS_PORT origin. Forwarded request headers do not choose that - origin. Do not expose the direct development server through a public proxy. + Open http://127.0.0.1:9080/ and choose owner-only OWNER SETUP, + or use http://127.0.0.1:9080/#setup. + + Read CHAT_SETUP_TOKEN from root .env locally; paste into setup. Choose a + display name and strong unique password; save, reopen, and unlock the file. + This registers the owner public identity and disables token-based setup. + The token grants neither login nor key recovery. OWNER SETUP remains visible + with existing-file/reset instructions; it never silently replaces a key. + Never publish private file/password. Keep both in KeePassXC with a separately + protected database backup. + + Create a visitor chat in another window at http://127.0.0.1:9080/. + Identity stays in each page's memory; browser login is not shared. Control-C + stops development. Restart invalidates sessions, preserving identities, + conversations, counts, and ciphertext. + + Direct development requires loopback and an exactly matching bind/origin. + Production uses a private listener behind Caddy HTTPS, with explicit + CHAT_HOST/HTTPS_PORT origin; forwarded headers cannot choose it. Never expose + direct development through a public proxy. OWNER FILE LOSS AND BACKEND RESET - A setup token grants registration permission. It cannot recover the private - key inside a lost owner file. If that file and its backups are gone, existing - messages cannot be decrypted with a newly generated identity. The reset below - intentionally starts a fresh chat service and clears all stored messages, - encrypted profiles, conversations, counters, and the owner registration. - It preserves the root .env and any previously exported backup archives. - It does not claim forensic erasure of backups, snapshots, or OS copies. - - Run these commands locally at the stack root for the current development - build. There is no reset operation in the HTTP API. Filesystem access to - the private chat directory is the administrative boundary. Production uses - ./bin/stack chat --owner-fingerprint and ./bin/stack chat --reset-owner - through an isolated maintenance container. Stop production with ./bin/stack - down first; restart with ./bin/stack up --production. No Rust is needed on - the VPS. See CHAT-PRODUCTION.txt before a destructive reset. + Setup tokens grant registration, not private-key recovery. A new identity + cannot decrypt old messages if the owner file/backups are lost. Reset clears + all messages, encrypted profiles, conversations, counters, and owner registration. + Root .env and exports survive. This does not forensically erase backups, + snapshots, or OS copies. + + Run development commands at the stack root. Reset has no HTTP API; private + chat-directory access is the administrative boundary. Production runs + ./bin/stack chat --owner-fingerprint and ./bin/stack chat --reset-owner in an + isolated maintenance container. First stop with ./bin/stack down; restart + with ./bin/stack up --production. No VPS Rust required. Read CHAT-PRODUCTION.txt + before destructive reset. Read the current public fingerprint, even if you have lost the private file: @@ -139,26 +122,23 @@ OWNER FILE LOSS AND BACKEND RESET cargo stack chat --reset-owner PASTE_CURRENT_OWNER_FINGERPRINT_HERE - A fingerprint mismatch refuses without deleting data. The server and reset - process share a filesystem lock. Direct development additionally requires - the loopback service port to be free. This prevents resetting a running service, including a - development process launched before the lock was added. Online snapshots and - reading the public owner fingerprint remain available while chat is running. + Mismatched fingerprints refuse without deletion. Server/reset share a lock; + direct development also requires a free loopback service port, protecting + older running processes without the lock. Online snapshots and fingerprint + reads remain available during operation. Restart: cargo stack chat - Choose OWNER SETUP and use the existing CHAT_SETUP_TOKEN from the same root - .env to generate, save, and reopen a fresh owner file. Back that file and its - password up in KeePassXC. Visitors must create fresh chat files too: their - previous files pin the former owner key and are correctly rejected after - replacement. A reset cannot prove continuity with the lost key. + Use OWNER SETUP and existing root .env CHAT_SETUP_TOKEN; generate, save, and + reopen a fresh file. Back up file/password in KeePassXC. Visitors also need + fresh files: old owner-key pins correctly reject replacement. Reset cannot + prove continuity with the lost key. - If an old owner file is found later, an old encrypted backup may still allow - recovering its original conversations in an isolated restored installation. - The reset does not remove existing exported archives, and it never substitutes - a new key into old ciphertext or old visitor files. + An owner file found later may recover old conversations from an encrypted + backup in isolation. Reset retains exports and never substitutes new keys + into old ciphertext or visitor files. FILE AND MESSAGE CRYPTOGRAPHY @@ -168,12 +148,10 @@ FILE AND MESSAGE CRYPTOGRAPHY a fixed purpose-only user ID. Names are not placed in public certificate IDs. The server rejects uploaded secret-key material and unsupported certificates. - New JSON identity files are indented and use an array of 80-character - Base64 ciphertext chunks; the final chunk may be shorter. JSON indentation, - quotes, and commas are additional to the ciphertext width. The reader joins - the chunks before Base64 decoding. No private fields become plaintext. - This is the application's own JSON envelope, not OpenPGP ASCII armor. - The new file-format identifier is authenticated as associated data: + New identity JSON uses indentation and 80-character Base64 ciphertext chunks; + the last may be shorter. JSON punctuation/indentation adds width. Readers join + chunks before decoding. Private fields stay encrypted. This application envelope + is not OpenPGP ASCII armor. Its identifier is authenticated as associated data: stack-chat-file/v2;argon2id-m65536-t3-p1;aes256-gcm @@ -181,10 +159,9 @@ FILE AND MESSAGE CRYPTOGRAPHY stack-chat-file/v1;argon2id-m65536-t3-p1;aes256-gcm - v1 uses its original identifier as associated data. Changing a version label - or converting its field shape does not convert a file: the authentication tag - binds the version. No existing file needs rewriting; old readers do not support - new v2 exports. Cryptographic algorithms and KDF parameters are unchanged. + v1 retains its original associated data. The tag binds versions: relabeling + or reshaping fields cannot convert files. Existing files need no rewrite; + old readers reject v2. Algorithms/KDF parameters stay fixed. Argon2id version 0x13 uses 65536 KiB, three passes, one lane, and a 32-byte derived key. A fresh CSPRNG salt of 16 bytes and AES-256-GCM nonce of 12 bytes @@ -203,11 +180,10 @@ FILE AND MESSAGE CRYPTOGRAPHY formats return a generic error. Mutable KDF keys, plaintext envelopes, and private serialization buffers are zeroized where practical. - The browser checks the file's exact origin and pinned owner certificate on - unlock. Owner identity creation pins its own public certificate. Visitor - creation pins the public certificate currently advertised over the origin's - trusted connection. First-visit trust is consequently still trust in the - served application and TLS; it is not an out-of-band identity guarantee. + Unlock checks exact origin and owner pin. Owner creation pins its own public + certificate; visitors pin the certificate advertised over the trusted origin + connection. First visits still trust served application/TLS, without an + out-of-band identity guarantee. Each text message is signed, then encrypted for both participants. A signed plaintext JSON object binds v=1, kind=message, exact origin, conversation ID, @@ -246,12 +222,11 @@ AUTHENTICATION AND STORAGE keys or message plaintext. OS diagnostics and a future reverse proxy need their own logging review before deployment. - Sends are transactional. Retrying exactly the same ciphertext, message ID, - sender, and conversation returns its existing sequence without incrementing - counts. Reusing an ID with different data is rejected. This handles a response - lost after the message was stored. Keep the page unlocked to retry; reload - discards the pending ciphertext and draft, so inspect history before resending. - Send retries are deliberate; messages are not automatically resent. + Transactional sends deduplicate exact ciphertext/message-ID/sender/conversation + retries, returning the original sequence/counts. Reused IDs with changed data + are rejected. This handles lost responses after storage. Keep the page unlocked + to retry; reload loses pending ciphertext/draft, so inspect history before + resending. Retries are deliberate, never automatic. Limits: 8192 UTF-8 bytes per text, 16384 bytes per signed payload, 65536 base64 characters per stored ciphertext, 50 history rows per API request, 1000 visitor @@ -297,33 +272,28 @@ BROWSER STATE AND LIMITATIONS addresses during connections. Bearer-token theft permits API use until expiry or lock, though decrypting or signing still requires the private key. - A malicious server can replace JavaScript or WASM and steal passwords and - plaintext on the next visit. A pinned key and LibreJS do not prevent that. - Shared-host compromise, browser extensions, a compromised OS, browser bugs, - dependency attacks, malicious friends, and denial of service remain risks. - A purpose label advises separation; it cannot prevent exporting and reusing - a key elsewhere. This application is not a SimpleX equivalent. + Malicious servers can replace JavaScript/WASM and steal passwords/plaintext + on the next visit; key pins and LibreJS cannot prevent it. Shared-host/OS + compromise, extensions, browser bugs, dependency attacks, malicious friends, + and denial of service remain risks. Purpose labels cannot prevent key export + or reuse. This is not a SimpleX equivalent. BACKUP, EXPORT, AND RESTORE - The existing cargo stack backup creates a GPG-encrypted archive and now uses - SQLite's online backup API for chat.sqlite. It does not copy a live SQLite - file or journal with ordinary file-copy code. It can take a consistent chat - snapshot while the local chat server runs. Existing Podman data still follows - the stack's pause/copy/resume process; the chat container stays unpaused. - Separate snapshots cover both chat and chat-local. A snapshot is atomic - for chat data; unrelated services do not share a global transaction with it. - The backup includes the single root .env and must remain private/encrypted. + cargo stack backup uses SQLite online backups, not ordinary live database/ + journal copies. chat and chat-local get separate consistent snapshots while + running; chat stays unpaused. Other Podman services retain pause/copy/resume. + Chat snapshots are atomic, without a cross-service transaction. Exports + include root .env and must stay private/encrypted. For a chat-only consistent database export: cargo run --locked -p stack-chat-server -- --root . --snapshot var/exports/chat-snapshot.sqlite - Create var/exports privately first if it does not exist. The destination must - not already exist. This standalone snapshot is ciphertext plus public metadata, - not a GPG-encrypted full-stack archive; encrypt it before off-machine storage. - It does not contain browser private identities. A server-side backup cannot - recover a lost user or owner file/password. + Create var/exports privately first; destination must not exist. Standalone + snapshots contain ciphertext/public metadata, without full-stack GPG encryption. + Encrypt before off-machine storage. Browser private identities are absent; + server backups cannot recover lost identity files/passwords. Restore a full stack using the existing README.txt backup/restore instructions. For a chat-only restore, stop the chat server, put the verified snapshot at @@ -334,33 +304,27 @@ BACKUP, EXPORT, AND RESTORE origin deliberately makes old files fail their origin binding; there is no origin migration UI yet. Do not edit an encrypted file by hand. - Keep at least one encrypted backup away from the VPS. Test the owner identity, - visitor identity, correct counts, and decrypted messages after a restore. - Keep private identity files and passwords in KeePassXC with a protected - database backup. Never place them in source control or the public source - archive. Deleting a message locally or losing a file does not delete stored - ciphertext, old exports, or other participants' copies. + Keep an encrypted backup off-VPS. After recovery, test owner/visitor identities, + counts, and decryption. Keep private files/passwords in KeePassXC with a protected + database backup, never source control/public archives. Local deletion or file + loss does not delete stored ciphertext, exports, or participants' copies. INTERFACE AND SITE STYLE - 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 - keyboard-accessible warning. Small screens keep readable form controls and - fit the ASCII rules to the available width instead of shrinking all text. - Scrolling belongs to the root viewport at the screen edge; the logo has no - inner scroll container. JavaScript licenses sit below the LibreJS badge. - No remote fonts, images, or additional scripts are required. + web/styles.css supplies red ASCII logo, 80-column desktop width, black/white + light/dark themes, blue links, green prompts/actions, ASCII frames, and bracketed + controls. License links retain amber/muted green. Yellow LibreJS badge has a + keyboard-accessible warning; JavaScript licenses sit below it. Small screens + retain readable controls and fit ASCII rules without shrinking all text. + Root viewport scrolls at the screen edge; no inner logo scrolling. + No remote fonts, images, or additional scripts. LICENSES, SOURCE, AND VERIFICATION - Portable root CLI builds now also need a musl C compiler because consistent - snapshots use bundled SQLite. The root CLI was built and executed as an - x86_64 static PIE with SQLite; no runtime SQLite package is needed on the VPS. - The local check used Alpine musl 1.2.6 headers with the host C compiler for - the C object build and Rust's self-contained musl runtime for final linking. + Bundled SQLite snapshots require a musl C compiler for portable CLI builds. + The root CLI ran as x86_64 static PIE; VPS SQLite packages are unnecessary. + Local checks compiled C with Alpine musl 1.2.6 headers/host compiler and + linked with Rust's self-contained musl runtime. The rendered dependency-license page is centralized on the main website at https://doan.luuduct.ai/THIRD-PARTY-LICENSES.html. Chat links point there; its @@ -399,16 +363,12 @@ LICENSES, SOURCE, AND VERIFICATION PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:chat PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:progress - Browser automation additionally needs Node and the root locked Playwright - development dependency, with browser downloads under .tools/browsers. See - TYPESCRIPT.txt for installation and the strict TypeScript build. These tools are - excluded from releases. The fixtures use temporary isolated installation roots - with one temporary .env each, and remove their private data on completion. - They listen on loopback port 9081 by default (override with CHAT_TEST_PORT), - leaving the normal local preview on 9080 available. The optional packaged - HTTPS variant is documented in CHAT-PRODUCTION.txt and retains its disposable - installation roots for inspection. Tests do not initialize the real owner - identity or touch the VPS. + Automation needs Node/root locked Playwright, with browsers in .tools/browsers; + see TYPESCRIPT.txt for installation/strict builds. Releases exclude these tools. + Fixtures isolate roots with one temporary .env each, deleting private data on + completion. Default loopback 9081 (CHAT_TEST_PORT overrides) leaves preview 9080 + free. Packaged HTTPS tests retain disposable roots; see CHAT-PRODUCTION.txt. + Tests neither initialize the real owner nor touch the VPS. LibreJS verification uses the Mozilla-distributed GNU LibreJS 7.21.1 in Playwright Firefox 157.0, without whitelisting the application. The full chat @@ -419,12 +379,10 @@ LICENSES, SOURCE, AND VERIFICATION https://addons.mozilla.org/firefox/downloads/file/4169076/librejs-7.21.1.xpi - Earlier tests exposed a LibreJS label mismatch: a combined GNU prefix and - or-later suffix was not recognized by that release. The table now uses its - recognized GNU-AGPL-3.0 identifier and the surrounding prose and legal headers - explicitly retain the version-3-or-later grant. Readable classic scripts and - workers are used instead of requiring module-script interception support. - This tests license recognition and operation, not the safety of delivered code. + LibreJS rejected a combined GNU prefix/or-later suffix. The table uses recognized + GNU-AGPL-3.0; prose/legal headers retain version-3-or-later. Readable classic + scripts/workers avoid module-script interception requirements. This tests + license recognition/operation, not delivered-code safety. The crypto browser probe fails closed without browser CSPRNG entropy and on unknown WASI imports. The application browser test uses real WASI/OpenSSL diff --git a/docs/CHAT-OPENSSL-MIGRATION.txt b/docs/CHAT-OPENSSL-MIGRATION.txt index 8c9ee28..4bb87fb 100644 --- a/docs/CHAT-OPENSSL-MIGRATION.txt +++ b/docs/CHAT-OPENSSL-MIGRATION.txt @@ -16,28 +16,33 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. OPENSSL BACKEND MIGRATION RECORD - 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. + Date: 2026-10-30. Historical compatibility/dependency-security experiment + using disposable identities. For the later messenger and packaged deployment, + see CHAT-APPLICATION.txt and CHAT-PRODUCTION.txt. DECISION AND FIXED ALGORITHMS - Retain Sequoia OpenPGP 2.4.2 and RFC 9980 ML-KEM-1024 + X448 encryption. - Retain ML-DSA-87 + Ed448 signatures, OpenPGP v6 keys, and AES-256 content - encryption. Change the cryptographic backend, not the algorithms or wire - protocol. Probe assertions reject an unexpected backend or key algorithms. - - The previous Rust backend reached cx448 0.1.1 -> crypto-bigint 0.5.5 during - curve arithmetic. It also included rsa 0.9.10. See CHAT-SECURITY-REVIEW.txt - for the original reachability investigation. Neither RustSec issue was - ignored. No mathematical implementation was patched locally. - - The current manifest enables only Sequoia's crypto-openssl feature. The - allow-experimental-crypto and allow-variable-time-crypto opt-ins are gone. - The resolved graph has no cx448, crypto-bigint, or rsa crate. This removes - those Rust backend dependencies; it does not prove that all side channels - are absent from a browser or that external C dependencies have no defects. + Retain Sequoia OpenPGP 2.4.2, RFC 9980 ML-KEM-1024 + X448 encryption, + ML-DSA-87 + Ed448 signatures, OpenPGP v6 keys, and AES-256 content encryption. + Only the backend changes; algorithms and wire protocol stay fixed. + Probe assertions reject unexpected backends or key algorithms. + + Previous Rust curve arithmetic reached cx448 0.1.1 -> crypto-bigint 0.5.5; + the backend also included rsa 0.9.10. Neither RustSec issue was ignored; + no mathematical implementation was patched locally. + RUSTSEC-2026-0387 affected required X448/Ed448 curve arithmetic, not unused RSA. + Its fix requires crypto-bigint >=0.7.6; cx448 0.1.1 requires incompatible 0.5. + A lockfile update alone could not fix it. No practical browser key-extraction + exploit was demonstrated; functional tests do not prove constant-time behavior. + The closed probe used no RSA private operations, but that did not establish + unreachability through hostile imports or future application interfaces. + https://rustsec.org/advisories/RUSTSEC-2026-0387.html + https://rustsec.org/advisories/RUSTSEC-2023-0071.html + + Only crypto-openssl is enabled. allow-experimental-crypto and + allow-variable-time-crypto are removed. The resolved graph has no cx448, + crypto-bigint, or rsa crate. Removing those dependencies does not prove + absence of browser side channels or external C defects. VERSIONS AND SOURCE PROVENANCE @@ -55,36 +60,29 @@ VERSIONS AND SOURCE PROVENANCE https://github.com/openssl/openssl/releases/download/openssl-3.6.5/openssl-3.6.5.tar.gz SHA-256 a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98 - Digests were checked against upstream GitHub release asset metadata. The - build script verifies each archive before extraction. Hash checking pins - these inputs; it is not a claim that upstream release signatures were - independently verified or that output is bit-for-bit reproducible across - hosts. Archives, SDK, libraries, and build products stay under ignored - .tools/ and target/. The native development library is supplied by the OS. + Digests match upstream GitHub release asset metadata; scripts verify them + before extraction. This pins inputs, without independently verifying release + signatures or proving cross-host bit-for-bit builds. Archives, SDK, libraries, + and build products stay under ignored .tools/ and target/. The OS supplies + the native development library. WHY WASI - The original Rust-backend proof used wasm32-unknown-unknown and generated - wasm-bindgen JavaScript. The OpenSSL proof uses a wasm32-wasip1 command - module and a small explicit browser WASI bridge. The Rust command calls - the same compatibility_probe function used by native tests. - - The browser harness loads the new WASI binary directly, not old generated - glue. It requires the output to identify OpenSSL 3.6.5, preventing a stale - Rust-backend artifact from being accepted as evidence of OpenSSL support. - Old browser-build commands are historical and must not be reused here. + The Rust proof used wasm32-unknown-unknown and wasm-bindgen glue. OpenSSL uses + a wasm32-wasip1 command and explicit browser WASI bridge, calling the native + tests' compatibility_probe. The browser loads this binary directly and + requires output identifying OpenSSL 3.6.5; stale Rust-backend artifacts cannot + count as OpenSSL evidence. Do not reuse historical browser-build commands. BUILD CONFIGURATION AND BOUNDARIES - infra/chat/openssl-wasi.conf adds a build target inheriting BASE_unix with - little-endian and 32-bit bignum configuration. It changes configuration, - not OpenSSL's cryptographic source routines. C code is compiled at -O2. - No third-party rand.patch, unconditional entropy-success patch, or custom - random-number generator is applied. A SHA-256 comparison of all 5889 original - regular files against the downloaded OpenSSL archive found no changed or - missing originals after the build; only the separate target configuration - was added. OpenSSL 3.6.5 already supports WASI - getentropy in providers/implementations/rands/seeding/rand_unix.c. + infra/chat/openssl-wasi.conf adds a BASE_unix target with little-endian, + 32-bit bignums; cryptographic routines are unchanged. C uses -O2. No rand.patch, + unconditional entropy-success patch, or custom RNG is applied. SHA-256 checks + of all 5889 original regular files against the downloaded archive found none + changed or missing after build; only the target configuration was added. + OpenSSL 3.6.5 supports WASI getentropy in + providers/implementations/rands/seeding/rand_unix.c. Configure selects --with-rand-seed=getrandom. WASI libc's entropy request reaches wasi_snapshot_preview1.random_get. The browser bridge services it @@ -92,28 +90,23 @@ BUILD CONFIGURATION AND BOUNDARIES bytes. There is no Math.random, fixed seed, or success-on-failure fallback. The negative test replaces that API with a failure and requires rejection. - Build options disable assembly, async operations, automatic config loading, + Static builds disable assembly, async operations, automatic config loading, DSO/modules, POSIX I/O, secure-memory arenas, shared libraries, sockets, - C stdio, thread pools, threads, and interactive console UI. They avoid - unsupported host capabilities and use static libraries. Disabling the - secure-memory arena means ordinary WASM linear memory is used; it does not - establish secure erasure, locked pages, or protection from delivered JS. - Disabling C stdio does not disable the Rust command's captured output. - - _WASI_EMULATED_GETPID and libwasi-emulated-getpid supply the SDK's process-ID - emulation. getuid/geteuid/getgid/getegid map to getpagesize, following the - common WASI port configuration: the browser module has no real OS user IDs - or privilege boundary. These values are not used as randomness or identity - credentials. This is an explicit portability assumption, not a general - POSIX security emulation layer. - - Rust bindings use the SDK's libclang and WASI sysroot with target - wasm32-wasip1 and -fvisibility=default. Without explicit visibility, the - initial bindgen attempt omitted function declarations. Rust's bundled WASI - libc search path precedes the SDK libraries: reversing that order initially - failed to link __wasi_init_tp. The SDK library path remains available for - the emulated-getpid archive. These failures were toolchain integration - issues; no generated cryptographic bindings were manually edited. + C stdio, thread pools, threads, and interactive console UI to avoid unsupported + capabilities. Ordinary WASM linear memory provides no secure-erasure, + locked-page, or delivered-JS protection. Rust output remains captured. + + _WASI_EMULATED_GETPID and libwasi-emulated-getpid supply SDK process-ID emulation. + getuid/geteuid/getgid/getegid map to getpagesize, following common WASI port + configuration. The browser module has no real OS user IDs or privilege boundary. + These values supply neither randomness nor identity credentials. This portability + assumption does not emulate general POSIX security. + + Bindings use SDK libclang/WASI sysroot, target wasm32-wasip1, and + -fvisibility=default; without explicit visibility, bindgen omitted declarations. + Rust's bundled WASI libc precedes SDK libraries; reversed order failed to link + __wasi_init_tp. SDK libraries remain available for emulated-getpid. These were + toolchain integration failures; generated cryptographic bindings were not edited. BROWSER CAPABILITIES @@ -123,11 +116,9 @@ BROWSER CAPABILITIES Listed filesystem/network operations return NOTCAPABLE or BADF. Unknown imports fail before instantiation. Standard output is capped at 65536 chars. - Those capability denials protect against accidentally connecting the WASI - module to host storage or networking. They do not isolate it from malicious - JavaScript delivered by the same server. Memory, clocks, randomness, and - imported bridge functions remain part of the trusted browser environment. - A test deadline closes Chromium after 120 seconds if execution stalls. + Denials prevent accidental host storage/network access, not malicious JS from + the same server. Memory, clocks, randomness, and bridge imports remain trusted. + The test closes Chromium after 120 seconds if execution stalls. VERIFICATION @@ -144,25 +135,20 @@ VERIFICATION A modified module requesting an unknown host import is also rejected before instantiation. These negative tests require the expected failure reason. - The harness also observes no external requests, cookies, localStorage, - sessionStorage, IndexedDB databases, or service-worker registrations. - Its HTTP responses carry Cache-Control: no-store. This establishes only - this probe's behavior, not that browsers/OSes cannot retain memory, caches, - crash dumps, swap, or restored state. A complete chat session does not exist. - - The native tests, WASI build, and browser test are separate checks. A native - pass cannot stand in for browser execution. A functional pass and a clean - vulnerability scan cannot stand in for a cryptographic or side-channel audit. + The harness observed no external requests, cookies, localStorage, + sessionStorage, IndexedDB databases, or service-worker registrations; responses + carry Cache-Control: no-store. This concerns only the probe. Browsers/OSes can + retain memory, caches, crash dumps, swap, and restored state. No complete chat + session existed at this checkpoint. Native tests, WASI build, and browser + execution are separate gates; functional tests and scans are not cryptographic + or side-channel audits. DEPENDENCY POLICY REVIEW - The RustSec database reports no advisories for the current resolved graph. - No advisory ignore was added. Bans on wildcards, unknown Git/registry sources, - and unreviewed duplicate versions remain enabled. The following existing - upstream API generations cannot be unified merely by cargo update. Duplicate - exceptions match only the exact older version; other versions remain subject - to the duplicate ban. All these packages still undergo advisory and license - checks. Cargo.lock pins both sides of each pair. + RustSec reports no advisories for this resolved graph; no ignore was added. + Bans on wildcards, unknown Git/registry sources, and unreviewed duplicates remain. + cargo update cannot unify these upstream API generations. Exceptions match only + exact older versions; advisory/license checks still apply. Cargo.lock pins both sides: block-buffer 0.10.4 vs 0.12.1 crypto-common 0.1.7 vs 0.2.2 @@ -196,23 +182,20 @@ DEPENDENCY POLICY REVIEW macros and other dependencies use syn 3. Changing that would require upstream migration or unrelated dependency downgrades. - The only new license allowance is ISC, scoped to libloading, a bindgen/clang - dependency. GNU-compatible third-party licenses remain correctly attributed. - cargo-about generates notices for the complete workspace. The static OpenSSL - C library and SDK are not Rust crates; their original licenses and sources - must accompany any distributed browser artifact as appropriate. Source - OpenSSL LICENSE.txt is Apache-2.0. Do not treat the Rust notice page alone - as complete documentation of external C/toolchain distribution obligations. + The only new license allowance is ISC for bindgen/clang's libloading. + GNU-compatible licenses retain attribution; cargo-about covers the workspace. + OpenSSL C and SDK are outside Cargo. Distributed browser artifacts must carry + their original licenses/sources as required. OpenSSL LICENSE.txt is Apache-2.0. + Rust notices alone do not cover external C/toolchain distribution obligations. EXTERNAL LIBRARY MAINTENANCE - cargo-deny does not audit the externally built OpenSSL C archive or SDK. - Review OpenSSL's release/advisory pages separately and rebuild when needed: + cargo-deny excludes external OpenSSL C and SDK. Review separately; rebuild as needed: https://openssl-library.org/news/timeline/ https://openssl-library.org/news/vulnerabilities-3.6/ - OpenSSL 3.6.5 is the tested security-patch release dated 2026-09-29. A green - Rust audit is not a lifetime security guarantee for this pinned C version. - Choose and document a supported update policy before production deployment. + Tested OpenSSL 3.6.5 is the 2026-09-29 security-patch release. A Rust audit + does not guarantee this pinned C version's future security. Document a supported + update policy before production deployment. REPRODUCE FROM THE STACK ROOT @@ -229,12 +212,10 @@ REPRODUCE FROM THE STACK ROOT PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:crypto cargo stack check - The build script pins archive versions and hashes, configures static OpenSSL, - installs it under .tools/openssl-wasi, builds the Rust WASI command, and prints - its SHA-256. It does not download/use an unverified precompiled OpenSSL binary. - It may reuse already extracted sources; use a fresh ignored tools/build tree - when independently verifying the source archive rather than trusting a - previously modified extraction. Downloads and test artifacts are not secrets. + The script pins versions/hashes, builds static OpenSSL under .tools/openssl-wasi, + builds the Rust WASI command, and prints its SHA-256. It uses no unverified + precompiled OpenSSL. Extracted sources may be reused; independent verification + needs a fresh ignored tools/build tree. Downloads/test artifacts are not secrets. Build logs and complete dependency trees are local ignored diagnostics in .tools/chat-openssl-*.log and .tools/chat-openssl-duplicates.txt. The native @@ -246,9 +227,8 @@ REMAINING WORK 7fba6b96377619ef41f056d4027c4409107372e9300b2dd69be865e72892df79 This is a diagnostic identifier, not a cross-host reproducibility promise. - This removes the specific Rust-backend dependency blocker and demonstrates - the fixed algorithms in a browser. It is not a complete messaging service, - audit of OpenSSL/WASI/JIT timing behavior, LibreJS certification, or proof - against malicious delivery. The file format, authentication, server/database, - quotas, hostile-input handling, pagination/counts, backup recovery, complete - session lifecycle, and browser-state tests still need implementation. + This checkpoint removed the Rust-backend blocker and demonstrated fixed + algorithms in-browser. It was not a complete messenger, OpenSSL/WASI/JIT timing + audit, LibreJS certification, or proof against malicious delivery. File format, + authentication, server/database, quotas, hostile-input handling, pagination/counts, + recovery, session lifecycle, and browser-state tests remained to implement. diff --git a/docs/CHAT-PRODUCTION.txt b/docs/CHAT-PRODUCTION.txt index 03f5ba4..fdb48a6 100644 --- a/docs/CHAT-PRODUCTION.txt +++ b/docs/CHAT-PRODUCTION.txt @@ -16,70 +16,57 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. PRODUCTION CHAT INTEGRATION - 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. - - Four services run through rootless Podman: Caddy, cgit, SearXNG, and chat. - The release contains statically linked x86_64 GNU/Linux management and chat - binaries, the WASM browser module, exact corresponding sources, and saved - native container images. The chat image starts FROM scratch: no compiler, - shell, package manager, or first-party Python. Its root filesystem is read - only, capabilities are dropped, and only its private data directory is writable. - - Caddy terminates HTTPS at CHAT_HOST and redirects www.CHAT_HOST while keeping - the requested path. CHAT_UPSTREAM defaults to chat:8080 on the private - container network. Chat publishes no host ports. Production publishes only - the gateway HTTP and TCP/UDP HTTPS ports. Existing host SSH policy is separate. - - The gateway supplies an explicit external origin selected from root .env. - The server accepts that exact HTTPS origin or the dedicated local gateway - origin. Forwarded client headers never select the trusted origin. Origin - checks supplement cryptographic authentication; they are not authentication. + Implemented on main. Builds/tests do not activate the VPS. Experimental; + no independent cryptographic or application security audit. Read + CHAT-APPLICATION.txt limitations before private use. + + Rootless Podman runs Caddy, cgit, SearXNG, and chat. Releases contain static + x86_64 GNU/Linux management/chat binaries, browser WASM, exact corresponding + sources, and native images. Chat starts FROM scratch: no compiler, shell, + package manager, or first-party Python. Root filesystem is read-only; + capabilities are dropped; only private data is writable. + + Caddy serves HTTPS at CHAT_HOST and redirects www.CHAT_HOST, preserving paths. + CHAT_UPSTREAM defaults to private chat:8080. Chat publishes no host ports; + only gateway HTTP and TCP/UDP HTTPS are published. Host SSH policy is separate. + + Root .env selects the explicit external origin. Chat accepts exactly that + HTTPS origin or the dedicated local gateway origin. Forwarded client headers + cannot select it. Origin checks supplement cryptographic authentication. BUILD ON THE WORKSTATION - Current releases require an x86_64 GNU/Linux build host and matching target. - Use the pinned Rust toolchain, Podman, Git, GnuPG, a GCC-compatible C compiler, - Linux UAPI headers, libclang, pkg-config, make, Perl, curl, tar, Node >=22.18.0, - and npm. Native - workspace checks need OpenSSL 3.5+ development libraries. Browser testing - additionally needs the pinned Playwright, Chromium, and Firefox. These tools remain - on the workstation; production does not need Cargo or a compiler. + Build host and target must be x86_64 GNU/Linux. Requires pinned Rust, Podman, + Git, GnuPG, GCC-compatible C compiler, Linux UAPI headers, libclang, pkg-config, + make, Perl, curl, tar, Node >=22.18.0, npm, and OpenSSL 3.5+ development libraries. + Browser tests also need pinned Playwright, Chromium, and Firefox. Workstation + tools stay local; production needs neither Cargo nor compiler. cargo stack release - This first builds/checks TypeScript, then runs formatting, strict Clippy, - all workspace tests, rustdoc, cargo-deny, - and cargo-about. It then builds static native binaries, the WASI module, - corresponding sources, the chat/cgit images, and the complete image export. - THIRD-PARTY-LICENSES.html is regenerated from the full workspace before - packaging. Check the archive checksum and test recovery before deployment. + Runs TypeScript build/checks, formatting, strict Clippy, workspace tests, + rustdoc, cargo-deny, and cargo-about. Builds static binaries, WASI, exact + sources, chat/cgit images, and complete image export. Regenerates workspace + THIRD-PARTY-LICENSES.html. Verify archive checksum and recovery before deployment. infra/chat/build-native.sh verifies OpenSSL 3.6.5's original source archive: a2157c2830efdec3788939b00c9b0638306d3f0bbb76dc4832ee503bb397df98 It verifies Alpine musl-dev 1.2.6-r3 headers: 310b51cff12e1d5ce5f135c558a82e2550427da5465bbd16c9ff9b05e63ee3d9 - Sources come from the official OpenSSL GitHub release and Alpine CDN. The - compiler uses isolated musl/GCC built-in headers plus host Linux UAPI headers; - glibc headers are excluded. OpenSSL is static, has no dynamic providers, and - seeds its RNG through getrandom. The native cryptographic compatibility probe - must pass after the build. WASI uses its separately verified SDK and OpenSSL - build recorded in CHAT-OPENSSL-MIGRATION.txt. No crypto algorithm was changed. - - Cached inputs live only under .tools/. Rebuild OpenSSL when its version, - source, or build flags change. An OpenSSL update requires reviewing upstream - security notices, updating every affected URL/hash, native and WASI rebuilds, - rerunning both browsers and cargo-deny, regenerating notices and exact source, - and repeating release recovery. Never approve a dependency advisory merely - to make the build pass. cargo-deny does not audit C/OpenSSL advisories. - - The source download includes first-party code, Cargo-vendored dependencies, - and unmodified OpenSSL source. Toolchain/sysroot development inputs are not - bundled as application sources. Saved images preserve the tested runtime. - An ARM host needs a separately supported native release; do not copy these - x86_64 binaries there and assume they will work. + Sources: official OpenSSL GitHub release and Alpine CDN. Compilation uses + isolated musl/GCC built-in and host Linux UAPI headers, excluding glibc. + Static OpenSSL has no dynamic providers and seeds through getrandom. The + native compatibility probe must pass. WASI uses separately verified SDK/OpenSSL + inputs in CHAT-OPENSSL-MIGRATION.txt. Cryptographic algorithms stay fixed. + + Inputs cache under .tools/. Version/source/flag changes require an OpenSSL + rebuild. Updates require upstream advisory review, every affected URL/hash, + native/WASI rebuilds, both browsers, cargo-deny, regenerated notices/sources, + and release recovery. Never waive advisories to pass. cargo-deny excludes C/OpenSSL. + + Source downloads include first-party code, Cargo-vendored dependencies, and + unmodified OpenSSL, excluding development toolchain/sysroot inputs. Saved + images preserve tested runtime. ARM requires a separately supported native release. LOCAL MODES AND ORIGIN BINDING @@ -98,36 +85,31 @@ LOCAL MODES AND ORIGIN BINDING https://CHAT_HOST/ with the configured HTTPS_PORT var/data/chat - These are distinct browser origins and require separate identity files. The - direct process and production deliberately use the same relative database - name on their respective machines. Do not switch an installation containing - valuable identities between direct development and production. Use a fresh - restored release directory for integration tests. Rebuild the release after - edits to refresh the packaged browser, server, sources, notices, and image. + Distinct origins require separate identity files. Direct development and + production share a relative database path on separate machines; do not switch + valuable installations between them. Integration tests need a fresh restored + release. Rebuild after edits to refresh browser, server, sources, notices, and image. - The single root .env holds public hostnames, ports, upstreams, backup settings, - SEARXNG_SECRET, and CHAT_SETUP_TOKEN. The example is public; actual .env is - ignored and never included in public releases or source downloads. Caddy keys - and chat databases are generated private runtime state under var/data. - Initialization preserves configured values and generates missing secrets. + One root .env holds hostnames, ports, upstreams, backups, SEARXNG_SECRET, and + CHAT_SETUP_TOKEN. Only the example is public; releases/source downloads exclude + actual .env. Caddy keys/chat databases stay under var/data. Initialization + preserves configured values and generates missing secrets. DEPLOY AND CREATE THE REAL OWNER FILE - Use the release upload/activation instructions in OPERATIONS.txt. Extract - the new prebuilt management binary into var/incoming/bootstrap and invoke - it with --root pointing at the current installation. Use the management - binary from that verified release so activation understands its service - schema. It verifies the archive and installs packaged chat artifacts before - starting services. + Follow OPERATIONS.txt. Extract the verified release's new management binary + into var/incoming/bootstrap; invoke with --root set to the current installation. + The new binary understands its release schema, verifies the archive, and + installs chat artifacts before startup. The host needs rootless Podman prerequisites, user linger, low-port permission, DNS A/AAAA records for CHAT_HOST and www.CHAT_HOST, and the normal 80/443 firewall rules. Caddy obtains and renews public certificates automatically. Public certificate validation requires standard reachable ACME ports. The systemd user service runs ./bin/stack up --production at boot and - ./bin/stack down on stop. Podman restart policies restart failed containers. - Neither mechanism compiles code or requests a registry pull for a complete - release on the matching architecture. Check all four services after activation: + ./bin/stack down on stop. Podman restarts + failed containers. Complete matching-architecture releases need no compilation + or registry pull. Check all four services after activation: ./bin/stack status @@ -136,57 +118,48 @@ DEPLOY AND CREATE THE REAL OWNER FILE The displayed limitations are CHAT-APPLICATION.txt. Chat has its own origin; the main website remains JavaScript-free. Its Message Me links lead to chat. - In the browser on the production HTTPS origin, choose OWNER SETUP. Read the - setup token from the production root .env locally; never publish it or send it - through chat. Choose a unique owner-file password, save the downloaded file, - reopen it, and unlock it. Store that file and password in KeePassXC and keep - a protected backup of the database. The setup token cannot replace this file. - Never copy a development owner file and silently change its pinned origin. + At the production HTTPS origin, choose OWNER SETUP. Read the root .env token + locally; never publish or send it through chat. Choose a unique password; + save, reopen, and unlock the downloaded owner file. Keep file/password in + KeePassXC with a protected database backup. The token cannot replace the file. + Never silently change a development file's pinned origin. BACKUP, RESTORE, AND KEY LOSS A complete encrypted application export: ./bin/stack backup --include-images - Download the .gpg and .sha256 files off the VPS. A backup on the same VPS is - vulnerable to loss of that VPS. Existing configured backup recipients apply. - This export includes the single .env, consistent SQLite snapshots for chat - and chat-local, Caddy certificate state, repositories, static binaries, WASM, - sources, and exact container images. SQLite uses its online backup API; chat - is left unpaused so a pending writer cannot block snapshot completion. - The database contains ciphertext and public keys, plus the metadata described - in CHAT-APPLICATION.txt. The owner private file and GnuPG secret key are not - server data; back them up separately. + Copy .gpg and .sha256 off the VPS; local backups cannot survive VPS loss. + Configured recipients apply. Export includes one .env, online SQLite snapshots + for chat/chat-local, Caddy certificates, repositories, static binaries, WASM, + sources, and exact images. Chat stays unpaused so pending writers can complete. + Database contents are ciphertext/public keys and CHAT-APPLICATION.txt metadata. + Owner private file and GnuPG secret key need separate backups. Restore to a new directory, verify, then explicitly start production mode: ./bin/stack restore /path/export.tar.gz.gpg /path/stack-restored cd /path/stack-restored ./bin/stack up --production - Restore defaults to local mode and changes container project names to avoid - accidentally replacing another installation. up --production selects the - production database and HTTPS origin again. Keep the same hostname/origin, - point DNS at the replacement host, and use unchanged owner/visitor files and - passwords. A new IP does not change an origin. A changed hostname or HTTPS - port does. Do not expose two restored copies simultaneously under one origin. - Server restart invalidates sessions; reopening identity files authenticates - again. Historical ciphertext and counters persist across restart and recovery. + Restore defaults to local mode with fresh project names, avoiding replacement + of another installation. up --production reselects production database/origin. + Keep hostname/origin, repoint DNS, and use unchanged identity files/passwords. + IP changes preserve origin; hostname/HTTPS-port changes do not. Never expose + two restored copies under one origin. Restart invalidates sessions; reopening + files authenticates again. Historical ciphertext/counters persist. - Losing the owner private file cannot be repaired by CHAT_SETUP_TOKEN. If its - backups are also lost, reset deliberately deletes every stored conversation - and message. It does not decrypt or recover anything. This backend operation - has no HTTP endpoint and requires filesystem/Podman access: + CHAT_SETUP_TOKEN cannot recover a lost private file. If backups are also lost, + reset deletes every conversation/message; it decrypts and recovers nothing. + Reset has no HTTP endpoint and requires filesystem/Podman access: ./bin/stack chat --owner-fingerprint ./bin/stack down ./bin/stack chat --reset-owner PASTE_CURRENT_OWNER_FINGERPRINT_HERE ./bin/stack up --production - A running server holds a filesystem lock; reset refuses until it stops. The - full fingerprint must match. Root .env and previous exports are preserved. - Create a new production owner file afterward. Old visitor files reject its - changed pinned owner key and need a new chat identity. A reset does not erase - copies already present in exports or external snapshots. + Reset requires a stopped server and matching full fingerprint. Root .env and + exports survive. Create a new production owner file; old visitor files reject + its changed key and need fresh identities. Exports/external snapshots are not erased. VERIFICATION diff --git a/docs/CHAT-SECURITY-REVIEW.txt b/docs/CHAT-SECURITY-REVIEW.txt deleted file mode 100644 index 1bb1108..0000000 --- a/docs/CHAT-SECURITY-REVIEW.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/>. - - -CHAT CRYPTOGRAPHY SECURITY REVIEW - - Date: 2026-10-30. Historical review of the initial Rust backend. - The current OpenSSL migration is recorded in CHAT-OPENSSL-MIGRATION.txt. - At that checkpoint, private-message use and deployment were not ready. - This historical review is not the current implementation status; see - CHAT-APPLICATION.txt and CHAT-PRODUCTION.txt for the implemented application. - -FIXED REQUIREMENT - - Encryption must remain RFC 9980 ML-KEM-1024 + X448 using v6 keys. - The compatibility probe pairs it with ML-DSA-87 + Ed448 signatures. - No fallback encryption profile is implemented or approved. - The findings below apply to checkpoint 436e217, before the backend change. - -TEST RESULTS - - Sequoia OpenPGP 2.4.2 with its Rust backend generated password-protected v6 - secret keys, serialized and reimported them, signed UTF-8 content, encrypted - to both participants, and decrypted successfully for both participants. - Wrong passwords, unexpected signers, and modified ciphertext were rejected. - The same probe passed in actual Chromium using Rust compiled to WASM. - - Functional tests are not a cryptographic audit, constant-time analysis, - conformance certification, or demonstration that side channels are absent. - The test uses no user-supplied key files and does not provide chat service. - -RUSTSEC-2026-0387: REACHABLE DEPENDENCY - - Sequoia 2.4.2's crypto-rust backend selects cx448 0.1.1 for both X448 - and Ed448. cx448 depends on crypto-bigint 0.5.5. - - Source paths within these exact published crates: - - sequoia-openpgp/src/crypto/backend/rust/asymmetric.rs - x448_generate_key, x448_derive_public, x448_shared_point - ed448_generate_key, ed448_sign - cx448/src/x448.rs - PublicKey::from(&Secret), Secret::as_diffie_hellman - cx448/src/curve/montgomery.rs - Montgomery scalar multiplication and projective-to-affine conversion - cx448/src/field.rs - elliptic_curve::bigint and constant-modulus Montgomery representation - cx448/src/field/element.rs - field subtraction, multiplication, inversion - cx448/src/field/scalar.rs - scalar arithmetic using crypto-bigint integer operations - - The flagged crate is part of the required curve arithmetic. It cannot be - dismissed as an unused RSA dependency. The advisory covers timing variation - in arithmetic intended to be constant-time and identifies >=0.7.6 as fixed. - cx448 0.1.1 requires the incompatible 0.5 series. Updating Cargo.lock alone - cannot satisfy that requirement with 0.7.6. Source changes or another backend - would require a separate review and tests; no local cryptographic patch has - been invented to bypass this gate. - - This establishes a reachable affected dependency and prevents a claim of - unreachability. It does not prove practical key extraction from this WASM - binary on a particular browser/CPU. No such exploit has been demonstrated. - The hybrid construction's independent component may preserve protection - under some component failures; that is not grounds for ignoring the audit. - - Advisory: https://rustsec.org/advisories/RUSTSEC-2026-0387.html - -RUSTSEC-2023-0071: RSA - - Sequoia's crypto-rust feature also includes rsa 0.9.10. The probe generates - only the specified PQ identities and calls their corresponding primitives; - it does not generate an RSA key or exercise RSA private-key operations. - - That observation applies only to this closed, generated-input probe. It is - not proof that a future importer, certificate verifier, authentication - endpoint, or decryption interface cannot be induced to use another algorithm. - The future application needs an explicit supported-algorithm policy and - hostile-input tests before any narrower exception could be assessed. - - Advisory: https://rustsec.org/advisories/RUSTSEC-2023-0071.html - -BACKEND CHECK - - In the installed Sequoia 2.4.2 source, the Nettle and Botan asymmetric - backends report these required composite algorithms unsupported. The OpenSSL - backend conditionally supports them, depending on the available OpenSSL - version/features. Its browser/WASM build has not been demonstrated here. - Native OpenSSL support alone would not satisfy client-side browser encryption. - - The Rust backend requires allow-experimental-crypto and - allow-variable-time-crypto. These are explicit prototype build opt-ins, - not security approvals or claims that the selected operations are safe. - -OTHER AUDIT GATES - - The new dependency graph also contains multiple crate versions. Its exact - graph is pinned in Cargo.lock. Duplicate bans have not been relaxed, and - no vulnerability advisory has been ignored. License permissions for Sequoia - and its dependencies must remain correctly attributed in generated notices. - - The project check must audit the whole workspace. A root-package-only - cargo-deny invocation misses a workspace member that is not a dependency - of the root CLI. The audit invocation was updated to use --workspace. - -GATE AT THE TIME OF THIS REVIEW - - Retain the fixed algorithms. Resolve the curve-backend dependency through - a reviewed upstream-compatible fix or demonstrate an acceptable alternative - backend in the browser. Repeat the native and browser tests, review imported - hostile inputs, and pass the full dependency audit before private-message use. diff --git a/docs/CONFIGURATION.txt b/docs/CONFIGURATION.txt index fc18c41..f0f8457 100644 --- a/docs/CONFIGURATION.txt +++ b/docs/CONFIGURATION.txt @@ -15,137 +15,129 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. CENTRAL CONFIGURATION - Each installation has one root .env for deployment settings and secrets. - The published .env.example documents every supported setting with public - defaults, private placeholders, and comments. Hostnames are public information; - this arrangement centralizes configuration, not secrecy or access control. - Public values remain visible in generated pages, DNS, certificates, and URLs. - - Existing installations keep their configured secrets and settings. Missing - public defaults are appended to the same .env by cargo stack config, service - initialization, or chat initialization. No second environment file is created. - The example is also the shared Rust configuration library's default source, - so missing public settings remain compatible with older exports. + One root .env holds each installation's deployment settings and secrets. + Public .env.example documents every supported key, public default, private + placeholder, and comment. Hostnames remain public in generated pages, DNS, + certificates, and URLs. Centralization is not secrecy or access control. + + cargo stack config, service initialization, and chat initialization preserve + existing settings/secrets and append missing public defaults to the same .env. + No second environment file. The shared Rust configuration library also reads + defaults from .env.example, keeping older exports compatible. PUBLIC SETTINGS BASE_DOMAIN - Root web/WKD domain. www aliases are derived from each configured host. + Root web/WKD domain. Derive www aliases from each configured host. SITE_HOST, GIT_HOST, SEARCH_HOST, WKD_HOST, CHAT_HOST - Fully qualified DNS names without schemes, paths, or ports. These - configure production HTTPS routes and their canonical www redirects. - CHAT_HOST also selects the exact trusted external chat origin. + Fully qualified DNS names; no scheme, path, or port. Set production + HTTPS routes and canonical www redirects. CHAT_HOST also selects the + exact trusted external chat origin. CHAT_LOCAL_HOST - Dedicated development gateway hostname ending in .localhost. Default: + Development gateway hostname ending in .localhost. Default: chat.localhost. Browser identity files bind to this origin and local port. WEB_BIND - Production host publish address. Default :: serves IPv4 and IPv6. Use - 127.0.0.1 for isolated staging; development mode always uses loopback. + Production publish address. Default :: serves IPv4/IPv6. Use 127.0.0.1 + for isolated staging. Development always binds loopback. HTTP_PORT, HTTPS_PORT - Production Caddy listener and Podman published ports. HTTPS also publishes - UDP for HTTP/3. Defaults are 80 and 443. Generated HTTPS links include a - nonstandard HTTPS port when configured. Ordinary public certificate - validation still needs the CA's standard external validation ports or an - appropriate alternative certificate/routing arrangement. Setting ports - alone does not configure DNS, firewall rules, or external port forwarding. + Caddy listeners and Podman published ports; defaults 80/443. HTTPS also + publishes UDP for HTTP/3. Generated links include nonstandard HTTPS ports. + Public certificate validation still needs standard external CA validation + ports or alternative certificate/routing arrangements. Port settings do + not configure DNS, firewall rules, or external forwarding. LOCAL_HTTP_PORT - Local Caddy HTTP port on 127.0.0.1. HTTPS host port is this value plus one. - Local Caddy still listens on container ports 80/443. --port overrides the - local port for that invocation. Existing installation/project names and - image state remain in var/state.json; an explicit .env local port takes - precedence over the previously saved port. + Local HTTP on 127.0.0.1; host HTTPS port is this value plus one. Caddy + still listens on container ports 80/443. --port overrides one invocation. + var/state.json retains installation/project names and image state. + An explicit .env local port overrides the saved port. CGIT_UPSTREAM, SEARXNG_UPSTREAM, CHAT_UPSTREAM - Proxy connection targets such as cgit:8080, searxng:8080, and chat:8080. These are - addresses, not upstream bind settings. The bundled images' internal 8080 - listeners and health checks remain image contracts. Changing a target - to another host/port requires an actual service at that address. + Proxy targets, e.g. cgit:8080, searxng:8080, chat:8080. Not bind settings. + Bundled internal 8080 listeners and health checks remain image contracts. + A changed target needs an actual service at that host/port. CHAT_BIND, CHAT_ORIGIN Direct development socket and exact browser origin. Defaults: - 127.0.0.1:9080 and http://127.0.0.1:9080. Direct development requires - loopback and an exact HTTP origin match. --bind overrides CHAT_BIND. - The container binds privately to 0.0.0.0:8080; its trusted origin comes - from CHAT_HOST/HTTPS_PORT or CHAT_LOCAL_HOST/LOCAL_HTTP_PORT instead. - Identity files pin their origin; editing these values does not migrate - encrypted identities or grant access on another origin. + 127.0.0.1:9080 and http://127.0.0.1:9080. Require loopback and an exact + HTTP origin match. --bind overrides CHAT_BIND. Containers bind privately + to 0.0.0.0:8080; trusted origin comes from CHAT_HOST/HTTPS_PORT or + CHAT_LOCAL_HOST/LOCAL_HTTP_PORT. Identity files pin their origin. + Editing these settings neither migrates encrypted identities nor grants + access on another origin. BACKUP_RECIPIENT, BACKUP_PUBLIC_KEY - Public OpenPGP fingerprint and project-relative public key path used for - encrypted exports. --recipient and --key override them. The secret GnuPG - key and revocation certificate remain outside the project. + Public OpenPGP fingerprint and project-relative public key path for + encrypted exports. --recipient/--key override them. Keep the secret + GnuPG key and revocation certificate outside the project. PRIVATE SETTINGS SEARXNG_SECRET - Generated on first stack initialization. Existing values are preserved. + Generated at first stack initialization; existing values preserved. CHAT_SETUP_TOKEN - Generated by chat initialization or first stack startup. Used only to authorize first owner - registration, including a fresh registration after an explicit backend - reset. It cannot recover a lost owner private key. + Generated by chat initialization or first startup. Authorizes only + first owner registration, including after an explicit backend reset. + Cannot recover a lost owner private key. RENDER AND APPLY - Edit .env locally. Never commit or publish it. Inspect the commented example - for exact keys. Hostnames, ports, socket addresses, fingerprints, and paths - are validated before use. Diagnostic formatting never dumps the config map. - Invalid environment-file syntax is reported without echoing its raw contents. + Edit .env locally; never commit or publish it. See .env.example for exact + keys. Validate hostnames, ports, sockets, fingerprints, and paths before use. + Diagnostics never dump the config map or echo invalid .env contents. Render public deployment files without starting services: cargo stack config cargo stack config --production - Outputs are var/local/ or var/production/: + Output under var/local/ or var/production/: Caddyfile cgitrc web/ - infra/Caddyfile, infra/Caddyfile.local, infra/containers/cgit/cgitrc, and the - first-party website HTML are templates using {{PUBLIC_KEY}} placeholders. - Do not run Caddy directly on an unrendered template. Podman mounts the generated - files. Public host/origin changes reach Caddy routes, www redirects, website - links, the cgit clone prefix, and the chat page's navigation. Local rendering - uses /git and /search paths and http://CHAT_LOCAL_HOST:LOCAL_HTTP_PORT for chat. + Templates use {{PUBLIC_KEY}} placeholders: infra/Caddyfile, + infra/Caddyfile.local, infra/containers/cgit/cgitrc, first-party website HTML. + Never run Caddy on unrendered templates. Podman mounts generated files. + Public host/origin changes reach routes, www redirects, website links, cgit + clone prefixes, and chat navigation. Local rendering uses /git, /search, + and http://CHAT_LOCAL_HOST:LOCAL_HTTP_PORT for chat. - To apply changes to the existing services: + Apply to existing local services: cargo stack up --local - Production uses its prebuilt management command and images: + Production uses prebuilt management command/images: ./bin/stack up --production - Rendered website files can be read by an already running file server, while - listeners, container environment, and loaded Caddy configuration require the - service update above. Restart the local chat server with cargo stack chat to - load its new bind, origin, or public navigation settings. Reopen your identity - file afterward, as with any chat restart. + Running file servers can read rendered website updates. Listener, container + environment, and loaded Caddy changes need the service update above. + Restart direct local chat with cargo stack chat for new bind/origin/navigation + settings. Reopen your identity file afterward, as after any chat restart. PUBLICATION AND LIMITS - The shared stack-config crate uses an explicit public allowlist for template - substitution. A {{CHAT_SETUP_TOKEN}} or other private/unknown placeholder - causes an error rather than publishing its value. Generated public pages and - proxy configuration never receive a full environment dump. Chat receives the public configuration allowlist plus CHAT_SETUP_TOKEN; - other containers receive only their declared service secrets. Caddy uses - rendered public configuration and does not need the .env or private tokens. - - The root .env, runtime files, local render outputs, exports, and tool caches - remain ignored by Git. Source templates, the commented example, validated - defaults, and this configuration implementation are public. Full encrypted - backups include the single .env; source-only releases do not include it. - - Personal content and attribution remain source content: copyright headers, - author names, canonical contact information, public key material/WKD hashes, - project repository metadata, and GNU license links. Changing a deployment - hostname does not create a new email identity or regenerate WKD keys. - Image digests, source hashes, and fixed crypto/protocol/resource bounds remain - reviewed reproducible code/configuration rather than private deployment knobs. + stack-config substitutes only explicitly allowlisted public values. + {{CHAT_SETUP_TOKEN}} and other private/unknown placeholders fail instead of + exposing values. Public pages/proxy config never receive a full environment + dump. Chat receives the public allowlist plus CHAT_SETUP_TOKEN; other + containers receive only declared secrets. Caddy needs rendered public config, + not .env or private tokens. + + Git ignores .env, runtime files, local renders, exports, and tool caches. + Source templates, commented example, validated defaults, and configuration + implementation remain public. Full encrypted backups include the single + .env; source-only releases exclude it. + + Personal content stays in source: copyright, author names, canonical contact, + public keys/WKD hashes, repository metadata, GNU license links. Changing a + hostname creates no new email identity and regenerates no WKD keys. + Image digests, source hashes, fixed crypto/protocol/resource bounds remain + reviewed reproducible code/config, not private deployment knobs. diff --git a/docs/GIT-HISTORY.txt b/docs/GIT-HISTORY.txt deleted file mode 100644 index 410b53b..0000000 --- a/docs/GIT-HISTORY.txt +++ /dev/null @@ -1,84 +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/>. - -GIT IDENTITY AND SIGNATURE REWRITE - - Requested to replace the historical ops <ops@localhost> identity with - Doan Luu Duc Tai <doan@luuduct.ai> and sign the history with the canonical - RSA-2048 key 3346AA3150F8F16828BB0D14F8C66DF77AFECEA6. - - Ten historical author identities and their corresponding committer identities - 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. - 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. - Existing objects and reflogs may still contain old IDs: this is an authorship - correction, not a claim of private-data removal or historical erasure. - -EXISTING CLONES - - The active development checkout is already aligned. Other clones must fetch - the new history instead of using an ordinary pull across divergent histories. - Preserve local-only commits and working changes first. A fresh development - clone is also possible; keep private .env and runtime data out of Git. - - For an existing clone with no local-only commits: - - git fetch origin - git switch main - git reset --keep origin/main - - --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. - Git changes do not remove or replace ignored .env or var/ data. - -ORIGINAL TO REWRITTEN COMMITS - - 47fcc566884d7078c153cdce9fb62399fcca5d9e c4b2f892a1c6508360a683c90e8c4d596c521336 - 37d5e4a152df67d247349d2ed289bf65859ead53 020d3454cad6619bf25c6ecb0a293502f40364bd - 8a327a41cdce40933b977f7c6662929488bcf83e 64a1b484abb96c91da9aa23e0e45576749f6cdfe - 3a8956f9cb85184ae2b8202d7a733124a0d3f95f 9599590f67c24f70c400b967d162095c63f6af61 - 2f5c323be4a44b80cf9e39d51210776146a77cbd 1632c88ba08c62966c1f0b1578741d8af007e6fd - 118ba081389cfd80b38c9c691fd6d75f6497dcb5 274e70679b83bcac3dee3599bd9389a3332462ec - 38aa5d1f2a8dfc8ea97c0fdce8feae7e37795533 5317fa43b79e4251fcbcff2b4f1243a961ac00fe - 902cfd395fb03d6147813560ac5fcd7146702a1d 463c6f48a06730c29f89b2f376e68dc805df5cc9 - e373f154dbeacc5a0e83b4ec73c3aa316239c029 5386a63bfb2f14cab99874e7c414e1a418b01f67 - 006a1e94075e90fccfe248cd66bf7d0586a86279 84960925108eb2b5950d4c299b15b18893e0c0d0 - 19a0280d7dabd4ca637d8070cc7d3691a0e85bd1 909dce458d4bbef6710c2b4a67cd906902bb7f3f - c06e29dae4bb290fd2849f69da1bfa940c5a8222 5bed750baa5d782427e98550d34124f569e2fff8 - 714866be200b882be437375006180456284bab1c 9c7dd654512b8f51af15d50dd75a515566723be7 - 9f070f7ad0952c61b4ee66d2a01ff1bdf7ade0a8 cad7ab1e1ab1dde8ff4ba349cd5b1a05bbd32b05 - faaac8558431c80a6b8fbcf2c8f17f16d8602ab6 1386bd16b0fd796314d9ad70aede0946bd5c46bd - 92bf96961c09d7df6b1bfea72eb8a107bcf9e221 d546193ee543a5b1a0a097d0a7deca76e81b7de2 - 0a0cdc0c44dd8b4fb44d8a859962c40c593e98eb f196233257d247c94550cf822b91bc3c9d8a7f8f - 1206813d47e8602f08cbeaf27e73453e089e7c52 834a21a7cadce64889856a2a7521440a1519e244 - d611c869eb12e7fff5754be31775f82200ec958b b46ece18a424eaea3f396ddae7e45e91d1c0e742 - 436e217c7858888702d2b6d9e655597ccadb7281 f196c27faf265cd14d8d7accf58e87b4df3c8a91 - 7a0ce2805258e8ac061202904379692d53d5dc95 cf2f0e8c6752c401f152a8e534ba166839d4307e - 774074bb2bbd3bc07f7094cdce0935eca7520725 a0057b13fa4b6bed8aee3132001e79a245efabc8 - 143880db086c617b843340ca7023a879507761f8 0a4da3b86eb69f0f09b802a55e36fa9cf1bbf38c - 556eaa133e9cfe7f4c8e542708119fdfd311357e e6b350a1d48ca0490b7a3447bb8d0a4235514b76 - b7374fe09306c495131cf3673addb76a1dcf017d 3034705b6679bff1802c4180b7b4711b94fed7f9 - be16d00a8a4750028073e018ab2c58d54af192c4 c3b361c45ac8dd898d5c83a161abed5fc138b6c0 - 28a772cab50b1064e317aedbe4689aea286b1ec4 6933ec28be3dac0dc17cd634c663db3b4818caad diff --git a/docs/LINTING.txt b/docs/LINTING.txt index 33084e9..bd1cdac 100644 --- a/docs/LINTING.txt +++ b/docs/LINTING.txt @@ -15,153 +15,129 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. STRICT LINT POLICY - Cargo.toml is the workspace policy; all four packages inherit it. - - Forbid rejects source-level attempts to lower a lint. Deny rejects a - violation but permits a narrower source-level override. Neither prevents - someone from changing the build configuration itself. Compiler/tool versions - are pinned, and the checked build is the supported development path. + Cargo.toml defines workspace policy; all four packages inherit it. + forbid rejects source-level lowering; deny permits narrower source overrides. + Neither prevents build-config edits. Pin compiler/tools; use checked builds. RUST AND CLIPPY - Every previously denied individual Clippy rule and every enabled Clippy - group now uses forbid. There are no blanket Clippy allow entries. This - includes all, correctness, suspicious, cargo, style, complexity, perf, - pedantic, nursery, multiple_crate_versions, and redundant_pub_crate. - All Rustdoc lints in its supported all group are forbidden too. - - Rust safety, documentation, visibility, casts, edition/future compatibility, - underscore bindings, and warnings use forbid. Unused-group members that do - not conflict with generated code are independently forbidden. Additional - restrictions cover panic/unimplemented/unreachable paths, panic inside Result - functions, unsafe allowance attributes, numeric/pointer casts, native-endian - data, string slicing, infinite loops, and test placement. Cargo.toml lists - the precise rules. Contradictory restriction groups are not enabled wholesale. - - The supported workarounds were implemented instead of lowering these rules: - - Clap derives became explicit checked Clap builders. All argument parsing - stays in Clap; application code does not implement a shell parser. - Both command schemas have regression tests for modes, required paths, - listener parsing, global --root, and maintenance conflicts. Help flags - and rejected-option exit codes were compared against the previous binaries. - The unused Clap derive feature and its lockfile dependency were removed. - - Tokio's runtime attribute became an explicit checked runtime builder. - Runtime construction errors propagate through the existing error path. - The broad generated expect/style/complexity allowances are no longer needed. - - Management and server implementations live inside private app namespaces. - Internal interfaces use pub(super), narrower than crate visibility. Only - the documented program entry point is re-exported at the binary root. - This satisfies both redundant_pub_crate and unreachable_pub without - exposing helper modules or allowing either lint. - - Serde containers specify crate = "serde". This supported attribute avoids - the generated extern-crate branch and its unused_extern_crates and - clippy::useless_attribute allowances. File and wire representations retain - their existing field names, ordering, tagging, and unknown-field checks. - - Result-returning tests report failed checks with anyhow::ensure instead - of panicking. This permits panic_in_result_fn without suppressions. + Every formerly denied individual Clippy rule and enabled group uses forbid. + No blanket allows. Groups include all, correctness, suspicious, cargo, style, + complexity, perf, pedantic, nursery; multiple_crate_versions and + redundant_pub_crate also remain forbidden. Forbid Rustdoc's supported all group. + + Forbid Rust safety/docs/visibility/cast/edition/future-compatibility checks, + underscore bindings, and warnings. Independently forbid unused-group members + compatible with generated code. Also restrict panic/unimplemented/unreachable + paths, panic in Result, unsafe allowance attributes, numeric/pointer casts, + native-endian data, string slices, infinite loops, and test placement. + Exact rules: Cargo.toml. Do not enable contradictory restriction groups wholesale. + + Workarounds preserve strictness: + + Explicit checked Clap builders replace derives. Clap still parses all + arguments; no application shell parser. Both command schemas test modes, + required paths, listeners, global --root, and maintenance conflicts. + Help/rejected-option exit codes were compared with previous binaries. + Removed unused derive feature and its lockfile dependency. + + Explicit checked Tokio runtime builder replaces runtime attribute. + Construction failures use existing error path; no broad generated + expect/style/complexity allowances remain. + + Management/server implementations use private app namespaces and + pub(super), narrower than crate visibility. Re-export only documented + entry point at binary root. Enforce redundant_pub_crate/unreachable_pub + without exposing helpers or allowing either lint. + + Serde containers set crate = "serde", avoiding generated extern-crate + branch and unused_extern_crates/clippy::useless_attribute allowances. + Preserve file/wire field names, ordering, tagging, unknown-field checks. + + Result-returning tests use anyhow::ensure instead of panicking, permitting + panic_in_result_fn without suppressions. THREE REMAINING RUST DENY SETTINGS - unused, nonstandard_style, and unused_qualifications remain deny. This is - a generated-code compatibility requirement, not permission to add source - allowances. clippy::allow_attributes and allow_attributes_without_reason - are forbidden for first-party source. - - The pinned Serde derive implementation unconditionally emits allowances for - non_upper_case_globals, unused_attributes, unused_qualifications, and - clippy::absolute_paths in serde_derive/src/dummy.rs. Its generated field - identifier visitor also allows non_camel_case_types. These are generated - attributes even when the first-party type has correct names and no redundant - qualification. They cannot be removed by renaming fields or imports. - - The supported crate-path workaround was applied and all macros were inspected. - Repeating Clippy with -F unused, -F nonstandard_style, or - -F unused_qualifications still rejects the pinned Serde expansion. There is - no supported derive setting to suppress that unconditional wrapper. Further - changes would require forking the generator or replacing the serialization - implementation, including security-sensitive identity/envelope/request formats. - Those are explicit upstream/format migrations, not configuration fixes. - - Every other unused-group member and non_snake_case is independently forbidden. - warnings itself is forbidden; the explicit deny groups provide the narrowly - required effective levels for the generated attributes. No first-party - allow/expect attributes were added. + unused, nonstandard_style, unused_qualifications stay deny for generated-code + compatibility, not permission for source allowances. First-party + clippy::allow_attributes and allow_attributes_without_reason are forbidden. + + Pinned serde_derive/src/dummy.rs unconditionally allows non_upper_case_globals, + unused_attributes, unused_qualifications, clippy::absolute_paths. Generated + field-identifier visitor also allows non_camel_case_types. Correct first-party + names/qualifications cannot remove these generated attributes. + + Applied supported crate-path workaround; inspected all macros. Clippy with + -F unused, -F nonstandard_style, or -F unused_qualifications still rejects + pinned Serde expansion. No supported derive setting removes its unconditional + wrapper. Further changes require a generator fork or serialization replacement, + including security-sensitive identity/envelope/request formats: explicit + upstream/format migrations, not configuration fixes. + + Independently forbid every other unused member and non_snake_case. warnings + remains forbidden; explicit deny groups supply narrow effective levels needed + by generated attributes. Added no first-party allow/expect attributes. DUPLICATE DEPENDENCIES - clippy.toml restricts allowed-duplicate-crates to generic-array, getrandom, - and syn: the names actually diagnosed in this workspace. The Clippy lint - and cargo group remain forbidden for every other dependency. + clippy.toml allowed-duplicate-crates contains only diagnosed names: + generic-array, getrandom, syn. Lint/cargo group forbid all other duplicates. + Pinned crypto/parser/build graph needs incompatible semver lines: - The incompatible lines come from the pinned crypto/parser/build graph: generic-array 0.14.7 and 1.4.5 getrandom 0.2.17 and 0.4.3 syn 2.0.119 and 3.0.9 - These are different semver compatibility lines, not duplicate patch releases. - Unifying them requires upstream API changes or older dependencies. No crypto - algorithm/backend changes or dependency downgrades were made for a lint. - cargo-deny continues to enforce its exact reviewed version exceptions in - deny.toml, including build/development dependencies. Clippy's name-only - configuration does not replace that stronger version-specific audit. + These are not duplicate patch releases. Unification needs upstream API changes + or older dependencies. No crypto/backend changes or downgrades for lint. + cargo-deny enforces exact reviewed deny.toml exceptions, including build/dev + dependencies. Clippy's name-only allowance cannot replace that stronger audit. TYPESCRIPT - The compiler checks strict mode and the additional indexed access, optional - property, unused, return, switch, override, and import checks. noCheck and - allowJs are explicitly false. Both declaration-library skip flags are false. - isolatedModules, erasableSyntaxOnly, and verbatimModuleSyntax remain enabled. - Browser/worker configurations use Bundler resolution with Preserve output; - they contain no runtime imports. Tests and tooling use NodeNext separately. - - eslint.config.ts extends the typed strict and stylistic TypeScript presets. - All diagnostics are errors and any warning fails the check. Inline config - is disabled; suppression directives and unsafe assertions are prohibited. - Additional rules reject ambiguous boolean coercion, unhandled/misused promises, - explicit or leaked any, non-null assertions, unsafe calls/returns/arguments, - eval, unsafe casts, and unchecked discriminated-union switches. Functions - expose checked return types; callback contexts retain their declared contracts. - - UI async tasks now have explicit rejection handlers at the DOM boundary. - Test HTTP handlers also catch rejected work rather than returning unobserved - promises to Node. WASI validates its start export before calling it, and the - shared host is installed as a frozen, non-writable global property. Dynamic - JSON and worker boundaries still validate unknown values at runtime. - - TypeScript 7.0.2 remains the emitting compiler, installed under the explicit - typescript-native npm alias. typescript-eslint 8.72.1 supports TypeScript - >=4.8.4 <6.1.0 and requires the JavaScript compiler API, so TypeScript 6.0.3 - supplies that supported lint API. Sources are checked by both compilers; - no unsupported-peer or ignore-peer-dependency install flags are used. - Every invocation names the intended compiler path to avoid npm bin collisions. - - Isolated declaration emission is a library-distribution constraint, not an - additional application safety check. This project serves classic scripts - for the tested LibreJS path and does not publish a TypeScript library. - moduleDetection=force is used for tests/tools; changing browser scripts to - ESM solely for that setting would change their loading/LibreJS contract. - TypeScript 7 removed allowSyntheticDefaultImports=false, so that obsolete - switch is not used. Typed linting checks unsafe interop at use sites. + Check strict mode, indexed access, optional properties, unused, returns, + switches, overrides, imports. Explicitly disable noCheck/allowJs and both + declaration-library skip flags. Enable isolatedModules, erasableSyntaxOnly, + verbatimModuleSyntax. Browser/worker: Bundler resolution, Preserve output, + no runtime imports. Tests/tools: separate NodeNext configurations. + + eslint.config.ts extends typed strict/stylistic presets. All diagnostics are + errors; warnings fail. Disable inline config; prohibit suppression directives + and unsafe assertions. Reject ambiguous boolean coercion, unhandled/misused + promises, explicit/leaked any, non-null assertions, unsafe calls/returns/ + arguments, eval, unsafe casts, unchecked discriminated-union switches. + Functions expose checked return types; callbacks retain declared contracts. + + DOM async tasks and test HTTP handlers catch rejections; Node receives no + unobserved promises. WASI validates start export before calling it. Shared + host is a frozen, non-writable global. JSON/worker boundaries validate unknown + values at runtime. + + TypeScript 7.0.2 emits through explicit typescript-native npm alias. + typescript-eslint 8.72.1 supports >=4.8.4 <6.1.0 and requires JavaScript + compiler API; TypeScript 6.0.3 supplies it. Both compilers check sources. + No unsupported-peer/ignore-peer-dependency install flags. Name intended + compiler path in every invocation to avoid npm bin collisions. + + Isolated declaration emission constrains library distribution, not application + safety. This app publishes no TypeScript library; classic scripts preserve + tested LibreJS loading. moduleDetection=force applies to tests/tools. Do not + change browser scripts to ESM solely for that setting. TypeScript 7 removed + allowSyntheticDefaultImports=false; omit obsolete switch. Typed lint checks + unsafe interop at use sites. DEVELOPMENT DEPENDENCY ADVISORY - ESLint and typescript-eslint currently request minimatch 10. The public - GHSA-g3hv-75wg-m249 advisory affects minimatch <11.0.1. The root npm override - pins the patched 11.0.3 release instead of ignoring the advisory or applying - npm audit fix --force. Its supported exports and Node engine were reviewed; - typed linting and rule-selection/negative-control checks exercise compatibility. - Remove the override when upstream ranges admit a patched version naturally. + ESLint/typescript-eslint request minimatch 10. GHSA-g3hv-75wg-m249 affects + minimatch <11.0.1. Root npm override pins patched 11.0.3; no advisory ignore + or npm audit fix --force. Reviewed exports/Node engine; typed lint and rule- + selection/negative-control checks exercise compatibility. Remove override + when upstream ranges naturally admit a patched version. - npm audit --audit-level=info is part of npm run check and therefore the Cargo - check/release path. Development dependency findings fail the build too. - Installed tools preserve their original notices and machine SPDX identifiers. - Human documentation calls SPDX MIT the Expat License. No third-party - JavaScript dependency is delivered to visitors. + npm audit --audit-level=info runs in npm run check and Cargo check/release. + Development findings fail too. Tools retain original notices/machine SPDX. + Human docs call MIT the Expat License. Visitors receive no third-party JS. CHECKS AND EXPORTS @@ -169,15 +145,14 @@ CHECKS AND EXPORTS cargo stack check cargo stack release - The first checks both TypeScript compilers, typed ESLint, and npm advisories, - then emits the browser/worker/test artifacts. Cargo also runs formatting, - strict Clippy, all workspace tests, strict Rustdoc, cargo-deny, and cargo-about. - Browser checks and GNU LibreJS controls are documented in TYPESCRIPT.txt. + npm build checks both compilers, typed ESLint, npm advisories; emits browser/ + worker/test artifacts. Cargo adds formatting, strict Clippy, all workspace + tests, strict Rustdoc, cargo-deny, cargo-about. Browser/LibreJS controls: + TYPESCRIPT.txt. - clippy.toml, eslint.config.ts, every tsconfig, and both lockfiles are included - in corresponding sources, releases, and backups. Installed node_modules, - runtime state, and the private .env remain outside public exports. Nothing - introduces another deployment environment file or a production Node runtime. + Corresponding sources/releases/backups include clippy.toml, eslint.config.ts, + every tsconfig, both lockfiles. Public exports exclude installed node_modules, + runtime state, private .env. No extra deployment env file or production Node. PRIMARY REFERENCES diff --git a/docs/MAP.txt b/docs/MAP.txt new file mode 100644 index 0000000..6f5e13d --- /dev/null +++ b/docs/MAP.txt @@ -0,0 +1,175 @@ +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/>. + +FILE MAP + + Public tree: every tracked file, including this map. + Static inventory; update when public paths change. Root: stack/. + Private/generated trees below list roles only; contents stay unlisted. + +stack/ Personal service source, build recipes and recovery tooling. +|-- .cargo/ Cargo command aliases. +| `-- config.toml Cargo stack alias. +|-- crates/ Workspace application/configuration crates. +| |-- chat-crypto/ Fixed-suite Rust and browser cryptography. +| | |-- browser/ Browser crypto types and WASI adapter. +| | | |-- protocol.d.ts Shared typed API, crypto, worker, WASI message contracts. +| | | `-- wasi.ts Browser WASI host: memory, I/O, entropy, command execution. +| | |-- src/ Rust crypto library and executable. +| | | |-- application.rs Protected identities, authentication proofs, message encryption/decryption. +| | | |-- lib.rs Public crypto API and fixed-suite compatibility round trip. +| | | `-- main.rs Native/WASI executable: request input and crypto result output. +| | |-- tests/ Real-browser crypto compatibility tests. +| | | `-- browser.ts Real-browser crypto probe, entropy-failure and network-isolation checks. +| | |-- Cargo.toml Crypto library/probe targets, fixed backend features, dependencies. +| | `-- README.txt Crypto suite, native/WASI build, compatibility checks. +| |-- chat-server/ Private-chat backend and browser client. +| | |-- src/ Rust HTTP server and maintenance entry. +| | | |-- app/ Server argument, HTTP, service and storage modules. +| | | | |-- cli.rs Server flags, listener defaults, maintenance argument conflicts. +| | | | |-- http.rs HTTP routes, packaged assets, response security headers. +| | | | |-- maintenance.rs Server file lock, owner fingerprint, destructive owner reset. +| | | | |-- service.rs Authentication challenges/sessions, authorization, chat operations. +| | | | `-- store.rs SQLite owner metadata, conversations, ciphertext history persistence. +| | | |-- app.rs Server initialization, origin/listener checks, command dispatch. +| | | `-- main.rs Chat server executable entry point. +| | |-- tests/ Chat browser integration and loading-state tests. +| | | |-- browser.ts Chat browser flows, owner/visitor access, packaged backup/restore. +| | | `-- progress.ts Crypto-download progress, unknown length, failure and LibreJS checks. +| | |-- web/ Chat markup, styling and TypeScript client. +| | | |-- app.ts Chat browser UI, credentials, API calls, encrypted conversations. +| | | |-- index.html Chat page markup and public-origin template. +| | | |-- javascript.html Browser JavaScript license/source listing. +| | | |-- style.css Chat page layout, controls, status and conversation styling. +| | | `-- worker.ts One-operation crypto worker; returns result/error, then closes. +| | |-- Cargo.toml Chat HTTP server dependencies and workspace lint inheritance. +| | `-- README.txt Server purpose, local startup, browser-test entry. +| |-- config/ Shared environment/configuration crate. +| | |-- src/ Validated configuration and public-rendering implementation. +| | | `-- lib.rs Root .env parsing/validation, defaults, public-only template values. +| | |-- Cargo.toml Shared configuration crate dependencies and lint inheritance. +| | `-- README.txt Configuration crate responsibilities and public rendering boundary. +| `-- README.txt Workspace crate roles and shared policy. +|-- docs/ Plaintext setup, policy, security and recovery guides. +| |-- CHAT-APPLICATION.txt Chat setup, protected files, user flows, recovery, security limits. +| |-- CHAT-OPENSSL-MIGRATION.txt OpenSSL crypto migration evidence, dependencies, reviewed exceptions. +| |-- CHAT-PRODUCTION.txt Chat release packaging, HTTPS activation, owner setup, production recovery. +| |-- CONFIGURATION.txt Supported root settings, validation, public/private state boundaries. +| |-- LINTING.txt Strict Rust/browser checks, generated-code limits, justified exceptions. +| |-- MAP.txt This public-file tree and private/runtime directory roles. +| |-- OPERATIONS.txt Stack development, encrypted backup/restore, host setup, deployment. +| |-- POLICY.txt License/header, source-comment, configuration, strictness and portability rules. +| `-- TYPESCRIPT.txt Typed browser/worker/test builds, ESLint policy, compiler/test commands. +|-- infra/ Service definitions, host integration and build recipes. +| |-- chat/ Native/WASI/TypeScript/source build scripts. +| | |-- build-browser.sh Link Rust/OpenSSL browser crypto command into WASI WebAssembly. +| | |-- build-native.sh Build static musl management/server commands and native crypto probe. +| | |-- build-openssl-wasi.sh Fetch verified SDK/OpenSSL sources; build browser crypto library. +| | |-- build-source.sh Archive corresponding source, vendored Rust crates and OpenSSL source. +| | |-- build-typescript.sh Install locked dev dependencies; run typed checks and emit browser JS. +| | `-- openssl-wasi.conf OpenSSL build target settings for WASI. +| |-- containers/ Container build contexts. +| | |-- cgit/ cgit image and its nginx/FastCGI process configuration. +| | | |-- .containerignore Restrict cgit build context to required container files. +| | | |-- Containerfile Build pinned Debian cgit/nginx/FastCGI/supervisor image. +| | | |-- cgitrc cgit repository listing, paths and presentation template. +| | | |-- entrypoint.sh Prepare cgit container runtime and start its supervisor. +| | | |-- nginx.conf Serve cgit HTTP/static assets; route CGI through fcgiwrap. +| | | `-- supervisord.conf Run nginx and fcgiwrap inside the cgit container. +| | `-- chat/ Prebuilt chat image recipe. +| | `-- Containerfile Package prebuilt static chat server and web/crypto assets. +| |-- searxng/ Search service configuration. +| | `-- settings.yml SearXNG defaults: private instance, rate limiting, HTML search. +| |-- Caddyfile Production domain routing, HTTPS, WKD and service reverse proxies. +| |-- Caddyfile.local Loopback development routing without public certificate requests. +| |-- host-setup.sh Debian ops-user Podman packages, UID/GID checks, low ports and linger. +| |-- podman.conf Legacy Podman override selecting slirp4netns rootless networking. +| |-- services.toml Service images, mounts, environment allowlists, security and health probes. +| `-- stack.service Systemd user boot unit for ~/stack start/stop. +|-- src/ Management executable source. +| |-- app/ Management command implementation modules. +| | |-- archive.rs Consistent snapshots, encrypted exports and validated directory restores. +| | |-- chat.rs Chat build/package artifacts, container settings and owner administration. +| | |-- cli.rs Management subcommands, flags and argument validation. +| | |-- files.rs Safe filesystem/archive operations, manifests and hashes. +| | |-- images.rs Export/import exact container images; enforce platform and content locks. +| | |-- process.rs Run child processes; capture output and report failures/status. +| | |-- project.rs Discover/lock project; settings, Podman commands, service lifecycle. +| | |-- release.rs Build checked release archives; validate/install production artifacts. +| | `-- render.rs Render per-mode Caddy, website and cgit configuration. +| |-- app.rs Management command dispatch, check pipeline and license generation. +| `-- main.rs Management executable entry point. +|-- tests/ Shared first-party browser-test helpers. +| `-- browser-support.ts Shared browser-test response validators, server and browser cleanup helpers. +|-- web/ Main-site template, styles, licenses and public key discovery. +| |-- .well-known/ Standard public discovery endpoints. +| | `-- openpgpkey/ WKD public-key discovery tree. +| | |-- hu/ Direct WKD hashed-user key files. +| | | `-- t76q8xqkeassgy1kr38re1ppj6cpc1dp Owner public key for direct WKD lookup. +| | |-- luuduct.ai/ Advanced WKD namespace for luuduct.ai. +| | | |-- hu/ Advanced WKD hashed-user key files. +| | | | `-- t76q8xqkeassgy1kr38re1ppj6cpc1dp Same owner public key for advanced luuduct.ai WKD lookup. +| | | `-- policy Advanced WKD policy marker for luuduct.ai. +| | `-- policy Direct WKD policy marker. +| |-- THIRD-PARTY-LICENSES.html Generated Rust dependency attribution and full license texts. +| |-- index.html Main-site public links, identity and service-origin template. +| `-- styles.css Main-site visual layout, links and tooltips. +|-- .env.example Public settings template; private-value placeholders. +|-- .gitattributes Whitespace handling for generated third-party license HTML. +|-- .gitignore Exclude secrets, runtime state, dependencies, build output. +|-- Cargo.lock Exact Rust dependency versions and source checksums. +|-- Cargo.toml Management binary, workspace members, dependencies, strict lints. +|-- LICENSE Unmodified GNU AGPLv3 license text; sources allow later versions. +|-- README.txt Project entry: setup, commands, checks, documentation links. +|-- about.hbs HTML template for generated Rust dependency licenses. +|-- about.toml License-page acceptance list and private-package handling. +|-- clippy.toml Reviewed duplicate-crate exceptions for Clippy. +|-- deny.toml Dependency advisory, license, source and duplicate-version policy. +|-- eslint.config.ts Typed ESLint rules and per-environment file scopes. +|-- package-lock.json Exact npm dev dependency versions, integrity and dependency graph. +|-- package.json Browser tooling dependencies and npm check/build/test commands. +|-- rust-toolchain.toml Pinned Rust version, formatting/lint components and target triples. +|-- tsconfig.browser.json Browser main-thread and WASI-host compiler scope. +|-- tsconfig.json Shared strict TypeScript compiler options. +|-- tsconfig.tests.json Node browser-automation compiler scope. +|-- tsconfig.tools.json Node ESLint configuration compiler scope. +`-- tsconfig.worker.json Web-worker compiler scope, separate from DOM globals. + +PRIVATE AND GENERATED PATHS — NOT PUBLIC SOURCE + + .env Sole private root configuration; never commit. + .git/ Local Git objects, refs, hooks and repository settings. + .tools/ Downloaded toolchains, build tools, sources and caches. + bin/ Prebuilt management/chat commands and packaged chat assets. + dist/ Locally built release tarballs and checksum files. + node_modules/ Locked npm development dependencies; recreated by npm ci. + target/ Cargo build output, WASM targets and generated rustdoc. + var/ Private/generated project state; excluded from Git. + backups/ Imported backup archives and recovery test destinations. + build/ Generated TypeScript, source/vendor bundles and build work. + data/ Persistent application databases, TLS keys and Git repos. + caddy/ ACME account/certificate keys, Caddy data/configuration. + chat/ Production chat database: owner identity and ciphertext. + chat-local/ Isolated local chat database and server state. + repos/ Served bare Git repositories; separate from root .git/. + searxng/ Runtime search configuration and persistent service files. + exports/ Encrypted application backups and checksum files. + incoming/ Copied release archives and temporary deployment bootstrap. + podman/ Recreated container storage/run state; never transfer as backup. + graphify/ Public-source graph index, visual map and extraction artifacts. + + Other var/ paths may hold generated fixtures or temporary work. This map does + not enumerate private files. Backups must keep .env and var/data; public Git + alone cannot recover services. See OPERATIONS.txt. diff --git a/docs/OPERATIONS.txt b/docs/OPERATIONS.txt index 2c9fa53..55dc81c 100644 --- a/docs/OPERATIONS.txt +++ b/docs/OPERATIONS.txt @@ -13,113 +13,85 @@ 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/>. -STACK OPERATIONS AND RECOVERY +STACK OPERATIONS - Application root: ~/stack - Development machine: local Linux workstation - Production host: ops@23.155.44.67 - Public source: https://git.doan.luuduct.ai/stack - License: GNU Affero General Public License, version 3 or later + Root: ~/stack. Develop on local Linux; production: ops@23.155.44.67. + Public source: https://git.doan.luuduct.ai/stack. + GNU Affero General Public License, version 3 or later. -WHAT YOU NEED TO KEEP +KEEP - A full encrypted export made with --include-images contains public source, - the compiled management command, .env, persistent application data, - certificate state, bare repositories, working Git history if present, and - the exact service images. It includes a file checksum manifest. + Full --include-images encrypted export: public source, compiled CLI, .env, + persistent data, certificates, bare repos, working Git history if present, + exact service images, checksum manifest. No old server filesystem needed. + Excludes engine storage, caches, old exports, host packages/SSH keys/firewall, + disks, OS configuration. Recreate host setup separately. + Public Git alone cannot recover .env, live data, TLS keys, or var/ repos. - It excludes the container engine's storage, build caches, old exports, - host packages, host SSH keys, firewall rules, disks, and OS configuration. - These are recreated on a new host. No old server filesystem is required. + Decryption needs GPG private key + passphrase. Keep key export/revocation + certificate in KeePassXC; keep independent database copy. Server holds public + key only. Never send private key/password through chat. + Default recipient: 3346AA3150F8F16828BB0D14F8C66DF77AFECEA6. - The public Git repository alone is not a backup: it excludes .env, live - data, private certificates, and application repositories under var/. +DEVELOP LOCAL - Your GPG private key and its passphrase are needed to decrypt backups. - Keep the private-key export and revocation certificate in KeePassXC and - keep an independent copy of the database. The server has only the public - key. This guide never needs your private key or password in chat. - - Default backup recipient fingerprint: - 3346AA3150F8F16828BB0D14F8C66DF77AFECEA6 - -DAILY DEVELOPMENT - - Run these from ~/stack on your workstation: + From ~/stack on workstation: cargo stack dev cargo stack status cargo stack down - Visit http://localhost:8080, http://localhost:8080/git/, and - http://localhost:8080/search/. To use different ports: + Open http://localhost:8080, http://localhost:8080/git/, + http://localhost:8080/search/. Alternate port: cargo stack dev --port 9080 - Local mode binds loopback only, rewrites public service links locally, - keeps public DNS untouched, and does not request public TLS certificates. - It automatically creates .env with a random SearXNG secret if absent. - Edit .env to change configured secrets. Do not commit it. - - Public service settings belong in infra/, and website content in web/. - New Rust backends belong in crates/, explicitly added to Cargo.toml. - Services are declared in infra/services.toml. A service receives only the - .env keys listed in its environment array, not every project secret. + Local mode: loopback only, local links, unchanged public DNS, no public TLS. + Missing .env: create with random SearXNG secret. Edit secrets there; never commit. + infra/: service settings. web/: content. crates/: new backends; add workspace members. + infra/services.toml declares services. Each gets only listed environment keys. - Rust commands use a project-specific Podman store under var/podman/. - A bare 'podman ps' lists your normal store, which may be empty. To inspect - this project's store manually, run from ~/stack: + Project engine storage: var/podman/. Bare 'podman ps' uses another store. + Inspect project containers from ~/stack: podman --root "$PWD/var/podman/storage" --runroot "$PWD/var/podman/run" ps -a - Reuse those two global options before 'logs CONTAINER', 'exec CONTAINER', - or 'images'. Container names are shown by cargo stack status. - Never copy var/podman/ to another machine; export images instead. + Keep both global options for 'logs CONTAINER', 'exec CONTAINER', 'images'. + cargo stack status gives names. Never migrate var/podman/; export images. -STRICT LOCAL CHECKS +CHECK LOCAL - Install the two development-only tools once: + Install development audit tools once: cargo install --locked --version 0.20.2 cargo-deny --root .tools cargo install --locked --version 0.9.3 --features cli cargo-about --root .tools - Then run: - cargo stack check - This checks formatting, all workspace Clippy targets/features, tests, - private rustdoc, dependency advisories, duplicate versions, sources, and - licenses. It regenerates THIRD-PARTY-LICENSES.html through cargo-about. - Use cargo fmt --all when formatting needs correction. - - After changing dependency requirements, update Cargo.lock deliberately, - run the complete check, and commit the lockfile and generated license page. - Never disable audit failures merely to get a release out. + Checks formatting, all workspace Clippy targets/features, tests, private + rustdoc, advisories, duplicate versions, sources, licenses. cargo-about + regenerates THIRD-PARTY-LICENSES.html. Format with cargo fmt --all. + Dependency changes: update Cargo.lock deliberately; run full check; commit + lockfile and license page. Never disable audit failures to ship. -EXPORT AND BACK UP PRODUCTION +BACK UP PRODUCTION - On the VPS: + On VPS: cd ~/stack ./bin/stack backup --include-images - The command briefly pauses Caddy, cgit, and SearXNG while copying their - application files, then resumes them before compression and encryption. - Chat remains unpaused so SQLite online backups can complete during active - writes. Consistent snapshots cover both chat and chat-local databases; raw - SQLite journals and server lock files are excluded. - It uses the published public key, verifies the recipient fingerprint, - checks bare Git repositories, saves exact images, and produces: + Briefly pauses Caddy/cgit/SearXNG during file copy; resumes before compression + and encryption. Chat stays live for SQLite online backup. Snapshots include + chat and chat-local; exclude raw journals and server locks. + Verifies public recipient fingerprint, checks bare repos, saves exact images: var/exports/stack-TIMESTAMP.tar.gz.gpg var/exports/stack-TIMESTAMP.tar.gz.gpg.sha256 - Both files have restrictive permissions. Temporary plaintext staging is - removed on normal completion and handled errors. No scheduled backup job - is installed. You decide when and where to retain exports. - - On your workstation, create a destination under stack and copy the two - actual filenames printed by the command: + Restrictive permissions. Removes temporary plaintext on success/handled errors. + No scheduled backup. Choose retention and off-host copies yourself. + On workstation, copy actual filenames printed above: umask 077 mkdir -p ~/stack/var/backups/production @@ -128,43 +100,31 @@ EXPORT AND BACK UP PRODUCTION cd ~/stack/var/backups/production sha256sum -c stack-TIMESTAMP.tar.gz.gpg.sha256 - Replace TIMESTAMP with the actual timestamp. A checksum detects accidental - corruption; keep the trusted encrypted file and checksum together. - Retain at least one copy on another device or location. - - Once copied and verified, delete only the corresponding VPS export files - if desired. Do not delete var/data or .env. + Replace TIMESTAMP. Checksum detects corruption; keep trusted export + checksum. + Keep another copy on separate device/location. After verification, optionally + delete matching VPS export files only. Never delete var/data or .env. + ./bin/stack backup without images needs registry/build access for local startup; + not standalone production recovery. Prefer --include-images. - A smaller export without images is available through ./bin/stack backup. - It needs registry/build access for local startup and is not a standalone - production deployment. Prefer --include-images for disaster recovery. +RESTORE ON LINUX -RESTORE ON ANOTHER LINUX MACHINE - - Install Podman, Git, GnuPG, and normal rootless networking prerequisites. - Rootless Podman needs at least 65536 subordinate UIDs and GIDs for the - target user. Use that distribution's supported Podman installation. - The current ready-made binary/images target x86_64 Linux (linux/amd64). - - Copy the encrypted export and its checksum to the new machine. Verify - the checksum first. Import your secret-key backup if not already present: + Host tools: Podman, Git, GnuPG, rootless networking prerequisites. + Target user needs >=65536 subordinate UIDs/GIDs. Use distro-supported Podman. + Prebuilt binary/images: x86_64 Linux (linux/amd64). + Copy export + checksum; verify checksum first. If needed, import key: gpg --import private-key-backup.asc - GnuPG asks for the key passphrase through its normal local interface. - Never pass it on the command line or put it in .env. - - If you already have a compatible stack command, restore with it: + GnuPG prompts locally. Never pass passphrase through arguments or .env. + Existing compatible CLI: ./bin/stack restore /path/to/stack-TIMESTAMP.tar.gz.gpg ~/stack-restored - The destination must not exist. Restore decrypts privately, rejects unsafe - archive paths and links, checks every manifest entry, assigns a unique - project identity, and defaults to local mode. It does not start services. - It refuses to overwrite an existing installation. + Destination must not exist. Restore decrypts privately; rejects unsafe paths + and links; checks every manifest entry; assigns unique project identity; + defaults local; starts nothing; never overwrites existing installation. - For a new machine with no stack command or Rust toolchain, bootstrap with - standard GnuPG and tar. The shell commands below work in bash and fish: + No CLI/toolchain yet: bootstrap trusted export with GnuPG/tar. Bash/fish: umask 077 mkdir -p ~/stack-bootstrap @@ -172,125 +132,98 @@ RESTORE ON ANOTHER LINUX MACHINE tar -xzf ~/stack-bootstrap/export.tar.gz -C ~/stack-bootstrap stack/bin/stack ~/stack-bootstrap/stack/bin/stack restore /path/to/stack-TIMESTAMP.tar.gz.gpg ~/stack - Only use this bootstrap with your own trusted export; the extracted binary - is executable code. The restore command validates the complete archive. - After successful restoration, delete ~/stack-bootstrap, which contains - the temporary decrypted archive. Keep only the encrypted export as backup. - - Start the recovered stack locally first: + Bootstrap executes extracted code: use only your trusted export. + Rust restore validates full archive. After success, delete ~/stack-bootstrap: + it holds decrypted archive. Retain encrypted backup. + Test restored stack locally first: cd ~/stack ./bin/stack up --local --port 8080 ./bin/stack status - Saved images load automatically and their identities are checked against - the image lock. No registry pull or compilation is needed on a matching - architecture. Check the homepage, Git repositories, search, and WKD. - Then stop it with ./bin/stack down before configuring production. + Saved images load automatically; image lock verifies identities. Matching + architecture needs no registry pull/build. Check homepage, Git, search, WKD. + ./bin/stack down before production setup. + Same restore accepts release archives: source/binary/images, no .env/live data. + Starting restored release creates fresh state; cannot recover lost data. - A release archive can be restored by the same command. Releases contain - source, a binary, and images, but no .env or application data. Starting a - restored release creates fresh state; it does not recover lost data. +NEW PRODUCTION HOST -SET UP A NEW PRODUCTION HOST - - Restore to the target user's ~/stack, using the steps above. On Debian, - adapt the username 'ops' in infra/host-setup.sh if necessary, review it, - and run: + Restore into target user's ~/stack. Debian: review infra/host-setup.sh; + replace 'ops' if needed; run: sudo sh ~/stack/infra/host-setup.sh - It installs Podman and networking tools, checks existing subordinate - UID/GID ranges, enables user linger for boot, and sets: + Installs Podman/network tools, checks existing subordinate ranges, enables + user linger, sets: net.ipv4.ip_unprivileged_port_start=80 - This allows rootless listeners on ports 80 and above system-wide; ports - below 80 remain privileged. It does not change SSH or your firewall. - If the user lacks subordinate ranges, allocate unused ranges through - the distribution's account administration before rerunning the script. - - On other Linux distributions, install equivalent prerequisites and set - that sysctl and user linger using the host's supported tools. Production - requires a systemd user manager for this project's supplied boot service. - - 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. - - 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 - configured in the root .env. Edit those values and reapply the service - configuration; infra/Caddyfile is now a public rendering template. - See CONFIGURATION.txt for all keys and the render-only commands. - Keep the www aliases and openpgpkey names pointing to the canonical hosts. + System-wide rootless ports >=80; ports <80 stay privileged. SSH/firewall unchanged. + Missing ranges: allocate unused ranges through distro account tools; rerun. + Other distros: equivalent packages, sysctl, linger. Supplied boot unit needs + systemd user manager. - Start production: + Host/provider firewall: allow 22/tcp, 80/tcp, 443/tcp, 443/udp for applicable + IPv4/IPv6. Never publish backend container ports. Preserve SSH; verify address + before changing DNS. A: new IPv4. AAAA: working new IPv6 only; remove stale AAAA. + Hosts live in root .env; edit and reapply rendered settings. infra/Caddyfile + is public template. Keys/render-only commands: CONFIGURATION.txt. + Preserve www aliases and openpgpkey names pointing to canonical hosts. cd ~/stack ./bin/stack up --production - Production binds 80/tcp, 443/tcp, and 443/udp. Caddy manages certificates - and renewals automatically, redirects HTTP to HTTPS, and redirects www - aliases to the canonical URLs. Certificate state is in var/data/caddy/. - Public certificate issuance needs working public DNS and connectivity. - - Enable startup at boot: + Production binds 80/tcp, 443/tcp, 443/udp. Caddy issues/renews certificates, + redirects HTTP to HTTPS and www to canonical URLs. State: var/data/caddy/. + Public issuance needs working public DNS/connectivity. + Enable boot startup: systemctl --user link ~/stack/infra/stack.service systemctl --user daemon-reload systemctl --user enable --now stack.service systemctl --user status stack.service - This unit assumes ~/stack. Edit its paths if deliberately using another - location. User linger keeps it running without an interactive login. - Application containers use an unless-stopped restart policy. + Unit assumes ~/stack; edit paths for other location. Uses bin/stack. + Linger keeps user service alive + without login. Containers use unless-stopped restart policy. - If offering SSH Git access at the former VPS path, create this optional - host symlink as the administrator: + Optional former VPS SSH Git path; administrator only: sudo install -d -m 755 /srv/git sudo ln -s /home/ops/stack/var/data/repos/stack /srv/git/stack - Do not overwrite an existing repository there. The current VPS already - has this link, updated for the new layout. Public HTTPS Git works without - the optional host link. + Never overwrite existing repo. Current VPS already has this layout link. + Public HTTPS Git needs no host symlink. -MAKE AND DEPLOY A RELEASE +BUILD AND DEPLOY - Develop and run the checks on your workstation, then: + Develop/check on workstation: cd ~/stack cargo stack release - Release reruns the full check, builds static Rust management and chat - binaries plus the browser WASM module, packages corresponding sources, - builds cgit/chat containers locally, and saves the configured image set. - Outputs are dist/stack-release-TIMESTAMP.tar.gz and its .sha256 file. - No .env, live data, .git history, or previous backup is included. - - Test the release in a fresh local directory before deploying, using the - restore command followed by up --local on an unused port. Inspect the - same four services and then stop the test installation. - - Commit and push reviewed public changes with normal Git: + Release reruns full check; builds static Rust CLI/chat + browser WASM; + packages matching source; builds cgit/chat containers; saves configured images. + Output: dist/stack-release-TIMESTAMP.tar.gz + .sha256. + Excludes .env, live data, .git history, previous backups. + Restore into fresh local test directory; up --local on free port; inspect + four services; stop test. Commit/push reviewed public changes: git add -A git diff --cached --stat - git commit -m 'Describe the change' + git commit -S3346AA3150F8F16828BB0D14F8C66DF77AFECEA6 -m 'Describe the change' git push origin main - .gitignore excludes configured secrets and all runtime/artifact trees. - Review the staged files. Deployment uses the release archive, not git pull. - - Copy the actual archive and checksum to production: + Review staged files. .gitignore excludes secrets/runtime/artifacts. + Use RSA-2048 signed commits; author/key: POLICY.txt. + Deploy archive, never git pull. Copy actual filenames: ssh ops@23.155.44.67 'mkdir -p ~/stack/var/incoming' scp dist/stack-release-TIMESTAMP.tar.gz ops@23.155.44.67:stack/var/incoming/ scp dist/stack-release-TIMESTAMP.tar.gz.sha256 ops@23.155.44.67:stack/var/incoming/ - On the VPS: + On VPS: cd ~/stack/var/incoming sha256sum -c stack-release-TIMESTAMP.tar.gz.sha256 @@ -301,49 +234,32 @@ MAKE AND DEPLOY A RELEASE ./bin/stack status rm -rf -- var/incoming/bootstrap - Use the management binary from the verified new release for activation. - Older binaries can reject newer service schemas. The verified release - binary handles activation without installing a compiler or overwriting - private configuration. - - Activation verifies the release and platform, replaces public source and - the binary, loads exact images, preserves .env and var/data, and replaces - the running containers. It does not compile Rust or build container images. - Expect a brief interruption while containers are replaced. Take a verified - export first if a future change could require recovery. - - After verifying production, delete the corresponding incoming archive and - checksum if you do not want release copies left on the VPS. - -RECOVERY LIMITS AND SECRET ROTATION - - Exports capture this application, not an entire bootable VPS image. - Host account, SSH, firewall, and package setup remain host responsibilities. - Changing CPU architecture requires a native release build. Registry access - is needed only when images are omitted or rebuilding for another target. - - Current persistent state includes files, Git repositories, Caddy state, - and encrypted chat records in SQLite. Chat uses the SQLite online backup - API; recovery testing must reopen both participants' unchanged identity - files and decrypt history. See CHAT-PRODUCTION.txt for this release's tests. - Future databases need their own supported snapshot and recovery procedure. - - If changing the OpenPGP backup recipient, publish its public key, update - the command's default fingerprint, and test encryption and restoration. - For one export, use --recipient FULL_FINGERPRINT --key /path/public-key.asc. - Keep old secret keys while any retained export still depends on them. - - The restore command accepts verified format-2 application archives. - -CENTRAL THIRD-PARTY LICENSE PAGE - - cargo-about generates web/THIRD-PARTY-LICENSES.html. Caddy serves the rendered - document at https://doan.luuduct.ai/THIRD-PARTY-LICENSES.html, using the - configured SITE_HOST for other deployments. Website and chat license links - use that same canonical page. Local previews use the local main-site origin. - - 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. + Use verified NEW release binary: old binary may reject new service schema. + Activation verifies archive/platform, replaces public source/binary, loads + exact images, preserves .env/var/data, replaces running containers. No compiler, + Rust build, image build, or private-config overwrite. Expect brief interruption. + Take verified export before changes needing recovery. Verify production; + optionally delete corresponding incoming archive/checksum. + +RECOVERY LIMITS; ROTATE KEYS + + Application export is not bootable VPS image. Accounts, SSH, firewall, + packages remain host duties. Other CPU architecture needs native release. + Registry needed only without saved images or when rebuilding another target. + State: files, Git repos, Caddy, encrypted SQLite chat. SQLite uses online backup. + Recovery proof: reopen BOTH participants' unchanged identities; decrypt history. + See CHAT-PRODUCTION.txt. Future databases need supported snapshot/recovery. + + New backup recipient: publish public key, update default fingerprint, test + encryption/restore. Single export: --recipient FULL_FINGERPRINT --key /path/public-key.asc. + Retain old secret keys while any retained export needs them. + Restore accepts verified format-2 application archives. + +LICENSE PAGE; REDIRECTS + + cargo-about generates web/THIRD-PARTY-LICENSES.html. Caddy serves canonical + https://doan.luuduct.ai/THIRD-PARTY-LICENSES.html; other deployments use SITE_HOST. + Website/chat links share page; local preview uses local main-site origin. + cgit Source/Raw expose generated file; chat /THIRD-PARTY-LICENSES.html redirects + to canonical page. Source exports retain offline license texts. + Homepage /message and /message/ redirect to current chat origin. diff --git a/docs/POLICY.txt b/docs/POLICY.txt index 4c6c6d3..dea595b 100644 --- a/docs/POLICY.txt +++ b/docs/POLICY.txt @@ -17,89 +17,80 @@ PROJECT CONVENTIONS License: GNU Affero General Public License, version 3 or later. SPDX identifier: AGPL-3.0-or-later. - Copyright holder: Doan Luu Duc Tai <doan@luuduct.ai>, 2026. - - Every nontrivial first-party source, configuration, template, and prose - file carries the AGPL copyright and permission header. LICENSE is the - unmodified license text. Binary public keys and empty WKD policy files - retain their protocol format. Generated Cargo.lock retains Cargo's own - metadata as well as the project notice. JSON npm manifests carry the legal - notice in a top-level // metadata field; compiler JSONC files use the usual - header syntax. Keep generated JavaScript legal markers when compiling. - - Do not add explanatory source comments. Express intent through structure - and names. Legal headers are the required exception. Use .txt for prose - documentation. The generated HTML license page is an explicit exception. - Rust documentation attributes provide crate metadata without comments. - - Keep deployment overrides and configured secrets in the single root .env. - Never commit .env or var/. - Only the root .env.example is published; environment variants and nested - examples are ignored. The commented .env.example publishes supported public - defaults and private placeholders. Public GPG keys, paths, templates, shared - configuration logic, and source belong in Git. Actual public hostnames remain - visible in rendered pages; .env centralization is not an access boundary. - TLS account/certificate private keys, databases, and other generated - private state are persistent data in var/data, not .env configuration. - The GPG secret key and revocation certificate remain outside this project. + Copyright holder/commit author: Doan Luu Duc Tai <doan@luuduct.ai>, 2026. + Sign commits with RSA-2048 key: + 3346AA3150F8F16828BB0D14F8C66DF77AFECEA6 + + Every nontrivial first-party source/config/template/prose file needs the AGPL + copyright and permission header. LICENSE stays unmodified. Binary public keys + and empty WKD policy files retain protocol format. Generated Cargo.lock keeps + Cargo metadata plus project notice. JSON npm manifests use top-level // legal + metadata; compiler JSONC uses its usual header syntax. Preserve generated + JavaScript legal markers. + + No explanatory source comments. Express intent through names/structure. + Required legal headers are the exception. Prose uses .txt; generated HTML + license page is an explicit exception. Rust doc attributes supply crate + metadata without comments. + + One root .env holds deployment overrides/configured secrets. Never commit + .env or var/. Publish only root .env.example; ignore variants/nested examples. + Its comments document public defaults/private placeholders. Public GPG keys, + paths, templates, shared config logic, and source belong in Git. Hostnames + stay visible in rendered pages; .env centralization is no access boundary. + TLS account/certificate private keys, databases, and generated private state + live under var/data, not .env. Keep GPG secret key/revocation certificate + outside the project. STRICTNESS - All enabled Clippy groups and individual rules are forbidden, with no - blanket allow entries. Rust and Rustdoc checks use forbid wherever supported - by generated code. Three Rust settings remain deny for pinned Serde derives; - their unaffected members are independently forbidden. First-party lint - allowances are forbidden. See LINTING.txt for tested workarounds, generated - attribute evidence, and the narrow duplicate-dependency configuration. - Private app namespaces retain narrow internal visibility while both - redundant_pub_crate and unreachable_pub are enforced. - - cargo-deny rejects duplicate crate versions, wildcard requirements, unknown - registries, unknown Git sources, and yanked versions. The chat prototype has - exact-version duplicate exceptions reviewed in CHAT-OPENSSL-MIGRATION.txt. - No RustSec advisories are ignored. First-party AGPL and required dependency - license allowances are scoped to their individual packages. - The dependency allowlist retains the requested permissive licenses and - Zlib; an unused allowance may produce an informational audit warning. - - Browser logic and automation use strict TypeScript configurations with - separate browser/worker/Node environments and checked untrusted responses. - npm dependencies are exact, development-only, integrity-locked, and installed - with lifecycle scripts disabled. Typed ESLint forbids unsafe any/assertions, - unchecked promises, and suppression directives. Both supported compiler APIs - and npm advisories are checked. See TYPESCRIPT.txt and LINTING.txt. - - Human license names follow https://www.gnu.org/licenses/license-list.html. - In particular, display Expat License for SPDX MIT. Do not alter original - copyright notices, legal texts, crate metadata, or machine SPDX identifiers. - cargo-about covers Rust dependencies. Supporting container applications - and their operating-system packages carry additional upstream licenses. + Forbid every enabled Clippy group/individual rule; no blanket allows. + Rust/Rustdoc use forbid where generated code supports it. Three Rust settings + stay deny for pinned Serde derives; unaffected members remain independently + forbidden. No first-party lint allowances. LINTING.txt records tested + workarounds, generated-attribute evidence, and narrow duplicate exceptions. + Private app namespaces keep narrow visibility while redundant_pub_crate and + unreachable_pub both remain enforced. + + cargo-deny rejects duplicate versions, wildcard requirements, unknown + registries/Git sources, and yanked versions. Chat has exact-version duplicate + exceptions reviewed in CHAT-OPENSSL-MIGRATION.txt. Ignore no RustSec advisory. + Scope first-party AGPL/required dependency license allowances per package. + Allowlist retains requested permissive licenses and Zlib; unused allowances + may produce informational audit warnings. + + Strict TypeScript separates browser/worker/Node environments and validates + untrusted responses. npm dependencies stay exact, development-only, + integrity-locked; disable installation lifecycle scripts. Typed ESLint rejects + unsafe any/assertions, unchecked promises, and suppression directives. Check + both supported compiler APIs and npm advisories. See TYPESCRIPT.txt/LINTING.txt. + + Human license names follow https://www.gnu.org/licenses/license-list.html: + display Expat License for SPDX MIT. Preserve original copyright, legal text, + crate metadata, and machine SPDX identifiers. cargo-about covers Rust. + Container applications/OS packages retain their additional upstream licenses. PORTABILITY - All first-party project files and state live below stack/. Standard host - integration consists of packages, subordinate UID/GID allocations, one - low-port sysctl setting, user linger, and a systemd user-service link. - Host SSH keys, firewall policy, accounts, and disks are host administration, - not application export contents. + All first-party files/state live below stack/. Standard host integration: + packages, subordinate UID/GID allocations, one low-port sysctl, user linger, + systemd user-service link. Host SSH keys, firewall policy, accounts, and disks + are host administration, excluded from application exports. - Releases contain static x86_64 Linux management/chat commands, the WASM - browser crypto module, exact corresponding sources, and native - linux/amd64 container images. They are portable across compatible x86_64 - Linux machines. An ARM machine needs a native release build; the command - rejects mismatched production images. Development mode may fetch/build - native images on an architecture mismatch. Container source and Rust - source are public so new targets can be added without restoring an OS. + Releases include static x86_64 Linux management/chat commands, WASM browser + crypto, exact corresponding sources, native linux/amd64 container images. + Compatible x86_64 Linux hosts can run them. ARM needs a native release build; + production rejects mismatched images. Development may fetch/build native + images on architecture mismatch. Public container/Rust sources permit new + targets without restoring an OS. - Generated third-party legal texts retain upstream whitespace and line endings. - .gitattributes exempts only THIRD-PARTY-LICENSES.html from whitespace errors; - first-party source checks remain strict. Workspace audits include every member. + Preserve upstream whitespace/line endings in generated third-party legal + texts. .gitattributes exempts only THIRD-PARTY-LICENSES.html from whitespace + errors. First-party checks stay strict; workspace audits cover every member. STATIC ASSET CACHING - Main-site stylesheet links include the SHA-256 of web/styles.css as a query - version. Update both website templates when CSS changes. The render test - checks that the published URL matches the current stylesheet, preventing - old cached CSS from being paired with new markup. Tooltip text carries the - native hidden attribute as well as CSS visibility rules, so a stylesheet - failure cannot expose it as ordinary page text. + Main-site stylesheet URLs include web/styles.css SHA-256 as query version. + Update both website templates after CSS changes. Render test checks the + published hash, preventing stale CSS/new markup pairs. Tooltip text uses + native hidden plus CSS visibility, so stylesheet failure cannot expose it. diff --git a/docs/TYPESCRIPT.txt b/docs/TYPESCRIPT.txt index 7fbc5a4..7fa5125 100644 --- a/docs/TYPESCRIPT.txt +++ b/docs/TYPESCRIPT.txt @@ -15,81 +15,75 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. TYPESCRIPT BROWSER TOOLCHAIN - All first-party browser logic and browser automation are TypeScript. - Rust still implements cryptography, the API, backups, and deployment. - Browsers execute JavaScript generated by TypeScript; TypeScript adds - compile-time checks and does not replace validation of untrusted input. + First-party browser logic/automation use TypeScript. Rust handles crypto, + API, backups, deployment. Browsers run generated JavaScript; compile-time + types never replace validation of untrusted input. SOURCE LAYOUT crates/chat-server/web/app.ts - Interface, session state, history, downloads, and API validation. + Interface, session, history, downloads, API validation. crates/chat-server/web/worker.ts - One-shot cryptographic worker; its lifetime ends after each request. + One-shot crypto worker; ends after each request. crates/chat-crypto/browser/wasi.ts - Restricted browser WASI host for the unchanged Rust/OpenSSL module. + Restricted WASI host for unchanged Rust/OpenSSL module. crates/chat-crypto/browser/protocol.d.ts - Shared API and cryptographic request/response contracts. Declarations - emit no JavaScript and are checked for both browser environments. + Shared API/crypto request/response contracts. No emitted JavaScript; + checked in both browser environments. crates/chat-crypto/tests/browser.ts - Real WebAssembly compatibility, entropy, and capability tests. + Real WebAssembly compatibility, entropy, capability tests. crates/chat-server/tests/browser.ts - Complete browser chat and recovery tests, including GNU LibreJS. + Complete browser chat/recovery tests, including GNU LibreJS. crates/chat-server/tests/progress.ts - Download progress and failure tests, including GNU LibreJS. + Download progress/failure tests, including GNU LibreJS. tests/browser-support.ts - Checked fixture parsing and typed browser-automation helpers. + Checked fixture parsing, typed browser-automation helpers. - eslint.config.ts and tsconfig.tools.json supply the typed lint-tool checks. - src/app and crates/chat-server/src/app contain the private Rust CLI - implementations; their parser and runtime changes are recorded in LINTING.txt. + eslint.config.ts/tsconfig.tools.json provide typed lint-tool checks. + Private Rust CLIs: src/app and crates/chat-server/src/app. Parser/runtime + changes: LINTING.txt. - tsconfig.json supplies shared strict checks. The browser, worker, and - test configurations use separate DOM, WebWorker, and Node environments. - Production browser builds cannot accidentally rely on Node APIs. - strict, unchecked indexed access, exact optional properties, unused - declarations/parameters, implicit returns, switch fallthrough, implicit - overrides, and indexed-property access are checked. Type errors prevent - emission. No suppression directives or untyped escape hatches are used. + tsconfig.json supplies shared strict checks. Separate browser/worker/test + configs use DOM/WebWorker/Node environments, preventing accidental production + Node API use. Check strict, unchecked indexed access, exact optional properties, + unused declarations/parameters, implicit returns, switch fallthrough, implicit + overrides, indexed-property access. Type errors prevent emission. + No suppression directives or untyped escape hatches. DEVELOPMENT - Install Node >=22.18.0 and npm on the development machine. Root package.json - and package-lock.json pin TypeScript 7.0.2, Playwright 1.64.1, Node type - declarations, platform compiler packages, and their integrity hashes. - ESLint 10.14.0 and typescript-eslint 8.72.1 provide typed strict linting. - TypeScript 6.0.3 supplies their supported JavaScript API; the pinned native - TypeScript 7.0.2 alias remains the emitting compiler. Both check the sources. - LINTING.txt documents the advisory-driven minimatch override. - There are no npm application/runtime dependencies. TypeScript and - Playwright use the Apache License, Version 2.0; Node declarations and - undici-types use the Expat License. Original notices remain in the - installed packages. SPDX identifiers retain their required spelling. + Development needs Node >=22.18.0/npm. Root package.json/package-lock.json pin + TypeScript 7.0.2, Playwright 1.64.1, Node declarations, platform compilers, + integrity hashes. ESLint 10.14.0/typescript-eslint 8.72.1 supply typed strict + linting. TypeScript 6.0.3 supplies their supported JavaScript API; native + TypeScript 7.0.2 alias emits. Both check sources. LINTING.txt explains the + advisory-driven minimatch override. No npm application/runtime dependencies. + TypeScript/Playwright: Apache License, Version 2.0. Node declarations/ + undici-types: Expat License. Installed packages retain original notices; + machine SPDX spelling stays unchanged. - Build and check all TypeScript, including browser tests: + Build/check all TypeScript, including browser tests: npm run build - infra/chat/build-typescript.sh installs the locked development packages - with lifecycle scripts disabled, checks browser/worker/test/tool configurations, - typed ESLint, both compiler versions, and npm advisories, then - emits JavaScript under var/build/typescript. The npm cache stays under - .tools/npm-cache. node_modules and generated outputs are ignored by Git. - Generated scripts are readable and unminified; no bundler is needed. + infra/chat/build-typescript.sh installs locked dev packages without lifecycle + scripts, checks browser/worker/test/tool configs, typed ESLint, both compilers, + npm advisories; emits JavaScript under var/build/typescript. npm cache: + .tools/npm-cache. Git ignores node_modules/generated output. Scripts stay + readable/unminified; no bundler needed. - cargo stack check includes this build, then the strict Rust checks and - cargo-about license generation. cargo stack release builds TypeScript - before packaging the complete production release. + cargo stack check runs this build, strict Rust checks, cargo-about generation. + cargo stack release builds TypeScript before packaging production artifacts. - Recheck without reinstalling packages after npm run build: + Recheck after npm run build without reinstalling: npm run check - Fetch the pinned Playwright browser versions once: + Fetch pinned Playwright browsers once: PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" node_modules/.bin/playwright install chromium firefox - After building the native chat server and WASI module: + Build native chat server/WASI module, then run: PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:crypto PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:chat @@ -97,42 +91,35 @@ DEVELOPMENT CHAT_LIBREJS=1 PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:chat CHAT_LIBREJS=1 PLAYWRIGHT_BROWSERS_PATH="$PWD/.tools/browsers" npm run test:progress - LibreJS variants require the signed Mozilla extension at - .tools/librejs.xpi as documented in CHAT-APPLICATION.txt. The complete - chat test proves LibreJS is active and rejects an unlicensed control. - Run chat variants sequentially because they share the default test port. - npm audit checks development dependencies as part of npm run check and the - Cargo check/release path. It does not audit Rust, browser-delivered code, or - containers; cargo-deny remains the separate strict Rust dependency audit. + LibreJS variants need signed Mozilla extension .tools/librejs.xpi; see + CHAT-APPLICATION.txt. Complete chat test proves LibreJS active and rejects an + unlicensed control. Run chat variants sequentially; they share default port. + npm audit checks dev dependencies in npm run check/Cargo check/release; + it does not audit Rust, delivered browser code, or containers. cargo-deny + remains the separate strict Rust dependency audit. RELEASES, SOURCE, AND LIBREJS - Generated app.js, worker.js, and wasi.mjs keep their existing public URLs. - They preserve the AGPL headers and recognized @license/@license-end - markers. The JavaScript license table links each generated file to its - complete corresponding TypeScript and Rust source archive. Classic scripts - and importScripts remain in use for LibreJS compatibility; the migration - introduces no runtime module loader or third-party browser scripts. - - Local native-server tests serve generated files from var/build/typescript. - The release packages those files into bin/chat/web and bin/chat/wasi.mjs. - Containers serve the packaged files. HTML and CSS are copied explicitly, - so TypeScript source files are not substituted for executable JavaScript. - /SOURCE.tar.gz includes TypeScript, shared declarations, all compiler - configurations, the npm lock, tests and build scripts, together with the - existing Cargo-vendored dependencies and verified OpenSSL source archive. - Node/npm/TypeScript are general-purpose development tools, documented and - pinned here; their installed copies and downloaded browsers are excluded. - - Source exports, releases, and backups carry the root npm manifests and - TypeScript configurations. Release activation and restored prebuilt images - need no Node, npm, TypeScript, or Rust installation on the destination. - They retain the single private root .env and existing persistent data. - The source archive excludes that .env, credentials, runtime databases, - exports, .git, node_modules, and build/cache directories. The root - .env.example remains public. No additional environment file is introduced. - - Test the actual generated JavaScript after any compiler upgrade. Static - types cannot guarantee privacy, security, or LibreJS recognition. Browser - storage restrictions, protocol validation, and algorithm choices continue - to be enforced by the existing runtime and Rust implementation. + Generated app.js/worker.js/wasi.mjs retain public URLs, AGPL headers, + recognized @license/@license-end markers. JavaScript license table links + each file to complete corresponding TypeScript/Rust source archive. + Classic scripts/importScripts preserve LibreJS compatibility. No runtime + module loader or third-party browser scripts added. + + Local native-server tests serve var/build/typescript. Release packages files + into bin/chat/web and bin/chat/wasi.mjs; containers serve packaged files. + Copy HTML/CSS explicitly; never substitute TypeScript for executable JS. + /SOURCE.tar.gz contains TypeScript, shared declarations, every compiler config, + npm lock, tests/build scripts, Cargo-vendored dependencies, verified OpenSSL + archive. Node/npm/TypeScript are general-purpose development tools pinned and + documented here. Exclude installed copies/downloaded browsers. + + Source exports/releases/backups carry root npm manifests/TypeScript configs. + Activation/restored prebuilt images need no destination Node/npm/TypeScript/ + Rust. Preserve single private root .env and persistent data. Source archive + excludes .env, credentials, runtime DBs, exports, .git, node_modules, build/cache + directories. Root .env.example remains public; no extra environment file. + + Test generated JavaScript after every compiler upgrade. Static types cannot + guarantee privacy, security, or LibreJS recognition. Existing runtime/Rust + still enforce browser storage restrictions, protocol validation, algorithms. |
