浏览代码

e2ee: stage 2

Adapt to E2EE changes in lib-jitsi-meet. Notably:

---
    e2ee: introduce per-participant randomly generated keys

    This the second stage in our E2EE journey.

    Instead of using a single pre-shared passphrase for deriving the key used for
    E2EE, we now establish a secure E2EE communication channel amongst peers.

    This channel is implemented using libolm, using XMPP groupchat or JVB channels
    as the transport.

    Once the secure E2EE channel has been established each participant will generate
    a random 32 byte key and exchange it over this channel.

    Keys are rotated (well, just re-created at the moment) when a participant joins
    or leaves.
---
j8
Saúl Ibarra Corretgé 5 年前
父节点
当前提交
7cafa205ee

+ 8
- 2
Makefile 查看文件

3
 DEPLOY_DIR = libs
3
 DEPLOY_DIR = libs
4
 LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
4
 LIBJITSIMEET_DIR = node_modules/lib-jitsi-meet/
5
 LIBFLAC_DIR = node_modules/libflacjs/dist/min/
5
 LIBFLAC_DIR = node_modules/libflacjs/dist/min/
6
+OLM_DIR = node_modules/olm
6
 RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
7
 RNNOISE_WASM_DIR = node_modules/rnnoise-wasm/dist/
7
 NODE_SASS = ./node_modules/.bin/node-sass
8
 NODE_SASS = ./node_modules/.bin/node-sass
8
 NPM = npm
9
 NPM = npm
22
 	rm -fr $(BUILD_DIR)
23
 	rm -fr $(BUILD_DIR)
23
 
24
 
24
 .NOTPARALLEL:
25
 .NOTPARALLEL:
25
-deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-css deploy-local
26
+deploy: deploy-init deploy-appbundle deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-olm deploy-css deploy-local
26
 
27
 
27
 deploy-init:
28
 deploy-init:
28
 	rm -fr $(DEPLOY_DIR)
29
 	rm -fr $(DEPLOY_DIR)
70
 		$(LIBFLAC_DIR)/libflac4-1.3.2.min.js.mem \
71
 		$(LIBFLAC_DIR)/libflac4-1.3.2.min.js.mem \
71
 		$(DEPLOY_DIR)
72
 		$(DEPLOY_DIR)
72
 
73
 
74
+deploy-olm:
75
+	cp \
76
+		$(OLM_DIR)/olm.wasm \
77
+		$(DEPLOY_DIR)
78
+
73
 deploy-rnnoise-binary:
79
 deploy-rnnoise-binary:
74
 	cp \
80
 	cp \
75
 		$(RNNOISE_WASM_DIR)/rnnoise.wasm \
81
 		$(RNNOISE_WASM_DIR)/rnnoise.wasm \
84
 	([ ! -x deploy-local.sh ] || ./deploy-local.sh)
90
 	([ ! -x deploy-local.sh ] || ./deploy-local.sh)
85
 
91
 
86
 .NOTPARALLEL:
92
 .NOTPARALLEL:
87
-dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac
93
+dev: deploy-init deploy-css deploy-rnnoise-binary deploy-lib-jitsi-meet deploy-libflac deploy-olm
88
 	$(WEBPACK_DEV_SERVER) --detect-circular-deps
94
 	$(WEBPACK_DEV_SERVER) --detect-circular-deps
89
 
95
 
90
 source-package:
96
 source-package:

+ 7
- 0
app.js 查看文件

4
 import 'jquery-contextmenu';
4
 import 'jquery-contextmenu';
5
 import 'jQuery-Impromptu';
5
 import 'jQuery-Impromptu';
6
 
6
 
7
+import 'olm';
8
+
7
 import conference from './conference';
9
 import conference from './conference';
8
 import API from './modules/API';
10
 import API from './modules/API';
9
 import UI from './modules/UI/UI';
11
 import UI from './modules/UI/UI';
11
 import remoteControl from './modules/remotecontrol/RemoteControl';
13
 import remoteControl from './modules/remotecontrol/RemoteControl';
