tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

bug1913599-shim-createencodedstreams.js (3625B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 /**
      8 * Bug 1913599 - Sites that depend on legacy createEncodedStreams()
      9 *
     10 * Several websites that offer end-to-end encrypted communication in
     11 * Chrome fail to work in Firefox, either ghosting the button that
     12 * offers this feature or erroring with a message like "Voice/Video
     13 * calling is not supported on this browser".
     14 *
     15 * These webpages rely on the older Chrome-only createEncodedStreams()
     16 * API instead of the standard RTCRtpScriptTransform API now available
     17 * in all browsers. The following shims the former using the latter.
     18 *
     19 * Note: this shim has inherent performance limitations being on
     20 * main thread. Websites are encouraged to upgrade to the standard
     21 * worker-based API directly for optimal performance in Firefox.
     22 */
     23 
     24 /* globals exportFunction, cloneInto */
     25 
     26 console.info(
     27  "createEncodedStreams() is being shimmed for compatibility reasons. Please consider updating to the RTCRtpScriptTransform API for optimal performance! See https://bugzil.la/1913599 for details."
     28 );
     29 
     30 const win = window.wrappedJSObject;
     31 if (!win.RTCRtpSender.prototype.createEncodedStreams) {
     32  win.RTCRtpSender.prototype.createEncodedStreams =
     33    win.RTCRtpReceiver.prototype.createEncodedStreams = exportFunction(
     34      function createEncodedStreams() {
     35        let onrtctransform; // appease linter
     36        function work() {
     37          const originals = [];
     38          onrtctransform = async ({ transformer: { readable, writable } }) => {
     39            const diverter = new TransformStream({
     40              transform: (original, controller) => {
     41                originals.push(original);
     42                controller.enqueue(original);
     43              },
     44            });
     45            const reinserter = new TransformStream({
     46              transform: (frame, controller) => {
     47                const original = originals.shift();
     48                original.data = frame.data;
     49                controller.enqueue(original);
     50              },
     51            });
     52            self.postMessage(
     53              { readable: diverter.readable, writable: reinserter.writable },
     54              { transfer: [diverter.readable, reinserter.writable] }
     55            );
     56            await readable
     57              .pipeThrough({
     58                writable: diverter.writable,
     59                readable: reinserter.readable,
     60              })
     61              .pipeTo(writable);
     62          };
     63        }
     64        this._worker = new Worker(
     65          `data:text/javascript,(${work.toString()})()`
     66        );
     67        this.transform = new window.RTCRtpScriptTransform(this._worker);
     68        this._dummy = onrtctransform; // appease linter
     69        const readableNow = new TransformStream();
     70        const writableNow = new TransformStream();
     71        const haveData = new Promise(
     72          r => (this._worker.onmessage = e => r(e.data))
     73        );
     74        haveData
     75          .then(({ readable }) => readable.pipeTo(readableNow.writable))
     76          .catch(e => readableNow.writable.abort(e));
     77        haveData
     78          .then(({ writable }) => writableNow.readable.pipeTo(writable))
     79          .catch(e => writableNow.readable.cancel(e));
     80 
     81        const result = new win.Object();
     82        result.readable = cloneInto(readableNow.readable, window, {
     83          wrapReflectors: true,
     84        });
     85        result.writable = cloneInto(writableNow.writable, window, {
     86          wrapReflectors: true,
     87        });
     88        return result;
     89      },
     90      window
     91    );
     92 }