Browse Source

feat(e2ee) disable e2ee when large number of participants

master
tmoldovan8x8 4 years ago
parent
commit
5ad98d193a
No account linked to committer's email address

+ 2
- 0
lang/main.json View File

@@ -213,7 +213,9 @@
213 213
         "done": "Done",
214 214
         "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.",
215 215
         "e2eeLabel": "Enable End-to-End Encryption",
216
+        "e2eeDisabledDueToMaxModeDescription": "Cannot enable End-to-End Encryption due to large number of participants in the conference.",
216 217
         "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.",
218
+        "e2eeWillDisableDueToMaxModeDescription": "WARNING: End-to-End Encryption will be automatically disabled if more participants join the conference.",
217 219
         "enterDisplayName": "Enter your name here",
218 220
         "embedMeeting": "Embed meeting",
219 221
         "error": "Error",

+ 8
- 3
react/features/base/participants/middleware.js View File

@@ -5,6 +5,7 @@ import { batch } from 'react-redux';
5 5
 import UIEvents from '../../../../service/UI/UIEvents';
6 6
 import { approveParticipant } from '../../av-moderation/actions';
7 7
 import { toggleE2EE } from '../../e2ee/actions';
8
+import { MAX_MODE } from '../../e2ee/constants';
8 9
 import { NOTIFICATION_TIMEOUT, showNotification } from '../../notifications';
9 10
 import { isForceMuted } from '../../participants-pane/functions';
10 11
 import { CALLING, INVITED } from '../../presence-status';
