Kaynağa Gözat

Merge pull request #1586 from slingamn/issue1577_no_truncation.2

deprecate message truncation
tags/v2.6.0-rc1
Shivaram Lingamneni 3 yıl önce
ebeveyn
işleme
788b37b12a
No account linked to committer's email address

+ 7
- 0
default.yaml Dosyayı Görüntüle

235
         # this works around that bug, allowing them to use SASL.
235
         # this works around that bug, allowing them to use SASL.
236
         send-unprefixed-sasl: true
236
         send-unprefixed-sasl: true
237
 
237
 
238
+        # traditionally, IRC servers will truncate and send messages that are
239
+        # too long to be relayed intact. this behavior can be disabled by setting
240
+        # allow-truncation to false, in which case Oragono will reject the message
241
+        # and return an error to the client. (note that this option defaults to true
242
+        # when unset.)
243
+        allow-truncation: false
244
+
238
     # IP-based DoS protection
245
     # IP-based DoS protection
239
     ip-limits:
246
     ip-limits:
240
         # whether to limit the total number of concurrent connections per IP/CIDR
247
         # whether to limit the total number of concurrent connections per IP/CIDR

+ 2
- 2
go.mod Dosyayı Görüntüle

10
 	github.com/go-sql-driver/mysql v1.5.0
10
 	github.com/go-sql-driver/mysql v1.5.0
11
 	github.com/go-test/deep v1.0.6 // indirect
11
 	github.com/go-test/deep v1.0.6 // indirect
12
 	github.com/gorilla/websocket v1.4.2
12
 	github.com/gorilla/websocket v1.4.2
13
-	github.com/goshuirc/irc-go v0.0.0-20210301225436-2c4b83d64847
13
+	github.com/goshuirc/irc-go v0.0.0-20210304031553-cf78e9176f96
14
 	github.com/onsi/ginkgo v1.12.0 // indirect
14
 	github.com/onsi/ginkgo v1.12.0 // indirect
15
 	github.com/onsi/gomega v1.9.0 // indirect
15
 	github.com/onsi/gomega v1.9.0 // indirect
16
 	github.com/oragono/confusables v0.0.0-20201108231250-4ab98ab61fb1
16
 	github.com/oragono/confusables v0.0.0-20201108231250-4ab98ab61fb1
24
 	gopkg.in/yaml.v2 v2.3.0
24
 	gopkg.in/yaml.v2 v2.3.0
25
 )
25
 )
26
 
26
 
27
-replace github.com/gorilla/websocket  => github.com/oragono/websocket v1.4.2-oragono1
27
+replace github.com/gorilla/websocket => github.com/oragono/websocket v1.4.2-oragono1

+ 2
- 0
go.sum Dosyayı Görüntüle

40
 github.com/goshuirc/irc-go v0.0.0-20210223005429-8d38e43fc6ed/go.mod h1:q/JhvvKLmif3y9q8MDQM+gRCnjEKnu5ClF298TTXJug=
40
 github.com/goshuirc/irc-go v0.0.0-20210223005429-8d38e43fc6ed/go.mod h1:q/JhvvKLmif3y9q8MDQM+gRCnjEKnu5ClF298TTXJug=
41
 github.com/goshuirc/irc-go v0.0.0-20210301225436-2c4b83d64847 h1:MmsZRpAsMxyw0P5/SFn2L6edhmIXRlolgXvOF+fgEiQ=
41
 github.com/goshuirc/irc-go v0.0.0-20210301225436-2c4b83d64847 h1:MmsZRpAsMxyw0P5/SFn2L6edhmIXRlolgXvOF+fgEiQ=
42
 github.com/goshuirc/irc-go v0.0.0-20210301225436-2c4b83d64847/go.mod h1:q/JhvvKLmif3y9q8MDQM+gRCnjEKnu5ClF298TTXJug=
42
 github.com/goshuirc/irc-go v0.0.0-20210301225436-2c4b83d64847/go.mod h1:q/JhvvKLmif3y9q8MDQM+gRCnjEKnu5ClF298TTXJug=
