From 3f571e15ccb26f937dec7cdb7a9158be7fd6dac3 Mon Sep 17 00:00:00 2001 From: Zach DeCook Date: Thu, 18 Aug 2022 21:49:45 -0400 Subject: [PATCH 1/2] AUTHENTICATE: support IRCv3.1 SASL PLAIN Authentication --- pkg/ircslack/irc_context.go | 2 ++ pkg/ircslack/irc_server.go | 61 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/pkg/ircslack/irc_context.go b/pkg/ircslack/irc_context.go index 76562ff..b36922a 100644 --- a/pkg/ircslack/irc_context.go +++ b/pkg/ircslack/irc_context.go @@ -29,6 +29,8 @@ type IrcContext struct { SlackDebug bool SlackConnected bool ServerName string + IsAuthenticating bool + AuthBase64 string Channels *Channels Users *Users ChunkSize int diff --git a/pkg/ircslack/irc_server.go b/pkg/ircslack/irc_server.go index 599f3c7..4e491a4 100644 --- a/pkg/ircslack/irc_server.go +++ b/pkg/ircslack/irc_server.go @@ -1,6 +1,7 @@ package ircslack import ( + "encoding/base64" "errors" "fmt" "html" @@ -28,6 +29,7 @@ type IrcCommandHandler func(*IrcContext, string, string, []string, string) // IrcCommandHandlers maps each IRC command to its handler function var IrcCommandHandlers = map[string]IrcCommandHandler{ + "AUTHENTICATE": IrcAuthenticateHandler, "CAP": IrcCapHandler, "NICK": IrcNickHandler, "USER": IrcUserHandler, @@ -590,6 +592,65 @@ func IrcPassHandler(ctx *IrcContext, prefix, cmd string, args []string, trailing } } +// IrcAuthenticateHandler is called when an AUTHENTICATE command is sent +func IrcAuthenticateHandler(ctx *IrcContext, prefix, cmd string, args []string, trailing string) { + if len(args) != 1 { + log.Warningf("Invalid AUTHENTICATE command args: %v %v", args, trailing) + return + } + // Check mechanism + if !ctx.IsAuthenticating { + if args[0] != "PLAIN" { + log.Warningf("Un-implemented mechanism for AUTHENTICATE: %v", args[0]) + if err := SendIrcNumeric(ctx, 904, "", "Unknown mechanism"); err != nil { + log.Warningf("Failed to send IRC message: %v", err) + } + return + } + if len(ctx.SlackAPIKey) > 0 { + if err := SendIrcNumeric(ctx, 907, "", "Already authenticated"); err != nil { + log.Warningf("Failed to send IRC message: %v", err) + } + } + // Ask for the data + if _, err := ctx.Conn.Write([]byte("AUTHENTICATE +\r\n")); err != nil { + log.Warningf("Failed to send IRC message: %v", err) + } + ctx.IsAuthenticating = true + return + } + + if args[0] == "*" { + ctx.IsAuthenticating = false + if err := SendIrcNumeric(ctx, 906, "", "Aborted authentication"); err != nil { + log.Warningf("Failed to send IRC message: %v", err) + } + } + if args[0] != "+" { + ctx.AuthBase64 += args[0] + } + if len(args[0]) != 400 || args[0] == "+" { + // Decode RFC4616 PLAIN SASL message + plain,_ := base64.StdEncoding.DecodeString(ctx.AuthBase64) + split := strings.Split(string(plain),string(0)) + // Is authzid RealName? Does this even matter since we're about to change it? + ctx.RealName = split[0] + ctx.OrigName = split[1] + ctx.SlackAPIKey = split[2] + if ctx.RealName == "" { ctx.RealName = ctx.OrigName} + ctx.FileHandler.SlackAPIKey = ctx.SlackAPIKey + // If we're ready, connect + if ctx.SlackClient == nil && ctx.RealName != "" && ctx.OrigName != "" { + if err := connectToSlack(ctx); err != nil { + log.Warningf("Cannot connect to Slack: %v", err) + // close the IRC connection to the client + ctx.Conn.Close() + } + } + ctx.IsAuthenticating = false + } +} + // IrcWhoHandler is called when a WHO command is sent func IrcWhoHandler(ctx *IrcContext, prefix, cmd string, args []string, trailing string) { sendErr := func() { From 2be16ceb037818957718c495f7a5106ac629023f Mon Sep 17 00:00:00 2001 From: stickler-ci Date: Fri, 19 Aug 2022 01:57:16 +0000 Subject: [PATCH 2/2] Fixing style errors. --- pkg/ircslack/irc_server.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/ircslack/irc_server.go b/pkg/ircslack/irc_server.go index 4e491a4..648d42c 100644 --- a/pkg/ircslack/irc_server.go +++ b/pkg/ircslack/irc_server.go @@ -631,13 +631,15 @@ func IrcAuthenticateHandler(ctx *IrcContext, prefix, cmd string, args []string, } if len(args[0]) != 400 || args[0] == "+" { // Decode RFC4616 PLAIN SASL message - plain,_ := base64.StdEncoding.DecodeString(ctx.AuthBase64) - split := strings.Split(string(plain),string(0)) + plain, _ := base64.StdEncoding.DecodeString(ctx.AuthBase64) + split := strings.Split(string(plain), string(0)) // Is authzid RealName? Does this even matter since we're about to change it? ctx.RealName = split[0] ctx.OrigName = split[1] ctx.SlackAPIKey = split[2] - if ctx.RealName == "" { ctx.RealName = ctx.OrigName} + if ctx.RealName == "" { + ctx.RealName = ctx.OrigName + } ctx.FileHandler.SlackAPIKey = ctx.SlackAPIKey // If we're ready, connect if ctx.SlackClient == nil && ctx.RealName != "" && ctx.OrigName != "" { @@ -646,7 +648,7 @@ func IrcAuthenticateHandler(ctx *IrcContext, prefix, cmd string, args []string, // close the IRC connection to the client ctx.Conn.Close() } - } + } ctx.IsAuthenticating = false } }