Browse Source

ref(e2ee): extract E2EEncryption module

Moves the logics which deal with JitsiConference events to a separate module.
dev1
paweldomas 5 years ago
parent
commit
ddb3ed92b5
3 changed files with 147 additions and 94 deletions
  1. 8
    93
      JitsiConference.js
  2. 18
    1
      modules/RTC/TraceablePeerConnection.js
  3. 121
    0
      modules/e2ee/E2EEncryption.js

+ 8
- 93
JitsiConference.js View File

26
     from './modules/connectivity/IceFailedHandling';
26
     from './modules/connectivity/IceFailedHandling';
27
 import ParticipantConnectionStatusHandler
27
 import ParticipantConnectionStatusHandler
28
     from './modules/connectivity/ParticipantConnectionStatus';
28
     from './modules/connectivity/ParticipantConnectionStatus';
29
-import E2EEContext from './modules/e2ee/E2EEContext';
29
+import { E2EEncryption } from './modules/e2ee/E2EEncryption';
30
 import E2ePing from './modules/e2eping/e2eping';
30
 import E2ePing from './modules/e2eping/e2eping';
31
 import Jvb121EventGenerator from './modules/event/Jvb121EventGenerator';
31
 import Jvb121EventGenerator from './modules/event/Jvb121EventGenerator';
32
 import RecordingManager from './modules/recording/RecordingManager';
32
 import RecordingManager from './modules/recording/RecordingManager';
235
     this.recordingManager = new RecordingManager(this.room);
235
     this.recordingManager = new RecordingManager(this.room);
236
     this._conferenceJoinAnalyticsEventSent = false;
236
     this._conferenceJoinAnalyticsEventSent = false;
237
 
237
 
238
-    const config = this.options.config;
239
-
240
-    if (browser.supportsInsertableStreams() && !(config.testing && config.testing.disableE2EE)) {
241
-        this._e2eeCtx = new E2EEContext({ salt: this.options.name });
238
+    if (this.isE2EESupported()) {
239
+        this._e2eEncryption = new E2EEncryption(this, { salt: this.options.name });
242
     }
240
     }
243
 }
241
 }
244
 
242
 
975
         actorParticipant = this.participants[actorId];
973
         actorParticipant = this.participants[actorId];
976
     }
974
     }
977
 
975
 
978
-    // Setup E2EE on the sender that is created for the unmuted track.
979
-    if (this._e2eeCtx && !track.isMuted() && browser.doesVideoMuteByStreamRemove()) {
980
-        if (this.p2pJingleSession) {
981
-            this._setupSenderE2EEForTrack(this.p2pJingleSession, track);
982
-        }
983
-        if (this.jvbJingleSession) {
984
-            this._setupSenderE2EEForTrack(this.jvbJingleSession, track);
985
-        }
986
-    }
987
-
988
     this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track, actorParticipant);
976
     this.eventEmitter.emit(JitsiConferenceEvents.TRACK_MUTE_CHANGED, track, actorParticipant);
989
 };
977
 };
990
 
978
 
1130
         this.room.setVideoMute(newTrack.isMuted());
1118
         this.room.setVideoMute(newTrack.isMuted());
1131
     }
1119
     }
1132
 
1120
 
1133
-    // Setup E2EE on the new track that has been added
1134
-    // to the conference, apply it on all the open peerconnections.
1135
-    if (this._e2eeCtx) {
1136
-        if (this.p2pJingleSession) {
1137
-            this._setupSenderE2EEForTrack(this.p2pJingleSession, newTrack);
1138
-        }
1139
-        if (this.jvbJingleSession) {
1140
-            this._setupSenderE2EEForTrack(this.jvbJingleSession, newTrack);
1141
-        }
1142
-    }
1143
-
1144
     newTrack.muteHandler = this._fireMuteChangeEvent.bind(this, newTrack);
1121
     newTrack.muteHandler = this._fireMuteChangeEvent.bind(this, newTrack);
1145
     newTrack.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
1122
     newTrack.audioLevelHandler = this._fireAudioLevelChangeEvent.bind(this);
1146
     newTrack.addEventListener(
1123
     newTrack.addEventListener(
1698
         return;
1675
         return;
1699
     }
1676
     }
