diff --git a/react/features/base/connection/reducer.ts b/react/features/base/connection/reducer.ts index 2ebe4e229f..bae27ce9e1 100644 --- a/react/features/base/connection/reducer.ts +++ b/react/features/base/connection/reducer.ts @@ -147,6 +147,13 @@ function _connectionFailed( return state; } + let preferVisitor; + + if (error.name === JitsiConnectionErrors.NOT_LIVE_ERROR) { + // we want to keep the state for the moment when the meeting is live + preferVisitor = state.preferVisitor; + } + return assign(state, { connecting: undefined, connection: undefined, @@ -154,7 +161,7 @@ function _connectionFailed( passwordRequired: error.name === JitsiConnectionErrors.PASSWORD_REQUIRED ? connection : undefined, - preferVisitor: undefined + preferVisitor }); } diff --git a/react/features/base/jwt/functions.ts b/react/features/base/jwt/functions.ts index 648bf53be7..f49215891b 100644 --- a/react/features/base/jwt/functions.ts +++ b/react/features/base/jwt/functions.ts @@ -176,10 +176,12 @@ export function validateJwt(jwt: string) { } } - if (!isValidUnixTimestamp(nbf)) { - errors.push({ key: JWT_VALIDATION_ERRORS.NBF_INVALID }); - } else if (currentTimestamp < nbf * 1000) { - errors.push({ key: JWT_VALIDATION_ERRORS.NBF_FUTURE }); + if (nbf) { // nbf value is optional + if (!isValidUnixTimestamp(nbf)) { + errors.push({ key: JWT_VALIDATION_ERRORS.NBF_INVALID }); + } else if (currentTimestamp < nbf * 1000) { + errors.push({ key: JWT_VALIDATION_ERRORS.NBF_FUTURE }); + } } if (!isValidUnixTimestamp(exp)) { diff --git a/react/features/visitors/middleware.ts b/react/features/visitors/middleware.ts index bfb89c6894..e91c387e38 100644 --- a/react/features/visitors/middleware.ts +++ b/react/features/visitors/middleware.ts @@ -178,19 +178,25 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => { if ('status' in msg && msg.status === 'live') { logger.info('The conference is now live!'); - WebsocketClient.getInstance().disconnect(); + WebsocketClient.getInstance().disconnect() + .then(() => { + let delay = 0; - let delay = 0; + // now let's connect to meeting + if ('randomDelayMs' in msg) { + delay = msg.randomDelayMs; + } - // now let's connect to meeting - if ('randomDelayMs' in msg) { - delay = msg.randomDelayMs; - } + if (WebsocketClient.getInstance().connectCount > 1) { + // if we keep connecting/disconnecting, let's slow it down + delay = 30 * 1000; + } - setTimeout(() => { - dispatch(joinConference()); - dispatch(setInVisitorsQueue(false)); - }, delay); + setTimeout(() => { + dispatch(joinConference()); + dispatch(setInVisitorsQueue(false)); + }, Math.random() * delay); + }); } }, diff --git a/react/features/visitors/websocket-client.ts b/react/features/visitors/websocket-client.ts index d1836c9844..6f08c8defc 100644 --- a/react/features/visitors/websocket-client.ts +++ b/react/features/visitors/websocket-client.ts @@ -26,6 +26,8 @@ export class WebsocketClient { private retriesCount = 0; + private _connectCount = 0; + /** * WebsocketClient getInstance. * @@ -95,6 +97,7 @@ export class WebsocketClient { this.retriesCount = 0; logger.info(`Connected to:${endpoint}`); + this._connectCount++; connectCallback?.(); this.stompClient.subscribe(endpoint, message => { @@ -112,16 +115,16 @@ export class WebsocketClient { /** * Disconnects the current stomp client instance and clears it. * - * @returns {void} + * @returns {Promise} */ - disconnect(): void { + disconnect(): Promise { if (!this.stompClient) { - return; + return Promise.resolve(); } const url = this.stompClient.brokerURL; - this.stompClient.deactivate().then(() => { + return this.stompClient.deactivate().then(() => { logger.info(`disconnected from: ${url}`); this.stompClient = undefined; }); @@ -135,4 +138,13 @@ export class WebsocketClient { isActive() { return this.stompClient !== undefined; } + + /** + * Returns the number of connections. + * + * @returns {number} The number of connections for the life of the app. + */ + get connectCount(): number { + return this._connectCount; + } } diff --git a/resources/prosody-plugins/mod_visitors_component.lua b/resources/prosody-plugins/mod_visitors_component.lua index 4dd72221b0..0b33644da7 100644 --- a/resources/prosody-plugins/mod_visitors_component.lua +++ b/resources/prosody-plugins/mod_visitors_component.lua @@ -19,7 +19,8 @@ local um_is_admin = require 'core.usermanager'.is_admin; local json = require 'cjson.safe'; local inspect = require 'inspect'; -local token_util = module:require 'token/util'.new(module); +-- will be initialized once the main virtual host module is initialized +local token_util; local MUC_NS = 'http://jabber.org/protocol/muc'; @@ -304,14 +305,34 @@ local function process_promotion_response(room, id, approved) allow = approved }):up()); end +-- if room metadata does not have visitors.live set to `true` and there are no occupants in the meeting +-- it will skip calling goLive endpoint local function go_live(room) + if room._jitsi_go_live_sent then + return; + end + + if not (room.jitsiMetadata and room.jitsiMetadata.visitors and room.jitsiMetadata.visitors.live) then + return; + end + + local has_occupant = false; + for _, occupant in room:each_occupant() do + if not is_admin(occupant.bare_jid) then + has_occupant = true; + break; + end + end + + -- when there is an occupant then go live + if not has_occupant then + return; + end + -- let's inform the queue service local function cb(content_, code_, response_, request_) local room = room; - if code_ == 200 then - -- meeting went live ??? - module:log('info', 'live') - else + if code_ ~= 200 then module:log('warn', 'External call to visitors_queue_service/golive failed. Code %s, Content %s', code_, content_) end @@ -324,6 +345,8 @@ local function go_live(room) conference = internal_room_jid_match_rewrite(room.jid) }; + room._jitsi_go_live_sent = true; + http.request(visitors_queue_service..'/golive', { headers = headers, method = 'POST', @@ -333,6 +356,10 @@ end module:hook('iq/host', stanza_handler, 10); +process_host_module(muc_domain_base, function(host_module, host) + token_util = module:require "token/util".new(host_module); +end); + process_host_module(muc_domain_prefix..'.'..muc_domain_base, function(host_module, host) -- if visitor mode is started, then you are not allowed to join without request/response exchange of iqs -> deny access -- check list of allowed jids for the room @@ -496,18 +523,20 @@ process_host_module(muc_domain_prefix..'.'..muc_domain_base, function(host_modul return; end - if room.jitsiMetadata and room.jitsiMetadata.visitors and room.jitsiMetadata.visitors.live then - go_live(room); - end + go_live(room); end, -2); -- metadata hook on -1 host_module:hook('jitsi-metadata-updated', function (event) if event.key == 'visitors' then - local room = event.room; - if room.jitsiMetadata and room.jitsiMetadata.visitors and room.jitsiMetadata.visitors.live then - go_live(room); - end + go_live(event.room); end end); + -- when metadata changed internally from another module + host_module:hook('room-metadata-changed', function (event) + go_live(event.room); + end); + host_module:hook('muc-occupant-joined', function (event) + go_live(event.room); + end); end if always_visitors_enabled then diff --git a/resources/prosody-plugins/token/util.lib.lua b/resources/prosody-plugins/token/util.lib.lua index c87d3f6050..2668815f24 100644 --- a/resources/prosody-plugins/token/util.lib.lua +++ b/resources/prosody-plugins/token/util.lib.lua @@ -247,13 +247,8 @@ end -- session.jitsi_meet_context_group - the group value from the token -- session.jitsi_meet_context_features - the features value from the token -- @param session the current session --- @param acceptedIssuers optional list of accepted issuers to check -- @return false and error -function Util:process_and_verify_token(session, acceptedIssuers) - if not acceptedIssuers then - acceptedIssuers = self.acceptedIssuers; - end - +function Util:process_and_verify_token(session) if session.auth_token == nil then if self.allowEmptyToken then return true; @@ -310,7 +305,7 @@ function Util:process_and_verify_token(session, acceptedIssuers) session.auth_token, self.signatureAlgorithm, key, - acceptedIssuers, + self.acceptedIssuers, self.acceptedAudiences ) if claims ~= nil then