Bug 1372073 - Add tests for Media Capture and Streams fingerprinting resistance. draft
authorChung-Sheng Fu <cfu@mozilla.com>
Tue, 19 Sep 2017 15:12:52 +0800
changeset 696991 8ce8c703070ac55cf51e3a2a95315b4878f8af11
parent 696990 58cc1c803cde15f7fbe7a9106916dd83c1eacdfa
child 739982 33671291d27818fdaa125234d987023c8d781c83
push id88850
push userbmo:cfu@mozilla.com
push dateMon, 13 Nov 2017 06:48:26 +0000
bugs1372073
milestone59.0a1
Bug 1372073 - Add tests for Media Capture and Streams fingerprinting resistance. MozReview-Commit-ID: DY9JpwJevkS
dom/media/tests/mochitest/mochitest.ini
dom/media/tests/mochitest/test_fingerprinting_resistance.html
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -301,8 +301,9 @@ skip-if = (android_version == '18') # an
 # Bug 1227781: Crash with bogus TURN server.
 [test_peerConnection_bug1227781.html]
 [test_peerConnection_stats.html]
 skip-if = toolkit == 'android' # android(Bug 1189784, timeouts on 4.3 emulator, Bug 1373858)
 [test_peerConnection_sender_and_receiver_stats.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_verifyDescriptions.html]
 skip-if = (android_version == '18')
+[test_fingerprinting_resistance.html]
new file mode 100644
--- /dev/null
+++ b/dom/media/tests/mochitest/test_fingerprinting_resistance.html
@@ -0,0 +1,107 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<script src="mediaStreamPlayback.js"></script>
+</head>
+<body>
+<script>
+/* global SimpleTest SpecialPowers */
+
+async function testEnumerateDevices(expectDevices) {
+  let devices = await navigator.mediaDevices.enumerateDevices();
+  if (!expectDevices) {
+    SimpleTest.is(devices.length, 0, "testEnumerateDevices: No devices");
+    return;
+  }
+  let cams = devices.filter((device) => device.kind == "videoinput");
+  let mics = devices.filter((device) => device.kind == "audioinput");
+  SimpleTest.ok((cams.length == 1) && (mics.length == 1),
+                "testEnumerateDevices: a microphone and a camera");
+}
+
+async function testGetUserMedia(expectDevices) {
+  const constraints = [
+    {audio: true}, {video: true}, {audio: true, video: true}
+  ];
+  for (let constraint of constraints) {
+    let message = "getUserMedia(" + JSON.stringify(constraint) + ")";
+    try {
+      let stream = await navigator.mediaDevices.getUserMedia(constraint);
+      SimpleTest.ok(expectDevices, message + " resolved");
+      if (!expectDevices) {
+        continue;
+      }
+
+      // We only do testGetUserMedia(true) when privacy.resistFingerprinting
+      // is true, test if MediaStreamTrack.label is spoofed.
+      for (let track of stream.getTracks()) {
+        switch (track.kind) {
+          case "audio":
+            SimpleTest.is(track.label, "Internal Microphone", "AudioStreamTrack.label");
+            break;
+          case "video":
+            SimpleTest.is(track.label, "Internal Camera", "VideoStreamTrack.label");
+            break;
+          default:
+            SimpleTest.ok(false, "Unknown kind: " + track.kind);
+            break;
+        }
+        track.stop();
+      }
+    } catch (e) {
+      if (!expectDevices) {
+        SimpleTest.is(e.name, "NotAllowedError", message + " throws NotAllowedError");
+      } else {
+        SimpleTest.ok(false, message + " failed: " + e);
+      }
+    }
+  }
+}
+
+async function testDevices() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["privacy.resistFingerprinting", true],
+      ["media.navigator.streams.fake", true]
+    ]
+  });
+  await testEnumerateDevices(true); // should list a microphone and a camera
+  await testGetUserMedia(true); // should get audio and video streams
+}
+
+async function testNoDevices() {
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["privacy.resistFingerprinting", false],
+      ["media.navigator.streams.fake", false],
+      ["media.audio_loopback_dev", "foo"],
+      ["media.video_loopback_dev", "bar"]
+    ]
+  });
+  await testEnumerateDevices(false); // should list nothing
+  await SpecialPowers.pushPrefEnv({
+    set: [
+      ["privacy.resistFingerprinting", true]
+    ]
+  });
+  await testEnumerateDevices(true); // should list a microphone and a camera
+  await testGetUserMedia(false); // should reject with NotAllowedError
+}
+
+createHTML({
+  title: "Neutralize the threat of fingerprinting of media devices API when 'privacy.resistFingerprinting' is true",
+  bug: "1372073"
+});
+
+runTest(async () => {
+  // Make sure enumerateDevices and getUserMedia work when
+  // privacy.resistFingerprinting is true.
+  await testDevices();
+
+  // Test that absence of devices can't be detected.
+  await testNoDevices();
+});
+</script>
+</body>
+</html>