43
+github.com/goshuirc/irc-go v0.0.0-20210304031553-cf78e9176f96 h1:sihI3HsrJWyS4MtBmxh5W4gDZD34SWodkWyUvJltswY=
44
+github.com/goshuirc/irc-go v0.0.0-20210304031553-cf78e9176f96/go.mod h1:q/JhvvKLmif3y9q8MDQM+gRCnjEKnu5ClF298TTXJug=
43
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
45
 github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
44
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
46
 github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
45
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
47
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=

+ 9
- 0
irc/channel.go Dosyayı Görüntüle

1361
 	details := client.Details()
1361
 	details := client.Details()
1362
 	chname := channel.Name()
1362
 	chname := channel.Name()
1363
 
1363
 
1364
+	if !client.server.Config().Server.Compatibility.allowTruncation {
1365
+		if !validateSplitMessageLen(histType, details.nickMask, chname, message) {
1366
+			rb.Add(nil, client.server.name, ERR_INPUTTOOLONG, details.nick, client.t("Line too long to be relayed without truncation"))
1367
+			// TODO(#1577) remove this logline:
1368
+			client.server.logger.Debug("internal", "rejected truncation-requiring DM from client", details.nick)
1369
+			return
1370
+		}
1371
+	}
1372
+
1364
 	// STATUSMSG targets are prefixed with the supplied min-prefix, e.g., @#channel
1373
 	// STATUSMSG targets are prefixed with the supplied min-prefix, e.g., @#channel
