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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  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. */
  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 injecct
  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. */
  53. handleReceiver(receiver, kind) {
  54. if (receiver[kJitsiE2EE]) {
  55. return;
  56. }
  57. receiver[kJitsiE2EE] = true;
  58. const receiverStreams
  59. = kind === 'video' ? receiver.createEncodedVideoStreams() : receiver.createEncodedAudioStreams();
  60. this._worker.postMessage({
  61. operation: 'decode',
  62. readableStream: receiverStreams.readableStream,
  63. writableStream: receiverStreams.writableStream
  64. }, [ receiverStreams.readableStream, receiverStreams.writableStream ]);
  65. }
  66. /**
  67. * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will injecct
  68. * a frame encoder.
  69. *
  70. * @param {RTCRtpSender} sender - The sender which will get the encoding funcction injected.
  71. * @param {string} kind - The kind of track this sender belongs to.
  72. */
  73. handleSender(sender, kind) {
  74. if (sender[kJitsiE2EE]) {
  75. return;
  76. }
  77. sender[kJitsiE2EE] = true;
  78. const senderStreams
  79. = kind === 'video' ? sender.createEncodedVideoStreams() : sender.createEncodedAudioStreams();
  80. this._worker.postMessage({
  81. operation: 'encode',
  82. readableStream: senderStreams.readableStream,
  83. writableStream: senderStreams.writableStream
  84. }, [ senderStreams.readableStream, senderStreams.writableStream ]);
  85. }
  86. /**
  87. * Sets the key to be used for E2EE.
  88. *
  89. * @param {string} value - Value to be used as the new key. May be falsy to disable end-to-end encryption.
  90. */
  91. setKey(value) {
  92. let key;
  93. if (value) {
  94. const encoder = new TextEncoder();
  95. key = encoder.encode(value);
  96. } else {
  97. key = false;
  98. }
  99. this._worker.postMessage({
  100. operation: 'setKey',
  101. key
  102. });
  103. }
  104. }