tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 50c5bd85257cf1f48a8e510ce2a5fc0174192652
parent 2b786cc8069b9ee137c2fdc4583c634ccaa0ed79
Author: agoloman <agoloman@mozilla.com>
Date:   Tue, 21 Oct 2025 03:20:40 +0300

Revert (Bug 1987929, Bug 1991701) - for causing perma failures @test_pointer_event.html.

This reverts commit 35055c39b060b8014a4dd74b2e97acdf2abd46ac.

Revert "Bug 1991701 - Re-enable touch on Linux with RFP and remove RFPTarget::PointerId. r=tjr,layout-reviewers,emilio"

This reverts commit 00f1baf7d5af86271b093ae8f9df906d941bbe53.

Diffstat:
Mdom/base/Element.cpp | 10++++++++++
Mdom/events/PointerEvent.cpp | 150+++++++++++++++++++++++++++-----------------------------------------------------
Mdom/events/PointerEvent.h | 30++++++++++++------------------
Mdom/events/PointerEventHandler.cpp | 26++++++++++++++++++++++++++
Mdom/events/TouchEvent.cpp | 46++++++++++++++++++++++------------------------
Mdom/webidl/PointerEvent.webidl | 11-----------
Mlayout/base/PositionedEventTargeting.cpp | 5+++--
Mtoolkit/components/resistfingerprinting/RFPTargets.inc | 3+--
Mtoolkit/components/resistfingerprinting/nsRFPService.cpp | 7+++++++
Mwidget/WidgetEventImpl.cpp | 17+++++++++++++++++
10 files changed, 148 insertions(+), 157 deletions(-)

diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp @@ -305,6 +305,11 @@ nsDOMAttributeMap* Element::Attributes() { } void Element::SetPointerCapture(int32_t aPointerId, ErrorResult& aError) { + if (OwnerDoc()->ShouldResistFingerprinting(RFPTarget::PointerId) && + aPointerId != PointerEventHandler::GetSpoofedPointerIdForRFP()) { + aError.ThrowNotFoundError("Invalid pointer id"); + return; + } const PointerInfo* pointerInfo = PointerEventHandler::GetPointerInfo(aPointerId); if (!pointerInfo) { @@ -331,6 +336,11 @@ void Element::SetPointerCapture(int32_t aPointerId, ErrorResult& aError) { } void Element::ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError) { + if (OwnerDoc()->ShouldResistFingerprinting(RFPTarget::PointerId) && + aPointerId != PointerEventHandler::GetSpoofedPointerIdForRFP()) { + aError.ThrowNotFoundError("Invalid pointer id"); + return; + } if (!PointerEventHandler::GetPointerInfo(aPointerId)) { aError.ThrowNotFoundError("Invalid pointer id"); return; diff --git a/dom/events/PointerEvent.cpp b/dom/events/PointerEvent.cpp @@ -227,78 +227,39 @@ NS_INTERFACE_MAP_END_INHERITING(MouseEvent) NS_IMPL_ADDREF_INHERITED(PointerEvent, MouseEvent) NS_IMPL_RELEASE_INHERITED(PointerEvent, MouseEvent) -uint16_t PointerEvent::ResistantInputSource(CallerType aCallerType) const { - const uint16_t inputSource = mEvent->AsPointerEvent()->mInputSource; - if (!ShouldResistFingerprinting(aCallerType)) { - return inputSource; - } - - MOZ_ASSERT(IsTrusted()); - - // Bug 1953665: Pen events are inconsistent between platforms. - // They might emit touch events on Windows and Android, but only mouse events - // in other platforms. In particular, touch is always disabled on macOS. -#if defined(XP_WIN) - if (inputSource == MouseEvent_Binding::MOZ_SOURCE_TOUCH || - inputSource == MouseEvent_Binding::MOZ_SOURCE_MOUSE) { - return inputSource; - } - // Similar to nsWindow::DispatchTouchEventFromWMPointer. - switch (mEvent->mMessage) { - case ePointerMove: - return mEvent->AsPointerEvent()->mPressure == 0 - ? MouseEvent_Binding::MOZ_SOURCE_MOUSE // hover - : MouseEvent_Binding::MOZ_SOURCE_TOUCH; - case ePointerUp: - case ePointerDown: - case ePointerCancel: - return MouseEvent_Binding::MOZ_SOURCE_TOUCH; - default: - return MouseEvent_Binding::MOZ_SOURCE_MOUSE; - } -#elif defined(MOZ_WIDGET_ANDROID) - return inputSource == MouseEvent_Binding::MOZ_SOURCE_MOUSE - ? MouseEvent_Binding::MOZ_SOURCE_MOUSE - : MouseEvent_Binding::MOZ_SOURCE_TOUCH; -#elif defined(MOZ_WIDGET_GTK) - return inputSource == MouseEvent_Binding::MOZ_SOURCE_TOUCH - ? MouseEvent_Binding::MOZ_SOURCE_TOUCH - : MouseEvent_Binding::MOZ_SOURCE_MOUSE; -#elif defined(MOZ_WIDGET_COCOA) - return MouseEvent_Binding::MOZ_SOURCE_MOUSE; -#else - return inputSource; -#endif -} - -void PointerEvent::GetPointerType(nsAString& aPointerType, - CallerType aCallerType) { +void PointerEvent::GetPointerType(nsAString& aPointerType) { if (mPointerType.isSome()) { aPointerType = mPointerType.value(); return; } - ConvertPointerTypeToString(ResistantInputSource(aCallerType), aPointerType); + +#if SPOOFED_MAX_TOUCH_POINTS <= 0 + if (ShouldResistFingerprinting()) { + aPointerType.AssignLiteral("mouse"); + return; + } +#endif + + ConvertPointerTypeToString(mEvent->AsPointerEvent()->mInputSource, + aPointerType); } int32_t PointerEvent::PointerId() { - return mEvent->AsPointerEvent()->pointerId; + return (ShouldResistFingerprinting(true)) + ? PointerEventHandler::GetSpoofedPointerIdForRFP() + : mEvent->AsPointerEvent()->pointerId; } -double PointerEvent::Width(CallerType aCallerType) const { - return ShouldResistFingerprinting(aCallerType) - ? 1.0 - : mEvent->AsPointerEvent()->mWidth; +double PointerEvent::Width() const { + return ShouldResistFingerprinting() ? 1.0 : mEvent->AsPointerEvent()->mWidth; } -double PointerEvent::Height(CallerType aCallerType) const { - return ShouldResistFingerprinting(aCallerType) - ? 1.0 - : mEvent->AsPointerEvent()->mHeight; +double PointerEvent::Height() const { + return ShouldResistFingerprinting() ? 1.0 : mEvent->AsPointerEvent()->mHeight; } -float PointerEvent::Pressure(CallerType aCallerType) { - if (mEvent->mMessage == ePointerUp || - !ShouldResistFingerprinting(aCallerType)) { +float PointerEvent::Pressure() { + if (mEvent->mMessage == ePointerUp || !ShouldResistFingerprinting()) { return mEvent->AsPointerEvent()->mPressure; } @@ -315,14 +276,14 @@ float PointerEvent::Pressure(CallerType aCallerType) { return spoofedPressure; } -float PointerEvent::TangentialPressure(CallerType aCallerType) { - return ShouldResistFingerprinting(aCallerType) +float PointerEvent::TangentialPressure() { + return ShouldResistFingerprinting() ? 0 : mEvent->AsPointerEvent()->tangentialPressure; } -int32_t PointerEvent::TiltX(CallerType aCallerType) { - if (ShouldResistFingerprinting(aCallerType)) { +int32_t PointerEvent::TiltX() { + if (ShouldResistFingerprinting()) { return 0; } if (mTiltX.isSome()) { @@ -333,8 +294,8 @@ int32_t PointerEvent::TiltX(CallerType aCallerType) { return *mTiltX; } -int32_t PointerEvent::TiltY(CallerType aCallerType) { - if (ShouldResistFingerprinting(aCallerType)) { +int32_t PointerEvent::TiltY() { + if (ShouldResistFingerprinting()) { return 0; } if (mTiltY.isSome()) { @@ -345,14 +306,12 @@ int32_t PointerEvent::TiltY(CallerType aCallerType) { return *mTiltY; } -int32_t PointerEvent::Twist(CallerType aCallerType) { - return ShouldResistFingerprinting(aCallerType) - ? 0 - : mEvent->AsPointerEvent()->twist; +int32_t PointerEvent::Twist() { + return ShouldResistFingerprinting() ? 0 : mEvent->AsPointerEvent()->twist; } -double PointerEvent::AltitudeAngle(CallerType aCallerType) { - if (ShouldResistFingerprinting(aCallerType)) { +double PointerEvent::AltitudeAngle() { + if (ShouldResistFingerprinting()) { return WidgetPointerHelper::GetDefaultAltitudeAngle(); } if (mAltitudeAngle.isSome()) { @@ -363,8 +322,8 @@ double PointerEvent::AltitudeAngle(CallerType aCallerType) { return *mAltitudeAngle; } -double PointerEvent::AzimuthAngle(CallerType aCallerType) { - if (ShouldResistFingerprinting(aCallerType)) { +double PointerEvent::AzimuthAngle() { + if (ShouldResistFingerprinting()) { return WidgetPointerHelper::GetDefaultAzimuthAngle(); } if (mAzimuthAngle.isSome()) { @@ -377,22 +336,13 @@ double PointerEvent::AzimuthAngle(CallerType aCallerType) { bool PointerEvent::IsPrimary() { return mEvent->AsPointerEvent()->mIsPrimary; } -int32_t PointerEvent::PersistentDeviceId(CallerType aCallerType) { - const auto MaybeNonZero = [&]() { - return mEvent->IsTrusted() && IsPointerEventMessage(mEvent->mMessage) && - !IsPointerEventMessageOriginallyMouseEventMessage(mEvent->mMessage); - }; - - if (ShouldResistFingerprinting(aCallerType)) { - return MaybeNonZero() && ResistantInputSource(aCallerType) == - MouseEvent_Binding::MOZ_SOURCE_MOUSE - ? 1 - : 0; - } - +int32_t PointerEvent::PersistentDeviceId() { if (mPersistentDeviceId.isNothing()) { - if (MaybeNonZero() && mEvent->AsPointerEvent()->mInputSource == - MouseEvent_Binding::MOZ_SOURCE_MOUSE) { + if (mEvent->IsTrusted() && + mEvent->AsPointerEvent()->mInputSource == + MouseEvent_Binding::MOZ_SOURCE_MOUSE && + IsPointerEventMessage(mEvent->mMessage) && + !IsPointerEventMessageOriginallyMouseEventMessage(mEvent->mMessage)) { // Follow the behavior which Chrome has for mouse. mPersistentDeviceId.emplace(1); } else { @@ -492,22 +442,22 @@ void PointerEvent::GetPredictedEvents( aPointerEvents.AppendElements(mPredictedEvents); } -bool PointerEvent::ShouldResistFingerprinting(CallerType aCallerType) const { - // There are a few simple situations we don't need to spoof this pointer +bool PointerEvent::ShouldResistFingerprinting(bool aForPointerId) const { + // There are three simple situations we don't need to spoof this pointer // event. - // * We are being called by a System caller - // * The pref privcy.resistFingerprinting' is false, we fast return here - // since we don't need to do any QI of following codes. - // * This event is generated by scripts. - // * This event is a mouse pointer event. + // 1. The pref privcy.resistFingerprinting' is false, we fast return here + // since we don't need to do any QI of following codes. + // 2. This event is generated by scripts. + // 3. This event is a mouse pointer event. // We don't need to check for the system group since pointer events won't be // dispatched to the system group. - RFPTarget target = RFPTarget::PointerEvents; - if (aCallerType == CallerType::System || - !nsContentUtils::ShouldResistFingerprinting("Efficiency Check", target) || + RFPTarget target = + aForPointerId ? RFPTarget::PointerId : RFPTarget::PointerEvents; + if (!nsContentUtils::ShouldResistFingerprinting("Efficiency Check", target) || !mEvent->IsTrusted() || - mEvent->AsPointerEvent()->mInputSource == - MouseEvent_Binding::MOZ_SOURCE_MOUSE) { + (mEvent->AsPointerEvent()->mInputSource == + MouseEvent_Binding::MOZ_SOURCE_MOUSE && + SPOOFED_MAX_TOUCH_POINTS == 0)) { return false; } diff --git a/dom/events/PointerEvent.h b/dom/events/PointerEvent.h @@ -41,20 +41,18 @@ class PointerEvent : public MouseEvent { PointerEvent* AsPointerEvent() final { return this; } int32_t PointerId(); - double Width(CallerType aCallerType = CallerType::System) const; - double Height(CallerType aCallerType = CallerType::System) const; - float Pressure(CallerType aCallerType = CallerType::System); - float TangentialPressure(CallerType aCallerType = CallerType::System); - int32_t TiltX(CallerType aCallerType = CallerType::System); - int32_t TiltY(CallerType aCallerType = CallerType::System); - int32_t Twist(CallerType aCallerType = CallerType::System); - double AltitudeAngle(CallerType aCallerType = CallerType::System); - double AzimuthAngle(CallerType aCallerType = CallerType::System); + double Width() const; + double Height() const; + float Pressure(); + float TangentialPressure(); + int32_t TiltX(); + int32_t TiltY(); + int32_t Twist(); + double AltitudeAngle(); + double AzimuthAngle(); bool IsPrimary(); - void GetPointerType( - nsAString& aPointerType, - mozilla::dom::CallerType aCallerType = CallerType::System); - int32_t PersistentDeviceId(CallerType aCallerType = CallerType::System); + int32_t PersistentDeviceId(); + void GetPointerType(nsAString& aPointerType); static bool EnableGetCoalescedEvents(JSContext* aCx, JSObject* aGlobal); void GetCoalescedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents); void GetPredictedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents); @@ -65,11 +63,7 @@ class PointerEvent : public MouseEvent { private: // This method returns the boolean to indicate whether spoofing pointer // event for fingerprinting resistance. - bool ShouldResistFingerprinting( - CallerType aCallerType = CallerType::System) const; - - uint16_t ResistantInputSource( - CallerType aCallerType = CallerType::System) const; + bool ShouldResistFingerprinting(bool aForPointerId = false) const; // When the instance is a trusted `pointermove` event but the widget event // does not have proper coalesced events (typically, the event is synthesized diff --git a/dom/events/PointerEventHandler.cpp b/dom/events/PointerEventHandler.cpp @@ -675,6 +675,32 @@ void PointerEventHandler::CheckPointerCaptureState(WidgetPointerEvent* aEvent) { PointerCaptureInfo* captureInfo = GetPointerCaptureInfo(aEvent->pointerId); + // When fingerprinting resistance is enabled, we need to map other pointer + // ids into the spoofed one. We don't have to do the mapping if the capture + // info exists for the non-spoofed pointer id because of we won't allow + // content to set pointer capture other than the spoofed one. Thus, it must be + // from chrome if the capture info exists in this case. And we don't have to + // do anything if the pointer id is the same as the spoofed one. + if (nsContentUtils::ShouldResistFingerprinting("Efficiency Check", + RFPTarget::PointerId) && + aEvent->pointerId != (uint32_t)GetSpoofedPointerIdForRFP() && + !captureInfo) { + PointerCaptureInfo* spoofedCaptureInfo = + GetPointerCaptureInfo(GetSpoofedPointerIdForRFP()); + + // We need to check the target element's document should resist + // fingerprinting. If not, we don't need to send a capture event + // since the capture info of the original pointer id doesn't exist + // in this case. + if (!spoofedCaptureInfo || !spoofedCaptureInfo->mPendingElement || + !spoofedCaptureInfo->mPendingElement->OwnerDoc() + ->ShouldResistFingerprinting(RFPTarget::PointerEvents)) { + return; + } + + captureInfo = spoofedCaptureInfo; + } + if (!captureInfo || captureInfo->mPendingElement == captureInfo->mOverrideElement) { return; diff --git a/dom/events/TouchEvent.cpp b/dom/events/TouchEvent.cpp @@ -226,38 +226,36 @@ bool TouchEvent::PrefEnabled(nsIDocShell* aDocShell) { } else if (touchEventsOverride == mozilla::dom::TouchEventsOverride::Disabled) { enabled = false; - } else if (nsContentUtils::ShouldResistFingerprinting( - aDocShell, RFPTarget::PointerEvents)) { -#ifdef MOZ_WIDGET_COCOA - enabled = false; -#else - enabled = true; -#endif } else { const int32_t prefValue = StaticPrefs::dom_w3c_touch_events_enabled(); if (prefValue == 2) { - enabled = PlatformSupportsTouch(); - - static bool firstTime = true; - // The touch screen data seems to be inaccurate in the parent process, - // and we really need the crash annotation in child processes. - if (firstTime && !XRE_IsParentProcess()) { - CrashReporter::RecordAnnotationBool( - CrashReporter::Annotation::HasDeviceTouchScreen, enabled); - firstTime = false; - } + if (nsContentUtils::ShouldResistFingerprinting( + aDocShell, RFPTarget::PointerEvents)) { + enabled = SPOOFED_MAX_TOUCH_POINTS != 0; + } else { + enabled = PlatformSupportsTouch(); + + static bool firstTime = true; + // The touch screen data seems to be inaccurate in the parent process, + // and we really need the crash annotation in child processes. + if (firstTime && !XRE_IsParentProcess()) { + CrashReporter::RecordAnnotationBool( + CrashReporter::Annotation::HasDeviceTouchScreen, enabled); + firstTime = false; + } #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) - if (enabled && aDocShell) { - // APZ might be disabled on this particular widget, in which case - // TouchEvent support will also be disabled. Try to detect that. - if (RefPtr<nsPresContext> pc = aDocShell->GetPresContext()) { - if (nsCOMPtr<nsIWidget> widget = pc->GetRootWidget()) { - enabled &= widget->AsyncPanZoomEnabled(); + if (enabled && aDocShell) { + // APZ might be disabled on this particular widget, in which case + // TouchEvent support will also be disabled. Try to detect that. + if (RefPtr<nsPresContext> pc = aDocShell->GetPresContext()) { + if (nsCOMPtr<nsIWidget> widget = pc->GetRootWidget()) { + enabled &= widget->AsyncPanZoomEnabled(); + } } } - } #endif + } } else { enabled = !!prefValue; } diff --git a/dom/webidl/PointerEvent.webidl b/dom/webidl/PointerEvent.webidl @@ -14,29 +14,18 @@ interface PointerEvent : MouseEvent readonly attribute long pointerId; - [NeedsCallerType] readonly attribute double width; - [NeedsCallerType] readonly attribute double height; - [NeedsCallerType] readonly attribute float pressure; - [NeedsCallerType] readonly attribute float tangentialPressure; - [NeedsCallerType] readonly attribute long tiltX; - [NeedsCallerType] readonly attribute long tiltY; - [NeedsCallerType] readonly attribute long twist; - [NeedsCallerType] readonly attribute double altitudeAngle; - [NeedsCallerType] readonly attribute double azimuthAngle; - [NeedsCallerType] readonly attribute DOMString pointerType; readonly attribute boolean isPrimary; - [NeedsCallerType] readonly attribute long persistentDeviceId; [Func="mozilla::dom::PointerEvent::EnableGetCoalescedEvents"] diff --git a/layout/base/PositionedEventTargeting.cpp b/layout/base/PositionedEventTargeting.cpp @@ -21,7 +21,6 @@ #include "mozilla/dom/DOMIntersectionObserver.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/MouseEventBinding.h" -#include "mozilla/dom/TouchEvent.h" #include "mozilla/gfx/Matrix.h" #include "mozilla/layers/LayersTypes.h" #include "nsContainerFrame.h" @@ -179,7 +178,9 @@ static bool HasTouchListener(const nsIContent* aContent) { return false; } - if (!TouchEvent::PrefEnabled(aContent->OwnerDoc()->GetDocShell())) { + // FIXME: Should this really use the pref rather than TouchEvent::PrefEnabled + // or such? + if (!StaticPrefs::dom_w3c_touch_events_enabled()) { return false; } diff --git a/toolkit/components/resistfingerprinting/RFPTargets.inc b/toolkit/components/resistfingerprinting/RFPTargets.inc @@ -35,7 +35,7 @@ ITEM_VALUE(NavigatorHWConcurrency, 16) ITEM_VALUE(NavigatorOscpu, 17) ITEM_VALUE(NavigatorPlatform, 18) ITEM_VALUE(NavigatorUserAgent, 19) -// We no longer use PointerId, it can renamed and reused +ITEM_VALUE(PointerId, 20) ITEM_VALUE(StreamVideoFacingMode, 21) ITEM_VALUE(JSDateTimeUTC, 22) ITEM_VALUE(JSMathFdlibm, 23) @@ -109,7 +109,6 @@ ITEM_VALUE(NavigatorHWConcurrencyTiered,74) ITEM_VALUE(WebGLRandomization, 75) ITEM_VALUE(EfficientCanvasRandomization, 76) -// !!! Adding a new target? Rename PointerId and repurpose it. /* * In certain cases, we precompute the value of ShouldRFP for e.g. a Document. diff --git a/toolkit/components/resistfingerprinting/nsRFPService.cpp b/toolkit/components/resistfingerprinting/nsRFPService.cpp @@ -310,6 +310,13 @@ Maybe<bool> nsRFPService::HandleExceptionalRFPTargets( StaticPrefs::privacy_spoof_english_DoNotUseDirectly() == 2); } + // We don't spoof the pointerId on multi-touch devices. +#if SPOOFED_MAX_TOUCH_POINTS > 0 + if (aTarget == RFPTarget::PointerId) { + return Some(false); + } +#endif + return Nothing(); } diff --git a/widget/WidgetEventImpl.cpp b/widget/WidgetEventImpl.cpp @@ -606,6 +606,23 @@ bool WidgetEvent::IsBlockedForFingerprintingResistance() const { keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_Control || keyboardEvent->mKeyNameIndex == KEY_NAME_INDEX_AltGraph); } + case ePointerEventClass: { + if (IsPointerEventMessageOriginallyMouseEventMessage(mMessage)) { + return false; + } + + if (SPOOFED_MAX_TOUCH_POINTS > 0) { + return false; + } + + const WidgetPointerEvent* pointerEvent = AsPointerEvent(); + + // We suppress the pointer events if it is not primary for fingerprinting + // resistance. It is because of that we want to spoof any pointer event + // into a mouse pointer event and the mouse pointer event only has + // isPrimary as true. + return !pointerEvent->mIsPrimary; + } default: return false; }