test_fingerprinting_resistance.html (3658B)
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="utf-8"> 5 <script src="mediaStreamPlayback.js"></script> 6 </head> 7 <body> 8 <script> 9 /* global SimpleTest SpecialPowers */ 10 11 async function testEnumerateDevices(header, 12 expectedCameras, 13 expectedMicrophones, 14 expectedSpeakers) { 15 const devices = await navigator.mediaDevices.enumerateDevices(); 16 const cams = devices.filter(({kind}) => kind == "videoinput"); 17 const mics = devices.filter(({kind}) => kind == "audioinput"); 18 const spkr = devices.filter(({kind}) => kind == "audiooutput"); 19 20 SimpleTest.is(cams.length, expectedCameras, `${header}: cameras`); 21 SimpleTest.is(mics.length, expectedMicrophones, `${header}: microphones`); 22 if (expectedSpeakers !== undefined) { 23 SimpleTest.is(spkr.length, expectedSpeakers, `${header}: speakers`); 24 } 25 } 26 27 async function testGetUserMedia(expectDevices) { 28 const constraints = [ 29 {audio: true}, 30 {video: true}, 31 {audio: true, video: true}, 32 {video: {width: {min: 1e9}}}, // impossible 33 {audio: {channelCount: {exact: 1e3}}}, // impossible 34 ]; 35 for (let constraint of constraints) { 36 let message = "getUserMedia(" + JSON.stringify(constraint) + ")"; 37 try { 38 let stream = await navigator.mediaDevices.getUserMedia(constraint); 39 SimpleTest.ok(expectDevices, message + " resolved"); 40 if (!expectDevices) { 41 continue; 42 } 43 44 // We only do testGetUserMedia(true) when privacy.resistFingerprinting 45 // is true, test if MediaStreamTrack.label is spoofed. 46 for (let track of stream.getTracks()) { 47 switch (track.kind) { 48 case "audio": 49 SimpleTest.is(track.label, "Internal Microphone", "AudioStreamTrack.label"); 50 break; 51 case "video": 52 SimpleTest.is(track.label, "Internal Camera", "VideoStreamTrack.label"); 53 break; 54 default: 55 SimpleTest.ok(false, "Unknown kind: " + track.kind); 56 break; 57 } 58 track.stop(); 59 } 60 } catch (e) { 61 if (!expectDevices) { 62 SimpleTest.is(e.name, "NotAllowedError", message + " throws NotAllowedError"); 63 } else { 64 SimpleTest.ok(false, message + " failed: " + e); 65 } 66 } 67 } 68 } 69 70 async function testPreGum() { 71 await SpecialPowers.pushPrefEnv({ 72 set: [ 73 ["privacy.resistFingerprinting", true], 74 ["media.navigator.streams.fake", true] 75 ] 76 }); 77 await testEnumerateDevices("testPreGum w/resist", 1, 1, 0); 78 await testGetUserMedia(true); // should get audio and video streams 79 } 80 81 async function testNoDevices() { 82 await SpecialPowers.pushPrefEnv({ 83 set: [ 84 ["privacy.resistFingerprinting", false], 85 ["media.navigator.permission.device", false], 86 ["media.navigator.streams.fake", false], 87 ["media.audio_loopback_dev", "foo"], 88 ["media.video_loopback_dev", "bar"] 89 ] 90 }); 91 await testEnumerateDevices("testNoDevices wo/resist", 0, 0); 92 await SpecialPowers.pushPrefEnv({ 93 set: [ 94 ["privacy.resistFingerprinting", true] 95 ] 96 }); 97 await testEnumerateDevices("testNoDevices w/resist", 1, 1, 1); 98 await testGetUserMedia(false); // should reject with NotAllowedError 99 } 100 101 createHTML({ 102 title: "Neutralize the threat of fingerprinting of media devices API when 'privacy.resistFingerprinting' is true", 103 bug: "1372073" 104 }); 105 106 runTest(async () => { 107 // Make sure enumerateDevices and getUserMedia work when 108 // privacy.resistFingerprinting is true. 109 await testPreGum(); 110 111 // Test that absence of devices can't be detected. 112 await testNoDevices(); 113 }); 114 </script> 115 </body> 116 </html>