deprecate message truncation

Implements #1577, but the issue should remain open until we clean up
the debugging loglines.
This commit is contained in:
Shivaram Lingamneni
2021-03-04 22:29:34 -05:00
parent 6fae02d335
commit 03185ea4a9
12 changed files with 148 additions and 29 deletions
+9
View File
@@ -1361,6 +1361,15 @@ func (channel *Channel) SendSplitMessage(command string, minPrefixMode modes.Mod
details := client.Details()
chname := channel.Name()
if !client.server.Config().Server.Compatibility.allowTruncation {
if !validateSplitMessageLen(histType, details.nickMask, chname, message) {
rb.Add(nil, client.server.name, ERR_INPUTTOOLONG, details.nick, client.t("Line too long to be relayed without truncation"))
// TODO(#1577) remove this logline:
client.server.logger.Debug("internal", "rejected truncation-requiring DM from client", details.nick)
return
}
}
// STATUSMSG targets are prefixed with the supplied min-prefix, e.g., @#channel
if minPrefixMode != modes.Mode(0) {
chname = fmt.Sprintf("%s%s", modes.ChannelModePrefixes[minPrefixMode], chname)
+7 -2
View File
@@ -740,8 +740,13 @@ func (client *Client) run(session *Session) {
msg, err := ircmsg.ParseLineStrict(line, true, MaxLineLen)
if err == ircmsg.ErrorLineIsEmpty {
continue
} else if err == ircmsg.ErrorLineTooLong {
} else if err == ircmsg.ErrorTagsTooLong {
session.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Input line contained excess tag data"))
continue
} else if err == ircmsg.ErrorBodyTooLong && !client.server.Config().Server.Compatibility.allowTruncation {
session.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Input line too long"))
// TODO(#1577) remove this logline:
client.server.logger.Debug("internal", "rejected MaxLineLen-exceeding line from client", client.Nick())
continue
} else if err != nil {
client.Quit(client.t("Received malformed line"), session)
@@ -1711,7 +1716,7 @@ func (session *Session) SendRawMessage(message ircmsg.IRCMessage, blocking bool)
// assemble message
line, err := message.LineBytesStrict(false, MaxLineLen)
if err != nil {
if !(err == nil || err == ircmsg.ErrorBodyTooLong) {
errorParams := []string{"Error assembling message for sending", err.Error(), message.Command}
errorParams = append(errorParams, message.Params...)
session.client.server.logger.Error("internal", errorParams...)
+4 -1
View File
@@ -569,7 +569,9 @@ type Config struct {
Compatibility struct {
ForceTrailing *bool `yaml:"force-trailing"`
forceTrailing bool
SendUnprefixedSasl bool `yaml:"send-unprefixed-sasl"`
SendUnprefixedSasl bool `yaml:"send-unprefixed-sasl"`
AllowTruncation *bool `yaml:"allow-truncation"`
allowTruncation bool
}
isupport isupport.List
IPLimits connection_limits.LimiterConfig `yaml:"ip-limits"`
@@ -1378,6 +1380,7 @@ func LoadConfig(filename string) (config *Config, err error) {
}
config.Server.Compatibility.forceTrailing = utils.BoolDefaultTrue(config.Server.Compatibility.ForceTrailing)
config.Server.Compatibility.allowTruncation = utils.BoolDefaultTrue(config.Server.Compatibility.AllowTruncation)
config.loadMOTD()
+46 -2
View File
@@ -1981,6 +1981,43 @@ func nickHandler(server *Server, client *Client, msg ircmsg.IRCMessage, rb *Resp
return false
}
// check whether a PRIVMSG or NOTICE is too long to be relayed without truncation
func validateLineLen(msgType history.ItemType, source, target, payload string) (ok bool) {
// :source PRIVMSG #target :payload\r\n
// 1: initial colon on prefix
// 1: space between prefix and command
// 1: space between command and target (first parameter)
// 1: space between target and payload (second parameter)
// 1: colon to send the payload as a trailing (we force trailing for PRIVMSG and NOTICE)
// 2: final \r\n
limit := MaxLineLen - 7
limit -= len(source)
switch msgType {
case history.Privmsg:
limit -= 7
case history.Notice:
limit -= 6
default:
return true
}
limit -= len(payload)
return limit >= 0
}
// check validateLineLen for an entire SplitMessage (which may consist of multiple lines)
func validateSplitMessageLen(msgType history.ItemType, source, target string, message utils.SplitMessage) (ok bool) {
if message.Is512() {
return validateLineLen(msgType, source, target, message.Message)
} else {
for _, messagePair := range message.Split {
if !validateLineLen(msgType, source, target, messagePair.Message) {
return false
}
}
return true
}
}
// helper to store a batched PRIVMSG in the session object
func absorbBatchedMessage(server *Server, client *Client, msg ircmsg.IRCMessage, batchTag string, histType history.ItemType, rb *ResponseBuffer) {
var errorCode, errorMessage string
@@ -2033,7 +2070,6 @@ func messageHandler(server *Server, client *Client, msg ircmsg.IRCMessage, rb *R
return false
}
cnick := client.Nick()
clientOnlyTags := msg.ClientOnlyTags()
if histType == history.Tagmsg && len(clientOnlyTags) == 0 {
// nothing to do
@@ -2046,7 +2082,7 @@ func messageHandler(server *Server, client *Client, msg ircmsg.IRCMessage, rb *R
message = msg.Params[1]
}
if histType != history.Tagmsg && message == "" {
rb.Add(nil, server.name, ERR_NOTEXTTOSEND, cnick, client.t("No text to send"))
rb.Add(nil, server.name, ERR_NOTEXTTOSEND, client.Nick(), client.t("No text to send"))
return false
}
@@ -2147,6 +2183,14 @@ func dispatchMessageToTarget(client *Client, tags map[string]string, histType hi
rb.Add(nil, server.name, ERR_NEEDREGGEDNICK, client.Nick(), tnick, client.t("You must be registered to send a direct message to this user"))
return
}
if !client.server.Config().Server.Compatibility.allowTruncation {
if !validateSplitMessageLen(histType, client.NickMaskString(), tnick, message) {
rb.Add(nil, server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Line too long to be relayed without truncation"))
// TODO(#1577) remove this logline:
client.server.logger.Debug("internal", "rejected truncation-requiring channel message from client", details.nick)
return
}
}
nickMaskString := details.nickMask
accountName := details.accountName
var deliverySessions []*Session
+1 -1
View File
@@ -54,7 +54,7 @@ func addAllTags(msg *ircmsg.IRCMessage, tags map[string]string, serverTime time.
}
func (m *MessageCache) handleErr(server *Server, err error) bool {
if err != nil {
if !(err == nil || err == ircmsg.ErrorBodyTooLong) {
server.logger.Error("internal", "Error assembling message for sending", err.Error())
// blank these out so Send will be a no-op
m.fullTags = nil