From 9eab67e5ca553f9f1e6665ca3217a37567eac08f Mon Sep 17 00:00:00 2001 From: daijro Date: Tue, 19 Nov 2024 00:03:41 -0600 Subject: [PATCH] feat: Media device count spoofing Spoof the amount of microphones (default is 3), cameras (1), and speakers (1) on the device. --- patches/media-device-spoofing.patch | 109 ++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 patches/media-device-spoofing.patch diff --git a/patches/media-device-spoofing.patch b/patches/media-device-spoofing.patch new file mode 100644 index 0000000..7cf66ad --- /dev/null +++ b/patches/media-device-spoofing.patch @@ -0,0 +1,109 @@ +diff --git a/dom/media/MediaDevices.cpp b/dom/media/MediaDevices.cpp +index 067094cb6b..9088f71793 100644 +--- a/dom/media/MediaDevices.cpp ++++ b/dom/media/MediaDevices.cpp +@@ -26,6 +26,7 @@ + #include "nsPIDOMWindow.h" + #include "nsGlobalWindowInner.h" + #include "nsQueryObject.h" ++#include "MaskConfig.hpp" + + namespace mozilla::dom { + +@@ -329,52 +330,52 @@ RefPtr MediaDevices::FilterExposedDevices( + exposed->AppendElement(device); + } + +- if (doc->ShouldResistFingerprinting(RFPTarget::MediaDevices)) { +- // We expose a single device of each kind. +- // Legacy mode also achieves the same thing, except for speakers. +- nsTHashSet seenKinds; ++ // Replaces the RFP-based device count spoofing with one that controls the ++ // number of devices exposed. + +- for (uint32_t i = 0; i < exposed->Length(); i++) { +- RefPtr device = exposed->ElementAt(i); +- if (seenKinds.Contains(device->mKind)) { +- exposed->RemoveElementAt(i); +- i--; +- continue; +- } +- seenKinds.Insert(device->mKind); +- } ++ if (!MaskConfig::GetBool("mediaDevices:enabled")) { ++ return exposed; ++ } + +- // We haven't seen at least one of each kind of device. +- // Audioinput, Videoinput, Audiooutput. +- // Insert fake devices. +- if (seenKinds.Count() != 3) { +- RefPtr fakeEngine = new MediaEngineFake(); +- RefPtr fakeDevices = new MediaDeviceSetRefCnt(); +- // The order in which we insert the fake devices is important. +- // Microphone is inserted first, then camera, then speaker. +- // If we haven't seen a microphone, insert a fake one. +- if (!seenKinds.Contains(MediaDeviceKind::Audioinput)) { +- fakeEngine->EnumerateDevices(MediaSourceEnum::Microphone, +- MediaSinkEnum::Other, fakeDevices); +- exposed->InsertElementAt(0, fakeDevices->LastElement()); +- } +- // If we haven't seen a camera, insert a fake one. +- if (!seenKinds.Contains(MediaDeviceKind::Videoinput)) { +- fakeEngine->EnumerateDevices(MediaSourceEnum::Camera, +- MediaSinkEnum::Other, fakeDevices); +- exposed->InsertElementAt(1, fakeDevices->LastElement()); +- } +- // If we haven't seen a speaker, insert a fake one. +- if (!seenKinds.Contains(MediaDeviceKind::Audiooutput) && +- mCanExposeMicrophoneInfo) { +- RefPtr info = new AudioDeviceInfo( +- nullptr, u""_ns, u""_ns, u""_ns, CUBEB_DEVICE_TYPE_OUTPUT, +- CUBEB_DEVICE_STATE_ENABLED, CUBEB_DEVICE_PREF_ALL, +- CUBEB_DEVICE_FMT_ALL, CUBEB_DEVICE_FMT_S16NE, 2, 44100, 44100, +- 44100, 128, 128); +- exposed->AppendElement( +- new MediaDevice(new MediaEngineFake(), info, u""_ns)); +- } ++ uint32_t numMics = MaskConfig::GetUint32("mediaDevices:micros").value_or(3); ++ uint32_t numWebcams = ++ MaskConfig::GetUint32("mediaDevices:webcams").value_or(1); ++ uint32_t numSpeakers = ++ MaskConfig::GetUint32("mediaDevices:speakers").value_or(1); ++ ++ // Clear existing devices. We'll add our own ++ exposed->Clear(); ++ ++ // We haven't seen at least one of each kind of device. ++ // Audioinput, Videoinput, Audiooutput. ++ // Insert fake devices. ++ RefPtr fakeEngine = new MediaEngineFake(); ++ RefPtr fakeDevices = new MediaDeviceSetRefCnt(); ++ // The order in which we insert the fake devices is important. ++ // Microphone is inserted first, then camera, then speaker ++ ++ // Insert fake microphones ++ for (uint32_t i = 0; i < numMics; ++i) { ++ fakeEngine->EnumerateDevices(MediaSourceEnum::Microphone, ++ MediaSinkEnum::Other, fakeDevices); ++ exposed->InsertElementAt(0, fakeDevices->LastElement()); ++ } ++ // Insert fake cameras ++ for (uint32_t i = 0; i < numWebcams; ++i) { ++ fakeEngine->EnumerateDevices(MediaSourceEnum::Camera, MediaSinkEnum::Other, ++ fakeDevices); ++ exposed->InsertElementAt(1, fakeDevices->LastElement()); ++ } ++ // Insert fake speakers (this is only accessed if the site has permission) ++ if (mCanExposeMicrophoneInfo) { ++ for (uint32_t i = 0; i < numSpeakers; ++i) { ++ RefPtr info = new AudioDeviceInfo( ++ nullptr, u""_ns, u""_ns, u""_ns, CUBEB_DEVICE_TYPE_OUTPUT, ++ CUBEB_DEVICE_STATE_ENABLED, CUBEB_DEVICE_PREF_ALL, ++ CUBEB_DEVICE_FMT_ALL, CUBEB_DEVICE_FMT_S16NE, 2, 44100, 44100, 44100, ++ 128, 128); ++ exposed->AppendElement( ++ new MediaDevice(new MediaEngineFake(), info, u""_ns)); + } + } +