tor-browser

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

commit 996938e0bc68f1eafeb22819beb9428c97df4388
parent e9fa485e4ac0f53d50f0a7ae49e10de7ca2deb84
Author: Pier Angelo Vendrame <pierov@torproject.org>
Date:   Thu,  6 Nov 2025 08:03:53 +0000

Bug 1987929 - Hide pen input in RFP on desktop. r=masayuki,webidl,saschanaz

The pen features (pressure, angles, etc...) are already spoofed.
However, we still tell that the input comes from a pen.
At this point, we can pretend it came from a mouse.

Differential Revision: https://phabricator.services.mozilla.com/D267267

Diffstat:
Mdom/events/PointerEvent.cpp | 146++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mdom/events/PointerEvent.h | 34++++++++++++++++++++--------------
Mdom/webidl/PointerEvent.webidl | 12++++++++++++
3 files changed, 133 insertions(+), 59 deletions(-)

diff --git a/dom/events/PointerEvent.cpp b/dom/events/PointerEvent.cpp @@ -227,42 +227,83 @@ NS_INTERFACE_MAP_END_INHERITING(MouseEvent) NS_IMPL_ADDREF_INHERITED(PointerEvent, MouseEvent) NS_IMPL_RELEASE_INHERITED(PointerEvent, MouseEvent) -void PointerEvent::GetPointerType(nsAString& aPointerType) { +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) const { if (mPointerType.isSome()) { aPointerType = mPointerType.value(); return; } - -#if SPOOFED_MAX_TOUCH_POINTS <= 0 - if (ShouldResistFingerprinting()) { - aPointerType.AssignLiteral("mouse"); - return; - } -#endif - - ConvertPointerTypeToString(mEvent->AsPointerEvent()->mInputSource, - aPointerType); + ConvertPointerTypeToString(ResistantInputSource(aCallerType), aPointerType); } -int32_t PointerEvent::PointerId() { +int32_t PointerEvent::PointerId(CallerType aCallerType) const { #ifdef MOZ_WIDGET_COCOA - if (ShouldResistFingerprinting()) { + if (ShouldResistFingerprinting(aCallerType)) { return PointerEventHandler::GetSpoofedPointerIdForRFP(); } #endif return mEvent->AsPointerEvent()->pointerId; } -double PointerEvent::Width() const { - return ShouldResistFingerprinting() ? 1.0 : mEvent->AsPointerEvent()->mWidth; +double PointerEvent::Width(CallerType aCallerType) const { + return ShouldResistFingerprinting(aCallerType) + ? 1.0 + : mEvent->AsPointerEvent()->mWidth; } -double PointerEvent::Height() const { - return ShouldResistFingerprinting() ? 1.0 : mEvent->AsPointerEvent()->mHeight; +double PointerEvent::Height(CallerType aCallerType) const { + return ShouldResistFingerprinting(aCallerType) + ? 1.0 + : mEvent->AsPointerEvent()->mHeight; } -float PointerEvent::Pressure() { - if (mEvent->mMessage == ePointerUp || !ShouldResistFingerprinting()) { +float PointerEvent::Pressure(CallerType aCallerType) const { + if (mEvent->mMessage == ePointerUp || + !ShouldResistFingerprinting(aCallerType)) { return mEvent->AsPointerEvent()->mPressure; } @@ -279,14 +320,14 @@ float PointerEvent::Pressure() { return spoofedPressure; } -float PointerEvent::TangentialPressure() { - return ShouldResistFingerprinting() +float PointerEvent::TangentialPressure(CallerType aCallerType) const { + return ShouldResistFingerprinting(aCallerType) ? 0 : mEvent->AsPointerEvent()->tangentialPressure; } -int32_t PointerEvent::TiltX() { - if (ShouldResistFingerprinting()) { +int32_t PointerEvent::TiltX(CallerType aCallerType) { + if (ShouldResistFingerprinting(aCallerType)) { return 0; } if (mTiltX.isSome()) { @@ -297,8 +338,8 @@ int32_t PointerEvent::TiltX() { return *mTiltX; } -int32_t PointerEvent::TiltY() { - if (ShouldResistFingerprinting()) { +int32_t PointerEvent::TiltY(CallerType aCallerType) { + if (ShouldResistFingerprinting(aCallerType)) { return 0; } if (mTiltY.isSome()) { @@ -309,12 +350,14 @@ int32_t PointerEvent::TiltY() { return *mTiltY; } -int32_t PointerEvent::Twist() { - return ShouldResistFingerprinting() ? 0 : mEvent->AsPointerEvent()->twist; +int32_t PointerEvent::Twist(CallerType aCallerType) const { + return ShouldResistFingerprinting(aCallerType) + ? 0 + : mEvent->AsPointerEvent()->twist; } -double PointerEvent::AltitudeAngle() { - if (ShouldResistFingerprinting()) { +double PointerEvent::AltitudeAngle(CallerType aCallerType) { + if (ShouldResistFingerprinting(aCallerType)) { return WidgetPointerHelper::GetDefaultAltitudeAngle(); } if (mAltitudeAngle.isSome()) { @@ -325,8 +368,8 @@ double PointerEvent::AltitudeAngle() { return *mAltitudeAngle; } -double PointerEvent::AzimuthAngle() { - if (ShouldResistFingerprinting()) { +double PointerEvent::AzimuthAngle(CallerType aCallerType) { + if (ShouldResistFingerprinting(aCallerType)) { return WidgetPointerHelper::GetDefaultAzimuthAngle(); } if (mAzimuthAngle.isSome()) { @@ -337,15 +380,26 @@ double PointerEvent::AzimuthAngle() { return *mAzimuthAngle; } -bool PointerEvent::IsPrimary() { return mEvent->AsPointerEvent()->mIsPrimary; } +bool PointerEvent::IsPrimary() const { + 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 (mEvent->IsTrusted() && - mEvent->AsPointerEvent()->mInputSource == - MouseEvent_Binding::MOZ_SOURCE_MOUSE && - IsPointerEventMessage(mEvent->mMessage) && - !IsPointerEventMessageOriginallyMouseEventMessage(mEvent->mMessage)) { + if (MaybeNonZero() && mEvent->AsPointerEvent()->mInputSource == + MouseEvent_Binding::MOZ_SOURCE_MOUSE) { // Follow the behavior which Chrome has for mouse. mPersistentDeviceId.emplace(1); } else { @@ -445,17 +499,19 @@ void PointerEvent::GetPredictedEvents( aPointerEvents.AppendElements(mPredictedEvents); } -bool PointerEvent::ShouldResistFingerprinting() const { - // There are three simple situations we don't need to spoof this pointer +bool PointerEvent::ShouldResistFingerprinting(CallerType aCallerType) const { + // There are a few simple situations we don't need to spoof this 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 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. // 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 (!nsContentUtils::ShouldResistFingerprinting("Efficiency Check", target) || + if (aCallerType == CallerType::System || + !nsContentUtils::ShouldResistFingerprinting("Efficiency Check", target) || !mEvent->IsTrusted() || mEvent->AsPointerEvent()->mInputSource == MouseEvent_Binding::MOZ_SOURCE_MOUSE) { diff --git a/dom/events/PointerEvent.h b/dom/events/PointerEvent.h @@ -40,19 +40,21 @@ class PointerEvent : public MouseEvent { PointerEvent* AsPointerEvent() final { return this; } - int32_t PointerId(); - 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(); - int32_t PersistentDeviceId(); - void GetPointerType(nsAString& aPointerType); + int32_t PointerId(CallerType aCallerType = CallerType::System) const; + double Width(CallerType aCallerType = CallerType::System) const; + double Height(CallerType aCallerType = CallerType::System) const; + float Pressure(CallerType aCallerType = CallerType::System) const; + float TangentialPressure(CallerType aCallerType = CallerType::System) const; + int32_t TiltX(CallerType aCallerType = CallerType::System); + int32_t TiltY(CallerType aCallerType = CallerType::System); + int32_t Twist(CallerType aCallerType = CallerType::System) const; + double AltitudeAngle(CallerType aCallerType = CallerType::System); + double AzimuthAngle(CallerType aCallerType = CallerType::System); + bool IsPrimary() const; + void GetPointerType( + nsAString& aPointerType, + mozilla::dom::CallerType aCallerType = CallerType::System) const; + int32_t PersistentDeviceId(CallerType aCallerType = CallerType::System); static bool EnableGetCoalescedEvents(JSContext* aCx, JSObject* aGlobal); void GetCoalescedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents); void GetPredictedEvents(nsTArray<RefPtr<PointerEvent>>& aPointerEvents); @@ -63,7 +65,11 @@ class PointerEvent : public MouseEvent { private: // This method returns the boolean to indicate whether spoofing pointer // event for fingerprinting resistance. - bool ShouldResistFingerprinting() const; + bool ShouldResistFingerprinting( + CallerType aCallerType = CallerType::System) const; + + uint16_t ResistantInputSource( + CallerType aCallerType = CallerType::System) 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/webidl/PointerEvent.webidl b/dom/webidl/PointerEvent.webidl @@ -12,20 +12,32 @@ interface PointerEvent : MouseEvent { constructor(DOMString type, optional PointerEventInit eventInitDict = {}); + [NeedsCallerType] 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"]