Allow AUTHENTICATE before NICK

Now that dc.nick is not blank during registration, sasl replies from the
server are correct and cap handling can be a bit simplified.
This commit is contained in:
Hubert Hirtz 2021-11-18 09:19:27 +01:00 committed by Simon Ser
parent 98af48d254
commit dcc1eff130

View file

@ -178,7 +178,8 @@ func updateNetworkAttrs(record *Network, attrs irc.Tags, subcommand string) erro
}
// ' ' and ':' break the IRC message wire format, '@' and '!' break prefixes,
// '*' and '?' break masks, '$' breaks server masks in PRIVMSG/NOTICE
// '*' and '?' break masks, '$' breaks server masks in PRIVMSG/NOTICE,
// "*" is the reserved nickname for registration
const illegalNickChars = " :@!*?$"
// permanentDownstreamCaps is the list of always-supported downstream
@ -280,6 +281,8 @@ func newDownstreamConn(srv *Server, ic ircConn, id uint64) *downstreamConn {
dc := &downstreamConn{
conn: *newConn(srv, ic, &options),
id: id,
nick: "*",
nickCM: "*",
supportedCaps: make(map[string]string),
caps: make(map[string]bool),
monitored: newCasemapMap(0),
@ -684,27 +687,24 @@ func (dc *downstreamConn) handleMessageUnregistered(ctx context.Context, msg *ir
case "AUTHENTICATE":
if !dc.caps["sasl"] {
return ircError{&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.ERR_SASLFAIL,
Params: []string{"*", "AUTHENTICATE requires the \"sasl\" capability to be enabled"},
}}
}
if len(msg.Params) == 0 {
return ircError{&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.ERR_SASLFAIL,
Params: []string{"*", "Missing AUTHENTICATE argument"},
}}
}
if dc.nick == "" {
return ircError{&irc.Message{
Command: irc.ERR_SASLFAIL,
Params: []string{"*", "Expected NICK command before AUTHENTICATE"},
}}
}
var resp []byte
if msg.Params[0] == "*" {
dc.saslServer = nil
return ircError{&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.ERR_SASLABORTED,
Params: []string{"*", "SASL authentication aborted"},
}}
@ -720,6 +720,7 @@ func (dc *downstreamConn) handleMessageUnregistered(ctx context.Context, msg *ir
}))
default:
return ircError{&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.ERR_SASLFAIL,
Params: []string{"*", fmt.Sprintf("Unsupported SASL mechanism %q", mech)},
}}
@ -733,6 +734,7 @@ func (dc *downstreamConn) handleMessageUnregistered(ctx context.Context, msg *ir
if err != nil {
dc.saslServer = nil
return ircError{&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.ERR_SASLFAIL,
Params: []string{"*", "Invalid base64-encoded response"},
}}
@ -744,6 +746,7 @@ func (dc *downstreamConn) handleMessageUnregistered(ctx context.Context, msg *ir
dc.saslServer = nil
if ircErr, ok := err.(ircError); ok && ircErr.Message.Command == irc.ERR_PASSWDMISMATCH {
return ircError{&irc.Message{
Prefix: dc.srv.prefix(),
Command: irc.ERR_SASLFAIL,
Params: []string{"*", ircErr.Message.Params[1]},
}}
@ -823,7 +826,7 @@ func (dc *downstreamConn) handleMessageUnregistered(ctx context.Context, msg *ir
dc.logger.Printf("unhandled message: %v", msg)
return newUnknownCommandError(msg.Command)
}
if dc.rawUsername != "" && dc.nick != "" && !dc.negotiatingCaps {
if dc.rawUsername != "" && dc.nick != "*" && !dc.negotiatingCaps {
return dc.register(ctx)
}
return nil
@ -832,11 +835,6 @@ func (dc *downstreamConn) handleMessageUnregistered(ctx context.Context, msg *ir
func (dc *downstreamConn) handleCapCommand(cmd string, args []string) error {
cmd = strings.ToUpper(cmd)
replyTo := dc.nick
if !dc.registered {
replyTo = "*"
}
switch cmd {
case "LS":
if len(args) > 0 {
@ -867,7 +865,7 @@ func (dc *downstreamConn) handleCapCommand(cmd string, args []string) error {
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: "CAP",
Params: []string{replyTo, "LS", strings.Join(caps, " ")},
Params: []string{dc.nick, "LS", strings.Join(caps, " ")},
})
if dc.capVersion >= 302 {
@ -890,13 +888,13 @@ func (dc *downstreamConn) handleCapCommand(cmd string, args []string) error {
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: "CAP",
Params: []string{replyTo, "LIST", strings.Join(caps, " ")},
Params: []string{dc.nick, "LIST", strings.Join(caps, " ")},
})
case "REQ":
if len(args) == 0 {
return ircError{&irc.Message{
Command: err_invalidcapcmd,
Params: []string{replyTo, cmd, "Missing argument in CAP REQ command"},
Params: []string{dc.nick, cmd, "Missing argument in CAP REQ command"},
}}
}
@ -936,7 +934,7 @@ func (dc *downstreamConn) handleCapCommand(cmd string, args []string) error {
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: "CAP",
Params: []string{replyTo, reply, args[0]},
Params: []string{dc.nick, reply, args[0]},
})
if !dc.registered {
@ -947,7 +945,7 @@ func (dc *downstreamConn) handleCapCommand(cmd string, args []string) error {
default:
return ircError{&irc.Message{
Command: err_invalidcapcmd,
Params: []string{replyTo, cmd, "Unknown CAP command"},
Params: []string{dc.nick, cmd, "Unknown CAP command"},
}}
}
return nil
@ -962,11 +960,6 @@ func (dc *downstreamConn) setSupportedCap(name, value string) {
return
}
replyTo := dc.nick
if !dc.registered {
replyTo = "*"
}
cap := name
if value != "" && dc.capVersion >= 302 {
cap = name + "=" + value
@ -975,7 +968,7 @@ func (dc *downstreamConn) setSupportedCap(name, value string) {
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: "CAP",
Params: []string{replyTo, "NEW", cap},
Params: []string{dc.nick, "NEW", cap},
})
}
@ -988,15 +981,10 @@ func (dc *downstreamConn) unsetSupportedCap(name string) {
return
}
replyTo := dc.nick
if !dc.registered {
replyTo = "*"
}
dc.SendMessage(&irc.Message{
Prefix: dc.srv.prefix(),
Command: "CAP",
Params: []string{replyTo, "DEL", name},
Params: []string{dc.nick, "DEL", name},
})
}