Compare commits

...

6 Commits

Author SHA1 Message Date
Дамян Минков
ba79af66fa feat: Adds user hidden feature and handle breakout rooms. 2022-02-11 14:16:25 -06:00
Дамян Минков
ea36be5e81 feat: Moves process_host_module to util. 2022-02-11 13:40:03 -06:00
hmuresan
a377671d66 fix crash 2022-02-11 12:18:29 +02:00
hmuresan
8459f2edb2 Replace moderator with user 2022-02-10 14:07:12 +02:00
hmuresan
4d2c2c0fac Remove moderator check for hidden participant 2022-02-10 14:07:12 +02:00
hmuresan
11b5059c43 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)
2022-02-10 14:07:12 +02:00
12 changed files with 168 additions and 108 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

@@ -1,7 +1,9 @@
local get_room_by_name_and_subdomain = module:require 'util'.get_room_by_name_and_subdomain;
local is_healthcheck_room = module:require 'util'.is_healthcheck_room;
local internal_room_jid_match_rewrite = module:require "util".internal_room_jid_match_rewrite;
local room_jid_match_rewrite = module:require "util".room_jid_match_rewrite;
local util = module:require 'util';
local get_room_by_name_and_subdomain = util.get_room_by_name_and_subdomain;
local is_healthcheck_room = util.is_healthcheck_room;
local internal_room_jid_match_rewrite = util.internal_room_jid_match_rewrite;
local process_host_module = util.process_host_module;
local room_jid_match_rewrite = util.room_jid_match_rewrite;
local array = require "util.array";
local json = require 'util.json';
local st = require 'util.stanza';
@@ -302,20 +304,11 @@ module:hook('message/host', on_message);
-- executed on every host added internally in prosody, including components
function process_host(host)
if host == muc_component_host then -- the conference muc component
module:log('info','Hook to muc events on %s', host);
module:log('info','Hook to muc events on %s', host);
local muc_module = module:context(host);
muc_module:hook('muc-occupant-joined', occupant_joined, -2); -- make sure it runs after allowners or similar
muc_module:hook('muc-set-affiliation', occupant_affiliation_changed, -1);
end
local muc_module = module:context(host);
muc_module:hook('muc-occupant-joined', occupant_joined, -2); -- make sure it runs after allowners or similar
muc_module:hook('muc-set-affiliation', occupant_affiliation_changed, -1);
end
if prosody.hosts[muc_component_host] == nil then
module:log('info', 'No muc component found, will listen for it: %s', muc_component_host);
-- when a host or component is added
prosody.events.add_handler('host-activated', process_host);
else
process_host(muc_component_host);
end
process_host_module(muc_component_host, process_host);

View File

@@ -3,6 +3,7 @@ local socket = require "socket";
local json = require "util.json";
local ext_events = module:require "ext_events";
local it = require "util.iterators";
local process_host_module = module:require 'util'.process_host_module;
-- we use async to detect Prosody 0.10 and earlier
local have_async = pcall(require, "util.async");
@@ -48,19 +49,10 @@ end
-- executed on every host added internally in prosody, including components
function process_host(host)
if host == muc_component_host then -- the conference muc component
module:log("info", "Hook to muc events on %s", host);
module:log("info", "Hook to muc events on %s", host);
local muc_module = module:context(host)
muc_module:hook("muc-occupant-joined", occupant_joined, -1);
end
local muc_module = module:context(host)
muc_module:hook("muc-occupant-joined", occupant_joined, -1);
end
if prosody.hosts[muc_component_host] == nil then
module:log("info", "No muc component found, will listen for it: %s", muc_component_host);
-- when a host or component is added
prosody.events.add_handler("host-activated", process_host);
else
process_host(muc_component_host);
end
process_host_module(muc_component_host, process_host);

View File

