feat(e2ee) disable e2ee when large number of participants
This commit is contained in:
parent
4cd5be9d8b
commit
5ad98d193a
|
@ -213,7 +213,9 @@
|
|||
"done": "Done",
|
||||
"e2eeDescription": "End-to-End Encryption is currently EXPERIMENTAL. Please keep in mind that turning on end-to-end encryption will effectively disable server-side provided services such as: phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
|
||||
"e2eeLabel": "Enable End-to-End Encryption",
|
||||
"e2eeDisabledDueToMaxModeDescription": "Cannot enable End-to-End Encryption due to large number of participants in the conference.",
|
||||
"e2eeWarning": "WARNING: Not all participants in this meeting seem to have support for End-to-End encryption. If you enable it they won't be able to see nor hear you.",
|
||||
"e2eeWillDisableDueToMaxModeDescription": "WARNING: End-to-End Encryption will be automatically disabled if more participants join the conference.",
|
||||
"enterDisplayName": "Enter your name here",
|
||||
"embedMeeting": "Embed meeting",
|
||||
"error": "Error",
|
||||
|
|
|
@ -5,6 +5,7 @@ import { batch } from 'react-redux';
|
|||
import UIEvents from '../../../../service/UI/UIEvents';
|
||||
import { approveParticipant } from '../../av-moderation/actions';
|
||||
import { toggleE2EE } from '../../e2ee/actions';
|
||||
import { MAX_MODE } from '../../e2ee/constants';
|
||||
import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications';
|
||||
import { isForceMuted } from '../../participants-pane/functions';
|
||||
import { CALLING, INVITED } from '../../presence-status';
|
||||
|
@ -327,16 +328,20 @@ StateListenerRegistry.register(
|
|||
/**
|
||||
* Handles a E2EE enabled status update.
|
||||
*
|
||||
* @param {Function} dispatch - The Redux dispatch function.
|
||||
* @param {Store} store - The redux store.
|
||||
* @param {Object} conference - The conference for which we got an update.
|
||||
* @param {string} participantId - The ID of the participant from which we got an update.
|
||||
* @param {boolean} newValue - The new value of the E2EE enabled status.
|
||||
* @returns {void}
|
||||
*/
|
||||
function _e2eeUpdated({ dispatch }, conference, participantId, newValue) {
|
||||
function _e2eeUpdated({ getState, dispatch }, conference, participantId, newValue) {
|
||||
const e2eeEnabled = newValue === 'true';
|
||||
|
||||
dispatch(toggleE2EE(e2eeEnabled));
|
||||
const { maxMode } = getState()['features/e2ee'];
|
||||
|
||||
if (maxMode !== MAX_MODE.THRESHOLD_EXCEEDED || !e2eeEnabled) {
|
||||
dispatch(toggleE2EE(e2eeEnabled));
|
||||
}
|
||||
|
||||
dispatch(participantUpdated({
|
||||
conference,
|
||||
|
|
|
@ -25,3 +25,12 @@ export const SET_EVERYONE_ENABLED_E2EE = 'SET_EVERYONE_ENABLED_E2EE';
|
|||
* }
|
||||
*/
|
||||
export const SET_EVERYONE_SUPPORT_E2EE = 'SET_EVERYONE_SUPPORT_E2EE';
|
||||
|
||||
/**
|
||||
* The type of the action which signals to set new value E2EE maxMode.
|
||||
*
|
||||
* {
|
||||
* type: SET_MAX_MODE
|
||||
* }
|
||||
*/
|
||||
export const SET_MAX_MODE = 'SET_MAX_MODE';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { SET_EVERYONE_ENABLED_E2EE, SET_EVERYONE_SUPPORT_E2EE, TOGGLE_E2EE } from './actionTypes';
|
||||
import { SET_EVERYONE_ENABLED_E2EE, SET_EVERYONE_SUPPORT_E2EE, SET_MAX_MODE, TOGGLE_E2EE } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Dispatches an action to enable / disable E2EE.
|
||||
|
@ -46,3 +46,16 @@ export function setEveryoneSupportE2EE(everyoneSupportE2EE: boolean) {
|
|||
everyoneSupportE2EE
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to set E2EE maxMode.
|
||||
*
|
||||
* @param {string} maxMode - The new value.
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function setE2EEMaxMode(maxMode: string) {
|
||||
return {
|
||||
type: SET_MAX_MODE,
|
||||
maxMode
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,17 +8,23 @@ import { translate } from '../../base/i18n';
|
|||
import { Switch } from '../../base/react';
|
||||
import { connect } from '../../base/redux';
|
||||
import { toggleE2EE } from '../actions';
|
||||
import { MAX_MODE } from '../constants';
|
||||
import { doesEveryoneSupportE2EE } from '../functions';
|
||||
|
||||
type Props = {
|
||||
|
||||
/**
|
||||
* The resource for the description, computed based on the maxMode and whether the switch is toggled or not.
|
||||
*/
|
||||
_descriptionResource: string,
|
||||
|
||||
/**
|
||||
* Custom e2ee labels.
|
||||
*/
|
||||
_e2eeLabels: Object,
|
||||
|
||||
/**
|
||||
* Whether E2EE is currently enabled or not.
|
||||
* Whether the switch is currently enabled or not.
|
||||
*/
|
||||
_enabled: boolean,
|
||||
|
||||
|
@ -27,6 +33,11 @@ type Props = {
|
|||
*/
|
||||
_everyoneSupportE2EE: boolean,
|
||||
|
||||
/**
|
||||
* Whether E2EE is currently enabled or not.
|
||||
*/
|
||||
_toggled: boolean,
|
||||
|
||||
/**
|
||||
* The redux {@code dispatch} function.
|
||||
*/
|
||||
|
@ -43,7 +54,7 @@ type State = {
|
|||
/**
|
||||
* True if the switch is toggled on.
|
||||
*/
|
||||
enabled: boolean
|
||||
toggled: boolean
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -59,10 +70,10 @@ class E2EESection extends Component<Props, State> {
|
|||
* @inheritdoc
|
||||
*/
|
||||
static getDerivedStateFromProps(props: Props, state: Object) {
|
||||
if (props._enabled !== state.enabled) {
|
||||
if (props._toggled !== state.toggled) {
|
||||
|
||||
return {
|
||||
enabled: props._enabled
|
||||
toggled: props._toggled
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -78,7 +89,7 @@ class E2EESection extends Component<Props, State> {
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
enabled: false
|
||||
toggled: false
|
||||
};
|
||||
|
||||
// Bind event handlers so they are only bound once for every instance.
|
||||
|
@ -92,9 +103,9 @@ class E2EESection extends Component<Props, State> {
|
|||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { _e2eeLabels, _everyoneSupportE2EE, t } = this.props;
|
||||
const { enabled } = this.state;
|
||||
const description = _e2eeLabels?.description || t('dialog.e2eeDescription');
|
||||
const { _descriptionResource, _enabled, _e2eeLabels, _everyoneSupportE2EE, t } = this.props;
|
||||
const { toggled } = this.state;
|
||||
const description = _e2eeLabels?.description || t(_descriptionResource);
|
||||
const label = _e2eeLabels?.label || t('dialog.e2eeLabel');
|
||||
const warning = _e2eeLabels?.warning || t('dialog.e2eeWarning');
|
||||
|
||||
|
@ -113,9 +124,10 @@ class E2EESection extends Component<Props, State> {
|
|||
{ label }
|
||||
</label>
|
||||
<Switch
|
||||
disabled = { !_enabled }
|
||||
id = 'e2ee-section-switch'
|
||||
onValueChange = { this._onToggle }
|
||||
value = { enabled } />
|
||||
value = { toggled } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -130,10 +142,10 @@ class E2EESection extends Component<Props, State> {
|
|||
* @returns {void}
|
||||
*/
|
||||
_onToggle() {
|
||||
const newValue = !this.state.enabled;
|
||||
const newValue = !this.state.toggled;
|
||||
|
||||
this.setState({
|
||||
enabled: newValue
|
||||
toggled: newValue
|
||||
});
|
||||
|
||||
sendAnalytics(createE2EEEvent(`enabled.${String(newValue)}`));
|
||||
|
@ -149,12 +161,28 @@ class E2EESection extends Component<Props, State> {
|
|||
* @returns {Props}
|
||||
*/
|
||||
function mapStateToProps(state) {
|
||||
const { enabled } = state['features/e2ee'];
|
||||
const { enabled: e2eeEnabled, maxMode } = state['features/e2ee'];
|
||||
const { e2eeLabels } = state['features/base/config'];
|
||||
|
||||
let descriptionResource = '';
|
||||
|
||||
if (e2eeLabels) {
|
||||
// When e2eeLabels are present, the descriptionResouse is ignored.
|
||||
descriptionResource = undefined;
|
||||
} else if (maxMode === MAX_MODE.THRESHOLD_EXCEEDED) {
|
||||
descriptionResource = 'dialog.e2eeDisabledDueToMaxModeDescription';
|
||||
} else if (maxMode === MAX_MODE.ENABLED) {
|
||||
descriptionResource = e2eeEnabled
|
||||
? 'dialog.e2eeWillDisableDueToMaxModeDescription' : 'dialog.e2eeDisabledDueToMaxModeDescription';
|
||||
} else {
|
||||
descriptionResource = 'dialog.e2eeDescription';
|
||||
}
|
||||
|
||||
return {
|
||||
_descriptionResource: descriptionResource,
|
||||
_e2eeLabels: e2eeLabels,
|
||||
_enabled: enabled,
|
||||
_enabled: maxMode === MAX_MODE.DISABLED || e2eeEnabled,
|
||||
_toggled: e2eeEnabled,
|
||||
_everyoneSupportE2EE: doesEveryoneSupportE2EE(state)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,3 +13,43 @@ export const E2EE_OFF_SOUND_ID = 'E2EE_OFF_SOUND';
|
|||
* @type {string}
|
||||
*/
|
||||
export const E2EE_ON_SOUND_ID = 'E2EE_ON_SOUND';
|
||||
|
||||
/**
|
||||
* The number of participants after which e2ee maxMode is set to MAX_MODE.ENABLED.
|
||||
*
|
||||
* @type {integer}
|
||||
*/
|
||||
export const MAX_MODE_LIMIT = 20;
|
||||
|
||||
/**
|
||||
* If the number of participants is greater then MAX_MODE_LIMIT + MAX_MODE_THRESHOLD
|
||||
* e2ee maxMode is set to MAX_MODE.THRESHOLD_EXCEEDED.
|
||||
*
|
||||
* @type {integer}
|
||||
*/
|
||||
export const MAX_MODE_THRESHOLD = 5;
|
||||
|
||||
export const MAX_MODE = {
|
||||
/**
|
||||
* Mode for which the e2ee can be enabled or disabled.
|
||||
* If e2ee is enabled, e2ee section is enabled with a warning text.
|
||||
* If e2ee is disabled, e2ee section is disabled with a warning text.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
ENABLED: 'max-mode-enabled',
|
||||
|
||||
/**
|
||||
* Mode for which the e2ee and the e2ee section are automatically disabled.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
THRESHOLD_EXCEEDED: 'max-mode-threshold-exceeded',
|
||||
|
||||
/**
|
||||
* The default e2ee maxMode, e2ee can be enabled/disabled, e2ee section is enabled.
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
DISABLED: 'max-mode-disabled'
|
||||
};
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import { getParticipantCount } from '../base/participants/functions';
|
||||
import { toState } from '../base/redux';
|
||||
|
||||
import { MAX_MODE_LIMIT, MAX_MODE_THRESHOLD } from './constants';
|
||||
|
||||
/**
|
||||
* Gets the value of a specific React {@code Component} prop of the currently
|
||||
* mounted {@link App}.
|
||||
|
@ -27,3 +29,29 @@ export function doesEveryoneSupportE2EE(stateful) {
|
|||
|
||||
return everyoneSupportE2EE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true is the number of participants is larger than {@code MAX_MODE_LIMIT}.
|
||||
*
|
||||
* @param {Function|Object} stateful - The redux store or {@code getState}
|
||||
* function.
|
||||
* @returns {boolean}.
|
||||
*/
|
||||
export function isMaxModeReached(stateful) {
|
||||
const participantCount = getParticipantCount(toState(stateful));
|
||||
|
||||
return participantCount >= MAX_MODE_LIMIT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true is the number of participants is larger than {@code MAX_MODE_LIMIT + MAX_MODE_THREHOLD}.
|
||||
*
|
||||
* @param {Function|Object} stateful - The redux store or {@code getState}
|
||||
* function.
|
||||
* @returns {boolean}.
|
||||
*/
|
||||
export function isMaxModeThresholdReached(stateful) {
|
||||
const participantCount = getParticipantCount(toState(stateful));
|
||||
|
||||
return participantCount >= MAX_MODE_LIMIT + MAX_MODE_THRESHOLD;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import { batch } from 'react-redux';
|
||||
|
||||
import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
|
||||
import { getCurrentConference } from '../base/conference';
|
||||
import { CONFERENCE_JOINED, getCurrentConference } from '../base/conference';
|
||||
import {
|
||||
getLocalParticipant,
|
||||
getParticipantById,
|
||||
|
@ -18,8 +18,9 @@ import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
|||
import { playSound, registerSound, unregisterSound } from '../base/sounds';
|
||||
|
||||
import { TOGGLE_E2EE } from './actionTypes';
|
||||
import { setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions';
|
||||
import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID } from './constants';
|
||||
import { setE2EEMaxMode, setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions';
|
||||
import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID, MAX_MODE } from './constants';
|
||||
import { isMaxModeReached, isMaxModeThresholdReached } from './functions';
|
||||
import logger from './logger';
|
||||
import { E2EE_OFF_SOUND_FILE, E2EE_ON_SOUND_FILE } from './sounds';
|
||||
|
||||
|
@ -46,6 +47,11 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
dispatch(unregisterSound(E2EE_ON_SOUND_ID));
|
||||
break;
|
||||
|
||||
case CONFERENCE_JOINED:
|
||||
_updateMaxMode(dispatch, getState);
|
||||
|
||||
break;
|
||||
|
||||
case PARTICIPANT_UPDATED: {
|
||||
const { id, e2eeEnabled, e2eeSupported } = action.participant;
|
||||
const oldParticipant = getParticipantById(getState(), id);
|
||||
|
@ -88,7 +94,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
const result = next(action);
|
||||
const { e2eeEnabled, e2eeSupported, local } = action.participant;
|
||||
const { everyoneEnabledE2EE } = getState()['features/e2ee'];
|
||||
const participantCount = getParticipantCount(getState());
|
||||
const participantCount = getParticipantCount(getState);
|
||||
|
||||
// the initial values
|
||||
if (participantCount === 1) {
|
||||
|
@ -116,6 +122,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
dispatch(setEveryoneSupportE2EE(false));
|
||||
}
|
||||
|
||||
_updateMaxMode(dispatch, getState);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -165,6 +173,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
});
|
||||
}
|
||||
|
||||
_updateMaxMode(dispatch, getState);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -207,3 +217,24 @@ StateListenerRegistry.register(
|
|||
dispatch(toggleE2EE(false));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Sets the maxMode based on the number of participants in the conference.
|
||||
*
|
||||
* @param { Dispatch<any>} dispatch - The redux dispatch function.
|
||||
* @param {Function|Object} getState - The {@code getState} function.
|
||||
* @private
|
||||
* @returns {void}
|
||||
*/
|
||||
function _updateMaxMode(dispatch, getState) {
|
||||
const state = getState();
|
||||
|
||||
if (isMaxModeThresholdReached(state)) {
|
||||
dispatch(setE2EEMaxMode(MAX_MODE.THRESHOLD_EXCEEDED));
|
||||
dispatch(toggleE2EE(false));
|
||||
} else if (isMaxModeReached(state)) {
|
||||
dispatch(setE2EEMaxMode(MAX_MODE.ENABLED));
|
||||
} else {
|
||||
dispatch(setE2EEMaxMode(MAX_MODE.DISABLED));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,14 @@ import { ReducerRegistry } from '../base/redux';
|
|||
import {
|
||||
SET_EVERYONE_ENABLED_E2EE,
|
||||
SET_EVERYONE_SUPPORT_E2EE,
|
||||
SET_MAX_MODE,
|
||||
TOGGLE_E2EE
|
||||
} from './actionTypes';
|
||||
import { MAX_MODE } from './constants';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
enabled: false
|
||||
enabled: false,
|
||||
maxMode: MAX_MODE.DISABLED
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -33,6 +36,13 @@ ReducerRegistry.register('features/e2ee', (state = DEFAULT_STATE, action) => {
|
|||
everyoneSupportE2EE: action.everyoneSupportE2EE
|
||||
};
|
||||
|
||||
case SET_MAX_MODE: {
|
||||
return {
|
||||
...state,
|
||||
maxMode: action.maxMode
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue