modified lib-jitsi-meet dev repo
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

E2EEContext.js 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /* global __filename */
  2. import { getLogger } from 'jitsi-meet-logger';
  3. import { createWorkerScript } from './Worker';
  4. const logger = getLogger(__filename);
  5. // Flag to set on senders / receivers to avoid setting up the encryption transform
  6. // more than once.
  7. const kJitsiE2EE = Symbol('kJitsiE2EE');
  8. /**
  9. * Context encapsulating the cryptography bits required for E2EE.
  10. * This uses the WebRTC Insertable Streams API which is explained in
  11. * https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md
  12. * that provides access to the encoded frames and allows them to be transformed.
  13. *
  14. * The encoded frame format is explained below in the _encodeFunction method.
  15. * High level design goals were:
  16. * - do not require changes to existing SFUs and retain (VP8) metadata.
  17. * - allow the SFU to rewrite SSRCs, timestamp, pictureId.
  18. * - allow for the key to be rotated frequently.
  19. */
  20. export default class E2EEcontext {
  21. /**
  22. * Build a new E2EE context instance, which will be used in a given conference.
  23. *
  24. * @param {string} options.salt - Salt to be used for key deviation.
  25. * FIXME: We currently use the MUC room name for this which has the same lifetime
  26. * as this context. While not (pseudo)random as recommended in
  27. * https://developer.mozilla.org/en-US/docs/Web/API/Pbkdf2Params
  28. * this is easily available and the same for all participants.
  29. * We currently do not enforce a minimum length of 16 bytes either.
  30. */
  31. constructor(options) {
  32. this._options = options;
  33. // Initialize the E2EE worker.
  34. this._worker = new Worker(createWorkerScript(), {
  35. name: 'E2EE Worker'
  36. });
  37. this._worker.onerror = e => logger.onerror(e);
  38. // Initialize the salt and convert it once.
  39. const encoder = new TextEncoder();
  40. // Send initial options to worker.
  41. this._worker.postMessage({
  42. operation: 'initialize',
  43. salt: encoder.encode(options.salt)
  44. });
  45. }
  46. /**
  47. * Handles the given {@code RTCRtpReceiver} by creating a {@code TransformStream} which will inject
  48. * a frame decoder.
  49. *
  50. * @param {RTCRtpReceiver} receiver - The receiver which will get the decoding function injected.
  51. * @param {string} kind - The kind of track this receiver belongs to.
  52. * @param {string} participantId - The participant id that this receiver belongs to.
  53. */
  54. handleReceiver(receiver, kind, participantId) {
  55. if (receiver[kJitsiE2EE]) {
  56. return;
  57. }
  58. receiver[kJitsiE2EE] = true;
  59. let receiverStreams;
  60. if (receiver.createEncodedStreams) {
  61. receiverStreams = receiver.createEncodedStreams();
  62. } else {
  63. receiverStreams = kind === 'video' ? receiver.createEncodedVideoStreams()
  64. : receiver.createEncodedAudioStreams();
  65. }
  66. this._worker.postMessage({
  67. operation: 'decode',
  68. readableStream: receiverStreams.readable || receiverStreams.readableStream,
  69. writableStream: receiverStreams.writable || receiverStreams.writableStream,
  70. participantId
  71. }, [ receiverStreams.readable || receiverStreams.readableStream,
  72. receiverStreams.writable || receiverStreams.writableStream ]);
  73. }
  74. /**
  75. * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will inject
  76. * a frame encoder.
  77. *
  78. * @param {RTCRtpSender} sender - The sender which will get the encoding function injected.
  79. * @param {string} kind - The kind of track this sender belongs to.
  80. * @param {string} participantId - The participant id that this sender belongs to.
  81. */
  82. handleSender(sender, kind, participantId) {
  83. if (sender[kJitsiE2EE]) {
  84. return;
  85. }
  86. sender[kJitsiE2EE] = true;
  87. let senderStreams;
  88. if (sender.createEncodedStreams) {
  89. senderStreams = sender.createEncodedStreams();
  90. } else {
  91. senderStreams = kind === 'video' ? sender.createEncodedVideoStreams()
  92. : sender.createEncodedAudioStreams();
  93. }
  94. this._worker.postMessage({
  95. operation: 'encode',
  96. readableStream: senderStreams.readable || senderStreams.readableStream,
  97. writableStream: senderStreams.writable || senderStreams.writableStream,
  98. participantId
  99. }, [ senderStreams.readable || senderStreams.readableStream,
  100. senderStreams.writable || senderStreams.writableStream ]);
  101. }
  102. /**
  103. * Sets the key to be used for E2EE.
  104. *
  105. * @param {string} value - Value to be used as the new key. May be falsy to disable end-to-end encryption.
  106. */
  107. setKey(value) {
  108. let key;
  109. if (value) {
  110. const encoder = new TextEncoder();
  111. key = encoder.encode(value);
  112. } else {
  113. key = false;
  114. }
  115. this._worker.postMessage({
  116. operation: 'setKey',
  117. key
  118. });
  119. }
  120. }