Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import { getLogger } from '@jitsi/logger';
  2. import * as JitsiConferenceEvents from '../../JitsiConferenceEvents';
  3. import RTCEvents from '../../service/RTC/RTCEvents';
  4. import browser from '../browser';
  5. import Deferred from '../util/Deferred';
  6. import Listenable from '../util/Listenable';
  7. import E2EEContext from './E2EEContext';
  8. const logger = getLogger('modules/e2ee/KeyHandler');
  9. /**
  10. * Abstract class that integrates {@link E2EEContext} with a key management system.
  11. */
  12. export class KeyHandler extends Listenable {
  13. /**
  14. * Build a new KeyHandler instance, which will be used in a given conference.
  15. * @param {JitsiConference} conference - the current conference.
  16. * @param {object} options - the options passed to {E2EEContext}, see implemention.
  17. */
  18. constructor(conference, options = {}) {
  19. super();
  20. this.conference = conference;
  21. this.e2eeCtx = new E2EEContext(options);
  22. this.enabled = false;
  23. this._enabling = undefined;
  24. this._firstEnable = false;
  25. // Conference media events in order to attach the encryptor / decryptor.
  26. // FIXME add events to TraceablePeerConnection which will allow to see when there's new receiver or sender
  27. // added instead of shenanigans around conference track events and track muted.
  28. //
  29. this.conference.on(
  30. JitsiConferenceEvents._MEDIA_SESSION_STARTED,
  31. this._onMediaSessionStarted.bind(this));
  32. this.conference.on(
  33. JitsiConferenceEvents.TRACK_ADDED,
  34. track => track.isLocal() && this._onLocalTrackAdded(track));
  35. this.conference.rtc.on(
  36. RTCEvents.REMOTE_TRACK_ADDED,
  37. (track, tpc) => this._setupReceiverE2EEForTrack(tpc, track));
  38. this.conference.on(
  39. JitsiConferenceEvents.TRACK_MUTE_CHANGED,
  40. this._trackMuteChanged.bind(this));
  41. }
  42. /**
  43. * Indicates whether E2EE is currently enabled or not.
  44. *
  45. * @returns {boolean}
  46. */
  47. isEnabled() {
  48. return this.enabled;
  49. }
  50. /**
  51. * Enables / disables End-To-End encryption.
  52. *
  53. * @param {boolean} enabled - whether E2EE should be enabled or not.
  54. * @returns {void}
  55. */
  56. async setEnabled(enabled) {
  57. this._enabling && await this._enabling;
  58. if (enabled === this.enabled) {
  59. return;
  60. }
  61. this._enabling = new Deferred();
  62. this.enabled = enabled;
  63. this._setEnabled && await this._setEnabled(enabled);
  64. this.conference.setLocalParticipantProperty('e2ee.enabled', enabled);
  65. // Only restart media sessions if E2EE is enabled. If it's later disabled
  66. // we'll continue to use the existing media sessions with an empty transform.
  67. if (!this._firstEnable && enabled) {
  68. this._firstEnable = true;
  69. this.conference._restartMediaSessions();
  70. }
  71. this.e2eeCtx.setEnabled(enabled);
  72. this._enabling.resolve();
  73. }
  74. /**
  75. * Setup E2EE on the new track that has been added to the conference, apply it on all the open peerconnections.
  76. * @param {JitsiLocalTrack} track - the new track that's being added to the conference.
  77. * @private
  78. */
  79. _onLocalTrackAdded(track) {
  80. for (const session of this.conference.getMediaSessions()) {
  81. this._setupSenderE2EEForTrack(session, track);
  82. }
  83. }
  84. /**
  85. * Setups E2E encryption for the new session.
  86. * @param {JingleSessionPC} session - the new media session.
  87. * @private
  88. */
  89. _onMediaSessionStarted(session) {
  90. const localTracks = this.conference.getLocalTracks();
  91. for (const track of localTracks) {
  92. this._setupSenderE2EEForTrack(session, track);
  93. }
  94. }
  95. /**
  96. * Setup E2EE for the receiving side.
  97. *
  98. * @private
  99. */
  100. _setupReceiverE2EEForTrack(tpc, track) {
  101. if (!this.enabled && !this._firstEnable) {
  102. return;
  103. }
  104. const receiver = tpc.findReceiverForTrack(track.track);
  105. if (receiver) {
  106. this.e2eeCtx.handleReceiver(receiver, track.getType(), track.getParticipantId());
  107. } else {
  108. logger.warn(`Could not handle E2EE for ${track}: receiver not found in: ${tpc}`);
  109. }
  110. }
  111. /**
  112. * Setup E2EE for the sending side.
  113. *
  114. * @param {JingleSessionPC} session - the session which sends the media produced by the track.
  115. * @param {JitsiLocalTrack} track - the local track for which e2e encoder will be configured.
  116. * @private
  117. */
  118. _setupSenderE2EEForTrack(session, track) {
  119. if (!this.enabled && !this._firstEnable) {
  120. return;
  121. }
  122. const pc = session.peerconnection;
  123. const sender = pc && pc.findSenderForTrack(track.track);
  124. if (sender) {
  125. this.e2eeCtx.handleSender(sender, track.getType(), track.getParticipantId());
  126. } else {
  127. logger.warn(`Could not handle E2EE for ${track}: sender not found in ${pc}`);
  128. }
  129. }
  130. /**
  131. * Setup E2EE on the sender that is created for the unmuted local video track.
  132. * @param {JitsiLocalTrack} track - the track for which muted status has changed.
  133. * @private
  134. */
  135. _trackMuteChanged(track) {
  136. if (browser.doesVideoMuteByStreamRemove() && track.isLocal() && track.isVideoTrack() && !track.isMuted()) {
  137. for (const session of this.conference.getMediaSessions()) {
  138. this._setupSenderE2EEForTrack(session, track);
  139. }
  140. }
  141. }
  142. }