12
 import translation from './modules/translation/translation';
14
 import translation from './modules/translation/translation';
13
 
15
 
16
+// Initialize Olm as early as possible.
17
+if (window.Olm) {
18
+    window.Olm.init();
19
+}
20
+
14
 window.APP = {
21
 window.APP = {
15
     API,
22
     API,
16
     conference,
23
     conference,

+ 0
- 31
conference.js 查看文件

110
 } from './react/features/base/util';
110
 } from './react/features/base/util';
111
 import { showDesktopPicker } from './react/features/desktop-picker';
111
 import { showDesktopPicker } from './react/features/desktop-picker';
112
 import { appendSuffix } from './react/features/display-name';
112
 import { appendSuffix } from './react/features/display-name';
113
-import { setE2EEKey } from './react/features/e2ee';
114
 import {
113
 import {
115
     maybeOpenFeedbackDialog,
114
     maybeOpenFeedbackDialog,
116
     submitFeedback
115
     submitFeedback
746
 
745
 
747
         this.roomName = roomName;
746
         this.roomName = roomName;
748
 
747
 
749
-        window.addEventListener('hashchange', this.onHashChange.bind(this), false);
750
-
751
         try {
748
         try {
752
             // Initialize the device list first. This way, when creating tracks
749
             // Initialize the device list first. This way, when creating tracks
753
             // based on preferred devices, loose label matching can be done in
750
             // based on preferred devices, loose label matching can be done in
1239
         }));
1236
         }));
1240
     },
1237
     },
1241
 
1238
 
