diff --git a/src/derp/bot.py b/src/derp/bot.py index 40ad43a..6483819 100644 --- a/src/derp/bot.py +++ b/src/derp/bot.py @@ -265,6 +265,12 @@ class Bot: if "*" in flags: self._opers.add(f"{nick}!{user}@{host}") + # JOIN — WHO the joining user to detect oper status + if msg.command == "JOIN" and msg.nick and msg.nick != self.nick: + channel = msg.params[0] if msg.params else "" + if channel: + await self.conn.send(format_msg("WHO", msg.nick)) + # QUIT — remove departed nicks from oper set if msg.command == "QUIT" and msg.prefix: self._opers.discard(msg.prefix) diff --git a/tests/test_integration.py b/tests/test_integration.py index 2bd3897..940e464 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -292,6 +292,27 @@ class TestAdmin: assert not any("Permission denied" in r for r in replies) assert any("Opers:" in r for r in replies) + def test_oper_detection_on_join(self): + """User joining a channel triggers WHO; oper detected mid-session.""" + h = _Harness(channels=["#test"]) + h.inject_registration() + # User joins the channel after the bot is already connected + h.conn.inject(":oper!oper@operhost JOIN #test") + # Server responds to the WHO triggered by the JOIN + h.conn.inject( + ":server 352 test #test oper operhost irc.server oper H* " + ":0 Oper Name" + ) + h.privmsg("oper", "#test", "!admins", user="oper", host="operhost") + asyncio.run(h.run()) + + # Verify WHO was sent for the joining nick + who_sent = [s for s in h.conn.sent if "WHO" in s and "oper" in s] + assert len(who_sent) >= 1 + replies = h.sent_privmsgs("#test") + assert not any("Permission denied" in r for r in replies) + assert any("oper!oper@operhost" in r for r in replies) + # -- Channel filter ---------------------------------------------------------