IRC: Add option for SASL authentication.

This additionally reverts to using sync IRC client, because upstream
https://github.com/jaraco/irc only supports it for the sync client.
This commit is contained in:
rht 2023-10-01 01:46:56 -04:00 committed by Anders Kaseorg
parent f11e960537
commit 2814accb09
3 changed files with 17 additions and 17 deletions

View file

@ -18,7 +18,9 @@ Example:
--stream is a Zulip stream. --stream is a Zulip stream.
--topic is a Zulip topic, is optionally specified, defaults to "IRC". --topic is a Zulip topic, is optionally specified, defaults to "IRC".
--nickserv-pw is a password for the nickserv, is optionally specified. Optional arguments:
--nickserv-pw is a password for the nickserv.
--sasl-password is a password for SASL authentication.
Specify your Zulip API credentials and server in a ~/.zuliprc file or using the options. Specify your Zulip API credentials and server in a ~/.zuliprc file or using the options.
@ -36,6 +38,7 @@ if __name__ == "__main__":
parser.add_argument("--stream", default="general") parser.add_argument("--stream", default="general")
parser.add_argument("--topic", default="IRC") parser.add_argument("--topic", default="IRC")
parser.add_argument("--nickserv-pw", default="") parser.add_argument("--nickserv-pw", default="")
parser.add_argument("--sasl-password", default=None)
options = parser.parse_args() options = parser.parse_args()
# Setting the client to irc_mirror is critical for this to work # Setting the client to irc_mirror is critical for this to work
@ -64,5 +67,6 @@ if __name__ == "__main__":
options.irc_server, options.irc_server,
options.nickserv_pw, options.nickserv_pw,
options.port, options.port,
sasl_password=options.sasl_password,
) )
bot.start() bot.start()

View file

@ -1,16 +1,13 @@
import multiprocessing as mp import multiprocessing as mp
import sys import sys
from typing import Any, Dict from typing import Any, Dict, Optional
import irc.bot import irc.bot
import irc.strings import irc.strings
from irc.client import Event, ServerConnection, ip_numstr_to_quad from irc.client import Event, ServerConnection, ip_numstr_to_quad
from irc.client_aio import AioReactor
class IRCBot(irc.bot.SingleServerIRCBot): class IRCBot(irc.bot.SingleServerIRCBot):
reactor_class = AioReactor
def __init__( def __init__(
self, self,
zulip_client: Any, zulip_client: Any,
@ -21,6 +18,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
server: str, server: str,
nickserv_password: str = "", nickserv_password: str = "",
port: int = 6667, port: int = 6667,
sasl_password: Optional[str] = None,
) -> None: ) -> None:
self.channel: irc.bot.Channel = channel self.channel: irc.bot.Channel = channel
self.zulip_client = zulip_client self.zulip_client = zulip_client
@ -31,19 +29,17 @@ class IRCBot(irc.bot.SingleServerIRCBot):
# Make sure the bot is subscribed to the stream # Make sure the bot is subscribed to the stream
self.check_subscription_or_die() self.check_subscription_or_die()
# Initialize IRC bot after proper connection to Zulip server has been confirmed. # Initialize IRC bot after proper connection to Zulip server has been confirmed.
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname) if sasl_password is not None:
irc.bot.SingleServerIRCBot.__init__(
self, [(server, port, sasl_password)], nickname, nickname, sasl_login=nickname
)
else:
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
def zulip_sender(self, sender_string: str) -> str: def zulip_sender(self, sender_string: str) -> str:
nick = sender_string.split("!")[0] nick = sender_string.split("!")[0]
return nick + "@" + self.IRC_DOMAIN return nick + "@" + self.IRC_DOMAIN
def connect(self, *args: Any, **kwargs: Any) -> None:
# Taken from
# https://github.com/jaraco/irc/blob/main/irc/client_aio.py,
# in particular the method of AioSimpleIRCClient
self.c = self.reactor.loop.run_until_complete(self.connection.connect(*args, **kwargs))
print("Listening now. Please send an IRC message to verify operation")
def check_subscription_or_die(self) -> None: def check_subscription_or_die(self) -> None:
resp = self.zulip_client.get_subscriptions() resp = self.zulip_client.get_subscriptions()
if resp["result"] != "success": if resp["result"] != "success":
@ -76,7 +72,7 @@ class IRCBot(irc.bot.SingleServerIRCBot):
at_the_specified_subject = msg["subject"].casefold() == self.topic.casefold() at_the_specified_subject = msg["subject"].casefold() == self.topic.casefold()
if in_the_specified_stream and at_the_specified_subject: if in_the_specified_stream and at_the_specified_subject:
msg["content"] = "@**{}**: ".format(msg["sender_full_name"]) + msg["content"] msg["content"] = "@**{}**: ".format(msg["sender_full_name"]) + msg["content"]
send = lambda x: self.c.privmsg(self.channel, x) send = lambda x: c.privmsg(self.channel, x)
else: else:
return return
else: else:
@ -86,9 +82,9 @@ class IRCBot(irc.bot.SingleServerIRCBot):
if u["email"] != msg["sender_email"] if u["email"] != msg["sender_email"]
] ]
if len(recipients) == 1: if len(recipients) == 1:
send = lambda x: self.c.privmsg(recipients[0], x) send = lambda x: c.privmsg(recipients[0], x)
else: else:
send = lambda x: self.c.privmsg_many(recipients, x) send = lambda x: c.privmsg_many(recipients, x)
for line in msg["content"].split("\n"): for line in msg["content"].split("\n"):
send(line) send(line)

View file

@ -1 +1 @@
irc==18.0 irc~=20.3