1242
-    /**
1243
-     * Handled location hash change events.
1244
-     */
1245
-    onHashChange() {
1246
-        const items = {};
1247
-        const parts = window.location.hash.substr(1).split('&');
1248
-
1249
-        for (const part of parts) {
1250
-            const param = part.split('=');
1251
-            const key = param[0];
1252
-
1253
-            if (!key) {
1254
-                continue; // eslint-disable-line no-continue
1255
-            }
1256
-
1257
-            items[key] = param[1];
1258
-        }
1259
-
1260
-        if (typeof items.e2eekey !== 'undefined') {
1261
-            APP.store.dispatch(setE2EEKey(items.e2eekey));
1262
-
1263
-            // Clean URL in browser history.
1264
-            const cleanUrl = window.location.href.split('#')[0];
1265
-
1266
-            history.replaceState(history.state, document.title, cleanUrl);
1267
-        }
1268
-    },
1269
-
1270
     /**
1239
     /**
1271
      * Exposes a Command(s) API on this instance. It is necessitated by (1) the
1240
      * Exposes a Command(s) API on this instance. It is necessitated by (1) the
1272
      * desire to keep room private to this instance and (2) the need of other
1241
      * desire to keep room private to this instance and (2) the need of other

+ 6
- 21
css/_e2ee.scss 查看文件

1
 #e2ee-section {
1
 #e2ee-section {
2
-    .title {
3
-        font-weight: 700;
4
-    }
2
+    display: flex;
3
+    flex-direction: column;
5
 
4
 
6
     .description {
5
     .description {
7
         font-size: 13px;
6
         font-size: 13px;
13
         }
12
         }
14
     }
13
     }
15
 
14
 
16
-    .key-field {
17
-        align-items: center;
15
+    .control-row {
18
         display: flex;
16
         display: flex;
19
         flex-direction: row;
17
         flex-direction: row;
18
+        justify-content: space-between;
19
+        margin-top: 15px;
20
 
20
 
21
         label {
21
         label {
22
             font-size: 14px;
22
             font-size: 14px;
23
-            font-weight: 700;
24
-        }
25
-
26
-        input {
27
-            background-color: inherit;
28
-            border: none;
29
-            color: inherit;
30
-            flex: 1;
31
-            padding: 0 5px;
32
-        }
33
-
34
-        a {
35
-            color: #6FB1EA;
36
-            cursor: pointer;
37
-            font-size: 14px;
38
-            text-decoration: none;
23
+            font-weight: bold;
39
         }
24
         }
40
     }
25
     }
41
 }
26
 }

+ 1
- 5
lang/main.json 查看文件

197
         "displayNameRequired": "Hi! What’s your name?",
197
         "displayNameRequired": "Hi! What’s your name?",
198
         "done": "Done",
198
         "done": "Done",
199
         "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: recording, live streaming and phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
199
         "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: recording, live streaming and phone participation. Also keep in mind that the meeting will only work for people joining from browsers with support for insertable streams.",
200
-        "e2eeLabel": "E2EE key",
201
-        "e2eeNoKey": "None",
202
-        "e2eeToggleSet": "Set key",
203
-        "e2eeSet": "Set",
200
+        "e2eeLabel": "Enable End-to-End Encryption",
204
         "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.",
201
         "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.",
205
         "enterDisplayName": "Please enter your name here",
202
         "enterDisplayName": "Please enter your name here",
206
         "error": "Error",
203
         "error": "Error",
697
             "document": "Toggle shared document",
694
             "document": "Toggle shared document",
698
             "download": "Download our apps",
695
             "download": "Download our apps",
699
             "embedMeeting": "Embed meeting",
696
             "embedMeeting": "Embed meeting",
700
-            "e2ee": "End-to-End Encryption",
701
             "feedback": "Leave feedback",
697
             "feedback": "Leave feedback",
702
             "fullScreen": "Toggle full screen",
698
             "fullScreen": "Toggle full screen",
703
             "grantModerator": "Grant Moderator",
699
             "grantModerator": "Grant Moderator",

+ 4
- 4
modules/API/API.js 查看文件

19
     processExternalDeviceRequest
19
     processExternalDeviceRequest
20
 } from '../../react/features/device-selection/functions';
20
 } from '../../react/features/device-selection/functions';
21
 import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
21
 import { isEnabled as isDropboxEnabled } from '../../react/features/dropbox';
22
-import { setE2EEKey } from '../../react/features/e2ee';
22
+import { toggleE2EE } from '../../react/features/e2ee/actions';
23
 import { invite } from '../../react/features/invite';
23
 import { invite } from '../../react/features/invite';
24
 import { toggleLobbyMode } from '../../react/features/lobby/actions.web';
24
 import { toggleLobbyMode } from '../../react/features/lobby/actions.web';
25
 import { RECORDING_TYPES } from '../../react/features/recording/constants';
25
 import { RECORDING_TYPES } from '../../react/features/recording/constants';
191
                 logger.error('Failed sending endpoint text message', err);
191
                 logger.error('Failed sending endpoint text message', err);
192
             }
192
             }
193
         },
193
         },
194
-        'e2ee-key': key => {
195
-            logger.debug('Set E2EE key command received');
196
-            APP.store.dispatch(setE2EEKey(key));
194
+        'toggle-e2ee': enabled => {
195
+            logger.debug('Toggle E2EE key command received');
196
+            APP.store.dispatch(toggleE2EE(enabled));
197
         },
197
         },
198
         'set-video-quality': frameHeight => {
198
         'set-video-quality': frameHeight => {
199
             logger.debug('Set video quality command received');
199
             logger.debug('Set video quality command received');

+ 19
- 2
package-lock.json 查看文件

10952
       }
10952
       }
10953
     },
10953
     },
10954
     "lib-jitsi-meet": {
10954
     "lib-jitsi-meet": {
10955
-      "version": "github:jitsi/lib-jitsi-meet#94318fce12c855aefefdf8586bc8772065b505c9",
10956
-      "from": "github:jitsi/lib-jitsi-meet#94318fce12c855aefefdf8586bc8772065b505c9",
10955
+      "version": "github:jitsi/lib-jitsi-meet#735c30ec4f1c17b81f68c4b6684489e05115aeb2",
10956
+      "from": "github:jitsi/lib-jitsi-meet#735c30ec4f1c17b81f68c4b6684489e05115aeb2",
10957
       "requires": {
10957
       "requires": {
10958
         "@jitsi/js-utils": "1.0.0",
10958
         "@jitsi/js-utils": "1.0.0",
10959
         "@jitsi/sdp-interop": "1.0.3",
10959
         "@jitsi/sdp-interop": "1.0.3",
10960
         "@jitsi/sdp-simulcast": "0.3.0",
10960
         "@jitsi/sdp-simulcast": "0.3.0",
10961
         "async": "0.9.0",
10961
         "async": "0.9.0",
10962
+        "base64-js": "1.3.1",
10962
         "current-executing-script": "0.1.3",
10963
         "current-executing-script": "0.1.3",
10963
         "jitsi-meet-logger": "github:jitsi/jitsi-meet-logger#5ec92357570dc8f0b7ffc1528820721c84c6af8b",
10964
         "jitsi-meet-logger": "github:jitsi/jitsi-meet-logger#5ec92357570dc8f0b7ffc1528820721c84c6af8b",
10964
         "lodash.clonedeep": "4.5.0",
10965
         "lodash.clonedeep": "4.5.0",
10966
+        "lodash.debounce": "4.0.8",
10965
         "lodash.isequal": "4.5.0",
10967
         "lodash.isequal": "4.5.0",
10966
         "sdp-transform": "2.3.0",
10968
         "sdp-transform": "2.3.0",
10967
         "strophe.js": "1.3.4",
10969
         "strophe.js": "1.3.4",
10968
         "strophejs-plugin-disco": "0.0.2",
10970
         "strophejs-plugin-disco": "0.0.2",
10969
         "strophejs-plugin-stream-management": "github:jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
10971
         "strophejs-plugin-stream-management": "github:jitsi/strophejs-plugin-stream-management#001cf02bef2357234e1ac5d163611b4d60bf2b6a",
10972
+        "uuid": "8.1.0",
10970
         "webrtc-adapter": "7.5.0"
10973
         "webrtc-adapter": "7.5.0"
10971
       },
10974
       },
10972
       "dependencies": {
10975
       "dependencies": {
10984
           "version": "0.7.3",
10987
           "version": "0.7.3",
10985
           "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
10988
           "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz",
10986
           "integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ=="
10989
           "integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ=="
10990
+        },
10991
+        "uuid": {
10992
+          "version": "8.1.0",
10993
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
10994
+          "integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg=="
10987
         }
10995
         }
10988
       }
10996
       }
10989
     },
10997
     },
11046
       "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
11054
       "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
11047
       "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
11055
       "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
11048
     },
11056
     },
11057
+    "lodash.debounce": {
11058
+      "version": "4.0.8",
11059
+      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
11060
+      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
11061
+    },
11049
     "lodash.flatten": {
11062
     "lodash.flatten": {
11050
       "version": "4.4.0",
11063
       "version": "4.4.0",
11051
       "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
11064
       "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
12940
       "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
12953
       "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
12941
       "dev": true
12954
       "dev": true
12942
     },
12955
     },
12956
+    "olm": {
12957
+      "version": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
12958
+      "integrity": "sha512-kumW7B+xWMdiGSU0BrECOd+9GnhvsnnHP6qTHGPIcHTL2F0m8sYlP08hkEpN7uX/TlnHCwqpkaZXPQ0GYtVe8A=="
12959
+    },
12943
     "on-finished": {
12960
     "on-finished": {
12944
       "version": "2.3.0",
12961
       "version": "2.3.0",
12945
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
12962
       "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",

+ 2
- 1
package.json 查看文件

56
     "jquery-i18next": "1.2.1",
56
     "jquery-i18next": "1.2.1",
57
     "js-md5": "0.6.1",
57
     "js-md5": "0.6.1",
58
     "jwt-decode": "2.2.0",
58
     "jwt-decode": "2.2.0",
59
-    "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#94318fce12c855aefefdf8586bc8772065b505c9",
59
+    "lib-jitsi-meet": "github:jitsi/lib-jitsi-meet#735c30ec4f1c17b81f68c4b6684489e05115aeb2",
60
     "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
60
     "libflacjs": "github:mmig/libflac.js#93d37e7f811f01cf7d8b6a603e38bd3c3810907d",
61
     "lodash": "4.17.19",
61
     "lodash": "4.17.19",
62
     "moment": "2.19.4",
62
     "moment": "2.19.4",
63
     "moment-duration-format": "2.2.2",
63
     "moment-duration-format": "2.2.2",
64
+    "olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
64
     "pixelmatch": "5.1.0",
65
     "pixelmatch": "5.1.0",
65
     "react": "16.9",
66
     "react": "16.9",
66
     "react-dom": "16.9",
67
     "react-dom": "16.9",

+ 3
- 3
react/features/e2ee/actionTypes.js 查看文件

1
 /**
1
 /**
2
- * The type of the action which signals the E2EE key has changed.
2
+ * The type of the action which signals that E2EE needs to be enabled / disabled.
3
  *
3
  *
4
  * {
4
  * {
5
- *     type: SET_E2EE_KEY
5
+ *     type: TOGGLE_E2EE
6
  * }
6
  * }
7
  */
