summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatt Arnold2025-02-20 20:08:19 -0500
committerMatt Arnold2025-02-20 20:08:19 -0500
commit5667670e4a28613bdc8689481d08eaf54e945f3e (patch)
tree11afa4505e9907884d36d9c4c4fa8615e0749fc6
parent3b9cdc51408d15c5efebc006ccb1c075282a6a71 (diff)
Add SASL auth
-rw-r--r--IRC.py60
1 files changed, 53 insertions, 7 deletions
diff --git a/IRC.py b/IRC.py
index c26d18e..5f8d09e 100644
--- a/IRC.py
+++ b/IRC.py
@@ -4,6 +4,37 @@ import socket
 import sys
 import irctokens
 import time
+import base64
+
+
+def create_sasl_plain_auth(username, password):
+    # per KICL this is the valid way to do it
+    auth_string = f"{username}\x00{username}\x00{password}"
+    auth_bytes = auth_string.encode("utf-8")
+    base64_auth = base64.b64encode(auth_bytes).decode("utf-8")
+
+    return base64_auth
+
+
+def decode_sasl_plain_auth(base64_auth):
+    """
+    Decode a SASL PLAIN authentication string for verification.
+
+    Args:
+        base64_auth (str): Base64 encoded SASL PLAIN authentication string
+
+    Returns:
+        tuple: (authorization_identity, username, password)
+    """
+    # Decode base64
+    auth_bytes = base64.b64decode(base64_auth)
+    auth_string = auth_bytes.decode("utf-8")
+
+    # Split on null bytes
+    parts = auth_string.split("\x00")
+
+    # Return the three components
+    return tuple(parts)
 
 
 class IRCBadMessage(Exception):
@@ -54,6 +85,7 @@ class IRCBot:
         if not self.connected:
             raise IRCError("Not Connected")
         encmsg = bytes(line.format() + LINEEND, "UTF-8")
+        printred(encmsg)
         expected = len(encmsg)
         if self.irc.send(encmsg) == expected:
             return str(encmsg)
@@ -61,7 +93,7 @@ class IRCBot:
             raise IRCError("Unexpected Send Length")
 
     def on_welcome(self, *args, **kwargs):
-        authmsg = irctokens.build("NICKSERV", ["IDENTIFY", self.config["nickpass"]])
+        authmsg = irctokens.build("NICKSERV", ["SET", "autoreplay-lines", "0"])
         self.send_cmd(authmsg)
         joinmsg = irctokens.build("JOIN", [self.config["channel"]])
         self.send_cmd(joinmsg)
@@ -89,14 +121,28 @@ class IRCBot:
         print("Connecting to: " + server)
         self.irc.connect((self.config["hostname"], self.config["port"]))
         self.connected = True
+        # perform SASL
+        caps_msg = irctokens.build("CAP", ["REQ", "sasl"])
+        printred(caps_msg)
+        self.send_cmd(caps_msg)
 
         # Perform user registration
-        password_msg = irctokens.build("PASS", [self.config["nickpass"]]).format()
-        print(password_msg)
-
-        usermsg = irctokens.build("USER", [botnick, "0", "*", "frog"]).format()
+        cap = irctokens.build("CAP", ["LS", "302"])
+        self.send_cmd(cap)
+        password_msg = irctokens.build("PASS", [self.config["nickpass"]])
+        printred(password_msg)
+        token = create_sasl_plain_auth(botnick, botnickpass)
+        usermsg = irctokens.build("USER", [botnick, "0", "*", "frog"])
+        auth = irctokens.build("AUTHENTICATE", ["PLAIN"])
+        self.send_cmd(auth)
+        # auth_st2 = irctokens.build("AUTHENTICATE", ["+"])
+        # self.send_cmd(auth_st2)
+        auth_st3 = irctokens.build("AUTHENTICATE", [token])
+        self.send_cmd(auth_st3)
+        cmd = irctokens.build("CAP", ["END"])
+        self.send_cmd(cmd)
         print(usermsg)
-        self.send_cmd(password_msg)
+        # s#elf.send_cmd(password_msg)
         nickmsg = irctokens.build("NICK", [botnick]).format()
         print(nickmsg)
         self.send_cmd(nickmsg)
@@ -114,6 +160,6 @@ class IRCBot:
             raise IRCError(str(nwmsg.params[0]))
         if nwmsg.command == "PING":
             print("Sending pong")
-            self.irc.send(bytes("PONG " + LINEEND, "UTF-8"))
+            self.irc.send(bytes("PONG " + nwmsg.params[0] + LINEEND, "UTF-8"))
 
         return msg