tor-browser

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

browser_webrtc_hooks.js (10059B)


      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 const ORIGIN = "https://example.com";
      6 
      7 async function tryPeerConnection(browser, expectedError = null) {
      8  let errtype = await SpecialPowers.spawn(browser, [], async function () {
      9    let pc = new content.RTCPeerConnection();
     10    try {
     11      await pc.createOffer({ offerToReceiveAudio: true });
     12      return null;
     13    } catch (err) {
     14      return err.name;
     15    }
     16  });
     17 
     18  let detail = expectedError
     19    ? `createOffer() threw a ${expectedError}`
     20    : "createOffer() succeeded";
     21  is(errtype, expectedError, detail);
     22 }
     23 
     24 // Helper for tests that use the peer-request-allowed and -blocked events.
     25 // A test that expects some of those events does the following:
     26 //  - call Events.on() before the test to setup event handlers
     27 //  - call Events.expect(name) after a specific event is expected to have
     28 //    occured.  This will fail if the event didn't occur, and will return
     29 //    the details passed to the handler for furhter checking.
     30 //  - call Events.off() at the end of the test to clean up.  At this point, if
     31 //    any events were triggered that the test did not expect, the test fails.
     32 const Events = {
     33  events: ["peer-request-allowed", "peer-request-blocked"],
     34  details: new Map(),
     35  handlers: new Map(),
     36  on() {
     37    for (let event of this.events) {
     38      let handler = data => {
     39        if (this.details.has(event)) {
     40          ok(false, `Got multiple ${event} events`);
     41        }
     42        this.details.set(event, data);
     43      };
     44      webrtcUI.on(event, handler);
     45      this.handlers.set(event, handler);
     46    }
     47  },
     48  expect(event) {
     49    let result = this.details.get(event);
     50    isnot(result, undefined, `${event} event was triggered`);
     51    this.details.delete(event);
     52 
     53    // All events should have a good origin
     54    is(result.origin, ORIGIN, `${event} event has correct origin`);
     55 
     56    return result;
     57  },
     58  off() {
     59    for (let event of this.events) {
     60      webrtcUI.off(event, this.handlers.get(event));
     61      this.handlers.delete(event);
     62    }
     63    for (let [event] of this.details) {
     64      ok(false, `Got unexpected event ${event}`);
     65    }
     66  },
     67 };
     68 
     69 var gTests = [
     70  {
     71    desc: "Basic peer-request-allowed event",
     72    run: async function testPeerRequestEvent(browser) {
     73      Events.on();
     74 
     75      await tryPeerConnection(browser);
     76 
     77      let details = Events.expect("peer-request-allowed");
     78      isnot(
     79        details.callID,
     80        undefined,
     81        "peer-request-allowed event includes callID"
     82      );
     83      isnot(
     84        details.windowID,
     85        undefined,
     86        "peer-request-allowed event includes windowID"
     87      );
     88 
     89      Events.off();
     90    },
     91  },
     92 
     93  {
     94    desc: "Immediate peer connection blocker can allow",
     95    run: async function testBlocker(browser) {
     96      Events.on();
     97 
     98      let blockerCalled = false;
     99      let blocker = params => {
    100        is(
    101          params.origin,
    102          ORIGIN,
    103          "Peer connection blocker origin parameter is correct"
    104        );
    105        blockerCalled = true;
    106        return "allow";
    107      };
    108 
    109      webrtcUI.addPeerConnectionBlocker(blocker);
    110 
    111      await tryPeerConnection(browser);
    112      is(blockerCalled, true, "Blocker was called");
    113      Events.expect("peer-request-allowed");
    114 
    115      webrtcUI.removePeerConnectionBlocker(blocker);
    116      Events.off();
    117    },
    118  },
    119 
    120  {
    121    desc: "Deferred peer connection blocker can allow",
    122    run: async function testDeferredBlocker(browser) {
    123      Events.on();
    124 
    125      let blocker = () => Promise.resolve("allow");
    126      webrtcUI.addPeerConnectionBlocker(blocker);
    127 
    128      await tryPeerConnection(browser);
    129      Events.expect("peer-request-allowed");
    130 
    131      webrtcUI.removePeerConnectionBlocker(blocker);
    132      Events.off();
    133    },
    134  },
    135 
    136  {
    137    desc: "Immediate peer connection blocker can deny",
    138    run: async function testBlockerDeny(browser) {
    139      Events.on();
    140 
    141      let blocker = () => "deny";
    142      webrtcUI.addPeerConnectionBlocker(blocker);
    143 
    144      await tryPeerConnection(browser, "NotAllowedError");
    145 
    146      Events.expect("peer-request-blocked");
    147 
    148      webrtcUI.removePeerConnectionBlocker(blocker);
    149      Events.off();
    150    },
    151  },
    152 
    153  {
    154    desc: "Multiple blockers work (both allow)",
    155    run: async function testMultipleAllowBlockers(browser) {
    156      Events.on();
    157 
    158      let blocker1Called = false,
    159        blocker1 = () => {
    160          blocker1Called = true;
    161          return "allow";
    162        };
    163      webrtcUI.addPeerConnectionBlocker(blocker1);
    164 
    165      let blocker2Called = false,
    166        blocker2 = () => {
    167          blocker2Called = true;
    168          return "allow";
    169        };
    170      webrtcUI.addPeerConnectionBlocker(blocker2);
    171 
    172      await tryPeerConnection(browser);
    173 
    174      Events.expect("peer-request-allowed");
    175      ok(blocker1Called, "First blocker was called");
    176      ok(blocker2Called, "Second blocker was called");
    177 
    178      webrtcUI.removePeerConnectionBlocker(blocker1);
    179      webrtcUI.removePeerConnectionBlocker(blocker2);
    180      Events.off();
    181    },
    182  },
    183 
    184  {
    185    desc: "Multiple blockers work (allow then deny)",
    186    run: async function testAllowDenyBlockers(browser) {
    187      Events.on();
    188 
    189      let blocker1Called = false,
    190        blocker1 = () => {
    191          blocker1Called = true;
    192          return "allow";
    193        };
    194      webrtcUI.addPeerConnectionBlocker(blocker1);
    195 
    196      let blocker2Called = false,
    197        blocker2 = () => {
    198          blocker2Called = true;
    199          return "deny";
    200        };
    201      webrtcUI.addPeerConnectionBlocker(blocker2);
    202 
    203      await tryPeerConnection(browser, "NotAllowedError");
    204 
    205      Events.expect("peer-request-blocked");
    206      ok(blocker1Called, "First blocker was called");
    207      ok(blocker2Called, "Second blocker was called");
    208 
    209      webrtcUI.removePeerConnectionBlocker(blocker1);
    210      webrtcUI.removePeerConnectionBlocker(blocker2);
    211      Events.off();
    212    },
    213  },
    214 
    215  {
    216    desc: "Multiple blockers work (deny first)",
    217    run: async function testDenyAllowBlockers(browser) {
    218      Events.on();
    219 
    220      let blocker1Called = false,
    221        blocker1 = () => {
    222          blocker1Called = true;
    223          return "deny";
    224        };
    225      webrtcUI.addPeerConnectionBlocker(blocker1);
    226 
    227      let blocker2Called = false,
    228        blocker2 = () => {
    229          blocker2Called = true;
    230          return "allow";
    231        };
    232      webrtcUI.addPeerConnectionBlocker(blocker2);
    233 
    234      await tryPeerConnection(browser, "NotAllowedError");
    235 
    236      Events.expect("peer-request-blocked");
    237      ok(blocker1Called, "First blocker was called");
    238      ok(
    239        !blocker2Called,
    240        "Peer connection blocker after a deny is not invoked"
    241      );
    242 
    243      webrtcUI.removePeerConnectionBlocker(blocker1);
    244      webrtcUI.removePeerConnectionBlocker(blocker2);
    245      Events.off();
    246    },
    247  },
    248 
    249  {
    250    desc: "Blockers may be removed",
    251    run: async function testRemoveBlocker(browser) {
    252      Events.on();
    253 
    254      let blocker1Called = false,
    255        blocker1 = () => {
    256          blocker1Called = true;
    257          return "allow";
    258        };
    259      webrtcUI.addPeerConnectionBlocker(blocker1);
    260 
    261      let blocker2Called = false,
    262        blocker2 = () => {
    263          blocker2Called = true;
    264          return "allow";
    265        };
    266      webrtcUI.addPeerConnectionBlocker(blocker2);
    267      webrtcUI.removePeerConnectionBlocker(blocker1);
    268 
    269      await tryPeerConnection(browser);
    270 
    271      Events.expect("peer-request-allowed");
    272 
    273      ok(!blocker1Called, "Removed peer connection blocker is not invoked");
    274      ok(blocker2Called, "Second peer connection blocker was invoked");
    275 
    276      webrtcUI.removePeerConnectionBlocker(blocker2);
    277      Events.off();
    278    },
    279  },
    280 
    281  {
    282    desc: "Blocker that throws is ignored",
    283    run: async function testBlockerThrows(browser) {
    284      Events.on();
    285      let blocker1Called = false,
    286        blocker1 = () => {
    287          blocker1Called = true;
    288          throw new Error("kaboom");
    289        };
    290      webrtcUI.addPeerConnectionBlocker(blocker1);
    291 
    292      let blocker2Called = false,
    293        blocker2 = () => {
    294          blocker2Called = true;
    295          return "allow";
    296        };
    297      webrtcUI.addPeerConnectionBlocker(blocker2);
    298 
    299      await tryPeerConnection(browser);
    300 
    301      Events.expect("peer-request-allowed");
    302      ok(blocker1Called, "First blocker was invoked");
    303      ok(blocker2Called, "Second blocker was invoked");
    304 
    305      webrtcUI.removePeerConnectionBlocker(blocker1);
    306      webrtcUI.removePeerConnectionBlocker(blocker2);
    307      Events.off();
    308    },
    309  },
    310 
    311  {
    312    desc: "Cancel peer request",
    313    run: async function testBlockerCancel(browser) {
    314      let blocker,
    315        blockerPromise = new Promise(resolve => {
    316          blocker = () => {
    317            resolve();
    318            // defer indefinitely
    319            return new Promise(() => {});
    320          };
    321        });
    322      webrtcUI.addPeerConnectionBlocker(blocker);
    323 
    324      await SpecialPowers.spawn(browser, [], async function () {
    325        new content.RTCPeerConnection().createOffer({
    326          offerToReceiveAudio: true,
    327        });
    328      });
    329 
    330      await blockerPromise;
    331 
    332      let eventPromise = new Promise(resolve => {
    333        webrtcUI.on("peer-request-cancel", function listener(details) {
    334          resolve(details);
    335          webrtcUI.off("peer-request-cancel", listener);
    336        });
    337      });
    338 
    339      await SpecialPowers.spawn(browser, [], async function () {
    340        content.location.reload();
    341      });
    342 
    343      let details = await eventPromise;
    344      isnot(
    345        details.callID,
    346        undefined,
    347        "peer-request-cancel event includes callID"
    348      );
    349      is(
    350        details.origin,
    351        ORIGIN,
    352        "peer-request-cancel event has correct origin"
    353      );
    354 
    355      webrtcUI.removePeerConnectionBlocker(blocker);
    356    },
    357  },
    358 ];
    359 
    360 add_task(async function test() {
    361  await runTests(gTests, {
    362    skipObserverVerification: true,
    363    cleanup() {
    364      is(
    365        webrtcUI.peerConnectionBlockers.size,
    366        0,
    367        "Peer connection blockers list is empty"
    368      );
    369    },
    370  });
    371 });