# N2Usenet HTTPS/Nym

N2Usenet HTTPS/Nym is the standalone clearnet-facing web gateway for posting to
Usenet through the existing TCPReset Mail2News and NNTP infrastructure.

It is intentionally separate from the onion `/compose/` deployment. M2Usenet
remains the onion-only compose UI integrated into Onion Newsreader; N2Usenet is
the standalone HTTPS/Nym service for `n2usenet.virebent.art`.

## Flow

```text
Browser
  -> HTTPS n2usenet.virebent.art
  -> N2Usenet Go backend
  -> local nym-socks5-client
  -> Nym network requester
  -> SMTP submission 51.178.55.22:587 STARTTLS + AUTH
     (TLS name mail.virebent.art)
  -> Postfix with SPF/DKIM/DMARC
  -> mail2news@mail2news.tcpreset.net
  -> Mail2News gateway
  -> Tor SOCKS
  -> peannyjkqwqfynd24p6dszvtchkq7hfkwymi5by5y332wmosy5dwfaqd.onion:119
  -> news.tcpreset.net INN
```

## Build

```bash
go test ./...
go build -o n2usenet ./cmd/n2usenet
go build -o n2u-check ./cmd/n2u-check
```

## Features

- **Proof-of-work anti-spam**: client computes a hashcash-style token before
  submission; the server only verifies it (never computes it) and caches
  spent tokens in memory with a TTL to reject replays.
- **Ed25519 signing**: the message is signed locally in the browser with the
  self-hosted TweetNaCl (`nacl`) library. The secret key never leaves the
  device; the server only verifies the signature against the submitted text.
- **VFACE identicon / `Face:` header**: the complete
  `username|email|public-key` identity deterministically generates a visual
  identicon (`identicons-cli` engine, same backend as
  `identicons.virebent.art`), embedded as a folded `Face:` header alongside
  `X-Ed25519-Pub`/`X-Ed25519-Sig` so any reader can re-verify authorship.
- **Optional persistent identity (save/load)**: after generating a keypair,
  "Save Identity" downloads a JSON file with the public/secret key and
  username/email. Loading that file later restores the complete identity, so
  the same identicon keeps appearing across posts and lets readers associate
  later signatures with the same public key. Username, email, and keypair are
  locked together while that identity is active. This is entirely optional:
  skip it for a fresh, unlinkable throwaway identity on every post. The file
  contains the secret key in clear, so it must be kept private, anyone holding
  it can sign as that identity.
- **Usenet-style line wrapping**: before signing, the message body is
  automatically word-wrapped to 72 columns (RFC 1855 Netiquette
  convention), for compatibility with classic terminal-based newsreaders.
  Blank lines and quoted lines (`>`) are left untouched. The wrap happens
  client-side, before the Ed25519 signature is computed, so the signature
  always covers the exact bytes that end up posted.
- **CSRF protection and per-IP rate limiting**, both server-side.
- **No access logs, ephemeral state**: identity and form data are kept only
  in browser tab memory and wiped after a successful send.
- **Nym followed by Tor for separate hops**: SOCKS5 through a local
  `nym-socks5-client`/`nym-network-requester` carries authenticated SMTP/TLS
  submission to the Virebent MTA. Postfix signs and relays the message to
  Mail2News. Mail2News then uses Tor to post to the TCPReset onion NNTP
  endpoint. The browser-to-N2Usenet hop remains HTTPS.

## Required Configuration

Set these in an environment file or systemd unit:

```text
N2U_LISTEN=127.0.0.1:8095
N2U_PUBLIC_BASE_URL=https://n2usenet.virebent.art

N2U_SMTP_HOST=51.178.55.22
N2U_SMTP_PORT=587
N2U_SMTP_TLS_SERVER_NAME=mail.virebent.art
N2U_SMTP_IMPLICIT_TLS=false
N2U_SMTP_RECIPIENT=mail2news@mail2news.tcpreset.net
N2U_SMTP_ENVELOPE_FROM=n2usenet@virebent.art
N2U_SMTP_SENDER=n2usenet@virebent.art
N2U_SMTP_USERNAME=n2usenet@virebent.art
N2U_SMTP_PASSWORD_FILE=/etc/n2usenet/smtp-password
N2U_SMTP_HELO=n2usenet.virebent.art
N2U_TRANSPORT_PROBE_INTERVAL=15m
N2U_MESSAGE_ID_DOMAIN=n2usenet.virebent.art
N2U_CSRF_KEY_FILE=/etc/n2usenet/csrf-key

N2U_IDENTICONS_CLI=/usr/local/bin/identicons-cli
N2U_REQUIRE_FACE=true

N2U_NYM_ENABLED=true
N2U_NYM_MANAGED=false
N2U_NYM_BINARY=/opt/n2usenet/bin/nym-socks5-client
N2U_NYM_HOME=/var/lib/n2usenet/nym
N2U_NYM_SOCKS=127.0.0.1:11080
```

