Add support for draft/account-registration proxying
This adds support for the draft/account-registration extension [1]. This allows downstreams to register on upstream networks. [1]: https://ircv3.net/specs/extensions/account-registration
This commit is contained in:
parent
e42b507377
commit
23fd727618
@ -1079,6 +1079,21 @@ func (dc *downstreamConn) updateSupportedCaps() {
|
|||||||
dc.unsetSupportedCap("sasl")
|
dc.unsetSupportedCap("sasl")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if uc := dc.upstream(); uc != nil && uc.caps["draft/account-registration"] {
|
||||||
|
// Strip "before-connect", because we require downstreams to be fully
|
||||||
|
// connected before attempting account registration.
|
||||||
|
values := strings.Split(uc.supportedCaps["draft/account-registration"], ",")
|
||||||
|
for i, v := range values {
|
||||||
|
if v == "before-connect" {
|
||||||
|
values = append(values[:i], values[i+1:]...)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dc.setSupportedCap("draft/account-registration", strings.Join(values, ","))
|
||||||
|
} else {
|
||||||
|
dc.unsetSupportedCap("draft/account-registration")
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := dc.user.msgStore.(chatHistoryMessageStore); ok && dc.network != nil {
|
if _, ok := dc.user.msgStore.(chatHistoryMessageStore); ok && dc.network != nil {
|
||||||
dc.setSupportedCap("draft/event-playback", "")
|
dc.setSupportedCap("draft/event-playback", "")
|
||||||
} else {
|
} else {
|
||||||
@ -2408,7 +2423,6 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
uc := dc.upstream()
|
uc := dc.upstream()
|
||||||
if uc == nil || !uc.caps["sasl"] {
|
if uc == nil || !uc.caps["sasl"] {
|
||||||
return ircError{&irc.Message{
|
return ircError{&irc.Message{
|
||||||
Prefix: dc.srv.prefix(),
|
|
||||||
Command: irc.ERR_SASLFAIL,
|
Command: irc.ERR_SASLFAIL,
|
||||||
Params: []string{dc.nick, "Upstream network authentication not supported"},
|
Params: []string{dc.nick, "Upstream network authentication not supported"},
|
||||||
}}
|
}}
|
||||||
@ -2436,6 +2450,23 @@ func (dc *downstreamConn) handleMessageRegistered(ctx context.Context, msg *irc.
|
|||||||
Params: []string{"PLAIN"},
|
Params: []string{"PLAIN"},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
case "REGISTER", "VERIFY":
|
||||||
|
// Check number of params here, since we'll use that to save the
|
||||||
|
// credentials on command success
|
||||||
|
if (msg.Command == "REGISTER" && len(msg.Params) < 3) || (msg.Command == "VERIFY" && len(msg.Params) < 2) {
|
||||||
|
return newNeedMoreParamsError(msg.Command)
|
||||||
|
}
|
||||||
|
|
||||||
|
uc := dc.upstream()
|
||||||
|
if uc == nil || !uc.caps["draft/account-registration"] {
|
||||||
|
return ircError{&irc.Message{
|
||||||
|
Command: "FAIL",
|
||||||
|
Params: []string{msg.Command, "TEMPORARILY_UNAVAILABLE", "*", "Upstream network account registration not supported"},
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
uc.logger.Printf("starting %v with account name %v", msg.Command, msg.Params[0])
|
||||||
|
uc.enqueueCommand(dc, msg)
|
||||||
case "MONITOR":
|
case "MONITOR":
|
||||||
// MONITOR is unsupported in multi-upstream mode
|
// MONITOR is unsupported in multi-upstream mode
|
||||||
uc := dc.upstream()
|
uc := dc.upstream()
|
||||||
|
42
upstream.go
42
upstream.go
@ -35,6 +35,7 @@ var permanentUpstreamCaps = map[string]bool{
|
|||||||
"server-time": true,
|
"server-time": true,
|
||||||
"setname": true,
|
"setname": true,
|
||||||
|
|
||||||
|
"draft/account-registration": true,
|
||||||
"draft/extended-monitor": true,
|
"draft/extended-monitor": true,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,6 +301,12 @@ func (uc *upstreamConn) endPendingCommands() {
|
|||||||
Command: irc.ERR_SASLABORTED,
|
Command: irc.ERR_SASLABORTED,
|
||||||
Params: []string{dc.nick, "SASL authentication aborted"},
|
Params: []string{dc.nick, "SASL authentication aborted"},
|
||||||
})
|
})
|
||||||
|
case "REGISTER", "VERIFY":
|
||||||
|
dc.SendMessage(&irc.Message{
|
||||||
|
Prefix: dc.srv.prefix(),
|
||||||
|
Command: "FAIL",
|
||||||
|
Params: []string{pendingCmd.msg.Command, "TEMPORARILY_UNAVAILABLE", pendingCmd.msg.Params[0], "Command aborted"},
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("Unsupported pending command %q", pendingCmd.msg.Command))
|
panic(fmt.Errorf("Unsupported pending command %q", pendingCmd.msg.Command))
|
||||||
}
|
}
|
||||||
@ -318,7 +325,7 @@ func (uc *upstreamConn) sendNextPendingCommand(cmd string) {
|
|||||||
|
|
||||||
func (uc *upstreamConn) enqueueCommand(dc *downstreamConn, msg *irc.Message) {
|
func (uc *upstreamConn) enqueueCommand(dc *downstreamConn, msg *irc.Message) {
|
||||||
switch msg.Command {
|
switch msg.Command {
|
||||||
case "LIST", "WHO", "AUTHENTICATE":
|
case "LIST", "WHO", "AUTHENTICATE", "REGISTER", "VERIFY":
|
||||||
// Supported
|
// Supported
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("Unsupported pending command %q", msg.Command))
|
panic(fmt.Errorf("Unsupported pending command %q", msg.Command))
|
||||||
@ -633,6 +640,21 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
|
|||||||
Params: []string{"END"},
|
Params: []string{"END"},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
case "REGISTER", "VERIFY":
|
||||||
|
if dc, cmd := uc.dequeueCommand(msg.Command); dc != nil {
|
||||||
|
if msg.Command == "REGISTER" {
|
||||||
|
var account, password string
|
||||||
|
if err := parseMessageParams(msg, nil, &account); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := parseMessageParams(cmd, nil, nil, &password); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
uc.network.autoSaveSASLPlain(context.TODO(), account, password)
|
||||||
|
}
|
||||||
|
|
||||||
|
dc.SendMessage(msg)
|
||||||
|
}
|
||||||
case irc.RPL_WELCOME:
|
case irc.RPL_WELCOME:
|
||||||
uc.registered = true
|
uc.registered = true
|
||||||
uc.logger.Printf("connection registered")
|
uc.logger.Printf("connection registered")
|
||||||
@ -1569,12 +1591,9 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if command == "LIST" || command == "WHO" {
|
if dc, _ := uc.dequeueCommand(command); dc != nil && downstreamID == 0 {
|
||||||
dc, _ := uc.dequeueCommand(command)
|
|
||||||
if dc != nil && downstreamID == 0 {
|
|
||||||
downstreamID = dc.id
|
downstreamID = dc.id
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
uc.forEachDownstreamByID(downstreamID, func(dc *downstreamConn) {
|
uc.forEachDownstreamByID(downstreamID, func(dc *downstreamConn) {
|
||||||
dc.SendMessage(&irc.Message{
|
dc.SendMessage(&irc.Message{
|
||||||
@ -1583,6 +1602,19 @@ func (uc *upstreamConn) handleMessage(msg *irc.Message) error {
|
|||||||
Params: []string{dc.nick, command, reason},
|
Params: []string{dc.nick, command, reason},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
case "FAIL":
|
||||||
|
var command string
|
||||||
|
if err := parseMessageParams(msg, &command); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if dc, _ := uc.dequeueCommand(command); dc != nil && downstreamID == 0 {
|
||||||
|
downstreamID = dc.id
|
||||||
|
}
|
||||||
|
|
||||||
|
uc.forEachDownstreamByID(downstreamID, func(dc *downstreamConn) {
|
||||||
|
dc.SendMessage(msg)
|
||||||
|
})
|
||||||
case "ACK":
|
case "ACK":
|
||||||
// Ignore
|
// Ignore
|
||||||
case irc.RPL_NOWAWAY, irc.RPL_UNAWAY:
|
case irc.RPL_NOWAWAY, irc.RPL_UNAWAY:
|
||||||
|
Loading…
Reference in New Issue
Block a user