From db81b15acb84d77316aac81cdf8de4dc445edb59 Mon Sep 17 00:00:00 2001 From: Shivaram Lingamneni Date: Fri, 15 Jan 2021 06:19:13 -0500 Subject: [PATCH] initial work on #1483 Add the new utf8-only cap, disallow non-utf8 when websockets are enabled --- irc/client.go | 9 ++++++--- irc/config.go | 6 ++++++ irc/ircconn.go | 14 +++++--------- irc/listeners.go | 1 + 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/irc/client.go b/irc/client.go index 0243c085..d6408711 100644 --- a/irc/client.go +++ b/irc/client.go @@ -686,9 +686,12 @@ func (client *Client) run(session *Session) { if err == errInvalidUtf8 { invalidUtf8 = true // handle as normal, including labeling } else if err != nil { - quitMessage := "connection closed" - if err == errReadQ { - quitMessage = "readQ exceeded" + var quitMessage string + switch err { + case errReadQ, errWSBinaryMessage: + quitMessage = err.Error() + default: + quitMessage = "connection closed" } client.Quit(quitMessage, session) // since the client did not actually send us a QUIT, diff --git a/irc/config.go b/irc/config.go index 8ddb3da8..de1a7ca8 100644 --- a/irc/config.go +++ b/irc/config.go @@ -837,6 +837,9 @@ func (conf *Config) prepareListeners() (err error) { } lconf.RequireProxy = block.TLS.Proxy || block.Proxy lconf.WebSocket = block.WebSocket + if lconf.WebSocket && !conf.Server.EnforceUtf8 { + return fmt.Errorf("enabling a websocket listener requires the use of server.enforce-utf8") + } lconf.HideSTS = block.HideSTS conf.Server.trueListeners[addr] = lconf } @@ -1446,6 +1449,9 @@ func (config *Config) generateISupport() (err error) { if config.Server.Casemapping == CasemappingPRECIS { isupport.Add("UTF8MAPPING", precisUTF8MappingToken) } + if config.Server.EnforceUtf8 { + isupport.Add("UTF8ONLY", "") + } isupport.Add("WHOX", "") err = isupport.RegenerateCachedReply() diff --git a/irc/ircconn.go b/irc/ircconn.go index 2f8f6984..980b34f5 100644 --- a/irc/ircconn.go +++ b/irc/ircconn.go @@ -19,8 +19,9 @@ const ( ) var ( - crlf = []byte{'\r', '\n'} - errReadQ = errors.New("ReadQ Exceeded") + crlf = []byte{'\r', '\n'} + errReadQ = errors.New("ReadQ Exceeded") + errWSBinaryMessage = errors.New("WebSocket binary messages are unsupported") ) // IRCConn abstracts away the distinction between a regular @@ -148,11 +149,7 @@ func (wc IRCWSConn) UnderlyingConn() *utils.WrappedConn { func (wc IRCWSConn) WriteLine(buf []byte) (err error) { buf = bytes.TrimSuffix(buf, crlf) - if !globalUtf8EnforcementSetting && !utf8.Valid(buf) { - // there's not much we can do about this; - // silently drop the message - return nil - } + // #1483: if we have websockets at all, then we're enforcing utf8 return wc.conn.WriteMessage(websocket.TextMessage, buf) } @@ -172,8 +169,7 @@ func (wc IRCWSConn) ReadLine() (line []byte, err error) { if messageType == websocket.TextMessage { return line, nil } else { - // for purposes of fakelag, treat non-text message as an empty line - return nil, nil + return nil, errWSBinaryMessage } } else if err == websocket.ErrReadLimit { return line, errReadQ diff --git a/irc/listeners.go b/irc/listeners.go index 8b709fcf..c50138f8 100644 --- a/irc/listeners.go +++ b/irc/listeners.go @@ -166,6 +166,7 @@ func (wl *WSListener) handle(w http.ResponseWriter, r *http.Request) { } return false }, + Subprotocols: []string{"text.ircv3.net"}, } conn, err := wsUpgrader.Upgrade(w, r, nil)