feat(e2ee) add externally managed key mode
This commit is contained in:
parent
be6adad61b
commit
2e69ec71c5
|
@ -826,6 +826,10 @@ var config = {
|
|||
// format: 'flac'
|
||||
//
|
||||
|
||||
// },
|
||||
// e2ee: {
|
||||
// labels,
|
||||
// externallyManagedKey: false
|
||||
// },
|
||||
|
||||
// Options related to end-to-end (participant to participant) ping.
|
||||
|
|
|
@ -52,7 +52,7 @@ import {
|
|||
processExternalDeviceRequest
|
||||
} from '../../react/features/device-selection/functions';
|
||||
import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
|
||||
import { toggleE2EE } from '../../react/features/e2ee/actions';
|
||||
import { setMediaEncryptionKey, toggleE2EE } from '../../react/features/e2ee/actions';
|
||||
import { setVolume } from '../../react/features/filmstrip';
|
||||
import { invite } from '../../react/features/invite';
|
||||
import {
|
||||
|
@ -364,6 +364,9 @@ function initCommands() {
|
|||
logger.debug('Toggle E2EE key command received');
|
||||
APP.store.dispatch(toggleE2EE(enabled));
|
||||
},
|
||||
'set-media-encryption-key': keyInfo => {
|
||||
APP.store.dispatch(setMediaEncryptionKey(JSON.parse(keyInfo)));
|
||||
},
|
||||
'set-video-quality': frameHeight => {
|
||||
logger.debug('Set video quality command received');
|
||||
sendAnalytics(createApiEvent('set.video.quality'));
|
||||
|
|
|
@ -50,6 +50,7 @@ const commands = {
|
|||
sendTones: 'send-tones',
|
||||
setFollowMe: 'set-follow-me',
|
||||
setLargeVideoParticipant: 'set-large-video-participant',
|
||||
setMediaEncryptionKey: 'set-media-encryption-key',
|
||||
setParticipantVolume: 'set-participant-volume',
|
||||
setTileView: 'set-tile-view',
|
||||
setVideoQuality: 'set-video-quality',
|
||||
|
@ -63,6 +64,7 @@ const commands = {
|
|||
toggleCamera: 'toggle-camera',
|
||||
toggleCameraMirror: 'toggle-camera-mirror',
|
||||
toggleChat: 'toggle-chat',
|
||||
toggleE2EE: 'toggle-e2ee',
|
||||
toggleFilmStrip: 'toggle-film-strip',
|
||||
toggleModeration: 'toggle-moderation',
|
||||
toggleRaiseHand: 'toggle-raise-hand',
|
||||
|
@ -1185,6 +1187,40 @@ export default class JitsiMeetExternalAPI extends EventEmitter {
|
|||
* @returns {void}
|
||||
*/
|
||||
stopRecording(mode) {
|
||||
this.executeCommand('startRecording', mode);
|
||||
this.executeCommand('stopRecording', mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets e2ee enabled/disabled.
|
||||
*
|
||||
* @param {boolean} enabled - The new value for e2ee enabled.
|
||||
* @returns {void}
|
||||
*/
|
||||
toggleE2EE(enabled) {
|
||||
this.executeCommand('toggleE2EE', enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key and keyIndex for e2ee.
|
||||
*
|
||||
* @param {Object} keyInfo - Json containing key information.
|
||||
* @param {CryptoKey} [keyInfo.encryptionKey] - The encryption key.
|
||||
* @param {number} [keyInfo.index] - The index of the encryption key.
|
||||
* @returns {void}
|
||||
*/
|
||||
async setMediaEncryptionKey(keyInfo) {
|
||||
const { key, index } = keyInfo;
|
||||
|
||||
if (key) {
|
||||
const exportedKey = await crypto.subtle.exportKey('raw', key);
|
||||
|
||||
this.executeCommand('setMediaEncryptionKey', JSON.stringify({
|
||||
exportedKey: Array.from(new Uint8Array(exportedKey)),
|
||||
index }));
|
||||
} else {
|
||||
this.executeCommand('setMediaEncryptionKey', JSON.stringify({
|
||||
exportedKey: false,
|
||||
index }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ export default [
|
|||
'doNotFlipLocalVideo',
|
||||
'dropbox',
|
||||
'e2eeLabels',
|
||||
'e2ee',
|
||||
'e2eping',
|
||||
'enableDisplayNameInStats',
|
||||
'enableEmailInStats',
|
||||
|
|
|
@ -314,6 +314,12 @@ function _translateLegacyConfig(oldValue: Object) {
|
|||
newValue.disableModeratorIndicator = interfaceConfig.DISABLE_FOCUS_INDICATOR;
|
||||
}
|
||||
|
||||
newValue.e2ee = newValue.e2ee || {};
|
||||
|
||||
if (oldValue.e2eeLabels) {
|
||||
newValue.e2ee.e2eeLabels = oldValue.e2eeLabels;
|
||||
}
|
||||
|
||||
return newValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -332,18 +332,23 @@ StateListenerRegistry.register(
|
|||
*/
|
||||
function _e2eeUpdated({ getState, dispatch }, conference, participantId, newValue) {
|
||||
const e2eeEnabled = newValue === 'true';
|
||||
|
||||
const { maxMode } = getState()['features/e2ee'] || {};
|
||||
|
||||
if (maxMode !== MAX_MODE.THRESHOLD_EXCEEDED || !e2eeEnabled) {
|
||||
dispatch(toggleE2EE(e2eeEnabled));
|
||||
}
|
||||
const { e2ee = {} } = getState()['features/base/config'];
|
||||
|
||||
dispatch(participantUpdated({
|
||||
conference,
|
||||
id: participantId,
|
||||
e2eeEnabled
|
||||
}));
|
||||
|
||||
if (e2ee.externallyManagedKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { maxMode } = getState()['features/e2ee'] || {};
|
||||
|
||||
if (maxMode !== MAX_MODE.THRESHOLD_EXCEEDED || !e2eeEnabled) {
|
||||
dispatch(toggleE2EE(e2eeEnabled));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,3 +34,12 @@ export const SET_EVERYONE_SUPPORT_E2EE = 'SET_EVERYONE_SUPPORT_E2EE';
|
|||
* }
|
||||
*/
|
||||
export const SET_MAX_MODE = 'SET_MAX_MODE';
|
||||
|
||||
/**
|
||||
* The type of the action which signals to set media encryption key for e2ee.
|
||||
*
|
||||
* {
|
||||
* type: SET_MEDIA_ENCRYPTION_KEY
|
||||
* }
|
||||
*/
|
||||
export const SET_MEDIA_ENCRYPTION_KEY = 'SET_MEDIA_ENCRYPTION_KEY';
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
// @flow
|
||||
|
||||
import { SET_EVERYONE_ENABLED_E2EE, SET_EVERYONE_SUPPORT_E2EE, SET_MAX_MODE, TOGGLE_E2EE } from './actionTypes';
|
||||
import {
|
||||
SET_EVERYONE_ENABLED_E2EE,
|
||||
SET_EVERYONE_SUPPORT_E2EE,
|
||||
SET_MAX_MODE,
|
||||
SET_MEDIA_ENCRYPTION_KEY,
|
||||
TOGGLE_E2EE } from './actionTypes';
|
||||
|
||||
/**
|
||||
* Dispatches an action to enable / disable E2EE.
|
||||
|
@ -59,3 +64,21 @@ export function setE2EEMaxMode(maxMode: string) {
|
|||
maxMode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an action to set media encryption key.
|
||||
*
|
||||
* @param {Object} keyInfo - Json containing key information.
|
||||
* @param {string} [keyInfo.encryptionKey] - The exported encryption key.
|
||||
* @param {number} [keyInfo.index] - The index of the encryption key.
|
||||
* @returns {{
|
||||
* type: SET_MEDIA_ENCRYPTION_KEY,
|
||||
* keyInfo: Object
|
||||
* }}
|
||||
*/
|
||||
export function setMediaEncryptionKey(keyInfo: Object) {
|
||||
return {
|
||||
type: SET_MEDIA_ENCRYPTION_KEY,
|
||||
keyInfo
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,8 +27,10 @@ export type Props = {
|
|||
* @returns {Props}
|
||||
*/
|
||||
export function _mapStateToProps(state: Object) {
|
||||
const { e2ee = {} } = state['features/base/config'];
|
||||
|
||||
return {
|
||||
_e2eeLabels: state['features/base/config'].e2eeLabels,
|
||||
_e2eeLabels: e2ee.labels,
|
||||
_showLabel: state['features/e2ee'].everyoneEnabledE2EE
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import {
|
|||
import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
|
||||
import { playSound, registerSound, unregisterSound } from '../base/sounds';
|
||||
|
||||
import { TOGGLE_E2EE } from './actionTypes';
|
||||
import { SET_MEDIA_ENCRYPTION_KEY, TOGGLE_E2EE } from './actionTypes';
|
||||
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';
|
||||
|
@ -31,6 +31,8 @@ import { E2EE_OFF_SOUND_FILE, E2EE_ON_SOUND_FILE } from './sounds';
|
|||
* @returns {Function}
|
||||
*/
|
||||
MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
switch (action.type) {
|
||||
case APP_WILL_MOUNT:
|
||||
dispatch(registerSound(
|
||||
|
@ -179,8 +181,6 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
}
|
||||
|
||||
case TOGGLE_E2EE: {
|
||||
const conference = getCurrentConference(getState);
|
||||
|
||||
if (conference && conference.isE2EEEnabled() !== action.enabled) {
|
||||
logger.debug(`E2EE will be ${action.enabled ? 'enabled' : 'disabled'}`);
|
||||
conference.toggleE2EE(action.enabled);
|
||||
|
@ -201,6 +201,36 @@ MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
|
|||
|
||||
break;
|
||||
}
|
||||
|
||||
case SET_MEDIA_ENCRYPTION_KEY: {
|
||||
if (conference && conference.isE2EESupported()) {
|
||||
const { exportedKey, index } = action.keyInfo;
|
||||
|
||||
if (exportedKey) {
|
||||
window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
new Uint8Array(exportedKey),
|
||||
'AES-GCM',
|
||||
false,
|
||||
[ 'encrypt', 'decrypt' ])
|
||||
.then(
|
||||
encryptionKey => {
|
||||
conference.setMediaEncryptionKey({
|
||||
encryptionKey,
|
||||
index
|
||||
});
|
||||
})
|
||||
.catch(error => logger.error('SET_MEDIA_ENCRYPTION_KEY error', error));
|
||||
} else {
|
||||
conference.setMediaEncryptionKey({
|
||||
encryptionKey: false,
|
||||
index
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return next(action);
|
||||
|
@ -229,6 +259,12 @@ StateListenerRegistry.register(
|
|||
function _updateMaxMode(dispatch, getState) {
|
||||
const state = getState();
|
||||
|
||||
const { e2ee = {} } = state['features/base/config'];
|
||||
|
||||
if (e2ee.externallyManagedKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMaxModeThresholdReached(state)) {
|
||||
dispatch(setE2EEMaxMode(MAX_MODE.THRESHOLD_EXCEEDED));
|
||||
dispatch(toggleE2EE(false));
|
||||
|
|
Loading…
Reference in New Issue