1365
 	if minPrefixMode != modes.Mode(0) {
1374
 	if minPrefixMode != modes.Mode(0) {
1366
 		chname = fmt.Sprintf("%s%s", modes.ChannelModePrefixes[minPrefixMode], chname)
1375
 		chname = fmt.Sprintf("%s%s", modes.ChannelModePrefixes[minPrefixMode], chname)

+ 7
- 2
irc/client.go Dosyayı Görüntüle

740
 		msg, err := ircmsg.ParseLineStrict(line, true, MaxLineLen)
740
 		msg, err := ircmsg.ParseLineStrict(line, true, MaxLineLen)
741
 		if err == ircmsg.ErrorLineIsEmpty {
741
 		if err == ircmsg.ErrorLineIsEmpty {
742
 			continue
742
 			continue
743
-		} else if err == ircmsg.ErrorLineTooLong {
743
+		} else if err == ircmsg.ErrorTagsTooLong {
744
+			session.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Input line contained excess tag data"))
745
+			continue
746
+		} else if err == ircmsg.ErrorBodyTooLong && !client.server.Config().Server.Compatibility.allowTruncation {
744
 			session.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Input line too long"))
747
 			session.Send(nil, client.server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Input line too long"))
748
+			// TODO(#1577) remove this logline:
749
+			client.server.logger.Debug("internal", "rejected MaxLineLen-exceeding line from client", client.Nick())
745
 			continue
750
 			continue
746
 		} else if err != nil {
751
 		} else if err != nil {
747
 			client.Quit(client.t("Received malformed line"), session)
752
 			client.Quit(client.t("Received malformed line"), session)
1711
 
1716
 
1712
 	// assemble message
1717
 	// assemble message
1713
 	line, err := message.LineBytesStrict(false, MaxLineLen)
1718
 	line, err := message.LineBytesStrict(false, MaxLineLen)
1714
-	if err != nil {
1719
+	if !(err == nil || err == ircmsg.ErrorBodyTooLong) {
1715
 		errorParams := []string{"Error assembling message for sending", err.Error(), message.Command}
1720
 		errorParams := []string{"Error assembling message for sending", err.Error(), message.Command}
1716
 		errorParams = append(errorParams, message.Params...)
1721
 		errorParams = append(errorParams, message.Params...)
1717
 		session.client.server.logger.Error("internal", errorParams...)
1722
 		session.client.server.logger.Error("internal", errorParams...)

+ 4
- 1
irc/config.go Dosyayı Görüntüle

569
 		Compatibility        struct {
569
 		Compatibility        struct {
570
 			ForceTrailing      *bool `yaml:"force-trailing"`
570
 			ForceTrailing      *bool `yaml:"force-trailing"`
571
 			forceTrailing      bool
571
 			forceTrailing      bool
572
-			SendUnprefixedSasl bool `yaml:"send-unprefixed-sasl"`
572
+			SendUnprefixedSasl bool  `yaml:"send-unprefixed-sasl"`
573
+			AllowTruncation    *bool `yaml:"allow-truncation"`
574
+			allowTruncation    bool
573
 		}
575
 		}
574
 		isupport                 isupport.List
576
 		isupport                 isupport.List
575
 		IPLimits                 connection_limits.LimiterConfig `yaml:"ip-limits"`
577
 		IPLimits                 connection_limits.LimiterConfig `yaml:"ip-limits"`
1378
 	}
1380
 	}
1379
 
1381
 
1380
 	config.Server.Compatibility.forceTrailing = utils.BoolDefaultTrue(config.Server.Compatibility.ForceTrailing)
1382
 	config.Server.Compatibility.forceTrailing = utils.BoolDefaultTrue(config.Server.Compatibility.ForceTrailing)
1383
+	config.Server.Compatibility.allowTruncation = utils.BoolDefaultTrue(config.Server.Compatibility.AllowTruncation)
1381
 
1384
 
1382
 	config.loadMOTD()
1385
 	config.loadMOTD()
1383
 
1386
 

+ 46
- 2
irc/handlers.go Dosyayı Görüntüle

1981
 	return false
1981
 	return false
1982
 }
1982
 }
1983
 
1983
 
1984
+// check whether a PRIVMSG or NOTICE is too long to be relayed without truncation
1985
+func validateLineLen(msgType history.ItemType, source, target, payload string) (ok bool) {
1986
+	// :source PRIVMSG #target :payload\r\n
1987
+	// 1: initial colon on prefix
1988
+	// 1: space between prefix and command
1989
+	// 1: space between command and target (first parameter)
1990
+	// 1: space between target and payload (second parameter)
1991
+	// 1: colon to send the payload as a trailing (we force trailing for PRIVMSG and NOTICE)
1992
+	// 2: final \r\n
1993
+	limit := MaxLineLen - 7
1994
+	limit -= len(source)
1995
+	switch msgType {
1996
+	case history.Privmsg:
1997
+		limit -= 7
1998
+	case history.Notice:
1999
+		limit -= 6
2000
+	default:
2001
+		return true
2002
+	}
2003
+	limit -= len(payload)
2004
+	return limit >= 0
2005
+}
2006
+
2007
+// check validateLineLen for an entire SplitMessage (which may consist of multiple lines)
2008
+func validateSplitMessageLen(msgType history.ItemType, source, target string, message utils.SplitMessage) (ok bool) {
2009
+	if message.Is512() {
2010
+		return validateLineLen(msgType, source, target, message.Message)
2011
+	} else {
2012
+		for _, messagePair := range message.Split {
2013
+			if !validateLineLen(msgType, source, target, messagePair.Message) {
2014
+				return false
2015
+			}
2016
+		}
2017
+		return true
2018
+	}
2019
+}
2020
+
1984
 // helper to store a batched PRIVMSG in the session object
2021
 // helper to store a batched PRIVMSG in the session object
1985
 func absorbBatchedMessage(server *Server, client *Client, msg ircmsg.IRCMessage, batchTag string, histType history.ItemType, rb *ResponseBuffer) {
2022
 func absorbBatchedMessage(server *Server, client *Client, msg ircmsg.IRCMessage, batchTag string, histType history.ItemType, rb *ResponseBuffer) {
1986
 	var errorCode, errorMessage string
2023
 	var errorCode, errorMessage string
2033
 		return false
2070
 		return false
2034
 	}
2071
 	}
2035
 
2072
 
2036
-	cnick := client.Nick()
2037
 	clientOnlyTags := msg.ClientOnlyTags()
2073
 	clientOnlyTags := msg.ClientOnlyTags()
2038
 	if histType == history.Tagmsg && len(clientOnlyTags) == 0 {
2074
 	if histType == history.Tagmsg && len(clientOnlyTags) == 0 {
2039
 		// nothing to do
2075
 		// nothing to do
2046
 		message = msg.Params[1]
2082
 		message = msg.Params[1]
2047
 	}
2083
 	}
2048
 	if histType != history.Tagmsg && message == "" {
2084
 	if histType != history.Tagmsg && message == "" {
2049
-		rb.Add(nil, server.name, ERR_NOTEXTTOSEND, cnick, client.t("No text to send"))
2085
+		rb.Add(nil, server.name, ERR_NOTEXTTOSEND, client.Nick(), client.t("No text to send"))
2050
 		return false
2086
 		return false
2051
 	}
2087
 	}
2052
 
2088
 
2147
 			rb.Add(nil, server.name, ERR_NEEDREGGEDNICK, client.Nick(), tnick, client.t("You must be registered to send a direct message to this user"))
2183
 			rb.Add(nil, server.name, ERR_NEEDREGGEDNICK, client.Nick(), tnick, client.t("You must be registered to send a direct message to this user"))
2148
 			return
2184
 			return
2149
 		}
2185
 		}
2186
+		if !client.server.Config().Server.Compatibility.allowTruncation {
2187
+			if !validateSplitMessageLen(histType, client.NickMaskString(), tnick, message) {
2188
+				rb.Add(nil, server.name, ERR_INPUTTOOLONG, client.Nick(), client.t("Line too long to be relayed without truncation"))
2189
+				// TODO(#1577) remove this logline:
2190
+				client.server.logger.Debug("internal", "rejected truncation-requiring channel message from client", details.nick)
2191
+				return
2192
+			}
2193
+		}
2150
 		nickMaskString := details.nickMask
2194
 		nickMaskString := details.nickMask
2151
 		accountName := details.accountName
2195
 		accountName := details.accountName
2152
 		var deliverySessions []*Session
2196
 		var deliverySessions []*Session

+ 1
- 1
irc/message_cache.go Dosyayı Görüntüle

54
 }
