feat(irc): gate on BBS user store (loopback /irc-auth), drop ssh irc@

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>
This commit is contained in:
Anthony Ettinger 2026-06-14 16:24:16 +00:00
parent 49db5e103d
commit 243ef58e59
8 changed files with 92 additions and 720 deletions

View file

@ -56,9 +56,9 @@ var TorIRCNames = map[string]bool{"tor-irc": true}
// member's pod (premium). Checked after the more specific tor-* routes.
var TorNames = map[string]bool{"tor": true}
// IRCNames route a member straight into the BBS's own (members-only) IRC
// network via an in-process client. Distinct from tor-irc@, which is a client
// for connecting OUT to remote IRC servers over Tor.
// IRCNames is kept only to reserve "irc" as an account/subdomain name: the BBS
// hosts its own IRC network at irc.<domain> but there is no in-BBS irc@ route —
// members connect with an external client. (Distinct from tor-irc@.)
var IRCNames = map[string]bool{"irc": true}
// NewsNames route a member into the BBS's own (members-only) Usenet/NNTP server
@ -93,9 +93,6 @@ func IsTorIRCName(u string) bool { return TorIRCNames[strings.ToLower(u)] }
// IsTorName reports whether the SSH username requests the generic tor passthrough.
func IsTorName(u string) bool { return TorNames[strings.ToLower(u)] }
// IsIRCName reports whether the SSH username requests the in-BBS IRC client.
func IsIRCName(u string) bool { return IRCNames[strings.ToLower(u)] }
// IsNewsName reports whether the SSH username requests the in-BBS newsreader.
func IsNewsName(u string) bool { return NewsNames[strings.ToLower(u)] }