Blockable admin user support

This commit is contained in:
Noah 2024-09-09 21:08:31 -07:00
parent 49712ee966
commit d4b69311ae
5 changed files with 37 additions and 24 deletions

View File

@ -62,7 +62,6 @@ func (s *Server) ProcessCommand(sub *Subscriber, msg messages.Message) bool {
"* `/bans` to list current banned users and their expiration date\n" + "* `/bans` to list current banned users and their expiration date\n" +
"* `/nsfw <username>` to mark their camera NSFW\n" + "* `/nsfw <username>` to mark their camera NSFW\n" +
"* `/cut <username>` to make them turn off their camera\n" + "* `/cut <username>` to make them turn off their camera\n" +
"* `/unmute-all` to lift all mutes on your side\n" +
"* `/help` to show this message\n" + "* `/help` to show this message\n" +
"* `/help-advanced` to show advanced admin commands\n\n" + "* `/help-advanced` to show advanced admin commands\n\n" +
"Note: shell-style quoting is supported, if a username has a space in it, quote the whole username, e.g.: `/kick \"username 2\"`", "Note: shell-style quoting is supported, if a username has a space in it, quote the whole username, e.g.: `/kick \"username 2\"`",
@ -189,7 +188,9 @@ func (s *Server) CutCommand(words []string, sub *Subscriber) {
func (s *Server) UnmuteAllCommand(words []string, sub *Subscriber) { func (s *Server) UnmuteAllCommand(words []string, sub *Subscriber) {
count := len(sub.muted) count := len(sub.muted)
sub.muted = map[string]struct{}{} sub.muted = map[string]struct{}{}
sub.unblockable = true
sub.ChatServer("Your mute on %d users has been lifted.", count) sub.ChatServer("Your mute on %d users has been lifted.", count)
s.SendWhoList()
} }
// KickCommand handles the `/kick` operator command. // KickCommand handles the `/kick` operator command.

View File

@ -13,7 +13,7 @@ import (
// Version of the config format - when new fields are added, it will attempt // Version of the config format - when new fields are added, it will attempt
// to write the settings.toml to disk so new defaults populate. // to write the settings.toml to disk so new defaults populate.
var currentVersion = 13 var currentVersion = 14
// Config for your BareRTC app. // Config for your BareRTC app.
type Config struct { type Config struct {
@ -33,6 +33,7 @@ type Config struct {
CORSHosts []string CORSHosts []string
AdminAPIKey string AdminAPIKey string
PermitNSFW bool PermitNSFW bool
BlockableAdmins bool
UseXForwardedFor bool UseXForwardedFor bool

View File

@ -126,7 +126,7 @@ func (s *Server) OnMessage(sub *Subscriber, msg messages.Message) {
log.Info("[%s to #%s] %s", sub.Username, msg.Channel, msg.Message) log.Info("[%s to #%s] %s", sub.Username, msg.Channel, msg.Message)
} }
if sub.Username == "" { if sub.Username == "" || !sub.authenticated {
sub.ChatServer("You must log in first.") sub.ChatServer("You must log in first.")
return return
} }
@ -180,11 +180,8 @@ func (s *Server) OnMessage(sub *Subscriber, msg messages.Message) {
// If the user is OP, just tell them we would. // If the user is OP, just tell them we would.
if sub.IsAdmin() { if sub.IsAdmin() {
sub.ChatServer("Your recent chat context would have been reported to your main website.") sub.ChatServer("Your recent chat context would have been reported to your main website.")
return } else if err := s.reportFilteredMessage(sub, msg); err != nil {
}
// Send the report to the main website. // Send the report to the main website.
if err := s.reportFilteredMessage(sub, msg); err != nil {
log.Error("Reporting filtered message: %s", err) log.Error("Reporting filtered message: %s", err)
} }
} }
@ -204,17 +201,17 @@ func (s *Server) OnMessage(sub *Subscriber, msg messages.Message) {
// Don't deliver it if the receiver has muted us. Note: admin users, even if muted, // Don't deliver it if the receiver has muted us. Note: admin users, even if muted,
// can still deliver a DM to the one who muted them. // can still deliver a DM to the one who muted them.
rcpt, err := s.GetSubscriber(strings.TrimPrefix(msg.Channel, "@")) rcpt, err := s.GetSubscriber(strings.TrimPrefix(msg.Channel, "@"))
if err == nil && rcpt.Mutes(sub.Username) && !sub.IsAdmin() { if err != nil {
log.Debug("Do not send message to %s: they have muted or booted %s", rcpt.Username, sub.Username)
return
} else if err != nil {
// Recipient was no longer online: the message won't be sent. // Recipient was no longer online: the message won't be sent.
sub.ChatServer("Could not deliver your message: %s appears not to be online.", msg.Channel) sub.ChatServer("Could not deliver your message: %s appears not to be online.", msg.Channel)
return return
} else if rcpt.Mutes(sub.Username) && !sub.IsAdmin() {
log.Debug("Do not send message to %s: they have muted or booted %s", rcpt.Username, sub.Username)
return
} }
// If the sender already mutes the recipient, reply back with the error. // If the sender already mutes the recipient, reply back with the error.
if err == nil && sub.Mutes(rcpt.Username) && !sub.IsAdmin() { if sub.Mutes(rcpt.Username) && !sub.IsAdmin() {
sub.ChatServer("You have muted %s and so your message has not been sent.", rcpt.Username) sub.ChatServer("You have muted %s and so your message has not been sent.", rcpt.Username)
return return
} }

View File

@ -50,6 +50,12 @@ type Subscriber struct {
blocked map[string]struct{} // usernames you have blocked blocked map[string]struct{} // usernames you have blocked
muted map[string]struct{} // usernames you muted muted map[string]struct{} // usernames you muted
// Admin "unblockable" override command, e.g. especially for your chatbot so it can
// still moderate the chat even if users had blocked it. The /unmute-all admin command
// will toggle this setting: then the admin chatbot will appear in the Who's Online list
// as normal and it can see user messages in chat.
unblockable bool
// Record which message IDs belong to this user. // Record which message IDs belong to this user.
midMu sync.Mutex midMu sync.Mutex
messageIDs map[int64]struct{} messageIDs map[int64]struct{}
@ -535,7 +541,7 @@ func (s *Server) SendWhoList() {
// If this person's VideoFlag is set to VIP Only, force their camera to "off" // If this person's VideoFlag is set to VIP Only, force their camera to "off"
// except when the person looking has the VIP status. // except when the person looking has the VIP status.
if (user.VideoStatus&messages.VideoFlagOnlyVIP == messages.VideoFlagOnlyVIP) && (!sub.IsVIP() && !sub.IsAdmin()) { if (user.VideoStatus&messages.VideoFlagOnlyVIP == messages.VideoFlagOnlyVIP) && !sub.IsVIP() {
who.Video = 0 who.Video = 0
} }
} }
@ -590,9 +596,21 @@ func (s *Subscriber) Blocks(other *Subscriber) bool {
return false return false
} }
// If either side is an admin, blocking is not allowed. // Admin blocking behavior: by default, admins are NOT blockable by users and retain visibility on
if s.IsAdmin() || other.IsAdmin() { // chat, especially to moderate webcams (messages may still be muted between blocked users).
//
// If your chat server allows admins to be blockable:
if !config.Current.BlockableAdmins && (s.IsAdmin() || other.IsAdmin()) {
return false return false
} else {
// Admins are blockable, unless they have the unblockable flag - e.g. if you have an admin chatbot on
// your server it will send the `/unmute-all` command to still retain visibility into user messages for
// auto-moderation. The `/unmute-all` sets the unblockable flag, so your admin chatbot still appears
// on the Who's Online list as well.
unblockable := (s.IsAdmin() && s.unblockable) || (other.IsAdmin() && other.unblockable)
if unblockable {
return false
}
} }
s.muteMu.RLock() s.muteMu.RLock()

View File

@ -1332,11 +1332,7 @@ export default {
if (!window.confirm( if (!window.confirm(
`Do you want to remove your mute on ${username}? If you un-mute them, you ` + `Do you want to remove your mute on ${username}? If you un-mute them, you ` +
`will be able to see their chat messages or DMs going forward, but most importantly, ` + `will be able to see their chat messages or DMs going forward, but most importantly, ` +
`they may be able to watch your webcam now if you are broadcasting!\n\n` + `they may be able to watch your webcam now if you are broadcasting!`,
`Note: currently you can only re-mute them the next time you see one of their ` +
`chat messages, or you can only boot them off your cam after they have already ` +
`opened it. If you are concerned about this, click Cancel and do not remove ` +
`the mute on ${username}.`
)) { )) {
return; return;
} }