1700
 
1677
 
1701
-    // Setup E2EE handling, if supported.
1702
-    this._setupReceiverE2EEForTrack(track);
1703
-
1704
     const id = track.getParticipantId();
1678
     const id = track.getParticipantId();
1705
     const participant = this.getParticipantById(id);
1679
     const participant = this.getParticipantById(id);
1706
 
1680
 
1750
     if (this.p2pJingleSession === session) {
1724
     if (this.p2pJingleSession === session) {
1751
         logger.info('P2P setAnswer');
1725
         logger.info('P2P setAnswer');
1752
 
1726
 
1753
-        // Setup E2EE.
1754
-        const localTracks = this.getLocalTracks();
1755
-
1756
-        for (const track of localTracks) {
1757
-            this._setupSenderE2EEForTrack(session, track);
1758
-        }
1759
-
1760
         this.p2pJingleSession.setAnswer(answer);
1727
         this.p2pJingleSession.setAnswer(answer);
1761
         this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, this.p2pJingleSession);
1728
         this.eventEmitter.emit(JitsiConferenceEvents._MEDIA_SESSION_STARTED, this.p2pJingleSession);
1762
     }
1729
     }
1943
                         JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED,
1910
                         JitsiConferenceEvents._MEDIA_SESSION_ACTIVE_CHANGED,
1944
                         jingleSession);
1911
                         jingleSession);
1945
                 }
1912
                 }
1946
-
1947
-                // Setup E2EE.
1948
-                for (const track of localTracks) {
1949
-                    this._setupSenderE2EEForTrack(jingleSession, track);
1950
-                }
1951
             },
1913
             },
1952
             error => {
1914
             error => {
1953
                 GlobalOnErrorHandler.callErrorHandler(error);
1915
                 GlobalOnErrorHandler.callErrorHandler(error);
2703
             this.eventEmitter.emit(
2665
             this.eventEmitter.emit(
2704
                 JitsiConferenceEvents._MEDIA_SESSION_STARTED,
2666
                 JitsiConferenceEvents._MEDIA_SESSION_STARTED,
2705
                 this.p2pJingleSession);
2667
                 this.p2pJingleSession);
2706
-
2707
-            // Setup E2EE.
2708
-            for (const track of localTracks) {
2709
-                this._setupSenderE2EEForTrack(jingleSession, track);
2710
-            }
2711
         },
2668
         },