@@ -33,6 +33,7 @@ local uuid_gen = require 'util.uuid'.generate;
local util = module:require 'util';
local internal_room_jid_match_rewrite = util.internal_room_jid_match_rewrite;
local is_healthcheck_room = util.is_healthcheck_room;
local process_host_module = util.process_host_module;
local BREAKOUT_ROOMS_IDENTITY_TYPE = 'breakout_rooms';
-- only send at most this often updates on breakout rooms to avoid flooding.
@@ -430,25 +431,6 @@ end
-- Module operations
-- process a host module directly if loaded or hooks to wait for its load
function process_host_module(name, callback)
local function process_host(host)
if host == name then
callback(module:context(host), host);
end
end
if prosody.hosts[name] == nil then
module:log('debug', 'No host/component found, will wait for it: %s', name)
-- when a host or component is added
prosody.events.add_handler('host-activated', process_host);
else
process_host(name);
end
end
-- operates on already loaded breakout rooms muc module
function process_breakout_rooms_muc_loaded(breakout_rooms_muc, host_module)
module:log('debug', 'Breakout rooms muc loaded');
@@ -542,7 +524,8 @@ function process_breakout_rooms_muc_loaded(breakout_rooms_muc, host_module)
end
-- process or waits to process the breakout rooms muc component
process_host_module(breakout_rooms_muc_component_config, function(host_module, host)
process_host_module(breakout_rooms_muc_component_config, function(host)
local host_module = module:context(host);
module:log('info', 'Breakout rooms component created %s', host);
local muc_module = prosody.hosts[host].modules.muc;
@@ -571,7 +554,8 @@ function process_main_muc_loaded(main_muc, host_module)
end
-- process or waits to process the main muc component
process_host_module(main_muc_component_config, function(host_module, host)
process_host_module(main_muc_component_config, function(host)
local host_module = module:context(host);
local muc_module = prosody.hosts[host].modules.muc;
if muc_module then

View File

@@ -43,6 +43,7 @@ local util = module:require "util";
local get_room_by_name_and_subdomain = util.get_room_by_name_and_subdomain;
local is_healthcheck_room = util.is_healthcheck_room;
local presence_check_status = util.presence_check_status;
local process_host_module = util.process_host_module;
local main_muc_component_config = module:get_option_string('main_muc');
if main_muc_component_config == nil then
@@ -205,24 +206,6 @@ function destroy_lobby_room(room, newjid, message)
end
end
-- process a host module directly if loaded or hooks to wait for its load
function process_host_module(name, callback)
local function process_host(host)
if host == name then
callback(module:context(host), host);
end
end
if prosody.hosts[name] == nil then
module:log('debug', 'No host/component found, will wait for it: %s', name)
-- when a host or component is added
prosody.events.add_handler('host-activated', process_host);
else
process_host(name);
end
end
-- operates on already loaded lobby muc module
function process_lobby_muc_loaded(lobby_muc, host_module)
module:log('debug', 'Lobby muc loaded');
@@ -280,7 +263,8 @@ function process_lobby_muc_loaded(lobby_muc, host_module)
end
-- process or waits to process the lobby muc component
process_host_module(lobby_muc_component_config, function(host_module, host)
process_host_module(lobby_muc_component_config, function(host)
local host_module = module:context(host);
-- lobby muc component created
module:log('info', 'Lobby component loaded %s', host);
@@ -298,7 +282,8 @@ process_host_module(lobby_muc_component_config, function(host_module, host)
end);
-- process or waits to process the main muc component
process_host_module(main_muc_component_config, function(host_module, host)
process_host_module(main_muc_component_config, function(host)
local host_module = module:context(host);
main_muc_service = prosody.hosts[host].modules.muc;
-- hooks when lobby is enabled to create its room, only done here or by admin

View File

@@ -0,0 +1,65 @@
--This module adds is_hidden tag 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 main virtual host.
local util = module:require 'util';
local is_user_hidden = util.is_user_hidden;
local process_host_module = util.process_host_module;
local TAG_NAME = 'is_hidden'
local USER_HIDDEN_FEATURE = 'http://jitsi.org/protocol/user_hidden';
-- main_muc
local main_muc_component_config = module:get_option_string('main_muc');
if main_muc_component_config == nil then
module:log('error', 'hidden_user not enabled missing main_muc config');
return ;
end
-- breakout_rooms_muc
local breakout_rooms_muc_component_config = module:get_option_string('breakout_rooms_muc');
function add_hidden_tag(event)
local stanza = event.stanza;
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)
local session = event.origin;
if is_user_hidden(session) then
stanza:tag(TAG_NAME):up()
end
end
function process_muc_component(host)
module:log("info", "Hook to presence on %s", host);
local muc_module = module:context(host);
muc_module:hook('presence/bare', add_hidden_tag);
muc_module:hook('presence/full', add_hidden_tag);
muc_module:hook('presence/host', add_hidden_tag);
-- announce it to the client
muc_module:hook('muc-disco#info', function(event)
event.reply:tag('feature', { var = USER_HIDDEN_FEATURE }):up();
end);
end
process_host_module(main_muc_component_config, process_muc_component);
if breakout_rooms_muc_component_config then
process_host_module(breakout_rooms_muc_component_config, process_muc_component);
end
module:log('info', 'Loaded mod_muc_user_hidden!');

View File

@@ -62,9 +62,11 @@ local st = require "util.stanza";
local timer = require 'util.timer';
local datetime = require 'util.datetime';
local get_room_from_jid = module:require "util".get_room_from_jid;
local is_healthcheck_room = module:require "util".is_healthcheck_room;
local room_jid_match_rewrite = module:require "util".room_jid_match_rewrite;
local util = module:require 'util';
local get_room_from_jid = util.get_room_from_jid;
local is_healthcheck_room = util.is_healthcheck_room;
local process_host_module = util.process_host_module;
local room_jid_match_rewrite = util.room_jid_match_rewrite;
local api_prefix = module:get_option("reservations_api_prefix");
local api_headers = module:get_option("reservations_api_headers");
@@ -575,15 +577,8 @@ end
function process_host(host)
if host == muc_component_host then -- the conference muc component
module:log("info", "Hook to muc events on %s", host);
module:context(host):hook("muc-room-destroyed", room_destroyed, -1);
end
module:log("info", "Hook to muc events on %s", host);
module:context(host):hook("muc-room-destroyed", room_destroyed, -1);
end
if prosody.hosts[muc_component_host] == nil then
module:log("info", "No muc component found, will listen for it: %s", muc_component_host)
prosody.events.add_handler("host-activated", process_host);
else
process_host(muc_component_host);
end
process_host_module(muc_component_host, process_host);

View File

@@ -1,6 +1,9 @@
local get_room_from_jid = module:require "util".get_room_from_jid;
local room_jid_match_rewrite = module:require "util".room_jid_match_rewrite;
local is_healthcheck_room = module:require "util".is_healthcheck_room;
local util = module:require 'util';
local get_room_from_jid = util.get_room_from_jid;
local is_healthcheck_room = util.is_healthcheck_room;
local room_jid_match_rewrite = util.room_jid_match_rewrite;
local process_host_module = util.process_host_module;
local jid_resource = require "util.jid".resource;
local ext_events = module:require "ext_events"
local st = require "util.stanza";
@@ -265,25 +268,16 @@ module:hook("message/host", on_message);
-- executed on every host added internally in prosody, including components
function process_host(host)
if host == muc_component_host then -- the conference muc component
module:log("info","Hook to muc events on %s", host);
module:log("info","Hook to muc events on %s", host);
local muc_module = module:context(host);
muc_module:hook("muc-room-created", room_created, -1);
muc_module:hook("muc-occupant-joined", occupant_joined, -1);
muc_module:hook("muc-occupant-pre-leave", occupant_leaving, -1);
muc_module:hook("muc-room-destroyed", room_destroyed, -1);
end
local muc_module = module:context(host);
muc_module:hook("muc-room-created", room_created, -1);
muc_module:hook("muc-occupant-joined", occupant_joined, -1);
muc_module:hook("muc-occupant-pre-leave", occupant_leaving, -1);
muc_module:hook("muc-room-destroyed", room_destroyed, -1);
end
if prosody.hosts[muc_component_host] == nil then
module:log("info","No muc component found, will listen for it: %s", muc_component_host)
-- when a host or component is added
prosody.events.add_handler("host-activated", process_host);
else
process_host(muc_component_host);
end
process_host_module(muc_component_host, process_host);
function get_participant_expressions_count(facialExpressions)
local count = 0;

View File

@@ -239,6 +239,17 @@ 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['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)
@@ -353,14 +364,34 @@ function presence_check_status(muc_x, status)
return false;
end
-- process a host module directly if loaded or hooks to wait for its load
function process_host_module(name, callback)
local function process_host(host)
if host == name then
callback(host);
end
end
if prosody.hosts[name] == nil then
module:log('debug', 'No host/component found, will wait for it: %s', name)
-- when a host or component is added
prosody.events.add_handler('host-activated', process_host);
else
process_host(name);
end
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;
async_handler_wrapper = async_handler_wrapper;
presence_check_status = presence_check_status;
process_host_module = process_host_module;
room_jid_match_rewrite = room_jid_match_rewrite;
room_jid_split_subdomain = room_jid_split_subdomain;
internal_room_jid_match_rewrite = internal_room_jid_match_rewrite;