123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- /* global __filename, RTCRtpScriptTransform */
-
- import { getLogger } from '@jitsi/logger';
-
- const logger = getLogger(__filename);
-
- // Flag to set on senders / receivers to avoid setting up the encryption transform
- // more than once.
- const kJitsiE2EE = Symbol('kJitsiE2EE');
-
- /**
- * Context encapsulating the cryptography bits required for E2EE.
- * This uses the WebRTC Insertable Streams API which is explained in
- * https://github.com/alvestrand/webrtc-media-streams/blob/master/explainer.md
- * that provides access to the encoded frames and allows them to be transformed.
- *
- * The encoded frame format is explained below in the _encodeFunction method.
- * High level design goals were:
- * - do not require changes to existing SFUs and retain (VP8) metadata.
- * - allow the SFU to rewrite SSRCs, timestamp, pictureId.
- * - allow for the key to be rotated frequently.
- */
- export default class E2EEcontext {
- /**
- * Build a new E2EE context instance, which will be used in a given conference.
- * @param {boolean} [options.sharedKey] - whether there is a uniques key shared amoung all participants.
- */
- constructor({ sharedKey } = {}) {
- // Determine the URL for the worker script. Relative URLs are relative to
- // the entry point, not the script that launches the worker.
- let baseUrl = '';
- const ljm = document.querySelector('script[src*="lib-jitsi-meet"]');
-
- if (ljm) {
- const idx = ljm.src.lastIndexOf('/');
-
- baseUrl = `${ljm.src.substring(0, idx)}/`;
- }
-
- let workerUrl = `${baseUrl}lib-jitsi-meet.e2ee-worker.js`;
-
- // If there is no baseUrl then we create the worker in a normal way
- // as you cant load scripts inside blobs from relative paths.
- // See: https://www.html5rocks.com/en/tutorials/workers/basics/#toc-inlineworkers-loadingscripts
- if (baseUrl && baseUrl !== '/') {
- // Initialize the E2EE worker. In order to avoid CORS issues, start the worker and have it
- // synchronously load the JS.
- const workerBlob
- = new Blob([ `importScripts("${workerUrl}");` ], { type: 'application/javascript' });
-
- workerUrl = window.URL.createObjectURL(workerBlob);
- }
-
- this._worker = new Worker(workerUrl, { name: 'E2EE Worker' });
-
- this._worker.onerror = e => logger.error(e);
-
- this._worker.postMessage({
- operation: 'initialize',
- sharedKey
- });
- }
-
- /**
- * Cleans up all state associated with the given participant. This is needed when a
- * participant leaves the current conference.
- *
- * @param {string} participantId - The participant that just left.
- */
- cleanup(participantId) {
- this._worker.postMessage({
- operation: 'cleanup',
- participantId
- });
- }
-
- /**
- * Cleans up all state associated with all participants in the conference. This is needed when disabling e2ee.
- *
- */
- cleanupAll() {
- this._worker.postMessage({
- operation: 'cleanupAll'
- });
- }
-
- /**
- * Handles the given {@code RTCRtpReceiver} by creating a {@code TransformStream} which will inject
- * a frame decoder.
- *
- * @param {RTCRtpReceiver} receiver - The receiver which will get the decoding function injected.
- * @param {string} kind - The kind of track this receiver belongs to.
- * @param {string} participantId - The participant id that this receiver belongs to.
- */
- handleReceiver(receiver, kind, participantId) {
- if (receiver[kJitsiE2EE]) {
- return;
- }
- receiver[kJitsiE2EE] = true;
-
- if (window.RTCRtpScriptTransform) {
- const options = {
- operation: 'decode',
- participantId
- };
-
- receiver.transform = new RTCRtpScriptTransform(this._worker, options);
- } else {
- const receiverStreams = receiver.createEncodedStreams();
-
- this._worker.postMessage({
- operation: 'decode',
- readableStream: receiverStreams.readable,
- writableStream: receiverStreams.writable,
- participantId
- }, [ receiverStreams.readable, receiverStreams.writable ]);
- }
- }
-
- /**
- * Handles the given {@code RTCRtpSender} by creating a {@code TransformStream} which will inject
- * a frame encoder.
- *
- * @param {RTCRtpSender} sender - The sender which will get the encoding function injected.
- * @param {string} kind - The kind of track this sender belongs to.
- * @param {string} participantId - The participant id that this sender belongs to.
- */
- handleSender(sender, kind, participantId) {
- if (sender[kJitsiE2EE]) {
- return;
- }
- sender[kJitsiE2EE] = true;
-
- if (window.RTCRtpScriptTransform) {
- const options = {
- operation: 'encode',
- participantId
- };
-
- sender.transform = new RTCRtpScriptTransform(this._worker, options);
- } else {
- const senderStreams = sender.createEncodedStreams();
-
- this._worker.postMessage({
- operation: 'encode',
- readableStream: senderStreams.readable,
- writableStream: senderStreams.writable,
- participantId
- }, [ senderStreams.readable, senderStreams.writable ]);
- }
- }
-
- /**
- * Set the E2EE key for the specified participant.
- *
- * @param {string} participantId - the ID of the participant who's key we are setting.
- * @param {Uint8Array | boolean} key - they key for the given participant.
- * @param {Number} keyIndex - the key index.
- */
- setKey(participantId, key, keyIndex) {
- this._worker.postMessage({
- operation: 'setKey',
- key,
- keyIndex,
- participantId
- });
- }
- }
|