2712
         error => {
2669
         error => {
2713
             logger.error(
2670
             logger.error(
3383
  * @returns {boolean}
3340
  * @returns {boolean}
3384
  */
3341
  */
3385
 JitsiConference.prototype.isE2EESupported = function() {
3342
 JitsiConference.prototype.isE2EESupported = function() {
3386
-    return Boolean(this._e2eeCtx);
3343
+    const config = this.options.config;
3344
+
3345
+    return browser.supportsInsertableStreams() && !(config.testing && config.testing.disableE2EE);
3387
 };
3346
 };
3388
 
3347
 
3389
 /**
3348
 /**
3393
  * @returns {void}
3352
  * @returns {void}
3394
  */
3353
  */
3395
 JitsiConference.prototype.setE2EEKey = function(key) {
3354
 JitsiConference.prototype.setE2EEKey = function(key) {
3396
-    if (!this._e2eeCtx) {
3355
+    if (!this._e2eEncryption) {
3397
         logger.warn('Cannot set E2EE key: there is no defined context, platform is likely unsupported.');
3356
         logger.warn('Cannot set E2EE key: there is no defined context, platform is likely unsupported.');
3398
 
3357
 
3399
         return;
3358
         return;
3400
     }
3359
     }
3401
 
3360
 
3402
-    this._e2eeCtx.setKey(key);
3361
+    this._e2eEncryption.setKey(key);
3403
 };
3362
 };
3404
 
3363
 
3405
 /**
3364
 /**
3480
         this.room.getLobby().approveAccess(id);
3439
         this.room.getLobby().approveAccess(id);
3481
     }
3440
     }
3482
 };
3441
 };
3483
-
3484
-/**
3485
- * Setup E2EE for the sending side, if supported.
3486
- * Note that this is only done for the JVB Peer Connecction.
3487
- *
3488
- * @returns {void}
3489
- */
3490
-JitsiConference.prototype._setupSenderE2EEForTrack = function(session, track) {
3491
-    if (!this._e2eeCtx) {
3492
-        return;
3493
-    }
3494
-    const pc = session.peerconnection;
3495
-    const sender = pc.findSenderForTrack(track.track);
3496
-
3497
-    if (sender) {
3498
-        this._e2eeCtx.handleSender(sender, track.getType(), track.getParticipantId());
3499
-    } else {
3500
-        logger.warn(`Could not handle E2EE for local ${track.getType()} track: sender not found`);
3501
-    }
3502
-};
3503
-
3504
-/**
3505
- * Setup E2EE for the receiving side, if supported.
3506
- * Note that this is only done for the JVB Peer Connecction.
3507
- *
3508
- * @returns {void}
3509
- */
3510
-JitsiConference.prototype._setupReceiverE2EEForTrack = function(track) {
3511
-    if (!this._e2eeCtx) {
3512
-        return;
3513
-    }
3514
-    const session = track.isP2P ? this.p2pJingleSession : this.jvbJingleSession;
3515
-    const pc = session && session.peerconnection;
3516
-
3517
-    if (pc) {
3518
-        const receiver = pc.findReceiverForTrack(track.track);
3519
-
3520
-        if (receiver) {
3521
-            this._e2eeCtx.handleReceiver(receiver, track.getType(), track.getParticipantId());
3522
-        } else {
3523
-            logger.warn(`Could not handle E2EE for remote ${track.getType()} track: receiver not found`);
3524
-        }
3525
-    }
3526
-};

+ 18
- 1
modules/RTC/TraceablePeerConnection.js View File

858
 
858
 
859
     remoteTracksMap.set(mediaType, remoteTrack);
859
     remoteTracksMap.set(mediaType, remoteTrack);
860
 
860
 
861
-    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_ADDED, remoteTrack);
861
+    this.eventEmitter.emit(RTCEvents.REMOTE_TRACK_ADDED, remoteTrack, this);
862
 };
862
 };
863
 
863
 
864
 /* eslint-enable max-params */
864
 /* eslint-enable max-params */
1441
     return this.localSSRCs.get(rtcId);
1441
     return this.localSSRCs.get(rtcId);
1442
 };
1442
 };
1443
 
1443
 
