Authenticate with SASL instead of messaging NickServ #4
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/sasl"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The bot identified by PRIVMSGing NickServ after registration. That leaves a window where it is connected but not logged in, and it needs a password for a service the network may not run.
SASL PLAIN authenticates during registration. The
irclibrary already implements the state machine — passsasl_loginalongside the password and it runsCAP LS->CAP REQ sasl->AUTHENTICATE PLAIN->CAP ENDbefore the bot is visible on the network.Config changes
passwordload_confignow rejects the key rather than ignoring it — a stale config should fail loudly, not connect unauthenticated.sasl_passwordsasl_accountVerification
333 tests, up from 309. Six drive the real handshake against a fake socket rather than just checking the wiring:
Also covered: a server that does not advertise
sasl, and one that rejects the credentials (904).Six mutations introduced and confirmed caught (sasl_login using the nick instead of the account; sasl_login never set; password not reaching the ServerSpec; the old
passwordkey silently ignored; account not defaulting to nick; login_failed reading the wrong slot).A library bug this works around
irc.client.Eventtakes(type, source, target, arguments=None), but the SASL code raisesEvent("login_failed", event.target, ["reason"])— three positional args, so the reason lands intargetandargumentsis always empty.My first
on_login_failedreadevent.argumentsand would have logged "no reason given" for every failure. The handshake test caught it; the handler now reads both slots, so it keeps working if the library is ever fixed.Known constraint: SASL and a server password are mutually exclusive
ServerConnection.connect()usespasswordfor SASL or forPASS, never both — the SASL branch returns before thePASSbranch. So if theallow {}block that matches the bot requires a class password, this cannot currently send it and do SASL.There is a test pinning that branch ordering, so if it ever changes upstream we find out from a failing test rather than in production. Supporting both would mean overriding
connect()to sendPASSfirst — happy to add it if the class password is staying.The bot identified by sending NickServ a PRIVMSG after registration, which means a window where it is connected but not logged in, and a password sitting in a plaintext config for a service the network may not even run. SASL PLAIN authenticates during registration instead. The irc library has a state machine for it: pass sasl_login alongside the password and it does CAP LS -> CAP REQ sasl -> AUTHENTICATE PLAIN -> CAP END before the bot is ever visible on the network. Config - password -> removed, and load_config now rejects the key outright rather than ignoring it and connecting unauthenticated. - sasl_password -> the account password; absent or empty disables SASL. - sasl_account -> defaults to the nick, set it only when they differ. A rejected login is reported on stderr. The library raises login_failed as Event(type, source, target) with the reason in the target slot and no arguments -- Event takes arguments fourth and the call passes three -- so on_login_failed reads both slots. Caught by a test that drives the real handshake; the first version read arguments alone and would have logged "no reason given" every time. Tests: 333, up from 309. Six cover the protocol exchange itself against a fake socket, including a server that does not advertise sasl and a server that rejects the credentials. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>