7
  */
8
-export const SET_E2EE_KEY = 'SET_E2EE_KEY';
8
+export const TOGGLE_E2EE = 'TOGGLE_E2EE';

+ 6
- 6
react/features/e2ee/actions.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { SET_E2EE_KEY } from './actionTypes';
3
+import { TOGGLE_E2EE } from './actionTypes';
4
 
4
 
5
 /**
5
 /**
6
- * Dispatches an action to set the E2EE key.
6
+ * Dispatches an action to enable / disable E2EE.
7
  *
7
  *
8
- * @param {string|undefined} key - The new key to be used for E2EE.
8
+ * @param {boolean} enabled - Whether E2EE is to be enabled or not.
9
  * @returns {Object}
9
  * @returns {Object}
10
  */
10
  */
11
-export function setE2EEKey(key: ?string) {
11
+export function toggleE2EE(enabled: boolean) {
12
     return {
12
     return {
13
-        type: SET_E2EE_KEY,
14
-        key
13
+        type: TOGGLE_E2EE,
14
+        enabled
15
     };
15
     };
16
 }
16
 }

+ 45
- 95
react/features/e2ee/components/E2EESection.js 查看文件

6
 import { createE2EEEvent, sendAnalytics } from '../../analytics';
6
 import { createE2EEEvent, sendAnalytics } from '../../analytics';
