Add spam detection in case a user copy/pastes a hyperlink to everybody on chat via their DMs: * If the same link is copied to many different people within a time window, the user can be kicked from the chat room with a warning. * The server remembers rate limits by username, so if they log back in and continue to spam the same links, they instead receive a temporary chat ban. * The spam threshold, time window and ban hours are configurable in the BareRTC settings.toml. Other fixes: * The front-end will send a "me" update with its current status and video setting in the 'onLoggedIn' handler. This should help alleviate rough server reboots when a ton of idle users are online, so they don't spam "me" updates to correct their status once the WhoLists begin to roll in.
85 lines
1.7 KiB
Go
85 lines
1.7 KiB
Go
package barertc
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
/* Functions to handle banned users */
|
|
|
|
// Ban is an entry on the ban list.
|
|
type Ban struct {
|
|
Username string
|
|
ExpiresAt time.Time
|
|
}
|
|
|
|
// Global storage for banned users in memory.
|
|
var (
|
|
banList = map[string]Ban{}
|
|
banListMu sync.RWMutex
|
|
)
|
|
|
|
// BanUser adds a user to the ban list.
|
|
func (s *Server) BanUser(username string, duration time.Duration) {
|
|
banListMu.Lock()
|
|
defer banListMu.Unlock()
|
|
banList[username] = Ban{
|
|
Username: username,
|
|
ExpiresAt: time.Now().Add(duration),
|
|
}
|
|
}
|
|
|
|
// UnbanUser lifts the ban of a user early.
|
|
func UnbanUser(username string) bool {
|
|
banListMu.RLock()
|
|
defer banListMu.RUnlock()
|
|
_, ok := banList[username]
|
|
if ok {
|
|
delete(banList, username)
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// StringifyBannedUsers returns a stringified list of all the current banned users.
|
|
func StringifyBannedUsers() string {
|
|
var lines = []string{}
|
|
banListMu.RLock()
|
|
defer banListMu.RUnlock()
|
|
for username, ban := range banList {
|
|
lines = append(lines, fmt.Sprintf(
|
|
"* `%s` banned until %s",
|
|
username,
|
|
ban.ExpiresAt.Format(time.RFC3339),
|
|
))
|
|
}
|
|
return strings.Join(lines, "\n")
|
|
}
|
|
|
|
// IsBanned returns whether the username is currently banned.
|
|
func IsBanned(username string) bool {
|
|
banListMu.Lock()
|
|
defer banListMu.Unlock()
|
|
ban, ok := banList[username]
|
|
if ok {
|
|
// Has the ban expired?
|
|
if time.Now().After(ban.ExpiresAt) {
|
|
delete(banList, username)
|
|
return false
|
|
}
|
|
}
|
|
return ok
|
|
}
|
|
|
|
// BanExpires returns the time.Duration string until the user's ban expires.
|
|
func BanExpires(username string) string {
|
|
banListMu.RLock()
|
|
defer banListMu.RUnlock()
|
|
ban, ok := banList[username]
|
|
if ok {
|
|
return time.Until(ban.ExpiresAt).String()
|
|
}
|
|
return ""
|
|
}
|