tor-browser

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

commit 35055c39b060b8014a4dd74b2e97acdf2abd46ac
parent 00f1baf7d5af86271b093ae8f9df906d941bbe53
Author: Pier Angelo Vendrame <pierov@torproject.org>
Date:   Mon, 20 Oct 2025 17:37:01 +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 | 138+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mdom/events/PointerEvent.h | 30++++++++++++++++++------------
Mdom/webidl/PointerEvent.webidl | 11+++++++++++
3 files changed, 125 insertions(+), 54 deletions(-)

diff --git a/dom/events/PointerEvent.cpp b/dom/events/PointerEvent.cpp @@ -227,37 +227,78 @@ 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) { 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() { 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) { + if (mEvent->mMessage == ePointerUp || + !ShouldResistFingerprinting(aCallerType)) { return mEvent->AsPointerEvent()->mPressure; } @@ -274,14 +315,14 @@ float PointerEvent::Pressure() { return spoofedPressure; } -float PointerEvent::TangentialPressure() { - return ShouldResistFingerprinting() +float PointerEvent::TangentialPressure(CallerType aCallerType) { + 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()) { @@ -292,8 +333,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()) { @@ -304,12 +345,14 @@ int32_t PointerEvent::TiltY() { return *mTiltY; } -int32_t PointerEvent::Twist() { - return ShouldResistFingerprinting() ? 0 : mEvent->AsPointerEvent()->twist; +int32_t PointerEvent::Twist(CallerType aCallerType) { + 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()) { @@ -320,8 +363,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()) { @@ -334,13 +377,22 @@ double PointerEvent::AzimuthAngle() { bool PointerEvent::IsPrimary() { return mEvent->AsPointerEvent()->mIsPrimary; } -int32_t PointerEvent::PersistentDeviceId() { +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; + } + 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 { @@ -440,17 +492,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 @@ -41,18 +41,20 @@ 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(); + 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); bool IsPrimary(); - int32_t PersistentDeviceId(); - void GetPointerType(nsAString& aPointerType); + void GetPointerType( + nsAString& aPointerType, + mozilla::dom::CallerType aCallerType = CallerType::System); + 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 @@ -14,18 +14,29 @@ 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"]