Просмотр исходного кода

feat(e2ee) add externally managed key mode

master
tmoldovan8x8 3 лет назад
Родитель
Сommit
2e69ec71c5
Аккаунт пользователя с таким Email не найден

+ 4
- 0
config.js Просмотреть файл

@@ -826,6 +826,10 @@ var config = {
826 826
     //     format: 'flac'
827 827
     //
828 828
 
829
+    // },
830
+    // e2ee: {
831
+    //   labels,
832
+    //   externallyManagedKey: false
829 833
     // },
830 834
 
831 835
     // Options related to end-to-end (participant to participant) ping.

+ 4
- 1
modules/API/API.js Просмотреть файл

@@ -52,7 +52,7 @@ import {
52 52
     processExternalDeviceRequest
53 53
 } from '../../react/features/device-selection/functions';
54 54
 import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
55
-import { toggleE2EE } from '../../react/features/e2ee/actions';
55
+import { setMediaEncryptionKey, toggleE2EE } from '../../react/features/e2ee/actions';
56 56
 import { setVolume } from '../../react/features/filmstrip';
57 57
 import { invite } from '../../react/features/invite';
58 58
 import {
@@ -364,6 +364,9 @@ function initCommands() {
364 364
             logger.debug('Toggle E2EE key command received');
365 365
             APP.store.dispatch(toggleE2EE(enabled));
366 366
         },
367
+        'set-media-encryption-key': keyInfo => {
368
+            APP.store.dispatch(setMediaEncryptionKey(JSON.parse(keyInfo)));
369
+        },
367 370
         'set-video-quality': frameHeight => {
368 371
             logger.debug('Set video quality command received');
369 372
             sendAnalytics(createApiEvent('set.video.quality'));

+ 37
- 1
modules/API/external/external_api.js Просмотреть файл

@@ -50,6 +50,7 @@ const commands = {
50 50
     sendTones: 'send-tones',
51 51
     setFollowMe: 'set-follow-me',
52 52
     setLargeVideoParticipant: 'set-large-video-participant',
53
+    setMediaEncryptionKey: 'set-media-encryption-key',
53 54
     setParticipantVolume: 'set-participant-volume',
54 55
     setTileView: 'set-tile-view',
55 56
     setVideoQuality: 'set-video-quality',
@@ -63,6 +64,7 @@ const commands = {
63 64
     toggleCamera: 'toggle-camera',
64 65
     toggleCameraMirror: 'toggle-camera-mirror',
65 66
     toggleChat: 'toggle-chat',
67
+    toggleE2EE: 'toggle-e2ee',
66 68
     toggleFilmStrip: 'toggle-film-strip',
67 69
     toggleModeration: 'toggle-moderation',
68 70
     toggleRaiseHand: 'toggle-raise-hand',
@@ -1185,6 +1187,40 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
1185 1187
      * @returns {void}
1186 1188
      */
1187 1189
     stopRecording(mode) {
1188
-        this.executeCommand('startRecording', mode);
1190
+        this.executeCommand('stopRecording', mode);
1191
+    }
1192
+
1193
+    /**
1194
+     * Sets e2ee enabled/disabled.
1195
+     *
1196
+     * @param {boolean} enabled - The new value for e2ee enabled.
1197
+     * @returns {void}
1198
+     */
1199
+    toggleE2EE(enabled) {
1200
+        this.executeCommand('toggleE2EE', enabled);
1201
+    }
1202
+
1203
+    /**
1204
+     * Sets the key and keyIndex for e2ee.
1205
+     *
1206
+     * @param {Object} keyInfo - Json containing key information.
1207
+     * @param {CryptoKey} [keyInfo.encryptionKey] - The encryption key.
1208
+     * @param {number} [keyInfo.index] - The index of the encryption key.
1209
+     * @returns {void}
1210
+     */
1211
+    async setMediaEncryptionKey(keyInfo) {
1212
+        const { key, index } = keyInfo;
1213
+
1214
+        if (key) {
1215
+            const exportedKey = await crypto.subtle.exportKey('raw', key);
1216
+
1217
+            this.executeCommand('setMediaEncryptionKey', JSON.stringify({
1218
+                exportedKey: Array.from(new Uint8Array(exportedKey)),
1219
+                index }));
1220
+        } else {
1221
+            this.executeCommand('setMediaEncryptionKey', JSON.stringify({
1222
+                exportedKey: false,
1223
+                index }));
1224
+        }
1189 1225
     }
1190 1226
 }

+ 1
- 0
react/features/base/config/configWhitelist.js Просмотреть файл

@@ -123,6 +123,7 @@ export default [
123 123
     'doNotFlipLocalVideo',
124 124
     'dropbox',
125 125
     'e2eeLabels',
126
+    'e2ee',
126 127
     'e2eping',
127 128
     'enableDisplayNameInStats',
128 129
     'enableEmailInStats',

+ 6
- 0
react/features/base/config/reducer.js Просмотреть файл

@@ -314,6 +314,12 @@ function _translateLegacyConfig(oldValue: Object) {
314 314
         newValue.disableModeratorIndicator = interfaceConfig.DISABLE_FOCUS_INDICATOR;
315 315
     }
316 316
 
317
+    newValue.e2ee = newValue.e2ee || {};
318
+
319
+    if (oldValue.e2eeLabels) {
320
+        newValue.e2ee.e2eeLabels = oldValue.e2eeLabels;
321
+    }
322
+
317 323
     return newValue;
318 324
 }
319 325
 

+ 11
- 6
react/features/base/participants/middleware.js Просмотреть файл

@@ -332,18 +332,23 @@ StateListenerRegistry.register(
332 332
  */
333 333
 function _e2eeUpdated({ getState, dispatch }, conference, participantId, newValue) {
334 334
     const e2eeEnabled = newValue === 'true';
335
-
336
-    const { maxMode } = getState()['features/e2ee'] || {};
337
-
338
-    if (maxMode !== MAX_MODE.THRESHOLD_EXCEEDED || !e2eeEnabled) {
339
-        dispatch(toggleE2EE(e2eeEnabled));
340
-    }
335
+    const { e2ee = {} } = getState()['features/base/config'];
341 336
 
342 337
     dispatch(participantUpdated({
343 338
         conference,
344 339
         id: participantId,
345 340
         e2eeEnabled
346 341
     }));
342
+
343
+    if (e2ee.externallyManagedKey) {
344
+        return;
345
+    }
346
+
347
+    const { maxMode } = getState()['features/e2ee'] || {};
348
+
349
+    if (maxMode !== MAX_MODE.THRESHOLD_EXCEEDED || !e2eeEnabled) {
350
+        dispatch(toggleE2EE(e2eeEnabled));
351
+    }
347 352
 }
348 353
 
349 354
 /**

+ 9
- 0
react/features/e2ee/actionTypes.js Просмотреть файл

@@ -34,3 +34,12 @@ export const SET_EVERYONE_SUPPORT_E2EE = 'SET_EVERYONE_SUPPORT_E2EE';
34 34
  * }
35 35
  */
36 36
 export const SET_MAX_MODE = 'SET_MAX_MODE';
37
+
38
+/**
39
+ * The type of the action which signals to set media encryption key for e2ee.
40
+ *
41
+ * {
42
+ *     type: SET_MEDIA_ENCRYPTION_KEY
43
+ * }
44
+ */
45
+export const SET_MEDIA_ENCRYPTION_KEY = 'SET_MEDIA_ENCRYPTION_KEY';

+ 24
- 1
react/features/e2ee/actions.js Просмотреть файл

@@ -1,6 +1,11 @@
1 1
 // @flow
2 2
 
3
-import { SET_EVERYONE_ENABLED_E2EE, SET_EVERYONE_SUPPORT_E2EE, SET_MAX_MODE, TOGGLE_E2EE } from './actionTypes';
3
+import {
4
+    SET_EVERYONE_ENABLED_E2EE,
5
+    SET_EVERYONE_SUPPORT_E2EE,
6
+    SET_MAX_MODE,
7
+    SET_MEDIA_ENCRYPTION_KEY,
8
+    TOGGLE_E2EE } from './actionTypes';
4 9
 
5 10
 /**
6 11
  * Dispatches an action to enable / disable E2EE.
@@ -59,3 +64,21 @@ export function setE2EEMaxMode(maxMode: string) {
59 64
         maxMode
60 65
     };
61 66
 }
67
+
68
+/**
69
+ * Dispatches an action to set media encryption key.
70
+ *
71
+ * @param {Object} keyInfo - Json containing key information.
72
+ * @param {string} [keyInfo.encryptionKey] - The exported encryption key.
73
+ * @param {number} [keyInfo.index] - The index of the encryption key.
74
+ * @returns {{
75
+ *     type: SET_MEDIA_ENCRYPTION_KEY,
76
+ *     keyInfo: Object
77
+ * }}
78
+ */
79
+export function setMediaEncryptionKey(keyInfo: Object) {
80
+    return {
81
+        type: SET_MEDIA_ENCRYPTION_KEY,
82
+        keyInfo
83
+    };
84
+}

+ 3
- 1
react/features/e2ee/components/AbstractE2EELabel.js Просмотреть файл

@@ -27,8 +27,10 @@ export type Props = {
27 27
  * @returns {Props}
28 28
  */
29 29
 export function _mapStateToProps(state: Object) {
30
+    const { e2ee = {} } = state['features/base/config'];
31
+
30 32
     return {
31
-        _e2eeLabels: state['features/base/config'].e2eeLabels,
33
+        _e2eeLabels: e2ee.labels,
32 34
         _showLabel: state['features/e2ee'].everyoneEnabledE2EE
33 35
     };
34 36
 }

+ 39
- 3
react/features/e2ee/middleware.js Просмотреть файл

@@ -17,7 +17,7 @@ import {
17 17
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
18 18
 import { playSound, registerSound, unregisterSound } from '../base/sounds';
19 19
 
20
-import { TOGGLE_E2EE } from './actionTypes';
20
+import { SET_MEDIA_ENCRYPTION_KEY, TOGGLE_E2EE } from './actionTypes';
21 21
 import { setE2EEMaxMode, setEveryoneEnabledE2EE, setEveryoneSupportE2EE, toggleE2EE } from './actions';
22 22
 import { E2EE_OFF_SOUND_ID, E2EE_ON_SOUND_ID, MAX_MODE } from './constants';
23 23
 import { isMaxModeReached, isMaxModeThresholdReached } from './functions';
@@ -31,6 +31,8 @@ import { E2EE_OFF_SOUND_FILE, E2EE_ON_SOUND_FILE } from './sounds';
31 31
  * @returns {Function}
32 32
  */
33 33
 MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
34
+    const conference = getCurrentConference(getState);
35
+
34 36
     switch (action.type) {
35 37
     case APP_WILL_MOUNT:
36 38
         dispatch(registerSound(
@@ -179,8 +181,6 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
179 181
     }
180 182
 
181 183
     case TOGGLE_E2EE: {
182
-        const conference = getCurrentConference(getState);
183
-
184 184
         if (conference && conference.isE2EEEnabled() !== action.enabled) {
185 185
             logger.debug(`E2EE will be ${action.enabled ? 'enabled' : 'disabled'}`);
186 186
             conference.toggleE2EE(action.enabled);
@@ -201,6 +201,36 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
201 201
 
202 202
         break;
203 203
     }
204
+
205
+    case SET_MEDIA_ENCRYPTION_KEY: {
206
+        if (conference && conference.isE2EESupported()) {
207
+            const { exportedKey, index } = action.keyInfo;
208
+
209
+            if (exportedKey) {
210
+                window.crypto.subtle.importKey(
211
+                    'raw',
212
+                    new Uint8Array(exportedKey),
213
+                    'AES-GCM',
214
+                    false,
215
+                    [ 'encrypt', 'decrypt' ])
216
+                .then(
217
+                    encryptionKey => {
218
+                        conference.setMediaEncryptionKey({
219
+                            encryptionKey,
220
+                            index
221
+                        });
222
+                    })
223
+                .catch(error => logger.error('SET_MEDIA_ENCRYPTION_KEY error', error));
224
+            } else {
225
+                conference.setMediaEncryptionKey({
226
+                    encryptionKey: false,
227
+                    index
228
+                });
229
+            }
230
+        }
231
+
232
+        break;
233
+    }
204 234
     }
205 235
 
206 236
     return next(action);
@@ -229,6 +259,12 @@ StateListenerRegistry.register(
229 259
 function _updateMaxMode(dispatch, getState) {
230 260
     const state = getState();
231 261
 
262
+    const { e2ee = {} } = state['features/base/config'];
263
+
264
+    if (e2ee.externallyManagedKey) {
265
+        return;
266
+    }
267
+
232 268
     if (isMaxModeThresholdReached(state)) {
233 269
         dispatch(setE2EEMaxMode(MAX_MODE.THRESHOLD_EXCEEDED));
234 270
         dispatch(toggleE2EE(false));

Загрузка…
Отмена
Сохранить