7
 import { translate } from '../../base/i18n';
7
 import { translate } from '../../base/i18n';
8
 import { getParticipants } from '../../base/participants';
8
 import { getParticipants } from '../../base/participants';
9
+import { Switch } from '../../base/react';
9
 import { connect } from '../../base/redux';
10
 import { connect } from '../../base/redux';
10
-import { setE2EEKey } from '../actions';
11
+import { toggleE2EE } from '../actions';
11
 
12
 
12
 
13
 
13
 type Props = {
14
 type Props = {
14
 
15
 
15
     /**
16
     /**
16
-     * Indicates whether all participants in the conference currently support E2EE.
17
+     * Whether E2EE is currently enabled or not.
17
      */
18
      */
18
-    _everyoneSupportsE2EE: boolean,
19
+    _enabled: boolean,
19
 
20
 
20
     /**
21
     /**
21
-     * The current E2EE key.
22
+     * Indicates whether all participants in the conference currently support E2EE.
22
      */
23
      */
23
-    _key: string,
24
+    _everyoneSupportsE2EE: boolean,
24
 
25
 
25
     /**
26
     /**
26
      * The redux {@code dispatch} function.
27
      * The redux {@code dispatch} function.
36
 type State = {
37
 type State = {
37
 
38
 
38
     /**
39
     /**
39
-     * True if the key is being edited.
40
+     * True if the switch is toggled on.
40
      */
41
      */
41
-    editing: boolean,
42
+    enabled: boolean,
42
 
43
 
43
     /**
44
     /**
44
      * True if the section description should be expanded, false otherwise.
45
      * True if the section description should be expanded, false otherwise.
45
      */
46
      */
46
-    expand: boolean,
47
-
48
-    /**
49
-     * The current E2EE key.
50
-     */
51
-    key: string
47
+    expand: boolean
52
 };
48
 };
