From 294a05ead630776149db1e5cd637a40cf6875ee9 Mon Sep 17 00:00:00 2001 From: Gab <24553253+gabrix73@users.noreply.github.com> Date: Sun, 16 Aug 2026 17:35:18 +0200 Subject: Secure private onion Mail2News ingress --- AGENTS.md | 12 ++++++++++++ README.md | 26 ++++++++++++++++---------- deploy/README.md | 27 +++++++++++++++++++++++++++ deploy/postfix/diego-master.cf.fragment | 12 ++++++++++++ deploy/postfix/m2usenet-ingress | 1 + deploy/postfix/victor-master.cf.fragment | 13 +++++++++++++ deploy/postfix/victor-transport.fragment | 3 +++ deploy/tor/.gitignore | 2 ++ deploy/tor/diego-torrc.fragment | 4 ++++ deploy/tor/victor-torrc.fragment | 7 +++++++ send.php | 20 ++++++++++---------- 11 files changed, 107 insertions(+), 20 deletions(-) create mode 100644 AGENTS.md create mode 100644 deploy/README.md create mode 100644 deploy/postfix/diego-master.cf.fragment create mode 100644 deploy/postfix/m2usenet-ingress create mode 100644 deploy/postfix/victor-master.cf.fragment create mode 100644 deploy/postfix/victor-transport.fragment create mode 100644 deploy/tor/.gitignore create mode 100644 deploy/tor/diego-torrc.fragment create mode 100644 deploy/tor/victor-torrc.fragment diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e4c647c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,12 @@ +# Repository guidance + +- Use the Gab Virebent identity for this repository and its Virebent remote. +- Commit and push tested source and deployment fragments to + `git.virebent.art/virebent/m2usenet-and-mail2news` before changing + production. +- Do not commit Tor client-authorization entries, private keys, credentials, + message contents, or production logs. +- Keep the integrated M2Usenet path Onion-only. Do not add a clearnet fallback. +- Treat SMTP `250` as relay acceptance, not proof of final NNTP publication. +- Hidden services must terminate on dedicated restricted listeners, never on + a Postfix listener that trusts loopback through `mynetworks`. diff --git a/README.md b/README.md index 4e555f3..06fb6a3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Privacy-focused Usenet posting system with authentication preprocessing** -m2usenet is a secure, privacy-oriented web interface for posting to Usenet newsgroups. The system preprocesses messages with cryptographic authentication (Hashcash + Ed25519) before forwarding them to external mail2news gateways, featuring automatic fallback between .onion and clearnet gateways. +m2usenet is a secure, privacy-oriented web interface for posting to Usenet newsgroups. The system preprocesses messages with cryptographic authentication (Hashcash + Ed25519) before forwarding them through Tor to a private Mail2News onion ingress. ## 🏗️ Architecture @@ -15,7 +15,7 @@ m2usenet is a secure, privacy-oriented web interface for posting to Usenet newsg └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ ``` -**Flow:** Web UI → Local sendmail → m2usenet preprocessor → External mail2news gateway → Usenet +**Current integrated flow:** Web UI → Tor → private Mail2News onion ingress → Mail2News → Tor/onion NNTP → Usenet ## 🔐 Security Features @@ -23,14 +23,21 @@ m2usenet is a secure, privacy-oriented web interface for posting to Usenet newsg - **Ed25519 Digital Signatures**: Cryptographic message authentication - **Tor Integration**: Primary routing through .onion networks - **No Data Collection**: Zero access logs, no tracking -- **Automatic Fallback**: .onion → clearnet gateway redundancy +- **Private SMTP ingress**: Tor v3 client authorization and restricted Postfix recipient policy ## 🌐 Gateway Configuration -| Priority | Gateway | Description | -|----------|---------|-------------| -| **Primary** | `mail2news@xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion` | Via Tor for privacy | -| **Fallback** | `mail2news@mail2news.tcpreset.net` | Clearnet for reliability | +| Role | Gateway | Description | +|------|---------|-------------| +| **Primary and retry** | `mail2news@xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion` | Private Onion ingress reached through Tor | + +There is no clearnet fallback in the integrated Onion Newsreader path. SMTP +acceptance means that the private relay queued the message; final NNTP +publication is asynchronous. + +The restricted Tor and Postfix deployment fragments are documented in +[`deploy/`](deploy/README.md). Authorization keys are deployment secrets and +must never be committed. ## 📋 Requirements @@ -98,8 +105,8 @@ sudo chmod 755 /var/www/m2usenet /var/log/m2usenet /home/m2usenet ```bash # Clone repository (or download files) cd /tmp -git clone https://github.com/your-repo/m2usenet.git -cd m2usenet +git clone ssh://git@git.virebent.art:2223/virebent/m2usenet-and-mail2news.git +cd m2usenet-and-mail2news # Copy web frontend sudo cp index.php send.php powWorker.js /var/www/m2usenet/ @@ -352,4 +359,3 @@ Contributions are welcome! Please read CONTRIBUTING.md for guidelines. **m2usenet v1.0.0** - Privacy-focused Usenet posting for the modern era - diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..5046bb5 --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,27 @@ +# Private M2Usenet onion ingress + +The integrated M2Usenet sender connects through Tor directly to the Mail2News +onion service. The production hidden service uses Tor v3 client authorization +and terminates on a dedicated loopback-only Postfix listener. + +Apply the fragments from this directory through the normal configuration +management or deployment process. They are intentionally not complete server +configuration files. + +Deployment order: + +1. Generate a Tor v3 client-authorization key pair outside the repository. +2. Install the public authorization entry in the hidden service's + `authorized_clients` directory on the Mail2News host. +3. Install the private authorization entry in `ClientOnionAuthDir` on the + M2Usenet host, mode `0600`, readable only by the Tor service account. +4. Install and compile the Postfix maps, then validate Postfix. +5. Validate Tor configuration and reload both services. +6. Test unauthorized connection rejection and recipient restrictions before + deploying `send.php`. +7. Deploy the committed application revision and verify final NNTP + publication with a controlled article. + +Never commit either authorization entry. A Tor hidden-service connection +arrives from loopback, so it must never be forwarded to a Postfix listener +that grants relay permission to `mynetworks`. diff --git a/deploy/postfix/diego-master.cf.fragment b/deploy/postfix/diego-master.cf.fragment new file mode 100644 index 0000000..2a2e1d5 --- /dev/null +++ b/deploy/postfix/diego-master.cf.fragment @@ -0,0 +1,12 @@ +# Dedicated ingress for the private Mail2News onion hidden service. +127.0.0.1:2526 inet n - n - 4 smtpd + -o syslog_name=postfix/m2usenet-onion + -o myhostname=xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion + -o smtpd_tls_security_level=none + -o smtpd_sasl_auth_enable=no + -o smtpd_relay_restrictions=reject_unauth_destination + -o smtpd_recipient_restrictions=check_recipient_access,hash:/etc/postfix/m2usenet-ingress,reject + -o smtpd_reject_unlisted_recipient=yes + -o smtpd_helo_required=yes + -o smtpd_recipient_limit=1 + -o message_size_limit=131072 diff --git a/deploy/postfix/m2usenet-ingress b/deploy/postfix/m2usenet-ingress new file mode 100644 index 0000000..fb42230 --- /dev/null +++ b/deploy/postfix/m2usenet-ingress @@ -0,0 +1 @@ +mail2news@xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion OK diff --git a/deploy/postfix/victor-master.cf.fragment b/deploy/postfix/victor-master.cf.fragment new file mode 100644 index 0000000..9012438 --- /dev/null +++ b/deploy/postfix/victor-master.cf.fragment @@ -0,0 +1,13 @@ +# Restricted target for the legacy qee4 hidden service. Do not forward it to +# the ordinary SMTP listener, which may trust loopback through mynetworks. +127.0.0.1:2527 inet n - n - 4 smtpd + -o syslog_name=postfix/qee-onion + -o myhostname=qee4i7sags6phsvb2yodwecfj7noimfhhalsjktsvikrwotxzis3raad.onion + -o smtpd_tls_security_level=none + -o smtpd_sasl_auth_enable=no + -o smtpd_relay_restrictions=reject_unauth_destination + -o smtpd_recipient_restrictions=reject_unauth_destination + -o smtpd_reject_unlisted_recipient=yes + -o smtpd_helo_required=yes + -o smtpd_recipient_limit=1 + -o message_size_limit=131072 diff --git a/deploy/postfix/victor-transport.fragment b/deploy/postfix/victor-transport.fragment new file mode 100644 index 0000000..cf7d820 --- /dev/null +++ b/deploy/postfix/victor-transport.fragment @@ -0,0 +1,3 @@ +# Exact lookup is required; relying only on a parent .onion key can select the +# ordinary SMTP transport depending on Postfix parent-domain matching policy. +xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion smtptor: diff --git a/deploy/tor/.gitignore b/deploy/tor/.gitignore new file mode 100644 index 0000000..e2124bd --- /dev/null +++ b/deploy/tor/.gitignore @@ -0,0 +1,2 @@ +*.auth +*.auth_private diff --git a/deploy/tor/diego-torrc.fragment b/deploy/tor/diego-torrc.fragment new file mode 100644 index 0000000..71847d6 --- /dev/null +++ b/deploy/tor/diego-torrc.fragment @@ -0,0 +1,4 @@ +# Client authorization entries are generated and installed outside Git under: +# /var/lib/tor/mail/authorized_clients/ +HiddenServiceDir /var/lib/tor/mail/ +HiddenServicePort 25 127.0.0.1:2526 diff --git a/deploy/tor/victor-torrc.fragment b/deploy/tor/victor-torrc.fragment new file mode 100644 index 0000000..b687f43 --- /dev/null +++ b/deploy/tor/victor-torrc.fragment @@ -0,0 +1,7 @@ +# The private client authorization entry is generated and installed outside +# Git under this directory with mode 0600. +ClientOnionAuthDir /var/lib/tor/onion_auth + +# Keep the legacy qee4 service isolated from the ordinary SMTP listener. +HiddenServiceDir /var/lib/tor/Mail/ +HiddenServicePort 25 127.0.0.1:2527 diff --git a/send.php b/send.php index 36e93b0..bb00986 100644 --- a/send.php +++ b/send.php @@ -19,17 +19,17 @@ ini_set('max_execution_time', 180); // SMTP Relay Configuration define('PRIMARY_RELAY', [ - 'host' => 'qee4i7sags6phsvb2yodwecfj7noimfhhalsjktsvikrwotxzis3raad.onion', + 'host' => 'xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion', 'port' => 25, 'mail2news' => 'mail2news@xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion', - 'name' => 'qee4-primary' + 'name' => 'mail2news-onion-primary' ]); define('FALLBACK_RELAY', [ 'host' => 'xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion', 'port' => 25, 'mail2news' => 'mail2news@xilb7y4kj6u6qfo45o3yk2kilfv54ffukzei3puonuqlncy7cn2afwyd.onion', - 'name' => 'smtp-fallback' + 'name' => 'mail2news-onion-retry' ]); // Security Configuration @@ -147,7 +147,7 @@ function sendMessage($data) { } if ($result['success']) { - secureLog("Message delivered successfully via {$relay['name']} relay"); + secureLog("Message accepted successfully by {$relay['name']} relay"); } else { secureLog("Message delivery failed on both PRIMARY and FALLBACK relays", 'ERROR'); } @@ -892,13 +892,13 @@ function sendViaNativePHPSMTP($data, $smtpRelay, $smtpPort, $mail2newsAddress) { @smtpSendCommand($socket, "QUIT\r\n", 221); $totalTime = microtime(true) - $startTime; - secureLog(sprintf("=== Message delivered successfully in %.2fs ===", $totalTime)); + secureLog(sprintf("=== Message accepted by relay in %.2fs ===", $totalTime)); fclose($socket); return [ 'success' => true, - 'message' => 'Message sent via secure onion gateway', + 'message' => 'Message accepted by the private Mail2News onion relay', 'messageId' => $messageId, 'gateway' => $mail2newsAddress ]; @@ -954,7 +954,7 @@ function successResponse($messageId, $gateway) {
-