54
 }
55
 
55
 
56
 func (m *MessageCache) handleErr(server *Server, err error) bool {
56
 func (m *MessageCache) handleErr(server *Server, err error) bool {
57
-	if err != nil {
57
+	if !(err == nil || err == ircmsg.ErrorBodyTooLong) {
58
 		server.logger.Error("internal", "Error assembling message for sending", err.Error())
58
 		server.logger.Error("internal", "Error assembling message for sending", err.Error())
59
 		// blank these out so Send will be a no-op
59
 		// blank these out so Send will be a no-op
60
 		m.fullTags = nil
60
 		m.fullTags = nil

+ 7
- 0
traditional.yaml Dosyayı Görüntüle

208
         # this works around that bug, allowing them to use SASL.
208
         # this works around that bug, allowing them to use SASL.
209
         send-unprefixed-sasl: true
209
         send-unprefixed-sasl: true
210
 
210
 
211
+        # traditionally, IRC servers will truncate and send messages that are
212
+        # too long to be relayed intact. this behavior can be disabled by setting
213
+        # allow-truncation to false, in which case Oragono will reject the message
214
+        # and return an error to the client. (note that this option defaults to true
215
+        # when unset.)
216
+        allow-truncation: true
217
+
211
     # IP-based DoS protection
218
     # IP-based DoS protection
212
     ip-limits:
219
     ip-limits:
213
         # whether to limit the total number of concurrent connections per IP/CIDR
220
         # whether to limit the total number of concurrent connections per IP/CIDR

+ 58
- 20
vendor/github.com/goshuirc/irc-go/ircmsg/message.go Dosyayı Görüntüle

9
 	"bytes"
9
 	"bytes"
10
 	"errors"
10
 	"errors"
11
 	"strings"
11
 	"strings"
12
+	"unicode/utf8"
12
 )
13
 )
13
 
14
 
14
 const (
15
 const (
34
 var (
35
 var (
35
 	// ErrorLineIsEmpty indicates that the given IRC line was empty.
36
 	// ErrorLineIsEmpty indicates that the given IRC line was empty.
36
 	ErrorLineIsEmpty = errors.New("Line is empty")
37
 	ErrorLineIsEmpty = errors.New("Line is empty")
38
+
37
 	// ErrorLineContainsBadChar indicates that the line contained invalid characters
39
 	// ErrorLineContainsBadChar indicates that the line contained invalid characters
38
 	ErrorLineContainsBadChar = errors.New("Line contains invalid characters")
40
 	ErrorLineContainsBadChar = errors.New("Line contains invalid characters")
39
-	// ErrorLineTooLong indicates that the message exceeded the maximum tag length
40
-	// (the name references 417 ERR_INPUTTOOLONG; we reserve the right to return it
41
-	// for messages that exceed the non-tag length limit)
42
-	ErrorLineTooLong = errors.New("Line could not be parsed because a specified length limit was exceeded")
41
+
42
+	// ErrorBodyTooLong indicates that the message body exceeded the specified
43
+	// length limit (typically 512 bytes). This error is non-fatal; if encountered
44
+	// when parsing a message, the message is parsed up to the length limit, and
45
+	// if encountered when serializing a message, the message is truncated to the limit.
46
+	ErrorBodyTooLong = errors.New("Line body exceeded the specified length limit; outgoing messages will be truncated")
47
+
48
+	// ErrorTagsTooLong indicates that the message exceeded the maximum tag length
49
+	// (the specified response on the server side is 417 ERR_INPUTTOOLONG).
50
+	ErrorTagsTooLong = errors.New("Line could not be processed because its tag data exceeded the length limit")
51
+
43
 	// ErrorInvalidTagContent indicates that a tag name or value was invalid
52
 	// ErrorInvalidTagContent indicates that a tag name or value was invalid
44
 	ErrorInvalidTagContent = errors.New("Line could not be processed because it contained an invalid tag name or value")
53
 	ErrorInvalidTagContent = errors.New("Line could not be processed because it contained an invalid tag name or value")
45
 
54
 
55
+	// ErrorCommandMissing indicates that an IRC message was invalid because it lacked a command.
46
 	ErrorCommandMissing = errors.New("IRC messages MUST have a command")
56
 	ErrorCommandMissing = errors.New("IRC messages MUST have a command")
47
-	ErrorBadParam       = errors.New("Cannot have an empty param, a param with spaces, or a param that starts with ':' before the last parameter")
57
+
58
+	// ErrorBadParam indicates that an IRC message could not be serialized because
59
+	// its parameters violated the syntactic constraints on IRC parameters:
60
+	// non-final parameters cannot be empty, contain a space, or start with `:`.
61
+	ErrorBadParam = errors.New("Cannot have an empty param, a param with spaces, or a param that starts with ':' before the last parameter")
48
 )
62
 )
49
 
63
 
50
 // IRCMessage represents an IRC message, as defined by the RFCs and as
64
 // IRCMessage represents an IRC message, as defined by the RFCs and as
161
 // slice off any amount of ' ' from the front of the string
175
 // slice off any amount of ' ' from the front of the string
162
 func trimInitialSpaces(str string) string {
176
 func trimInitialSpaces(str string) string {
163
 	var i int
177
 	var i int
164
-	for i = 0; i < len(str) && str[i] == ' '; i += 1 {
178
+	for i = 0; i < len(str) && str[i] == ' '; i++ {
165
 	}
179
 	}
166
 	return str[i:]
180
 	return str[i:]
167
 }
181
 }
170
 	// remove either \n or \r\n from the end of the line:
184
 	// remove either \n or \r\n from the end of the line:
171
 	line = strings.TrimSuffix(line, "\n")
185
 	line = strings.TrimSuffix(line, "\n")
172
 	line = strings.TrimSuffix(line, "\r")
186
 	line = strings.TrimSuffix(line, "\r")
187
+	// whether we removed them ourselves, or whether they were removed previously,
188
+	// they count against the line limit:
189
+	if truncateLen != 0 {
190
+		if truncateLen <= 2 {
191
+			return ircmsg, ErrorLineIsEmpty
192
+		}
193
+		truncateLen -= 2
194
+	}
173
 	// now validate for the 3 forbidden bytes:
195
 	// now validate for the 3 forbidden bytes:
174
 	if strings.IndexByte(line, '\x00') != -1 || strings.IndexByte(line, '\n') != -1 || strings.IndexByte(line, '\r') != -1 {
196
 	if strings.IndexByte(line, '\x00') != -1 || strings.IndexByte(line, '\n') != -1 || strings.IndexByte(line, '\r') != -1 {
175
 		return ircmsg, ErrorLineContainsBadChar
197
 		return ircmsg, ErrorLineContainsBadChar
187
 		}
209
 		}
188
 		tags := line[1:tagEnd]
210
 		tags := line[1:tagEnd]
189
 		if 0 < maxTagDataLength && maxTagDataLength < len(tags) {
211
 		if 0 < maxTagDataLength && maxTagDataLength < len(tags) {
190
-			return ircmsg, ErrorLineTooLong
212
+			return ircmsg, ErrorTagsTooLong
191
 		}
213
 		}
192
 		err = ircmsg.parseTags(tags)
214
 		err = ircmsg.parseTags(tags)
193
 		if err != nil {
215
 		if err != nil {
198
 	}
220
 	}
199
 
221
 
200
 	// truncate if desired
222
 	// truncate if desired
201
-	if 0 < truncateLen && truncateLen < len(line) {
223
+	if truncateLen != 0 && truncateLen < len(line) {
224
+		err = ErrorBodyTooLong
202
 		line = line[:truncateLen]
225
 		line = line[:truncateLen]
203
 	}
226
 	}
204
 
227
 
252
 		line = line[paramEnd+1:]
275
 		line = line[paramEnd+1:]
253
 	}
276
 	}
254
 
277
 
255
-	return ircmsg, nil
278
+	return ircmsg, err
256
 }
279
 }