53
 
49
 
54
 /**
50
 /**
58
  * @extends Component
54
  * @extends Component
59
  */
55
  */
60
 class E2EESection extends Component<Props, State> {
56
 class E2EESection extends Component<Props, State> {
61
-    fieldRef: Object;
57
+    /**
58
+     * Implements React's {@link Component#getDerivedStateFromProps()}.
59
+     *
60
+     * @inheritdoc
61
+     */
62
+    static getDerivedStateFromProps(props: Props, state: Object) {
63
+        if (props._enabled !== state.enabled) {
64
+
65
+            return {
66
+                enabled: props._enabled
67
+            };
68
+        }
69
+
70
+        return null;
71
+    }
62
 
72
 
63
     /**
73
     /**
64
-     * Initializes a new {@code E2EEDialog  } instance.
74
+     * Instantiates a new component.
65
      *
75
      *
66
-     * @param {Object} props - The read-only properties with which the new
67
-     * instance is to be initialized.
76
+     * @inheritdoc
68
      */
77
      */
69
     constructor(props: Props) {
78
     constructor(props: Props) {
70
         super(props);
79
         super(props);
71
 
80
 
72
-        this.fieldRef = React.createRef();
73
-
74
         this.state = {
81
         this.state = {
75
-            editing: false,
76
-            expand: false,
77
-            key: this.props._key
82
+            enabled: false,
83
+            expand: false
78
         };
84
         };
79
 
85
 
80
         // Bind event handlers so they are only bound once for every instance.
86
         // Bind event handlers so they are only bound once for every instance.
81
         this._onExpand = this._onExpand.bind(this);
87
         this._onExpand = this._onExpand.bind(this);
82
-        this._onKeyChange = this._onKeyChange.bind(this);
83
-        this._onSet = this._onSet.bind(this);
84
-        this._onToggleSetKey = this._onToggleSetKey.bind(this);
88
+        this._onToggle = this._onToggle.bind(this);
85
     }
89
     }
86
 
90
 
87
     /**
91
     /**
92
      */
96
      */
93
     render() {
97
     render() {
94
         const { _everyoneSupportsE2EE, t } = this.props;
98
         const { _everyoneSupportsE2EE, t } = this.props;
95
-        const { editing, expand } = this.state;
99
+        const { enabled, expand } = this.state;
96
         const description = t('dialog.e2eeDescription');
100
         const description = t('dialog.e2eeDescription');
97
 
101
 
98
         return (
102
         return (
112
                             { t('dialog.e2eeWarning') }
116
                             { t('dialog.e2eeWarning') }
113
                         </span>
117
                         </span>
114
                 }
118
                 }
115
-                <div className = 'key-field'>
119
+                <div className = 'control-row'>
116
                     <label>
120
                     <label>
117
-                        { t('dialog.e2eeLabel') }:
121
+                        { t('dialog.e2eeLabel') }
118
                     </label>
122
                     </label>
119
-                    <input
120
-                        disabled = { !editing }
121
-                        name = 'e2eeKey'
122
-                        onChange = { this._onKeyChange }
123
-                        onKeyDown = { this._onKeyDown }
124
-                        placeholder = { t('dialog.e2eeNoKey') }
125
-                        ref = { this.fieldRef }
126
-                        type = 'password'
127
-                        value = { this.state.key } />
128
-                    { editing && <a onClick = { this._onSet }>
129
-                        { t('dialog.e2eeSet') }
130
-                    </a> }
131
-                    { !editing && <a onClick = { this._onToggleSetKey }>
132
-                        { t('dialog.e2eeToggleSet') }
133
-                    </a> }
123
+                    <Switch
124
+                        onValueChange = { this._onToggle }
125
+                        value = { enabled } />
134
                 </div>
126
                 </div>
135
             </div>
127
             </div>
136
         );
128
         );
149
         });
