diff --git a/core/chat/client.go b/core/chat/client.go index d868c3a76..1d02522b6 100644 --- a/core/chat/client.go +++ b/core/chat/client.go @@ -14,6 +14,7 @@ import ( "github.com/owncast/owncast/utils" "github.com/teris-io/shortid" + "golang.org/x/time/rate" ) const channelBufSize = 100 @@ -35,6 +36,8 @@ type Client struct { usernameChangeChannel chan models.NameChangeEvent doneCh chan bool + + rateLimiter *rate.Limiter } const ( @@ -61,7 +64,9 @@ func NewClient(ws *websocket.Conn) *Client { socketID, _ := shortid.Generate() clientID := socketID - return &Client{time.Now(), 0, userAgent, ipAddress, nil, clientID, nil, socketID, ws, ch, pingch, usernameChangeChannel, doneCh} + rateLimiter := rate.NewLimiter(0.6, 5) + + return &Client{time.Now(), 0, userAgent, ipAddress, nil, clientID, nil, socketID, ws, ch, pingch, usernameChangeChannel, doneCh, rateLimiter} } // GetConnection gets the connection for the client. @@ -124,6 +129,15 @@ func (c *Client) handleClientSocketError(err error) { _server.removeClient(c) } +func (c *Client) passesRateLimit() bool { + if !c.rateLimiter.Allow() { + log.Warnln("Client", c.ClientID, "has exceeded the messaging rate limiting thresholds.") + return false + } + + return true +} + // Listen read request via channel. func (c *Client) listenRead() { for { @@ -155,6 +169,10 @@ func (c *Client) listenRead() { messageType := messageTypeCheck["type"] + if !c.passesRateLimit() { + continue + } + if messageType == CHAT { c.chatMessageReceived(data) } else if messageType == NAMECHANGE { diff --git a/go.mod b/go.mod index 384716adb..890ae01fe 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/teris-io/shortid v0.0.0-20171029131806-771a37caa5cf github.com/yuin/goldmark v1.3.1 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b + golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.4.0 mvdan.cc/xurls v1.1.0 diff --git a/go.sum b/go.sum index 7930956ac..d0106bbbf 100644 --- a/go.sum +++ b/go.sum @@ -79,6 +79,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= +golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=