Better admin moderator controls over webcams

This commit is contained in:
Noah 2023-08-04 19:24:42 -07:00
parent 7edf6b0ea2
commit e0dcc33519
3 changed files with 46 additions and 1 deletions

View File

@ -330,6 +330,15 @@ func (s *Server) OnOpen(sub *Subscriber, msg Message) {
secret := util.RandomString(16) secret := util.RandomString(16)
log.Info("WebRTC: %s opens %s with secret %s", sub.Username, other.Username, secret) log.Info("WebRTC: %s opens %s with secret %s", sub.Username, other.Username, secret)
// If the current user is an admin and was booted or muted, inform them.
if sub.IsAdmin() {
if other.Boots(sub.Username) {
sub.ChatServer("Note: %s had booted you off their camera before, and won't be notified of your watch.", other.Username)
} else if other.Mutes(sub.Username) {
sub.ChatServer("Note: %s had muted you before, and won't be notified of your watch.", other.Username)
}
}
// Ring the target of this request and give them the secret. // Ring the target of this request and give them the secret.
other.SendJSON(Message{ other.SendJSON(Message{
Action: ActionRing, Action: ActionRing,
@ -353,6 +362,14 @@ func (s *Server) OnBoot(sub *Subscriber, msg Message) {
sub.booted[msg.Username] = struct{}{} sub.booted[msg.Username] = struct{}{}
sub.muteMu.Unlock() sub.muteMu.Unlock()
// If the subject of the boot is an admin, inform them they have been booted.
if other, err := s.GetSubscriber(msg.Username); err == nil && other.IsAdmin() {
other.ChatServer(
"%s has booted you off of their camera!",
sub.Username,
)
}
s.SendWhoList() s.SendWhoList()
} }
@ -370,6 +387,14 @@ func (s *Server) OnMute(sub *Subscriber, msg Message, mute bool) {
sub.muteMu.Unlock() sub.muteMu.Unlock()
// If the subject of the mute is an admin, inform them they have been booted.
if other, err := s.GetSubscriber(msg.Username); err == nil && other.IsAdmin() {
other.ChatServer(
"%s has muted you! Your new mute status is: %v",
sub.Username, mute,
)
}
// Send the Who List in case our cam will show as disabled to the muted party. // Send the Who List in case our cam will show as disabled to the muted party.
s.SendWhoList() s.SendWhoList()
} }

View File

@ -116,6 +116,11 @@ func (sub *Subscriber) ReadLoop(s *Server) {
}() }()
} }
// IsAdmin safely checks if the subscriber is an admin.
func (sub *Subscriber) IsAdmin() bool {
return sub.JWTClaims != nil && sub.JWTClaims.IsAdmin
}
// SendJSON sends a JSON message to the websocket client. // SendJSON sends a JSON message to the websocket client.
func (sub *Subscriber) SendJSON(v interface{}) error { func (sub *Subscriber) SendJSON(v interface{}) error {
data, err := json.Marshal(v) data, err := json.Marshal(v)
@ -393,7 +398,7 @@ func (s *Server) SendWhoList() {
} }
// If this person had booted us, force their camera to "off" // If this person had booted us, force their camera to "off"
if user.Boots(sub.Username) || user.Mutes(sub.Username) { if (user.Boots(sub.Username) || user.Mutes(sub.Username)) && !sub.IsAdmin() {
who.Video = 0 who.Video = 0
} }

View File

@ -155,6 +155,7 @@ const app = Vue.createApp({
// Streams per username. // Streams per username.
streams: {}, streams: {},
muted: {}, // muted bool per username muted: {}, // muted bool per username
booted: {}, // booted bool per username
poppedOut: {}, // popped-out video per username poppedOut: {}, // popped-out video per username
// RTCPeerConnections per username. // RTCPeerConnections per username.
@ -655,6 +656,13 @@ const app = Vue.createApp({
this.startWebRTC(msg.username, true); this.startWebRTC(msg.username, true);
}, },
onRing(msg) { onRing(msg) {
// Admin moderation feature: if the user has booted an admin off their camera, do not
// notify if the admin re-opens their camera.
if (this.isBootedAdmin(msg.username)) {
this.startWebRTC(msg.username, false);
return;
}
this.ChatServer(`${msg.username} has opened your camera.`); this.ChatServer(`${msg.username} has opened your camera.`);
this.startWebRTC(msg.username, false); this.startWebRTC(msg.username, false);
}, },
@ -1021,6 +1029,7 @@ const app = Vue.createApp({
}, },
onWatch(msg) { onWatch(msg) {
// The user has our video feed open now. // The user has our video feed open now.
if (this.isBootedAdmin(msg.username)) return;
this.webcam.watching[msg.username] = true; this.webcam.watching[msg.username] = true;
}, },
onUnwatch(msg) { onUnwatch(msg) {
@ -1510,6 +1519,7 @@ const app = Vue.createApp({
} }
this.sendBoot(username); this.sendBoot(username);
this.WebRTC.booted[username] = true;
// Close the WebRTC peer connection. // Close the WebRTC peer connection.
if (this.WebRTC.pc[username] != undefined) { if (this.WebRTC.pc[username] != undefined) {
@ -1523,6 +1533,11 @@ const app = Vue.createApp({
`in place for the remainder of your current chat session.` `in place for the remainder of your current chat session.`
); );
}, },
isBootedAdmin(username) {
return (this.WebRTC.booted[username] === true || this.muted[username] === true) &&
this.whoMap[username] != undefined &&
this.whoMap[username].op;
},
// Stop broadcasting. // Stop broadcasting.
stopVideo() { stopVideo() {