141
         });
150
     }
142
     }
151
 
143
 
152
-    _onKeyChange: (Object) => void;
153
-
154
-    /**
155
-     * Updates the entered key.
156
-     *
157
-     * @param {Object} event - The DOM event triggered from the entered value having changed.
158
-     * @private
159
-     * @returns {void}
160
-     */
161
-    _onKeyChange(event) {
162
-        this.setState({ key: event.target.value.trim() });
163
-    }
164
-
165
-    _onKeyDown: (Object) => void;
144
+    _onToggle: () => void;
166
 
145
 
167
     /**
146
     /**
168
-     * Handler for the keydown event on the form, preventing the closing of the dialog.
169
-     *
170
-     * @param {Object} event - The DOM event triggered by keydown events.
171
-     * @returns {void}
172
-     */
173
-    _onKeyDown(event) {
174
-        if (event.key === 'Enter') {
175
-            event.preventDefault();
176
-        }
177
-    }
178
-
179
-    _onSet: () => void;
180
-
181
-    /**
182
-     * Dispatches an action to set/unset the E2EE key.
147
+     * Callback to be invoked when the user toggles E2EE on or off.
183
      *
148
      *
184
      * @private
149
      * @private
185
      * @returns {void}
150
      * @returns {void}
186
      */
151
      */
187
-    _onSet() {
188
-        const { key } = this.state;
189
-
190
-        sendAnalytics(createE2EEEvent(`key.${key ? 'set' : 'unset'}`));
191
-        this.props.dispatch(setE2EEKey(key));
152
+    _onToggle() {
153
+        const newValue = !this.state.enabled;
192
 
154
 
193
         this.setState({
155
         this.setState({
194
-            editing: false
156
+            enabled: newValue
195
         });
157
         });
196
-    }
197
 
158
 
198
-    _onToggleSetKey: () => void;
199
-
200
-    /**
201
-     * Sets the section into edit mode so then the user can set the key.
202
-     *
203
-     * @returns {void}
204
-     */
205
-    _onToggleSetKey() {
206
-        this.setState({
207
-            editing: true
208
-        }, () => {
209
-            this.fieldRef.current.focus();
210
-        });
159
+        sendAnalytics(createE2EEEvent(`enabled.${String(newValue)}`));
160
+        this.props.dispatch(toggleE2EE(newValue));
211
     }
161
     }
212
 }
162
 }
213
 
163
 
219
  * @returns {Props}
169
  * @returns {Props}
220
  */
170
  */
221
 function mapStateToProps(state) {
171
 function mapStateToProps(state) {
222
-    const { e2eeKey } = state['features/e2ee'];
172
+    const { enabled } = state['features/e2ee'];
223
     const participants = getParticipants(state).filter(p => !p.local);
173
     const participants = getParticipants(state).filter(p => !p.local);
224
 
174
 
225
     return {
175
     return {
226
-        _everyoneSupportsE2EE: participants.every(p => Boolean(p.e2eeSupported)),
227
-        _key: e2eeKey || ''
176
+        _enabled: enabled,
177
+        _everyoneSupportsE2EE: participants.every(p => Boolean(p.e2eeSupported))
228
     };
178
     };
229
 }
179
 }
230
 
180
 

+ 7
- 7
react/features/e2ee/middleware.js 查看文件

4
 import { getLocalParticipant, participantUpdated } from '../base/participants';
4
 import { getLocalParticipant, participantUpdated } from '../base/participants';
5
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
5
 import { MiddlewareRegistry, StateListenerRegistry } from '../base/redux';
6
 
6
 
7
-import { SET_E2EE_KEY } from './actionTypes';
8
-import { setE2EEKey } from './actions';
7
+import { TOGGLE_E2EE } from './actionTypes';
8
+import { toggleE2EE } from './actions';
9
 import logger from './logger';
9
 import logger from './logger';
10
 
10
 
11
 /**
11
 /**
16
  */
16
  */
17
 MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
