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 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /* global __filename */
  2. import { createWorkerScript } from './Worker';
  3. import { getLogger } from 'jitsi-meet-logger';
  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. * @param {string} options.myUserId- local client id. This is the local MUC resourcepart.
  31. */
  32. constructor(options) {
  33. this._options = options;
  34. // Initialize the E2EE worker.
  35. this._worker = new Worker(createWorkerScript(), {
  36. name: 'E2EE Worker'
  37. });
  38. this._worker.onerror = e => logger.onerror(e);
  39. // Initialize the salt and convert it once.
  40. const encoder = new TextEncoder();
  41. // Send initial options to worker.
  42. this._worker.postMessage({
  43. operation: 'initialize',
  44. salt: encoder.encode(options.salt)
  45. });
  46. }
  47. /**
  48. * Handles the given {@code RTCRtpReceiver} by creating a {@code TransformStream} which will inject
  49. * a frame decoder.
  50. *
  51. * @param {RTCRtpReceiver} receiver - The receiver which will get the decoding function injected.
  52. * @param {string} kind - The kind of track this receiver belongs to.
  53. * @param {string} participantId - The (muc participant) id that this receiver belongs to.
  54. */
  55. handleReceiver(receiver, kind, participantId) {
  56. if (receiver[kJitsiE2EE]) {
  57. return;
  58. }
  59. receiver[kJitsiE2EE] = true;
  60. const receiverStreams
  61. = kind === 'video' ? receiver.createEncodedVideoStreams() : receiver.createEncodedAudioStreams();
  62. this._worker.postMessage({
  63. operation: 'decode',
  64. readableStream: receiverStreams.readableStream,
  65. writableStream: receiverStreams.writableStream,
  66. participantId
  67. }, [ receiverStreams.readableStream, receiverStreams.writableStream ]);
  68. }
  69. /**
  70. * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will inject
  71. * a frame encoder.
  72. *
  73. * @param {RTCRtpSender} sender - The sender which will get the encoding function injected.
  74. * @param {string} kind - The kind of track this sender belongs to.
  75. */
  76. handleSender(sender, kind) {
  77. if (sender[kJitsiE2EE]) {
  78. return;
  79. }
  80. sender[kJitsiE2EE] = true;
  81. const senderStreams
  82. = kind === 'video' ? sender.createEncodedVideoStreams() : sender.createEncodedAudioStreams();
  83. this._worker.postMessage({
  84. operation: 'encode',
  85. readableStream: senderStreams.readableStream,
  86. writableStream: senderStreams.writableStream,
  87. participantId: this._options.myUserId
  88. }, [ senderStreams.readableStream, senderStreams.writableStream ]);
  89. }
  90. /**
  91. * Sets the key to be used for E2EE.
  92. *
  93. * @param {string} value - Value to be used as the new key. May be falsy to disable end-to-end encryption.
  94. */
  95. setKey(value) {
  96. let key;
  97. if (value) {
  98. const encoder = new TextEncoder();
  99. key = encoder.encode(value);
  100. } else {
  101. key = false;
  102. }
  103. this._worker.postMessage({
  104. operation: 'setKey',
  105. key
  106. });
  107. }
  108. }