1444
+/**
1445
+ * Checks if given track belongs to this peerconnection instance.
1446
+ *
1447
+ * @param {JitsiLocalTrack|JitsiRemoteTrack} track - The track to be checked.
1448
+ * @returns {boolean}
1449
+ */
1450
+TraceablePeerConnection.prototype.containsTrack = function(track) {
1451
+    if (track.isLocal()) {
1452
+        return this.localTracks.has(track.rtcId);
1453
+    }
1454
+
1455
+    const participantId = track.getParticipantId();
1456
+    const remoteTracksMap = this.remoteTracks.get(participantId);
1457
+
1458
+    return Boolean(remoteTracksMap && remoteTracksMap.get(track.getType()) === track);
1459
+};
1460
+
1444
 /**
1461
 /**
1445
  * Add {@link JitsiLocalTrack} to this TPC.
1462
  * Add {@link JitsiLocalTrack} to this TPC.
1446
  * @param {JitsiLocalTrack} track
1463
  * @param {JitsiLocalTrack} track

+ 121
- 0
modules/e2ee/E2EEncryption.js View File

1
+/* global __filename */
2
+import { getLogger } from 'jitsi-meet-logger';
3
+
4
+import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
5
+import browser from '../browser';
6
+import RTCEvents from '../../service/RTC/RTCEvents';
7
+
8
+import E2EEContext from './E2EEContext';
9
+
10
+const logger = getLogger(__filename);
11
+
12
+/**
13
+ * This module integrates {@link E2EEContext} with {@link JitsiConference} in order to enable E2E encryption.
14
+ */
15
+export class E2EEncryption {
16
+    /**
17
+     * A constructor.
18
+     * @param {JitsiConference} conference - The conference instance for which E2E encryption is to be enabled.
19
+     * @param {Object} options
20
+     * @param {string} options.salt - Salt to be used for key deviation. Check {@link E2EEContext} for more details.
21
+     */
22
+    constructor(conference, { salt }) {
23
+        this.conference = conference;
24
+        this._e2eeCtx = new E2EEContext({ salt });
25
+        this.conference.on(
26
+            JitsiConferenceEvents._MEDIA_SESSION_STARTED,
27
+            this._onMediaSessionStarted.bind(this));
28
+
29
+        // FIXME add events to TraceablePeerConnection which will allow to see when there's new receiver or sender
30
+        //  added instead of shenanigans around conference track events and track muted.
31
+        this.conference.on(
32
+            JitsiConferenceEvents.TRACK_ADDED,
33
+            track => track.isLocal() && this._onLocalTrackAdded(track));
34
+        this.conference.rtc.on(
35
+            RTCEvents.REMOTE_TRACK_ADDED,
36
+            (track, tpc) => this._setupReceiverE2EEForTrack(tpc, track));
37
+        this.conference.on(
38
+            JitsiConferenceEvents.TRACK_MUTE_CHANGED,
39
+            this._trackMuteChanged.bind(this));
40
+    }
41
+
42
+    /**
43
+     * Setups E2E encryption for the new session.
44
+     * @param {JingleSessionPC} session - the new media session.
45
+     * @private
46
+     */
47
+    _onMediaSessionStarted(session) {
48
+        const localTracks = this.conference.getLocalTracks();
49
+
50
+        for (const track of localTracks) {
51
+            this._setupSenderE2EEForTrack(session, track);
52
+        }
53
+    }
54
+
55
+    /**
56
+     * Setup E2EE on the new track that has been added to the conference, apply it on all the open peerconnections.
57
+     * @param {JitsiLocalTrack} track - the new track that's being added to the conference.
58
+     * @private
59
+     */
60
+    _onLocalTrackAdded(track) {
61
+        for (const session of this.conference._getMediaSessions()) {
62
+            this._setupSenderE2EEForTrack(session, track);
63
+        }
64
+    }
65
+
66
+    /**
67
+     * Sets the key to be used for End-To-End encryption.
68
+     *
69
+     * @param {string} key - the key to be used.
70
+     * @returns {void}
71
+     */
72
+    setKey(key) {
73
+        this._e2eeCtx.setKey(key);
74
+    }
75
+
76
+    /**
77
+     * Setup E2EE for the receiving side.
78
+     *
79
+     * @returns {void}
80
+     */
81
+    _setupReceiverE2EEForTrack(tpc, track) {
82
+        const receiver = tpc.findReceiverForTrack(track.track);
83
+
84
+        if (receiver) {
85
+            this._e2eeCtx.handleReceiver(receiver, track.getType(), track.getParticipantId());
86
+        } else {
87
+            logger.warn(`Could not handle E2EE for ${track}: receiver not found in: ${tpc}`);
88
+        }
89
+    }
90
+
91
+    /**
92
+     * Setup E2EE for the sending side.
93
+     *
94
+     * @param {JingleSessionPC} session - the session which sends the media produced by the track.
95
+     * @param {JitsiLocalTrack} track - the local track for which e2e encoder will be configured.
96
+     * @returns {void}
97
+     */
98
+    _setupSenderE2EEForTrack(session, track) {
99
+        const pc = session.peerconnection;
100
+        const sender = pc && pc.findSenderForTrack(track.track);
101
+
102
+        if (sender) {
103
+            this._e2eeCtx.handleSender(sender, track.getType(), track.getParticipantId());
104
+        } else {
105
+            logger.warn(`Could not handle E2EE for ${track}: sender not found in ${pc}`);
106
+        }
107
+    }
108
+
109
+    /**
110
+     * Setup E2EE on the sender that is created for the unmuted local video track.
111
+     * @param {JitsiLocalTrack} track - the track for which muted status has changed.
112
+     * @private
113
+     */
114
+    _trackMuteChanged(track) {
115
+        if (browser.doesVideoMuteByStreamRemove() && track.isLocal() && track.isVideoTrack() && !track.isMuted()) {
116
+            for (const session of this.conference._getMediaSessions()) {
117
+                this._setupSenderE2EEForTrack(session, track);
118
+            }
119
+        }
120
+    }
121
+}

Loading…
Cancel
Save