Do not commit provider credentials, SMTP credentials, private keys, or operator
secrets. The provider address is deployment configuration.

## Notes

- Hashcash replay protection is memory-only and is not written to disk.
- IP rate limiting uses an in-memory keyed hash and is not persisted.
- Ed25519 signatures are verified server-side when posts are submitted.
- `Face:` is mandatory by default: every accepted identity must produce a VFACE
  header from `username|email|ed25519-public-key`.
- The browser still generates/loads the Ed25519 identity and signs messages
  locally. The server never receives the Ed25519 secret key.
- Browser identity, message fields, and submission state are kept only in tab
  memory. After a successful send, the UI clears the key material and form
  inputs immediately.
- SMTP uses a fixed envelope sender by default, `n2usenet@virebent.art`, so the
  Mail2News relay does not depend on the user's pseudonymous email passing
  remote sender policy checks.
- The RFC 5322 `From:` header publishes the complete profile identity,
  `username <email>`. `Sender:` identifies `n2usenet@virebent.art` as the
  submitting agent, while SMTP AUTH and the envelope sender remain fixed on
  that service account. The profile email is a signed pseudonymous identity
  claim, not proof that the user controls its domain.
- SMTP credentials are read from a root-managed file and AUTH is rejected by
  the application configuration unless TLS is enabled.
- Production uses the MTA's global IPv4 address as the SOCKS destination while
  still verifying `mail.virebent.art` in TLS. This keeps the Nym requester's
  non-global-address filter strict when the MTA host resolves its own hostname
  to local interface addresses.
- `/submit` returns `Cache-Control: no-store` and the browser path uses fetch
  so successful submissions do not leave the full form state in the rendered
  response page.
- The CSRF cookie is session-scoped without a fixed elapsed-time expiry. The
  browser refreshes the signed token immediately before submission. Production
  uses a root-managed signing key so restarts do not invalidate open tabs, and
  valid session tokens are reused so multiple tabs cannot rotate each other's
  cookie.
- `/healthz` reports only process liveness. `/readyz` reports the cached result
  of a background Nym/STARTTLS/SMTP AUTH probe and never creates transport
  traffic in response to an HTTP request.
- `n2usenet-gateway-watch.timer` checks the active Nym gateway registration
  daily. It rotates only within 24 hours of expiry, verifies the complete SMTP
  path without sending mail, and restores the previous gateway database if the
  replacement fails.
- The app does not add a clearnet fallback to the M2Usenet onion PHP sender.
- The service now prefers the `N2U_*` environment variable prefix and still
  accepts legacy `M2U_*` variables during the rollout.

## Current Production Status

As of 2026-07-13 the standalone service is live on `pietro` and the Nym SMTP
transport is working through a dedicated requester on `victor` and a local
`nym-socks5-client` on `pietro`.

Working deployment shape:

- `victor` and `rasmus` are SSH aliases for the same host, `51.178.55.22`.
- `victor` runs `n2usenet-network-requester.service`.
- `pietro` runs `n2usenet-socks.service` on `127.0.0.1:11080`.
- `pietro` runs `n2usenet.service` with authenticated SMTP submission to
  `51.178.55.22:587` through Nym and verifies `mail.virebent.art` in TLS.
- `pietro` uses `n2usenet@virebent.art` as the SMTP envelope sender.
- `victor` Postfix relays to `mail2news@mail2news.tcpreset.net` with the
  domain's SPF, DKIM, and DMARC policy.

`identicons-cli` is already available on `victor` at `/usr/local/bin/identicons-cli`.
Its output was checked against the `Ch1ffr3punk/identicons` engine using
multiple deterministic `username|email|pubkey` inputs; the decoded 48x48 PNG
outputs matched byte-for-byte.

Direct SMTP checks from `victor` confirm that `mail2news.tcpreset.net` accepts:

- `25` with STARTTLS.
- `587` with STARTTLS.
- `465` with implicit TLS.
