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)
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.
other.SendJSON(Message{
Action: ActionRing,
@ -353,6 +362,14 @@ func (s *Server) OnBoot(sub *Subscriber, msg Message) {
sub.booted[msg.Username] = struct{}{}
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()
}
@ -370,6 +387,14 @@ func (s *Server) OnMute(sub *Subscriber, msg Message, mute bool) {
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.
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.
func (sub *Subscriber) SendJSON(v interface{}) error {
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 user.Boots(sub.Username) || user.Mutes(sub.Username) {
if (user.Boots(sub.Username) || user.Mutes(sub.Username)) && !sub.IsAdmin() {
who.Video = 0
}

View File

@ -155,6 +155,7 @@ const app = Vue.createApp({
// Streams per username.
streams: {},
muted: {}, // muted bool per username
booted: {}, // booted bool per username
poppedOut: {}, // popped-out video per username
// RTCPeerConnections per username.
@ -655,6 +656,13 @@ const app = Vue.createApp({
this.startWebRTC(msg.username, true);
},
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.startWebRTC(msg.username, false);
},
@ -1021,6 +1029,7 @@ const app = Vue.createApp({
},
onWatch(msg) {
// The user has our video feed open now.
if (this.isBootedAdmin(msg.username)) return;
this.webcam.watching[msg.username] = true;
},
onUnwatch(msg) {
@ -1510,6 +1519,7 @@ const app = Vue.createApp({
}
this.sendBoot(username);
this.WebRTC.booted[username] = true;
// Close the WebRTC peer connection.
if (this.WebRTC.pc[username] != undefined) {
@ -1523,6 +1533,11 @@ const app = Vue.createApp({
`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.
stopVideo() {