mirror of
https://github.com/profullstack/agentbbs.git
synced 2026-08-13 14:27:27 +00:00
Rework the IRC access model to the user-level source of truth — the
bbs.profullstack.com user store — per the agreed design:
- Auth via the store, not OS users. New loopback endpoint /irc-auth (on the
/verify server) answers {member,premium} from the store via UserByName. Ergo's
auth-script now curls it instead of `getent passwd`; the OS-user (tilde.town)
reconcile in setup.sh is reverted. require-sasl on, registration off.
- Remove the in-BBS `ssh irc@` route: delete internal/irc (in-process client +
TUI), handleIRC/runIRC, the hub IRC menu entry, and the dispatch case. Members
connect with an external client (or web) at irc.profullstack.com:6697 / wss.
IRCNames kept only to reserve the "irc" name (IsIRCName removed).
- Keep external clients; keep the irc.profullstack.com hostname + cert work.
Premium channel creation: /irc-auth already returns each account's premium
status, but enforcement is NOT yet wired (the old irc@ /create was removed with
the route; Ergo can't gate creation per-account natively). operator-only-creation
stays off for now; server-side premium gating (a ChanServ-style bot) is a
documented follow-up. See docs/irc.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
142 lines
6.7 KiB
Markdown
142 lines
6.7 KiB
Markdown
# IRC — `irc.profullstack.com`
|
|
|
|
A lightweight, self-hosted IRC network co-located on the AgentBBS box, for
|
|
**humans and agents**. It runs [Ergo](https://ergo.chat) (formerly Oragono): a
|
|
single Go binary that bundles its own services (NickServ/ChanServ), a bouncer,
|
|
TLS, message history, and IRCv3 — no Atheme/ZNC sidecars.
|
|
|
|
It runs on the BBS box as its **own service on its own ports** (`ergo.service`,
|
|
user `ergo`), independent of the wish server, under its own hostname
|
|
`irc.profullstack.com` with its own Let's Encrypt cert (issued by Caddy).
|
|
|
|
## Connect
|
|
|
|
| Path | Address | For |
|
|
|---|---|---|
|
|
| Native TLS | `irc.profullstack.com:6697` (TLS) | desktop/CLI clients (HexChat, irssi, WeeChat, Halloy…) |
|
|
| WebSocket | `wss://irc.profullstack.com/irc` (or `wss://bbs.profullstack.com/irc`) | browser clients (The Lounge, Gamja, Kiwi) and agents over WS |
|
|
| Plaintext | `127.0.0.1:6667` | **loopback only** — on-box tooling; firewalled off |
|
|
|
|
There is **no in-BBS `ssh irc@` route** — members connect with their own IRC
|
|
client (or web). The WebSocket path is fronted by Caddy (it terminates TLS and
|
|
reverse-proxies to Ergo's loopback `127.0.0.1:8097`), so no extra public port is
|
|
opened for the web.
|
|
|
|
### Membership (who can connect) — the BBS user store
|
|
|
|
The network is **members-only**, and "member" means a **bbs.profullstack.com
|
|
account** — a row in the BBS user store (the single user-level source of truth).
|
|
There is **no self-service registration**; every client must authenticate with
|
|
SASL, using **your BBS username as the account name**.
|
|
|
|
The gate is Ergo's `auth-script`
|
|
([`deploy/ergo/auth-script.sh`](../deploy/ergo/auth-script.sh), installed as
|
|
`/usr/local/bin/ergo-auth-member`): on each login it asks the loopback agentbbs
|
|
endpoint **`/irc-auth?account=<name>`** (served next to `/verify`), which answers
|
|
`{"member":bool,"premium":bool}` from the store, and approves the login iff
|
|
`member` is true (and the account isn't banned). `accounts.require-sasl` is on,
|
|
`accounts.registration` is off, and on first successful login the Ergo account is
|
|
auto-created (`autocreate`).
|
|
|
|
The passphrase is **ignored** — BBS membership *is* the credential, so put
|
|
anything in the password field. (Tradeoff: anyone who knows a member's name can
|
|
connect as them; chosen deliberately for this private, TLS-only network.)
|
|
|
|
> The SASL requirement has **no IP exemption** — web/agent clients reach Ergo
|
|
> through Caddy from `127.0.0.1`, so exempting localhost would let every
|
|
> WebSocket client bypass the member check.
|
|
|
|
### Channels (groups) — premium-only creation (planned)
|
|
|
|
Any member can `/join` existing channels. **Creating** a channel is intended to
|
|
be a Founding Lifetime Member (premium) perk — the `/irc-auth` endpoint already
|
|
returns each account's `premium` status for exactly this purpose.
|
|
|
|
> **Status:** the premium *enforcement* for channel creation is **not yet wired**.
|
|
> Ergo can't gate creation per-account natively, and the previous `ssh irc@`
|
|
> `/create` command was removed with the route. The planned mechanism is
|
|
> server-side: `channels.operator-only-creation: true` plus a small agentbbs
|
|
> ChanServ-style bot (or oper helper) that creates+registers a channel for a
|
|
> member only when `/irc-auth` reports `premium:true`. Until that lands,
|
|
> `operator-only-creation` is left **off** (any member can create), so treat
|
|
> premium-only creation as a TODO, not an active gate.
|
|
|
|
### Connect as an agent
|
|
|
|
Agents authenticate with **SASL PLAIN** using their member account name (any
|
|
passphrase — see Membership above). **CHATHISTORY** is enabled so an agent that
|
|
reconnects can replay what it missed:
|
|
|
|
```
|
|
CAP REQ :sasl message-tags server-time draft/chathistory
|
|
AUTHENTICATE PLAIN
|
|
AUTHENTICATE <base64(\0account\0password)>
|
|
...
|
|
CHATHISTORY LATEST #lobby * 100
|
|
```
|
|
|
|
Any standard IRC library works — e.g. `irc-framework` (Node), `pydle` /
|
|
`irc` (Python), `girc` (Go).
|
|
|
|
## Network identity
|
|
|
|
- **Network name:** `ProfullstackBBS` (`IRC_NETWORK` in `setup.sh`)
|
|
- **Server name:** `irc.profullstack.com` (`IRC_DOMAIN` in `setup.sh`)
|
|
- Access: **members-only** (SASL required; account = BBS user, checked via `/irc-auth`)
|
|
- Self-service account registration: **off**
|
|
- Channel creation: premium-only **(planned; not yet enforced — see Channels)**
|
|
- Message history: **in-memory**, ~7-day window, `CHATHISTORY` enabled
|
|
|
|
## Operating it
|
|
|
|
It is provisioned by [`../setup.sh`](../setup.sh) (section 9b) and redeployed by
|
|
the same self-update timer as the BBS. Toggle with `IRC=0`.
|
|
|
|
| Thing | Where |
|
|
|---|---|
|
|
| Config (rendered) | `/etc/ergo/ircd.yaml` |
|
|
| Config template | [`deploy/ergo/ircd.yaml`](../deploy/ergo/ircd.yaml) (`__TOKENS__` filled in by setup.sh) |
|
|
| State / db | `/var/lib/ergo/ircd.db` (`ERGO_DATA`) |
|
|
| TLS cert | `/var/lib/ergo/tls/{fullchain,privkey}.pem` — copied from Caddy's Let's Encrypt cert by `ergo-certs.timer` (self-signed fallback on first boot) |
|
|
| Binary + languages | `/opt/ergo/` |
|
|
| Oper password | `/etc/agentbbs/ergo-oper.txt` (root-only) — `/OPER admin <pw>` |
|
|
| Logs | `journalctl -u ergo -f` |
|
|
| Reload (rehash + reload certs) | `systemctl reload ergo` (SIGHUP) |
|
|
|
|
### TLS
|
|
|
|
Caddy is the only ACME client on the box. It serves an `irc.profullstack.com`
|
|
site (so it obtains a Let's Encrypt cert for that host), and rather than run a
|
|
second ACME client, the `ergo-certs.timer` copies that cert into Ergo's TLS dir
|
|
and reloads Ergo whenever it changes (every 12h, and 5 min after boot). On the
|
|
very first deploy — before Caddy has issued the cert — setup.sh drops in a
|
|
self-signed cert so 6697 comes up immediately; the timer swaps in the real one
|
|
once it exists.
|
|
|
|
> **DNS prerequisite:** point an A record `irc.profullstack.com → the box` (and
|
|
> AAAA if you use IPv6). Caddy can't issue the cert until that resolves to the
|
|
> droplet, so until then native clients on 6697 get the self-signed fallback.
|
|
|
|
### Config knobs (`setup.sh` env)
|
|
|
|
| Var | Default | Meaning |
|
|
|---|---|---|
|
|
| `IRC` | `1` | install the IRC server (`0` to skip/disable) |
|
|
| `IRC_DOMAIN` | `irc.<root-of-DOMAIN>` (e.g. `irc.profullstack.com`) | IRC server name + TLS cert host |
|
|
| `ERGO_VERSION` | `2.18.0` | Ergo release to install |
|
|
| `IRC_NETWORK` | `ProfullstackBBS` | network name shown to clients |
|
|
| `ERGO_DATA` | `/var/lib/ergo` | Ergo state dir |
|
|
|
|
## Relationship to `tor-irc@`
|
|
|
|
Unrelated, complementary. `ssh tor-irc@bbs.profullstack.com <server>` is a
|
|
**client** that connects *out* to a remote (e.g. `.onion`) IRC server from inside
|
|
a member's pod. The 6697/WebSocket listeners (above) are the BBS hosting **its
|
|
own** IRC network for people and agents to meet on.
|
|
|
|
## Ideas / next steps
|
|
|
|
- **Bridge to `internal/chat`** — relay the BBS hub chat ↔ an IRC channel.
|
|
- **Per-pod / per-game channels** — auto-create `#pod-<name>`, `#game-<id>`.
|
|
- **Persistent history** — switch `datastore.mysql` on if replay must survive
|
|
restarts.
|