From fe564af756cf67fd29f9b6957d2080aa5031eb5a Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Fri, 10 Dec 2021 10:44:40 +0100 Subject: [PATCH] Handle upstream multi-line SASL References: https://todo.sr.ht/~emersion/soju/173 --- downstream.go | 2 +- irc.go | 1 + upstream.go | 28 +++++++++++++++++++--------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/downstream.go b/downstream.go index 026b04b..ad4c352 100644 --- a/downstream.go +++ b/downstream.go @@ -983,7 +983,7 @@ func (dc *downstreamConn) handleAuthenticateCommand(msg *irc.Message) (result *d dc.sasl.pendingResp.WriteString(chunk) - if len(chunk) == 400 { + if len(chunk) == maxSASLLength { return nil, nil // Multi-line response, wait for the next command } diff --git a/irc.go b/irc.go index 5355f1a..1da97a2 100644 --- a/irc.go +++ b/irc.go @@ -25,6 +25,7 @@ const ( const ( maxMessageLength = 512 maxMessageParams = 15 + maxSASLLength = 400 ) // The server-time layout, as defined in the IRCv3 spec. diff --git a/upstream.go b/upstream.go index 4863ba2..ae30c2d 100644 --- a/upstream.go +++ b/upstream.go @@ -619,16 +619,26 @@ func (uc *upstreamConn) handleMessage(ctx context.Context, msg *irc.Message) err return err } - // TODO: send response in multiple chunks if >= 400 bytes - var respStr = "+" - if len(resp) != 0 { - respStr = base64.StdEncoding.EncodeToString(resp) - } + // <= instead of < because we need to send a final empty response if + // the last chunk is exactly 400 bytes long + for i := 0; i <= len(resp); i += maxSASLLength { + j := i + maxSASLLength + if j > len(resp) { + j = len(resp) + } - uc.SendMessage(ctx, &irc.Message{ - Command: "AUTHENTICATE", - Params: []string{respStr}, - }) + chunk := resp[i:j] + + var respStr = "+" + if len(chunk) != 0 { + respStr = base64.StdEncoding.EncodeToString(chunk) + } + + uc.SendMessage(ctx, &irc.Message{ + Command: "AUTHENTICATE", + Params: []string{respStr}, + }) + } case irc.RPL_LOGGEDIN: if err := parseMessageParams(msg, nil, nil, &uc.account); err != nil { return err