feat(hidden-moderator) Moderator can join hidden based on jwt

- hidden moderator is not seen by other participants
- hidden moderator does not see their own thumbnail
- hidden moderator cannot unmute their video/audio or share screen
- hidden moderator can see and control other participants in meet( stop video, kick etc)
This commit is contained in:
hmuresan 2022-02-09 11:49:22 +02:00
parent fd4c1ce9a0
commit 11b5059c43
6 changed files with 74 additions and 4 deletions

View File

@ -148,6 +148,7 @@ import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/Au
import { createPresenterEffect } from './react/features/stream-effects/presenter';
import { createRnnoiseProcessor } from './react/features/stream-effects/rnnoise';
import { endpointMessageReceived } from './react/features/subtitles';
import { muteLocal } from './react/features/video-menu/actions.any';
import UIEvents from './service/UI/UIEvents';
const logger = Logger.getLogger(__filename);
@ -2600,13 +2601,21 @@ export default {
* @returns {void}
*/
_onConferenceJoined() {
const { dispatch } = APP.store;
APP.UI.initConference();
if (!config.disableShortcuts) {
APP.keyboardshortcut.init();
}
APP.store.dispatch(conferenceJoined(room));
dispatch(conferenceJoined(room));
if (room.isHidden()) {
dispatch(muteLocal(true, MEDIA_TYPE.AUDIO));
dispatch(muteLocal(true, MEDIA_TYPE.VIDEO));
dispatch(setAudioUnmutePermissions(true));
dispatch(setVideoUnmutePermissions(true));
}
},
/**

View File

@ -265,6 +265,12 @@ export function shouldHideShareAudioHelper(state: Object): boolean {
* @returns {boolean}
*/
export function shouldHideSelfView(state: Object) {
const { conference } = state['features/base/conference'];
if (conference?.isHidden()) {
return true;
}
return getParticipantCount(state) === 1 ? false : getHideSelfView(state);
}

View File

@ -104,11 +104,11 @@ function _onFollowMeCommand(attributes = {}, id, store) {
// The Command(s) API will send us our own commands and we don't want
// to act upon them.
if (participantSendingCommand.local) {
if (participantSendingCommand?.local) {
return;
}
if (participantSendingCommand.role !== 'moderator') {
if (participantSendingCommand && participantSendingCommand.role !== 'moderator') {
logger.warn('Received follow-me command not from moderator');
return;

View File

@ -210,6 +210,7 @@ export const shouldRenderInviteButton = (state: Object) => {
* @returns {Array<string>}
*/
export function getSortedParticipantIds(stateful: Object | Function): Array<string> {
const { conference } = stateful['features/base/conference'];
const { id } = getLocalParticipant(stateful);
const remoteParticipants = getRemoteParticipantsSorted(stateful);
const reorderedParticipants = new Set(remoteParticipants);
@ -226,7 +227,7 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri
const dominant = [];
const dominantId = dominantSpeaker?.id;
const local = remoteRaisedHandParticipants.has(id) ? [] : [ id ];
let local = remoteRaisedHandParticipants.has(id) ? [] : [ id ];
// In case dominat speaker has raised hand, keep the order in the raised hand queue.
// In case they don't have raised hand, goes first in the participants list.
@ -235,6 +236,11 @@ export function getSortedParticipantIds(stateful: Object | Function): Array<stri
dominant.push(dominantId);
}
if (conference.isHidden()) {
local = [];
remoteRaisedHandParticipants.delete(id);
}
// Move self and participants with raised hand to the top of the list.
return [
...dominant,

View File

@ -0,0 +1,36 @@
--This module adds is_hidden tag when the user from jwt is moderator and when
--jwt contains `hidden` flag set to true, or removes it in case it was
--added maliciously from client sent presence.
--The module must be enabled under the muc component.
local is_user_hidden = module:require "util".is_user_hidden;
local tag_name = "is_hidden"
module:log("info", "Loading mod_muc_user_hidden!");
function add_hidden_tag(event)
local stanza = event.stanza;
local session = event.origin;
if stanza == nil or stanza.name ~= "presence" then
return
end
stanza:maptags(function(tag)
if tag and tag.name == tag_name then
module:log("info", "Removing %s tag from presence stanza!", tag_name);
return nil;
else
return tag;
end
end)
if is_user_hidden(session) then
stanza:tag(tag_name):up()
end
end
module:hook("presence/bare", add_hidden_tag);
module:hook("presence/full", add_hidden_tag);
module:hook("presence/host", add_hidden_tag);
module:log("info", "Loaded mod_muc_user_hidden!");

View File

@ -239,6 +239,18 @@ function is_feature_allowed(session, feature)
end
end
-- Utility function to check whether the user should be hidden.
function is_user_hidden(session)
local context_user = session.jitsi_meet_context_user
if (context_user ~= nil
and (context_user['moderator'] == "true" or context_user['moderator'] == true)
and (context_user['hidden'] == "true" or context_user['hidden'] == true)) then
return true;
else
return false;
end
end
--- Extracts the subdomain and room name from internal jid node [foo]room1
-- @return subdomain(optional, if extracted or nil), the room name
function extract_subdomain(room_node)
@ -356,6 +368,7 @@ end
return {
extract_subdomain = extract_subdomain;
is_feature_allowed = is_feature_allowed;
is_user_hidden = is_user_hidden;
is_healthcheck_room = is_healthcheck_room;
get_room_from_jid = get_room_from_jid;
get_room_by_name_and_subdomain = get_room_by_name_and_subdomain;