Fix IRC listener relay of bodies and modes, and JOIN names (closes #127)
check / check (push) Canceled after 0s

The IRC listener relayed only the first line of a PRIVMSG or NOTICE
body; it now sends one line per body line. A MODE change reached IRC
listener members without its key, limit or mask, and "+o bob" went out
as one trailing parameter; each value is now its own parameter, in the
relay and in the echo to the IRC listener user who made the change.
CR, LF and NUL are now removed from each parameter of a line sent to an
IRC listener connection, before the leading ':' is decided, and from
the whole line, so a stored body line, key or mask cannot start a line
of its own. The channel name check moved from the HTTP handler into
service.JoinChannel, so the IRC listener's JOIN refuses the same names
with 403.

Model: opus-5-5
This commit is contained in:
2026-10-20 10:48:25 +00:00
committed by sneak
parent 5b430cf835
commit bf509c5b06
9 changed files with 299 additions and 46 deletions
+28 -12
View File
@@ -3,6 +3,7 @@ package ircserver
import (
"context"
"encoding/json"
"slices"
"strings"
"time"
@@ -105,7 +106,7 @@ func (c *Conn) deliverIRCMessage(
case isNumeric(command):
c.deliverNumeric(msg, text)
case command == irc.CmdPrivmsg || command == irc.CmdNotice:
c.deliverTextMessage(msg, command, text)
c.deliverTextMessage(msg, command, bodyLines)
case command == irc.CmdJoin:
c.deliverJoin(msg)
case command == irc.CmdPart:
@@ -123,7 +124,7 @@ func (c *Conn) deliverIRCMessage(
case command == irc.CmdWallops:
c.deliverWallops(msg, text)
case command == irc.CmdMode:
c.deliverMode(msg, text)
c.deliverMode(msg, bodyLines)
case command == irc.CmdPing:
// Server-originated PING — reply with PONG.
c.sendFromServer("PING", c.serverSfx)
@@ -179,10 +180,12 @@ func (c *Conn) deliverNumeric(
c.send(FormatMessage(from, msg.Command, allParams...))
}
// deliverTextMessage sends PRIVMSG or NOTICE.
// deliverTextMessage sends PRIVMSG or NOTICE, one line for
// each line of the body.
func (c *Conn) deliverTextMessage(
msg *db.IRCMessage,
command, text string,
command string,
bodyLines []string,
) {
from := msg.From
target := msg.To
@@ -201,7 +204,9 @@ func (c *Conn) deliverTextMessage(
prefix = from + "!" + from + "@*"
}
c.send(FormatMessage(prefix, command, target, text))
for _, line := range bodyLines {
c.send(FormatMessage(prefix, command, target, line))
}
}
// deliverJoin sends a JOIN notification.
@@ -351,15 +356,26 @@ func (c *Conn) deliverWallops(
))
}
// deliverMode sends a MODE change notification.
// deliverMode sends a MODE change notification. The first
// body line is the change, possibly followed by its values
// separated by spaces ("+o bob"); any further lines are
// values ("+k", "secret"). Each goes out as its own
// parameter, as IRC sends them.
func (c *Conn) deliverMode(
msg *db.IRCMessage,
text string,
bodyLines []string,
) {
prefix := msg.From + "!" + msg.From + "@*"
target := msg.To
if text != "" {
c.send(FormatMessage(prefix, "MODE", target, text))
if len(bodyLines) == 0 || bodyLines[0] == "" {
return
}
prefix := msg.From + "!" + msg.From + "@*"
params := slices.Concat(
[]string{msg.To},
strings.Fields(bodyLines[0]),
bodyLines[1:],
)
c.send(FormatMessage(prefix, "MODE", params...))
}