Add TLS transport support

Connect over TLS (default port 6697) using native-tls with the system
OpenSSL trust store for certificate verification. Unify the plaintext and
TLS transports behind a single Box<dyn Read + Write>, dropping the
read/write socket clone that a TLS session cannot support. Add a `tls`
config key and IRC_TLS override; the port auto-defaults to 6697 when TLS
is enabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Jean Chevronnet 2026-07-28 14:57:44 +00:00
parent 05c004d32d
commit ef80b77760
No known key found for this signature in database
GPG key ID: 439666D63A9477E4
5 changed files with 78 additions and 28 deletions

View file

@ -39,12 +39,13 @@ cargo run -- /etc/rustbot.conf # explicit path
RUSTBOT_CONFIG=/etc/rustbot.conf cargo run
```
Config file keys: `server`, `port`, `nick`, `user`, `realname`,
`channels` (comma/space-separated), `prefix`, `password`.
Config file keys: `server`, `port`, `tls`, `nick`, `user`, `realname`,
`channels` (comma/space-separated), `prefix`, `password`, `sasl_user`, `sasl_pass`.
Whole-line `#`/`;` comments only — inline comments would clash with channel `#`s.
Environment overrides: `IRC_SERVER`, `IRC_PORT`, `IRC_NICK`, `IRC_REALNAME`,
`IRC_CHANNELS`, `IRC_PREFIX`, `IRC_PASSWORD`.
Environment overrides: `IRC_SERVER`, `IRC_PORT`, `IRC_TLS`, `IRC_NICK`,
`IRC_REALNAME`, `IRC_CHANNELS`, `IRC_PREFIX`, `IRC_PASSWORD`,
`IRC_SASL_USER`, `IRC_SASL_PASS`.
```sh
IRC_NICK=mybot IRC_CHANNELS='#test' cargo run # override the file for one run
@ -101,9 +102,19 @@ Two of these do real work:
`sasl_user`/`sasl_pass` in the config (or `IRC_SASL_USER`/`IRC_SASL_PASS`).
base64 is hand-rolled, so this stays dependency-free.
## TLS
Set `tls = true` and the port defaults to 6697. The transport wraps the socket
with `native-tls`, which verifies certificates against the **system OpenSSL
trust store** — so TLS security fixes arrive via OS updates rather than a
vendored crypto crate. Plaintext still works with `tls = false` / `port = 6667`.
Plain TCP and TLS share one code path: `Connection` holds a single
`Box<dyn Read + Write>`, since the single-threaded event loop never needs the
old read/write socket split (which TLS can't do anyway).
## Roadmap / natural next steps
- **TLS** (port 6697, or the `tls` STARTTLS cap) — the one remaining item that
needs a dependency (`rustls`/`native-tls`).
- **Read timeout + client-sent PING** to detect dead connections faster.
- **STARTTLS** (the `tls` cap) for networks without a dedicated TLS port.
- Split commands into a registry/trait once there are many of them.