Bug 1811836: Move devicechange rfp check from OnDeviceChange to MaybeResumeDeviceExposure where we always have window. r=tjr

Differential Revision: https://phabricator.services.mozilla.com/D222291
This commit is contained in:
Fatih 2024-09-17 15:41:27 +00:00
Родитель b1b95fe1bc
Коммит 6bf386cd12
3 изменённых файлов: 106 добавлений и 24 удалений

Просмотреть файл

@ -200,15 +200,18 @@ void MediaDevices::MaybeResumeDeviceExposure() {
return;
}
}
bool shouldResistFingerprinting =
window->AsGlobal()->ShouldResistFingerprinting(RFPTarget::MediaDevices);
MediaManager::Get()->GetPhysicalDevices()->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr(this), this,
haveDeviceListChange = mHaveUnprocessedDeviceListChange,
enumerateDevicesPromises = std::move(mPendingEnumerateDevicesPromises)](
enumerateDevicesPromises = std::move(mPendingEnumerateDevicesPromises),
shouldResistFingerprinting](
RefPtr<const MediaDeviceSetRefCnt> aAllDevices) mutable {
RefPtr<MediaDeviceSetRefCnt> exposedDevices =
FilterExposedDevices(*aAllDevices);
if (haveDeviceListChange) {
if (haveDeviceListChange && !shouldResistFingerprinting) {
if (ShouldQueueDeviceChange(*exposedDevices)) {
NS_DispatchToCurrentThread(NS_NewRunnableFunction(
"devicechange", [self = RefPtr(this), this] {
@ -762,28 +765,6 @@ void MediaDevices::OnDeviceChange() {
return;
}
// Do not fire event to content script when
// privacy.resistFingerprinting is true.
if (nsContentUtils::ShouldResistFingerprinting(
"Guarding the more expensive RFP check with a simple one",
RFPTarget::MediaDevices)) {
nsCOMPtr<nsPIDOMWindowInner> window = GetOwnerWindow();
auto* wrapper = GetWrapper();
if (!window && wrapper) {
nsCOMPtr<nsIGlobalObject> global = xpc::NativeGlobal(wrapper);
window = do_QueryInterface(global);
}
if (!window) {
return;
}
if (nsGlobalWindowInner::Cast(window)->ShouldResistFingerprinting(
RFPTarget::MediaDevices)) {
return;
}
}
mHaveUnprocessedDeviceListChange = true;
MaybeResumeDeviceExposure();
}

Просмотреть файл

@ -83,3 +83,6 @@ skip-if = ["os != 'linux'"] # the only platform with real devices
["test_setSinkId_preMutedElement.html"]
["test_unfocused_pref.html"]
["test_ondevicechange_resistfingerprinting.html"]
run-sequentially = "sets prefs that may disrupt other tests"

Просмотреть файл

@ -0,0 +1,98 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
</head>
<body>
<script type="application/javascript">
"use strict";
createHTML({
title: "ondevicechange test with privacy.resistFingerprinting",
bug: "1811836",
});
async function resolveOnEvent(target, name) {
return new Promise(r =>
target.addEventListener(name, r, { once: true })
);
}
let eventCount = 0;
async function triggerVideoDevicechange() {
++eventCount;
// "media.getusermedia.fake-camera-name" specifies the name of the single
// fake video camera.
// Changing the pref imitates replacing one device with another.
return pushPrefs([
"media.getusermedia.fake-camera-name",
`devicechange ${eventCount}`,
]);
}
runTest(async () => {
const basePrefs = [
// Use the fake video backend to trigger devicechange events.
["media.navigator.streams.fake", true],
// Loopback would override fake.
["media.video_loopback_dev", ""],
// Make fake devices count as real, permission-wise, or devicechange
// events won't be exposed
["media.navigator.permission.fake", true],
// For gUM.
["media.navigator.permission.disabled", true],
];
await withPrefs(
[
...basePrefs,
// Enable privacy.resistFingerprinting to test the prevention of
// device list changes.
["privacy.resistFingerprinting", true],
],
async () => {
const topDevices = navigator.mediaDevices;
const topEventPromise1 = resolveOnEvent(topDevices, "devicechange");
(await topDevices.getUserMedia({ video: true }))
.getTracks()[0]
.stop();
await triggerVideoDevicechange(); // Pop pref list after this.
const racer = {};
is(
await Promise.race([topEventPromise1, racer]),
racer,
"devicechange event is NOT fired in top window for replaced device when " +
"privacy.resistFingerprinting is enabled"
);
await SpecialPowers.popPrefEnv();
}
);
await withPrefs(
[
...basePrefs,
// Disable privacy.resistFingerprinting to test the exposure of device list
// changes.
["privacy.resistFingerprinting", false],
],
async () => {
const topDevices = navigator.mediaDevices;
const topEventPromise2 = resolveOnEvent(topDevices, "devicechange");
await triggerVideoDevicechange();
await topEventPromise2;
ok(
true,
"devicechange event is fired in top window for replaced device when " +
"privacy.resistFingerprinting is disabled"
);
await SpecialPowers.popPrefEnv();
}
);
});
</script>
</body>
</html>