257
 
280
 
258
 // helper to parse tags
281
 // helper to parse tags
337
 }
360
 }
338
 
361
 
339
 // line returns a sendable line created from an IRCMessage.
362
 // line returns a sendable line created from an IRCMessage.
340
-func (ircmsg *IRCMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) ([]byte, error) {
341
-	if len(ircmsg.Command) < 1 {
363
+func (ircmsg *IRCMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) (result []byte, err error) {
364
+	if len(ircmsg.Command) == 0 {
342
 		return nil, ErrorCommandMissing
365
 		return nil, ErrorCommandMissing
343
 	}
366
 	}
344
 
367
 
382
 	lenTags = buf.Len()
405
 	lenTags = buf.Len()
383
 
406
 
384
 	if 0 < tagLimit && tagLimit < buf.Len() {
407
 	if 0 < tagLimit && tagLimit < buf.Len() {
385
-		return nil, ErrorLineTooLong
408
+		return nil, ErrorTagsTooLong
386
 	}
409
 	}
387
 	if (0 < clientOnlyTagDataLimit && clientOnlyTagDataLimit < lenClientOnlyTags) || (0 < serverAddedTagDataLimit && serverAddedTagDataLimit < lenRegularTags) {
410
 	if (0 < clientOnlyTagDataLimit && clientOnlyTagDataLimit < lenClientOnlyTags) || (0 < serverAddedTagDataLimit && serverAddedTagDataLimit < lenRegularTags) {
388
-		return nil, ErrorLineTooLong
411
+		return nil, ErrorTagsTooLong
389
 	}
412
 	}
390
 
413
 
391
 	if len(ircmsg.Prefix) > 0 {
414
 	if len(ircmsg.Prefix) > 0 {
408
 		buf.WriteString(param)
431
 		buf.WriteString(param)
409
 	}
432
 	}
410
 
433
 
411
-	// truncate if desired
412
-	// -2 for \r\n
413
-	restLen := buf.Len() - lenTags
414
-	if 0 < truncateLen && (truncateLen-2) < restLen {
415
-		buf.Truncate(lenTags + (truncateLen - 2))
434
+	// truncate if desired; leave 2 bytes over for \r\n:
435
+	if truncateLen != 0 && (truncateLen-2) < (buf.Len()-lenTags) {
436
+		err = ErrorBodyTooLong
437
+		newBufLen := lenTags + (truncateLen - 2)
438
+		buf.Truncate(newBufLen)
439
+		// XXX: we may have truncated in the middle of a UTF8-encoded codepoint;
440
+		// if so, remove additional bytes, stopping when the sequence either
441
+		// ends in a valid codepoint, or we have removed 3 bytes (the maximum
442
+		// length of the remnant of a once-valid, truncated codepoint; we don't
443
+		// want to truncate the entire message if it wasn't UTF8 in the first
444
+		// place).
445
+		for i := 0; i < (utf8.UTFMax - 1); i++ {
446
+			r, n := utf8.DecodeLastRune(buf.Bytes())
447
+			if r == utf8.RuneError && n <= 1 {
448
+				newBufLen--
449
+				buf.Truncate(newBufLen)
450
+			} else {
451
+				break
452
+			}
453
+		}
416
 	}
454
 	}
417
 	buf.WriteString("\r\n")
455
 	buf.WriteString("\r\n")
418
 
456
 
419
-	result := buf.Bytes()
457
+	result = buf.Bytes()
420
 	toValidate := result[:len(result)-2]
458
 	toValidate := result[:len(result)-2]
421
 	if bytes.IndexByte(toValidate, '\x00') != -1 || bytes.IndexByte(toValidate, '\r') != -1 || bytes.IndexByte(toValidate, '\n') != -1 {
459
 	if bytes.IndexByte(toValidate, '\x00') != -1 || bytes.IndexByte(toValidate, '\r') != -1 || bytes.IndexByte(toValidate, '\n') != -1 {
422
 		return nil, ErrorLineContainsBadChar
460
 		return nil, ErrorLineContainsBadChar
423
 	}
461
 	}
424
-	return result, nil
462
+	return result, err
425
 }
463
 }

