зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1548087 - enumerateDevices should only expose devices which are allowed to use by FeturePolicy r=baku,jib
Differential Revision: https://phabricator.services.mozilla.com/D42958 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
b21cdcbc87
Коммит
6945142351
|
@ -3161,8 +3161,10 @@ RefPtr<MediaManager::DevicesPromise> MediaManager::EnumerateDevices(
|
|||
__func__);
|
||||
}
|
||||
uint64_t windowId = aWindow->WindowID();
|
||||
Document* doc = aWindow->GetExtantDoc();
|
||||
MOZ_ASSERT(doc);
|
||||
|
||||
nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
|
||||
nsIPrincipal* principal = doc->NodePrincipal();
|
||||
|
||||
RefPtr<GetUserMediaWindowListener> windowListener =
|
||||
GetWindowListener(windowId);
|
||||
|
@ -3183,8 +3185,30 @@ RefPtr<MediaManager::DevicesPromise> MediaManager::EnumerateDevices(
|
|||
|
||||
DeviceEnumerationType videoEnumerationType = DeviceEnumerationType::Normal;
|
||||
DeviceEnumerationType audioEnumerationType = DeviceEnumerationType::Normal;
|
||||
bool resistFingerprinting = nsContentUtils::ResistFingerprinting(aCallerType);
|
||||
|
||||
// Only expose devices which are allowed to use:
|
||||
// https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices
|
||||
MediaSourceEnum videoType = dom::FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("camera"))
|
||||
? MediaSourceEnum::Camera
|
||||
: MediaSourceEnum::Other;
|
||||
MediaSourceEnum audioType = dom::FeaturePolicyUtils::IsFeatureAllowed(
|
||||
doc, NS_LITERAL_STRING("microphone"))
|
||||
? MediaSourceEnum::Microphone
|
||||
: MediaSourceEnum::Other;
|
||||
|
||||
auto devices = MakeRefPtr<MediaDeviceSetRefCnt>();
|
||||
MediaSinkEnum audioOutputType = MediaSinkEnum::Other;
|
||||
// TODO bug Bug 1577199 we don't seem to support the "speaker" feature policy
|
||||
// yet.
|
||||
if (Preferences::GetBool("media.setsinkid.enabled")) {
|
||||
audioOutputType = MediaSinkEnum::Speaker;
|
||||
} else if (audioType == MediaSourceEnum::Other &&
|
||||
videoType == MediaSourceEnum::Other) {
|
||||
return DevicesPromise::CreateAndResolve(devices, __func__);
|
||||
}
|
||||
|
||||
bool resistFingerprinting = nsContentUtils::ResistFingerprinting(aCallerType);
|
||||
// In order of precedence: resist fingerprinting > loopback > fake pref
|
||||
if (resistFingerprinting) {
|
||||
videoEnumerationType = DeviceEnumerationType::Fake;
|
||||
|
@ -3194,30 +3218,29 @@ RefPtr<MediaManager::DevicesPromise> MediaManager::EnumerateDevices(
|
|||
nsAutoCString videoLoopDev, audioLoopDev;
|
||||
bool wantFakes = Preferences::GetBool("media.navigator.streams.fake");
|
||||
// Video
|
||||
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
|
||||
// Loopback prefs take precedence over fake prefs
|
||||
if (!videoLoopDev.IsEmpty()) {
|
||||
videoEnumerationType = DeviceEnumerationType::Loopback;
|
||||
} else if (wantFakes) {
|
||||
videoEnumerationType = DeviceEnumerationType::Fake;
|
||||
if (videoType == MediaSourceEnum::Camera) {
|
||||
Preferences::GetCString("media.video_loopback_dev", videoLoopDev);
|
||||
// Loopback prefs take precedence over fake prefs
|
||||
if (!videoLoopDev.IsEmpty()) {
|
||||
videoEnumerationType = DeviceEnumerationType::Loopback;
|
||||
} else if (wantFakes) {
|
||||
videoEnumerationType = DeviceEnumerationType::Fake;
|
||||
}
|
||||
}
|
||||
|
||||
// Audio
|
||||
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
|
||||
// Loopback prefs take precedence over fake prefs
|
||||
if (!audioLoopDev.IsEmpty()) {
|
||||
audioEnumerationType = DeviceEnumerationType::Loopback;
|
||||
} else if (wantFakes) {
|
||||
audioEnumerationType = DeviceEnumerationType::Fake;
|
||||
if (audioType == MediaSourceEnum::Microphone) {
|
||||
Preferences::GetCString("media.audio_loopback_dev", audioLoopDev);
|
||||
// Loopback prefs take precedence over fake prefs
|
||||
if (!audioLoopDev.IsEmpty()) {
|
||||
audioEnumerationType = DeviceEnumerationType::Loopback;
|
||||
} else if (wantFakes) {
|
||||
audioEnumerationType = DeviceEnumerationType::Fake;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MediaSinkEnum audioOutputType = MediaSinkEnum::Other;
|
||||
if (Preferences::GetBool("media.setsinkid.enabled")) {
|
||||
audioOutputType = MediaSinkEnum::Speaker;
|
||||
}
|
||||
auto devices = MakeRefPtr<MediaDeviceSetRefCnt>();
|
||||
return EnumerateDevicesImpl(windowId, MediaSourceEnum::Camera,
|
||||
MediaSourceEnum::Microphone, audioOutputType,
|
||||
return EnumerateDevicesImpl(windowId, videoType, audioType, audioOutputType,
|
||||
videoEnumerationType, audioEnumerationType, false,
|
||||
devices)
|
||||
->Then(
|
||||
|
|
|
@ -106,7 +106,9 @@ runTest(async () => {
|
|||
let [sameOriginDevices, differentOriginDevices] = origins.map(o => devicesMap.get(o));
|
||||
|
||||
is(sameOriginDevices.length, devices.length);
|
||||
is(differentOriginDevices.length, devices.length);
|
||||
// Camera and microphone are allowed for documents that are same-origin by
|
||||
// default.
|
||||
is(differentOriginDevices.length, 0);
|
||||
[...sameOriginDevices, ...differentOriginDevices].forEach(d => validateDevice(d));
|
||||
|
||||
for (let device of sameOriginDevices) {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>enumerateDevices: test enumerateDevices should not expose camera devices if they are not allowed to use</title>
|
||||
<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices">
|
||||
<meta name='assert' content='Check that the enumerateDevices() method should not exposed camera devices.'/>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="instructions">Description</h1>
|
||||
<p class="instructions">This test checks for the presence of camera in
|
||||
<code>navigator.mediaDevices.enumerateDevices()</code> method.</p>
|
||||
<div id='log'></div>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
"use strict";
|
||||
promise_test(async () => {
|
||||
assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists");
|
||||
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const mediaInfo of deviceList) {
|
||||
assert_not_equals(mediaInfo.deviceId, undefined, "mediaInfo's deviceId should exist.");
|
||||
assert_not_equals(mediaInfo.kind, undefined, "mediaInfo's kind should exist.");
|
||||
assert_not_equals(mediaInfo.label, undefined, "mediaInfo's label should exist.");
|
||||
assert_not_equals(mediaInfo.groupId, undefined, "mediaInfo's groupId should exist.");
|
||||
assert_in_array(mediaInfo.kind, ["audioinput", "audiooutput"]);
|
||||
}
|
||||
}, "Camera is not exposed in mediaDevices.enumerateDevices()");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
Feature-Policy: camera 'none'
|
|
@ -0,0 +1,30 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>enumerateDevices: test enumerateDevices should not expose microphone devices if they are not allowed to use</title>
|
||||
<link rel="help" href="https://w3c.github.io/mediacapture-main/#dom-mediadevices-enumeratedevices">
|
||||
<meta name='assert' content='Check that the enumerateDevices() method should not exposed microphone devices.'/>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="instructions">Description</h1>
|
||||
<p class="instructions">This test checks for the presence of microphone in
|
||||
<code>navigator.mediaDevices.enumerateDevices()</code> method.</p>
|
||||
<div id='log'></div>
|
||||
<script src=/resources/testharness.js></script>
|
||||
<script src=/resources/testharnessreport.js></script>
|
||||
<script>
|
||||
"use strict";
|
||||
promise_test(async () => {
|
||||
assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists");
|
||||
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const mediaInfo of deviceList) {
|
||||
assert_not_equals(mediaInfo.deviceId, undefined, "mediaInfo's deviceId should exist.");
|
||||
assert_not_equals(mediaInfo.kind, undefined, "mediaInfo's kind should exist.");
|
||||
assert_not_equals(mediaInfo.label, undefined, "mediaInfo's label should exist.");
|
||||
assert_not_equals(mediaInfo.groupId, undefined, "mediaInfo's groupId should exist.");
|
||||
assert_in_array(mediaInfo.kind, ["videoinput", "audiooutput"]);
|
||||
}
|
||||
}, "Microphone is not exposed in mediaDevices.enumerateDevices()");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1 @@
|
|||
Feature-Policy: microphone 'none'
|
|
@ -17,26 +17,26 @@
|
|||
"use strict";
|
||||
//NOTE ALEX: for completion, a test for ondevicechange event is missing.
|
||||
promise_test(async () => {
|
||||
assert_true(undefined !== navigator.mediaDevices.enumerateDevices, "navigator.mediaDevices.enumerateDevices exists");
|
||||
const device_list = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const mediainfo of device_list) {
|
||||
assert_true(undefined !== mediainfo.deviceId, "mediaInfo's deviceId should exist.");
|
||||
assert_true(undefined !== mediainfo.kind, "mediaInfo's kind should exist.");
|
||||
assert_in_array(mediainfo.kind, ["videoinput", "audioinput", "audiooutput"]);
|
||||
assert_true(undefined !== mediainfo.label, "mediaInfo's label should exist.");
|
||||
assert_true(undefined !== mediainfo.groupId, "mediaInfo's groupId should exist.");
|
||||
assert_not_equals(navigator.mediaDevices.enumerateDevices, undefined, "navigator.mediaDevices.enumerateDevices exists");
|
||||
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const mediaInfo of deviceList) {
|
||||
assert_not_equals(mediaInfo.deviceId, undefined, "mediaInfo's deviceId should exist.");
|
||||
assert_not_equals(mediaInfo.kind, undefined, "mediaInfo's kind should exist.");
|
||||
assert_not_equals(mediaInfo.label, undefined, "mediaInfo's label should exist.");
|
||||
assert_not_equals(mediaInfo.groupId, undefined, "mediaInfo's groupId should exist.");
|
||||
assert_in_array(mediaInfo.kind, ["videoinput", "audioinput", "audiooutput"]);
|
||||
}
|
||||
}, "mediaDevices.enumerateDevices() is present and working");
|
||||
|
||||
promise_test(async () => {
|
||||
const device_list = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const mediainfo of device_list) {
|
||||
if (mediainfo.kind == "audioinput" || mediainfo.kind == "videoinput") {
|
||||
assert_true(mediainfo instanceof InputDeviceInfo);
|
||||
} else if ( mediainfo.kind == "audiooutput" ) {
|
||||
assert_true(mediainfo instanceof MediaDeviceInfo);
|
||||
const deviceList = await navigator.mediaDevices.enumerateDevices();
|
||||
for (const mediaInfo of deviceList) {
|
||||
if (mediaInfo.kind == "audioinput" || mediaInfo.kind == "videoinput") {
|
||||
assert_true(mediaInfo instanceof InputDeviceInfo);
|
||||
} else if ( mediaInfo.kind == "audiooutput" ) {
|
||||
assert_true(mediaInfo instanceof MediaDeviceInfo);
|
||||
} else {
|
||||
assert_unreached("mediainfo.kind should be one of 'audioinput', 'videoinput', or 'audiooutput'.")
|
||||
assert_unreached("mediaInfo.kind should be one of 'audioinput', 'videoinput', or 'audiooutput'.")
|
||||
}
|
||||
}
|
||||
}, "InputDeviceInfo is supported");
|
||||
|
|
Загрузка…
Ссылка в новой задаче