@@ -327,16 +328,20 @@ StateListenerRegistry.register(
327 328
 /**
328 329
  * Handles a E2EE enabled status update.
329 330
  *
330
- * @param {Function} dispatch - The Redux dispatch function.
331
+ * @param {Store} store - The redux store.
331 332
  * @param {Object} conference - The conference for which we got an update.
332 333
  * @param {string} participantId - The ID of the participant from which we got an update.
333 334
  * @param {boolean} newValue - The new value of the E2EE enabled status.
334 335
  * @returns {void}
335 336
  */
336
-function _e2eeUpdated({ dispatch }, conference, participantId, newValue) {
337
+function _e2eeUpdated({ getState, dispatch }, conference, participantId, newValue) {
337 338
     const e2eeEnabled = newValue === 'true';
338 339
 
339
-    dispatch(toggleE2EE(e2eeEnabled));
340
+    const { maxMode } = getState()['features/e2ee'];
341
+
342
+    if (maxMode !== MAX_MODE.THRESHOLD_EXCEEDED || !e2eeEnabled) {
343
+        dispatch(toggleE2EE(e2eeEnabled));
344
+    }
340 345
 
341 346
     dispatch(participantUpdated({
342 347
         conference,

+ 9
- 0
react/features/e2ee/actionTypes.js View File

@@ -25,3 +25,12 @@ export const SET_EVERYONE_ENABLED_E2EE = 'SET_EVERYONE_ENABLED_E2EE';
25 25
  * }
26 26
  */
27 27
 export const SET_EVERYONE_SUPPORT_E2EE = 'SET_EVERYONE_SUPPORT_E2EE';
28
+
29
+/**
30
+ * The type of the action which signals to set new value E2EE maxMode.
31
+ *
32
+ * {
33
+ *     type: SET_MAX_MODE
34
+ * }
35
+ */
36
+export const SET_MAX_MODE = 'SET_MAX_MODE';

+ 14
- 1
react/features/e2ee/actions.js View File

@@ -1,6 +1,6 @@
1 1
 // @flow
2 2
 
3
-import { SET_EVERYONE_ENABLED_E2EE, SET_EVERYONE_SUPPORT_E2EE, TOGGLE_E2EE } from './actionTypes';
3
+import { SET_EVERYONE_ENABLED_E2EE, SET_EVERYONE_SUPPORT_E2EE, SET_MAX_MODE, TOGGLE_E2EE } from './actionTypes';
4 4
 
5 5
 /**
6 6
  * Dispatches an action to enable / disable E2EE.
@@ -46,3 +46,16 @@ export function setEveryoneSupportE2EE(everyoneSupportE2EE: boolean) {
46 46
         everyoneSupportE2EE
47 47
     };
48 48
 }
49
+
50
+/**
51
+ * Dispatches an action to set E2EE maxMode.
52
+ *
53
+ * @param {string} maxMode - The new value.
54
+ * @returns {Object}
55
+ */
56
+export function setE2EEMaxMode(maxMode: string) {
57
+    return {
58
+        type: SET_MAX_MODE,
59
+        maxMode
60
+    };
61
+}

+ 41
- 13
react/features/e2ee/components/E2EESection.js View File

@@ -8,17 +8,23 @@ import { translate } from '../../base/i18n';
8 8
 import { Switch } from '../../base/react';
9 9
 import { connect } from '../../base/redux';
10 10
 import { toggleE2EE } from '../actions';
11
+import { MAX_MODE } from '../constants';
11 12
 import { doesEveryoneSupportE2EE } from '../functions';
12 13
 
13 14
 type Props = {
14 15
 
16
+    /**
17
+     * The resource for the description, computed based on the maxMode and whether the switch is toggled or not.
18
+     */
19
+    _descriptionResource: string,
20
+
15 21
     /**
16 22
      * Custom e2ee labels.
17 23
      */
18 24
     _e2eeLabels: Object,
19 25
 
20 26
     /**
21
-     * Whether E2EE is currently enabled or not.
27
+     * Whether the switch is currently enabled or not.
22 28
      */
23 29
     _enabled: boolean,
24 30
 
@@ -27,6 +33,11 @@ type Props = {
27 33
      */
28 34
     _everyoneSupportE2EE: boolean,
29 35
 
36
+    /**
37
+     * Whether E2EE is currently enabled or not.
38
+     */
39
+    _toggled: boolean,
40
+
30 41
     /**
31 42
      * The redux {@code dispatch} function.
32 43
      */
@@ -43,7 +54,7 @@ type State = {
43 54
     /**
44 55
      * True if the switch is toggled on.
45 56
      */
46
-    enabled: boolean
57
+    toggled: boolean
47 58
 };
48 59
 
49 60
 /**
@@ -59,10 +70,10 @@ class E2EESection extends Component<Props, State> {
59 70
      * @inheritdoc
60 71
      */
61 72
     static getDerivedStateFromProps(props: Props, state: Object) {
62
-        if (props._enabled !== state.enabled) {
73
+        if (props._toggled !== state.toggled) {
63 74
 
64 75
             return {
65
-                enabled: props._enabled
76
+                toggled: props._toggled
66 77
             };
67 78
         }
68 79
 
@@ -78,7 +89,7 @@ class E2EESection extends Component<Props, State> {
78 89
         super(props);
79 90
 
80 91
         this.state = {
81
-            enabled: false
92
+            toggled: false
82 93
         };
83 94
 
84 95
         // Bind event handlers so they are only bound once for every instance.
@@ -92,9 +103,9 @@ class E2EESection extends Component<Props, State> {
92 103
      * @returns {ReactElement}
93 104
      */
94 105
     render() {
95
-        const { _e2eeLabels, _everyoneSupportE2EE, t } = this.props;
96
-        const { enabled } = this.state;
97
-        const description = _e2eeLabels?.description || t('dialog.e2eeDescription');
106
+        const { _descriptionResource, _enabled, _e2eeLabels, _everyoneSupportE2EE, t } = this.props;
107
+        const { toggled } = this.state;
108
+        const description = _e2eeLabels?.description || t(_descriptionResource);
98 109
         const label = _e2eeLabels?.label || t('dialog.e2eeLabel');
99 110
         const warning = _e2eeLabels?.warning || t('dialog.e2eeWarning');
100 111
 
@@ -113,9 +124,10 @@ class E2EESection extends Component<Props, State> {
113 124
                         { label }
114 125
                     </label>
115 126
                     <Switch
127
+                        disabled = { !_enabled }
116 128
                         id = 'e2ee-section-switch'
117 129
                         onValueChange = { this._onToggle }
118
-                        value = { enabled } />
130
+                        value = { toggled } />
119 131
                 </div>
120 132
             </div>
121 133
         );
@@ -130,10 +142,10 @@ class E2EESection extends Component<Props, State> {
130 142
      * @returns {void}
131 143
      */
132 144
     _onToggle() {
133
-        const newValue = !this.state.enabled;
145
+        const newValue = !this.state.toggled;
134 146
 
135 147
         this.setState({
136
-            enabled: newValue
148
+            toggled: newValue
137 149
         });
138 150
 
139 151
         sendAnalytics(createE2EEEvent(`enabled.${String(newValue)}`));
@@ -149,12 +161,28 @@ class E2EESection extends Component<Props, State> {
149 161
  * @returns {Props}
150 162
  */
151 163
 function mapStateToProps(state) {
152
-    const { enabled } = state['features/e2ee'];
164
+    const { enabled: e2eeEnabled, maxMode } = state['features/e2ee'];
153 165
     const { e2eeLabels } = state['features/base/config'];
154 166
 
167
+    let descriptionResource = '';
168
+
169
+    if (e2eeLabels) {
170
+        // When e2eeLabels are present, the descriptionResouse is ignored.
171
+        descriptionResource = undefined;
172
+    } else if (maxMode === MAX_MODE.THRESHOLD_EXCEEDED) {
173
+        descriptionResource = 'dialog.e2eeDisabledDueToMaxModeDescription';
174
+    } else if (maxMode === MAX_MODE.ENABLED) {
175
+        descriptionResource = e2eeEnabled
176
+            ? 'dialog.e2eeWillDisableDueToMaxModeDescription' : 'dialog.e2eeDisabledDueToMaxModeDescription';
177
+    } else {
178
+        descriptionResource = 'dialog.e2eeDescription';
179
+    }
180
+
155 181
     return {
182
+        _descriptionResource: descriptionResource,
156 183
         _e2eeLabels: e2eeLabels,
157
-        _enabled: enabled,
184
+        _enabled: maxMode === MAX_MODE.DISABLED || e2eeEnabled,
185
+        _toggled: e2eeEnabled,
158 186
         _everyoneSupportE2EE: doesEveryoneSupportE2EE(state)
159 187
     };
160 188
 }

+ 40
- 0
react/features/e2ee/constants.js View File

@@ -13,3 +13,43 @@ export const E2EE_OFF_SOUND_ID = 'E2EE_OFF_SOUND';
13 13
  * @type {string}
14 14
  */
15 15
 export const E2EE_ON_SOUND_ID = 'E2EE_ON_SOUND';
16
+
17
+/**
18
+ * The number of participants after which e2ee maxMode is set to MAX_MODE.ENABLED.
19
+ *
20
+ * @type {integer}
21
+ */
22
+export const MAX_MODE_LIMIT = 20;
23
+
24
+/**
25
+ * If the number of participants is greater then MAX_MODE_LIMIT + MAX_MODE_THRESHOLD
26
+ * e2ee maxMode is set to MAX_MODE.THRESHOLD_EXCEEDED.
27
+ *
28
+ * @type {integer}
29
+ */
30
+export const MAX_MODE_THRESHOLD = 5;
31
+
32
+export const MAX_MODE = {
33
+    /**
34
+     * Mode for which the e2ee can be enabled or disabled.
35
+     * If e2ee is enabled, e2ee section is enabled with a warning text.
36
+     * If e2ee is disabled, e2ee section is disabled with a warning text.
37
+     *
38
+     * @type {string}
39
+     */
40
+    ENABLED: 'max-mode-enabled',
41
+
42
+    /**
43
+     * Mode for which the e2ee and the e2ee section are automatically disabled.
44
+     *
45
+     * @type {string}
46
+     */
47
+    THRESHOLD_EXCEEDED: 'max-mode-threshold-exceeded',
48
+
49
+    /**
50
+     * The default e2ee maxMode, e2ee can be enabled/disabled, e2ee section is enabled.
51
+     *
52
+     * @type {string}
53
+     */
54
+    DISABLED: 'max-mode-disabled'
55
+};

+ 28
- 0
react/features/e2ee/functions.js View File

@@ -2,6 +2,8 @@
2 2
 import { getParticipantCount } from '../base/participants/functions';
3 3
 import { toState } from '../base/redux';
4 4
 
5
+import { MAX_MODE_LIMIT, MAX_MODE_THRESHOLD } from './constants';
6
+
5 7
 /**
6 8
  * Gets the value of a specific React {@code Component} prop of the currently
7 9
  * mounted {@link App}.
@@ -27,3 +29,29 @@ export function doesEveryoneSupportE2EE(stateful) {
27 29
 
28 30
     return everyoneSupportE2EE;
29 31
 }
32
+
33
+/**
34
+ * Returns true is the number of participants is larger than {@code MAX_MODE_LIMIT}.
35
+ *
36
+ * @param {Function|Object} stateful - The redux store or {@code getState}
37
+ * function.
38
+ * @returns {boolean}.
39
+ */
40
+export function isMaxModeReached(stateful) {
41
+    const participantCount = getParticipantCount(toState(stateful));
42
+
43
+    return participantCount >= MAX_MODE_LIMIT;
44
+}
45
+
46
+/**
47
+ * Returns true is the number of participants is larger than {@code MAX_MODE_LIMIT + MAX_MODE_THREHOLD}.
48
+ *
49
+ * @param {Function|Object} stateful - The redux store or {@code getState}
50
+ * function.
51
+ * @returns {boolean}.
52
+ */
53
+export function isMaxModeThresholdReached(stateful) {
54
+    const participantCount = getParticipantCount(toState(stateful));
55
+
56
+    return participantCount >= MAX_MODE_LIMIT + MAX_MODE_THRESHOLD;
57
+}

+ 35
- 4
react/features/e2ee/middleware.js View File

@@ -3,7 +3,7 @@
3 3
 import { batch } from 'react-redux';
4 4
 
5 5
 import { APP_WILL_MOUNT, APP_WILL_UNMOUNT } from '../base/app';
6
-import { getCurrentConference } from '../base/conference';
6
+import { CONFERENCE_JOINED, getCurrentConference } from '../base/conference';
7 7
 import {
8 8
     getLocalParticipant,
9 9
     getParticipantById,
@@ -18,8 +18,9 @@ import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
18 18
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
19 19
 
20 20
 import { TOGGLE_E2EE } from './actionTypes';
21
-import { setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions';
22
-import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID } from './constants';
21
+import { setE2EEMaxMode, setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions';
22
+import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID, MAX_MODE } from './constants';
23
+import { isMaxModeReached, isMaxModeThresholdReached } from './functions';
23 24
 import logger from './logger';
24 25
 import { E2EE_OFF_SOUND_FILE, E2EE_ON_SOUND_FILE } from './sounds';
25 26
 
@@ -46,6 +47,11 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
46 47
         dispatch(unregisterSound(E2EE_ON_SOUND_ID));
47 48
         break;
48 49
 
50
+    case CONFERENCE_JOINED:
51
+        _updateMaxMode(dispatch, getState);
52
+
53
+        break;
54
+
49 55
     case PARTICIPANT_UPDATED: {
50 56
         const { id, e2eeEnabled, e2eeSupported } = action.participant;
51 57
         const oldParticipant = getParticipantById(getState(), id);
@@ -88,7 +94,7 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
88 94
         const result = next(action);
89 95
         const { e2eeEnabled, e2eeSupported, local } = action.participant;
90 96
         const { everyoneEnabledE2EE } = getState()['features/e2ee'];
91
-        const participantCount = getParticipantCount(getState());
97
+        const participantCount = getParticipantCount(getState);
92 98
 
93 99
         // the initial values
94 100
         if (participantCount === 1) {
@@ -116,6 +122,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
116 122
             dispatch(setEveryoneSupportE2EE(false));
117 123
         }
118 124
 
125
+        _updateMaxMode(dispatch, getState);
126
+
119 127
         return result;
120 128
     }
121 129
 
@@ -165,6 +173,8 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
165 173
             });
166 174
         }
167 175
 
176
+        _updateMaxMode(dispatch, getState);
177
+
168 178
         return result;
169 179
     }
170 180
 
@@ -207,3 +217,24 @@ StateListenerRegistry.register(
207 217
             dispatch(toggleE2EE(false));
208 218
         }
209 219
     });
220
+
221
+/**
222
+ * Sets the maxMode based on the number of participants in the conference.
223
+ *
224
+ * @param { Dispatch<any>} dispatch - The redux dispatch function.
225
+ * @param {Function|Object} getState - The {@code getState} function.
226
+ * @private
227
+ * @returns {void}
228
+ */
229
+function _updateMaxMode(dispatch, getState) {
230
+    const state = getState();
231
+
232
+    if (isMaxModeThresholdReached(state)) {
233
+        dispatch(setE2EEMaxMode(MAX_MODE.THRESHOLD_EXCEEDED));
234
+        dispatch(toggleE2EE(false));
235
+    } else if (isMaxModeReached(state)) {
236
+        dispatch(setE2EEMaxMode(MAX_MODE.ENABLED));
237
+    } else {
238
+        dispatch(setE2EEMaxMode(MAX_MODE.DISABLED));
239
+    }
240
+}

+ 11
- 1
react/features/e2ee/reducer.js View File

@@ -5,11 +5,14 @@ import { ReducerRegistry } from '../base/redux';
5 5
 import {
6 6
     SET_EVERYONE_ENABLED_E2EE,
7 7
     SET_EVERYONE_SUPPORT_E2EE,
8
+    SET_MAX_MODE,
8 9
     TOGGLE_E2EE
9 10
 } from './actionTypes';
11
+import { MAX_MODE } from './constants';
10 12
 
11 13
 const DEFAULT_STATE = {
12
-    enabled: false
14
+    enabled: false,
15
+    maxMode: MAX_MODE.DISABLED
13 16
 };
14 17
 
15 18
 /**
@@ -33,6 +36,13 @@ ReducerRegistry.register('features/e2ee', (state = DEFAULT_STATE, action) => {
33 36
             everyoneSupportE2EE: action.everyoneSupportE2EE
34 37
         };
35 38
 
39
+    case SET_MAX_MODE: {
40
+        return {
41
+            ...state,
42
+            maxMode: action.maxMode
43
+        };
44
+    }
45
+
36 46
     default:
37 47
         return state;
38 48
     }

Loading…
Cancel
Save