+ 4
- 0
vendor/github.com/goshuirc/irc-go/ircreader/ircreader.go Dosyayı Görüntüle

63
 			line := cc.buf[cc.start : cc.searchFrom+nlidx]
63
 			line := cc.buf[cc.start : cc.searchFrom+nlidx]
64
 			cc.start = cc.searchFrom + nlidx + 1
64
 			cc.start = cc.searchFrom + nlidx + 1
65
 			cc.searchFrom = cc.start
65
 			cc.searchFrom = cc.start
66
+			// treat \r\n as the line terminator if it was present
67
+			if 0 < len(line) && line[len(line)-1] == '\r' {
68
+				line = line[:len(line)-1]
69
+			}
66
 			return line, nil
70
 			return line, nil
67
 		}
71
 		}
68
 
72
 

+ 1
- 1
vendor/modules.txt Dosyayı Görüntüle

21
 # github.com/gorilla/websocket v1.4.2 => github.com/oragono/websocket v1.4.2-oragono1
21
 # github.com/gorilla/websocket v1.4.2 => github.com/oragono/websocket v1.4.2-oragono1
22
 ## explicit
22
 ## explicit
23
 github.com/gorilla/websocket
23
 github.com/gorilla/websocket
24
-# github.com/goshuirc/irc-go v0.0.0-20210301225436-2c4b83d64847
24
+# github.com/goshuirc/irc-go v0.0.0-20210304031553-cf78e9176f96
25
 ## explicit
25
 ## explicit
26
 github.com/goshuirc/irc-go/ircfmt
26
 github.com/goshuirc/irc-go/ircfmt
27
 github.com/goshuirc/irc-go/ircmsg
27
 github.com/goshuirc/irc-go/ircmsg

Loading…
İptal
Kaydet