diff --git a/config.js b/config.js index 7202607ee..422d2f1b0 100644 --- a/config.js +++ b/config.js @@ -542,12 +542,15 @@ var config = { // Disables responsive tiles. // disableResponsiveTiles: false, - // Hides lobby button + // DEPRECATED. Please use `securityUi?.hideLobbyButton` instead. + // Hides lobby button. // hideLobbyButton: false, + // DEPRECATED. Please use `lobby?.autoKnock` instead. // If Lobby is enabled starts knocking automatically. // autoKnockLobby: false, + // DEPRECATED. Please use `lobby?.enableChat` instead. // Enable lobby chat. // enableLobbyChat: true, @@ -572,6 +575,22 @@ var config = { // customUrl: '' // }, + // Configs for the lobby screen. + // lobby { + // // If Lobby is enabled, it starts knocking automatically. Replaces `autoKnockLobby`. + // autoKnock: false, + // // Enables the lobby chat. Replaces `enableLobbyChat`. + // enableChat: true, + // }, + + // Configs for the security related UI elements. + // securityUi: { + // // Hides the lobby button. Replaces `hideLobbyButton`. + // hideLobbyButton: false, + // // Hides the possibility to set and enter a lobby password. + // disableLobbyPassword: false, + // }, + // Disable app shortcuts that are registered upon joining a conference // disableShortcuts: false, diff --git a/react/features/base/config/configType.ts b/react/features/base/config/configType.ts index 9e974a2ec..63dbbfbe8 100644 --- a/react/features/base/config/configType.ts +++ b/react/features/base/config/configType.ts @@ -396,6 +396,10 @@ export interface IConfig { validatorRegExpString?: string; }; liveStreamingEnabled?: boolean; + lobby?: { + autoKnock?: boolean; + enableChat?: boolean; + }; localRecording?: { disable?: boolean; disableSelfRecording?: boolean; @@ -466,6 +470,10 @@ export interface IConfig { enabled?: boolean; mode?: 'always' | 'recording'; }; + securityUi?: { + disableLobbyPassword?: boolean; + hideLobbyButton?: boolean; + }; serviceUrl?: string; sipInviteUrl?: string; speakerStats?: { diff --git a/react/features/base/config/configWhitelist.ts b/react/features/base/config/configWhitelist.ts index 702427279..04e64c4dd 100644 --- a/react/features/base/config/configWhitelist.ts +++ b/react/features/base/config/configWhitelist.ts @@ -185,6 +185,7 @@ export default [ 'inviteAppName', 'liveStreaming', 'liveStreamingEnabled', + 'lobby', 'localRecording', 'localSubject', 'logging', @@ -209,6 +210,7 @@ export default [ 'resolution', 'salesforceUrl', 'screenshotCapture', + 'securityUi', 'speakerStats', 'startAudioMuted', 'startAudioOnly', diff --git a/react/features/base/config/functions.any.ts b/react/features/base/config/functions.any.ts index 504b5859f..0d71bd2cd 100644 --- a/react/features/base/config/functions.any.ts +++ b/react/features/base/config/functions.any.ts @@ -316,3 +316,13 @@ export function getDialOutStatusUrl(state: IReduxState) { export function getDialOutUrl(state: IReduxState) { return state['features/base/config'].guestDialOutUrl; } + +/** + * Selector to return the security UI config. + * + * @param {IReduxState} state - State object. + * @returns {Object} + */ +export function getSecurityUiConfig(state: IReduxState) { + return state['features/base/config']?.securityUi || {}; +} diff --git a/react/features/base/config/reducer.ts b/react/features/base/config/reducer.ts index 32410557e..6abc2290b 100644 --- a/react/features/base/config/reducer.ts +++ b/react/features/base/config/reducer.ts @@ -535,6 +535,30 @@ function _translateLegacyConfig(oldValue: IConfig) { }; } + if (oldValue.autoKnockLobby !== undefined + && newValue.lobby?.autoKnock === undefined) { + newValue.lobby = { + ...newValue.lobby || {}, + autoKnock: oldValue.autoKnockLobby + }; + } + + if (oldValue.enableLobbyChat !== undefined + && newValue.lobby?.enableChat === undefined) { + newValue.lobby = { + ...newValue.lobby || {}, + enableChat: oldValue.enableLobbyChat + }; + } + + if (oldValue.hideLobbyButton !== undefined + && newValue.securityUi?.hideLobbyButton === undefined) { + newValue.securityUi = { + ...newValue.securityUi || {}, + hideLobbyButton: oldValue.hideLobbyButton + }; + } + _setDeeplinkingDefaults(newValue.deeplinking as IDeeplinkingConfig); return newValue; diff --git a/react/features/lobby/actions.any.ts b/react/features/lobby/actions.any.ts index 5b35131f8..c679da23b 100644 --- a/react/features/lobby/actions.any.ts +++ b/react/features/lobby/actions.any.ts @@ -20,7 +20,7 @@ import { SET_PASSWORD_JOIN_FAILED } from './actionTypes'; import { LOBBY_CHAT_INITIALIZED, MODERATOR_IN_CHAT_WITH_LEFT } from './constants'; -import { getKnockingParticipants, getLobbyEnabled } from './functions'; +import { getKnockingParticipants, getLobbyConfig, getLobbyEnabled } from './functions'; import { IKnockingParticipant } from './types'; /** @@ -389,9 +389,9 @@ export function setLobbyMessageListener() { return async (dispatch: IStore['dispatch'], getState: IStore['getState']) => { const state = getState(); const conference = getCurrentConference(state); - const { enableLobbyChat = true } = state['features/base/config']; + const { enableChat = true } = getLobbyConfig(state); - if (!enableLobbyChat) { + if (!enableChat) { return; } diff --git a/react/features/lobby/components/AbstractLobbyScreen.js b/react/features/lobby/components/AbstractLobbyScreen.js index 0c858aff7..1c1a5e15b 100644 --- a/react/features/lobby/components/AbstractLobbyScreen.js +++ b/react/features/lobby/components/AbstractLobbyScreen.js @@ -3,6 +3,7 @@ import React, { PureComponent } from 'react'; import { conferenceWillJoin, getConferenceName } from '../../base/conference'; +import { getSecurityUiConfig } from '../../base/config/functions.any'; import { INVITE_ENABLED, getFeatureFlag } from '../../base/flags'; import { getLocalParticipant } from '../../base/participants'; import { getFieldValue } from '../../base/react'; @@ -443,6 +444,7 @@ export function _mapStateToProps(state: Object): $Shape { const { disableInviteFunctions } = state['features/base/config']; const { knocking, passwordJoinFailed } = state['features/lobby']; const { iAmSipGateway } = state['features/base/config']; + const { disableLobbyPassword } = getSecurityUiConfig(state); const showCopyUrlButton = inviteEnabledFlag || !disableInviteFunctions; const deviceStatusVisible = isDeviceStatusVisible(state); const { membersOnly } = state['features/base/conference']; @@ -460,7 +462,7 @@ export function _mapStateToProps(state: Object): $Shape { _participantId: participantId, _participantName: localParticipant?.name, _passwordJoinFailed: passwordJoinFailed, - _renderPassword: !iAmSipGateway, + _renderPassword: !iAmSipGateway && !disableLobbyPassword, showCopyUrlButton }; } diff --git a/react/features/lobby/components/web/LobbySection.tsx b/react/features/lobby/components/web/LobbySection.tsx index 82aff88fb..3ccb4bbf6 100644 --- a/react/features/lobby/components/web/LobbySection.tsx +++ b/react/features/lobby/components/web/LobbySection.tsx @@ -2,6 +2,7 @@ import React, { PureComponent } from 'react'; import { WithTranslation } from 'react-i18next'; import { IReduxState } from '../../../app/types'; +import { getSecurityUiConfig } from '../../../base/config/functions.any'; import { translate } from '../../../base/i18n/functions'; import { isLocalParticipantModerator } from '../../../base/participants/functions'; import { connect } from '../../../base/redux/functions'; @@ -83,25 +84,22 @@ class LobbySection extends PureComponent { } return ( - <> -
-

- { t('lobby.enableDialogText') } -

-
- - -
+
+

+ { t('lobby.enableDialogText') } +

+
+ +
-
- +
); } @@ -129,7 +127,7 @@ class LobbySection extends PureComponent { */ function mapStateToProps(state: IReduxState): Partial { const { conference } = state['features/base/conference']; - const { hideLobbyButton } = state['features/base/config']; + const { hideLobbyButton } = getSecurityUiConfig(state); return { _lobbyEnabled: state['features/lobby'].lobbyEnabled, diff --git a/react/features/lobby/functions.ts b/react/features/lobby/functions.ts index 1c3fb1165..80b1daabf 100644 --- a/react/features/lobby/functions.ts +++ b/react/features/lobby/functions.ts @@ -44,6 +44,15 @@ export function getKnockingParticipantsById(state: IReduxState) { return getKnockingParticipants(state).map(participant => participant.id); } +/** + * Selector to return the lobby config. + * + * @param {IReduxState} state - State object. + * @returns {Object} + */ +export function getLobbyConfig(state: IReduxState) { + return state['features/base/config']?.lobby || {}; +} /** * Function that handles the visibility of the lobby chat message. @@ -56,13 +65,13 @@ export function showLobbyChatButton( ) { return function(state: IReduxState) { - const { enableLobbyChat = true } = state['features/base/config']; + const { enableChat = true } = getLobbyConfig(state); const { lobbyMessageRecipient, isLobbyChatActive } = state['features/chat']; const conference = getCurrentConference(state); const lobbyLocalId = conference?.myLobbyUserId(); - if (!enableLobbyChat) { + if (!enableChat) { return false; } diff --git a/react/features/prejoin/functions.ts b/react/features/prejoin/functions.ts index 0de518d5f..65fb90515 100644 --- a/react/features/prejoin/functions.ts +++ b/react/features/prejoin/functions.ts @@ -2,6 +2,7 @@ import { IReduxState } from '../app/types'; import { getRoomName } from '../base/conference/functions'; import { getDialOutStatusUrl, getDialOutUrl } from '../base/config/functions'; import { isAudioMuted, isVideoMutedByUser } from '../base/media/functions'; +import { getLobbyConfig } from '../lobby/functions'; /** * Selector for the visibility of the 'join by phone' button. @@ -159,11 +160,12 @@ export function isPrejoinPageVisible(state: IReduxState): boolean { * @returns {boolean} */ export function shouldAutoKnock(state: IReduxState): boolean { - const { iAmRecorder, iAmSipGateway, autoKnockLobby, prejoinConfig } = state['features/base/config']; + const { iAmRecorder, iAmSipGateway, prejoinConfig } = state['features/base/config']; const { userSelectedSkipPrejoin } = state['features/base/settings']; + const { autoKnock } = getLobbyConfig(state); const isPrejoinEnabled = prejoinConfig?.enabled; return Boolean(((isPrejoinEnabled && !userSelectedSkipPrejoin) - || autoKnockLobby || (iAmRecorder && iAmSipGateway)) + || autoKnock || (iAmRecorder && iAmSipGateway)) && !state['features/lobby'].knocking); } diff --git a/react/features/security/components/security-dialog/AbstractSecurityDialogButton.js b/react/features/security/components/security-dialog/AbstractSecurityDialogButton.js index 23ce03140..fcf267c88 100644 --- a/react/features/security/components/security-dialog/AbstractSecurityDialogButton.js +++ b/react/features/security/components/security-dialog/AbstractSecurityDialogButton.js @@ -3,6 +3,7 @@ import type { Dispatch } from 'redux'; import { createToolbarEvent, sendAnalytics } from '../../../analytics'; +import { getSecurityUiConfig } from '../../../base/config/functions.any'; import { LOBBY_MODE_ENABLED, MEETING_PASSWORD_ENABLED, @@ -81,7 +82,7 @@ export default class AbstractSecurityDialogButton */ export function _mapStateToProps(state: Object) { const { conference } = state['features/base/conference']; - const { hideLobbyButton } = state['features/base/config']; + const { hideLobbyButton } = getSecurityUiConfig(state); const { locked } = state['features/base/conference']; const { lobbyEnabled } = state['features/lobby']; const lobbySupported = conference && conference.isLobbySupported(); diff --git a/react/features/security/components/security-dialog/native/SecurityDialog.js b/react/features/security/components/security-dialog/native/SecurityDialog.js index 9f937be43..93afc1990 100644 --- a/react/features/security/components/security-dialog/native/SecurityDialog.js +++ b/react/features/security/components/security-dialog/native/SecurityDialog.js @@ -5,6 +5,7 @@ import { } from 'react-native'; import type { Dispatch } from 'redux'; +import { getSecurityUiConfig } from '../../../../base/config/functions.any'; import { MEETING_PASSWORD_ENABLED, getFeatureFlag } from '../../../../base/flags'; import { translate } from '../../../../base/i18n'; import JitsiScreen from '../../../../base/modal/components/JitsiScreen'; @@ -502,7 +503,7 @@ class SecurityDialog extends PureComponent { */ function _mapStateToProps(state: Object): Object { const { conference, locked, password } = state['features/base/conference']; - const { hideLobbyButton } = state['features/base/config']; + const { disableLobbyPassword, hideLobbyButton } = getSecurityUiConfig(state); const { lobbyEnabled } = state['features/lobby']; const { roomPasswordNumberOfDigits } = state['features/base/config']; const lobbySupported = conference && conference.isLobbySupported(); @@ -518,7 +519,7 @@ function _mapStateToProps(state: Object): Object { _lockedConference: Boolean(conference && locked), _password: password, _passwordNumberOfDigits: roomPasswordNumberOfDigits, - _roomPasswordControls: visible + _roomPasswordControls: visible && !disableLobbyPassword }; } diff --git a/react/features/security/components/security-dialog/web/SecurityDialog.tsx b/react/features/security/components/security-dialog/web/SecurityDialog.tsx index 055d06d40..0e414ae1c 100644 --- a/react/features/security/components/security-dialog/web/SecurityDialog.tsx +++ b/react/features/security/components/security-dialog/web/SecurityDialog.tsx @@ -3,6 +3,7 @@ import React, { useEffect, useState } from 'react'; import { IReduxState } from '../../../../app/types'; import { setPassword as setPass } from '../../../../base/conference/actions'; +import { getSecurityUiConfig } from '../../../../base/config/functions.any'; import { isLocalParticipantModerator } from '../../../../base/participants/functions'; import { connect } from '../../../../base/redux/functions'; import Dialog from '../../../../base/ui/components/web/Dialog'; @@ -37,6 +38,11 @@ interface IProps { */ _conference: Object; + /** + * Whether to hide the lobby password section. + */ + _disableLobbyPassword?: boolean; + /** * The value for how the conference is locked (or undefined if not locked) * as defined by room-lock constants. @@ -73,6 +79,7 @@ function SecurityDialog({ _buttonsWithNotifyClick, _canEditPassword, _conference, + _disableLobbyPassword, _locked, _password, _passwordNumberOfDigits, @@ -94,16 +101,21 @@ function SecurityDialog({ titleKey = 'security.title'>
- + {!_disableLobbyPassword && ( + <> +
+ + + )} { _showE2ee ? <>
@@ -131,7 +143,11 @@ function mapStateToProps(state: IReduxState) { locked, password } = state['features/base/conference']; - const { roomPasswordNumberOfDigits, buttonsWithNotifyClick } = state['features/base/config']; + const { + roomPasswordNumberOfDigits, + buttonsWithNotifyClick + } = state['features/base/config']; + const { disableLobbyPassword } = getSecurityUiConfig(state); const showE2ee = Boolean(e2eeSupported) && isLocalParticipantModerator(state); @@ -140,6 +156,7 @@ function mapStateToProps(state: IReduxState) { _canEditPassword: isLocalParticipantModerator(state), _conference: conference, _dialIn: state['features/invite'], + _disableLobbyPassword: disableLobbyPassword, _locked: locked, _password: password, _passwordNumberOfDigits: roomPasswordNumberOfDigits,