17
 MiddlewareRegistry.register(({ dispatch, getState }) => next => action => {
18
     switch (action.type) {
18
     switch (action.type) {
19
-    case SET_E2EE_KEY: {
19
+    case TOGGLE_E2EE: {
20
         const conference = getCurrentConference(getState);
20
         const conference = getCurrentConference(getState);
21
 
21
 
22
         if (conference) {
22
         if (conference) {
23
-            logger.debug(`New E2EE key: ${action.key}`);
24
-            conference.setE2EEKey(action.key);
23
+            logger.debug(`E2EE will be ${action.enabled ? 'enabled' : 'disabled'}`);
24
+            conference.toggleE2EE(action.enabled);
25
 
25
 
26
             // Broadccast that we enabled / disabled E2EE.
26
             // Broadccast that we enabled / disabled E2EE.
27
             const participant = getLocalParticipant(getState);
27
             const participant = getLocalParticipant(getState);
28
 
28
 
29
             dispatch(participantUpdated({
29
             dispatch(participantUpdated({
30
-                e2eeEnabled: Boolean(action.key),
30
+                e2eeEnabled: action.enabled,
31
                 id: participant.id,
31
                 id: participant.id,
32
                 local: true
32
                 local: true
33
             }));
33
             }));
48
     state => getCurrentConference(state),
48
     state => getCurrentConference(state),
49
     (conference, { dispatch }, previousConference) => {
49
     (conference, { dispatch }, previousConference) => {
50
         if (previousConference) {
50
         if (previousConference) {
51
-            dispatch(setE2EEKey(undefined));
51
+            dispatch(toggleE2EE(false));
52
         }
52
         }
53
     });
53
     });

+ 4
- 8
react/features/e2ee/reducer.js 查看文件

2
 
2
 
3
 import { ReducerRegistry } from '../base/redux';
3
 import { ReducerRegistry } from '../base/redux';
4
 
4
 
5
-import { SET_E2EE_KEY } from './actionTypes';
5
+import { TOGGLE_E2EE } from './actionTypes';
6
 
6
 
7
 const DEFAULT_STATE = {
7
 const DEFAULT_STATE = {
8
-
9
-    /**
10
-     * E2EE key.
11
-     */
12
-    e2eeKey: undefined
8
+    enabled: false
13
 };
9
 };
14
 
10
 
15
 /**
11
 /**
17
  */
13
  */
18
 ReducerRegistry.register('features/e2ee', (state = DEFAULT_STATE, action) => {
14
 ReducerRegistry.register('features/e2ee', (state = DEFAULT_STATE, action) => {
19
     switch (action.type) {
15
     switch (action.type) {
20
-    case SET_E2EE_KEY:
16
+    case TOGGLE_E2EE:
21
         return {
17
         return {
22
             ...state,
18
             ...state,
23
-            e2eeKey: action.key
19
+            enabled: action.enabled
24
         };
20
         };
25
 
21
 
26
     default:
22
     default:

+ 5
- 2
webpack.config.js 查看文件

140
         // Allow the use of the real filename of the module being executed. By
140
         // Allow the use of the real filename of the module being executed. By
141
         // default Webpack does not leak path-related information and provides a
141
         // default Webpack does not leak path-related information and provides a
142
         // value that is a mock (/index.js).
142
         // value that is a mock (/index.js).
143
-        __filename: true
143
+        __filename: true,
144
+
145
+        // Provide an empty 'fs' module.
146
+        fs: 'empty'
144
     },
147
     },
145
     optimization: {
148
     optimization: {
146
         concatenateModules: minimize,
149
         concatenateModules: minimize,
187
         entry: {
190
         entry: {
188
             'app.bundle': './app.js'
191
             'app.bundle': './app.js'
189
         },
192
         },
190
-        performance: getPerformanceHints(4 * 1024 * 1024)
193
+        performance: getPerformanceHints(4.5 * 1024 * 1024)
191
     }),
194
     }),
192
     Object.assign({}, config, {
195
     Object.assign({}, config, {
193
         entry: {
196
         entry: {

正在加载...
取消
保存