/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef __nsRFPService_h__ #define __nsRFPService_h__ #include "mozilla/Atomics.h" #include "mozilla/EventForwards.h" #include "mozilla/Mutex.h" #include "nsIDocument.h" #include "nsIObserver.h" #include "nsDataHashtable.h" #include "nsString.h" // Defines regarding spoofed values of Navigator object. These spoofed values // are returned when 'privacy.resistFingerprinting' is true. // We decided to give different spoofed values according to the platform. The // reason is that it is easy to detect the real platform. So there is no benefit // for hiding the platform: it only brings breakages, like keyboard shortcuts won't // work in MAC OS if we spoof it as a window platform. #ifdef XP_WIN #define SPOOFED_UA_OS "Windows NT 6.1; Win64; x64" #define SPOOFED_APPVERSION "5.0 (Windows)" #define SPOOFED_OSCPU "Windows NT 6.1; Win64; x64" #define SPOOFED_PLATFORM "Win64" #elif defined(XP_MACOSX) #define SPOOFED_UA_OS "Macintosh; Intel Mac OS X 10.13" #define SPOOFED_APPVERSION "5.0 (Macintosh)" #define SPOOFED_OSCPU "Intel Mac OS X 10.13" #define SPOOFED_PLATFORM "MacIntel" #elif defined(MOZ_WIDGET_ANDROID) #define SPOOFED_UA_OS "Android 6.0; Mobile" #define SPOOFED_APPVERSION "5.0 (Android 6.0)" #define SPOOFED_OSCPU "Linux armv7l" #define SPOOFED_PLATFORM "Linux armv7l" #else // For Linux and other platforms, like BSDs, SunOS and etc, we will use Linux // platform. #define SPOOFED_UA_OS "X11; Linux x86_64" #define SPOOFED_APPVERSION "5.0 (X11)" #define SPOOFED_OSCPU "Linux x86_64" #define SPOOFED_PLATFORM "Linux x86_64" #endif #define SPOOFED_APPNAME "Netscape" #define LEGACY_BUILD_ID "20100101" // Forward declare LRUCache, defined in nsRFPService.cpp class LRUCache; namespace mozilla { enum KeyboardLang { EN = 0x01 }; #define RFP_KEYBOARD_LANG_STRING_EN "en" typedef uint8_t KeyboardLangs; enum KeyboardRegion { US = 0x01 }; #define RFP_KEYBOARD_REGION_STRING_US "US" typedef uint8_t KeyboardRegions; // This struct has the information about how to spoof the keyboardEvent.code, // keyboardEvent.keycode and modifier states. struct SpoofingKeyboardCode { CodeNameIndex mCode; uint8_t mKeyCode; Modifiers mModifierStates; }; struct SpoofingKeyboardInfo { KeyNameIndex mKeyIdx; nsString mKey; SpoofingKeyboardCode mSpoofingCode; }; class KeyboardHashKey : public PLDHashEntryHdr { public: typedef const KeyboardHashKey& KeyType; typedef const KeyboardHashKey* KeyTypePointer; KeyboardHashKey(const KeyboardLangs aLang, const KeyboardRegions aRegion, const KeyNameIndexType aKeyIdx, const nsAString &aKey) : mLang(aLang) , mRegion(aRegion) , mKeyIdx(aKeyIdx) , mKey(aKey) {} explicit KeyboardHashKey(KeyTypePointer aOther) : mLang(aOther->mLang) , mRegion(aOther->mRegion) , mKeyIdx(aOther->mKeyIdx) , mKey(aOther->mKey) {} KeyboardHashKey(KeyType aOther) : mLang(aOther.mLang) , mRegion(aOther.mRegion) , mKeyIdx(aOther.mKeyIdx) , mKey(aOther.mKey) {} ~KeyboardHashKey() {} bool KeyEquals(KeyTypePointer aOther) const { return mLang == aOther->mLang && mRegion == aOther->mRegion && mKeyIdx == aOther->mKeyIdx && mKey == aOther->mKey; } static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } static PLDHashNumber HashKey(KeyTypePointer aKey) { PLDHashNumber hash = mozilla::HashString(aKey->mKey); return mozilla::AddToHash(hash, aKey->mRegion, aKey->mKeyIdx, aKey->mLang); } enum { ALLOW_MEMMOVE = true }; KeyboardLangs mLang; KeyboardRegions mRegion; KeyNameIndexType mKeyIdx; nsString mKey; }; enum TimerPrecisionType { All = 1, RFPOnly = 2 }; class nsRFPService final : public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSIOBSERVER static nsRFPService* GetOrCreate(); static bool IsResistFingerprintingEnabled(); static bool IsTimerPrecisionReductionEnabled(TimerPrecisionType aType); enum TimeScale { Seconds = 1, MilliSeconds = 1000, MicroSeconds = 1000000 }; // The following Reduce methods can be called off main thread. static double ReduceTimePrecisionAsUSecs( double aTime, int64_t aContextMixin, TimerPrecisionType aType = TimerPrecisionType::All); static double ReduceTimePrecisionAsMSecs( double aTime, int64_t aContextMixin, TimerPrecisionType aType = TimerPrecisionType::All); static double ReduceTimePrecisionAsSecs( double aTime, int64_t aContextMixin, TimerPrecisionType aType = TimerPrecisionType::All); // Used by the JS Engine, as it doesn't know about the TimerPrecisionType enum static double ReduceTimePrecisionAsUSecsWrapper( double aTime); // Public only for testing purposes static double ReduceTimePrecisionImpl( double aTime, TimeScale aTimeScale, double aResolutionUSec, int64_t aContextMixin, TimerPrecisionType aType); static nsresult RandomMidpoint(long long aClampedTimeUSec, long long aResolutionUSec, int64_t aContextMixin, long long* aMidpointOut, uint8_t * aSecretSeed = nullptr); // This method calculates the video resolution (i.e. height x width) based // on the video quality (480p, 720p, etc). static uint32_t CalculateTargetVideoResolution(uint32_t aVideoQuality); // Methods for getting spoofed media statistics and the return value will // depend on the video resolution. static uint32_t GetSpoofedTotalFrames(double aTime); static uint32_t GetSpoofedDroppedFrames(double aTime, uint32_t aWidth, uint32_t aHeight); static uint32_t GetSpoofedPresentedFrames(double aTime, uint32_t aWidth, uint32_t aHeight); // This method generates the spoofed value of User Agent. static nsresult GetSpoofedUserAgent(nsACString &userAgent); /** * This method for getting spoofed modifier states for the given keyboard event. * * @param aDoc [in] the owner's document for getting content language. * @param aKeyboardEvent [in] the keyboard event that needs to be spoofed. * @param aModifier [in] the modifier that needs to be spoofed. * @param aOut [out] the spoofed state for the given modifier. * @return true if there is a spoofed state for the modifier. */ static bool GetSpoofedModifierStates(const nsIDocument* aDoc, const WidgetKeyboardEvent* aKeyboardEvent, const Modifiers aModifier, bool& aOut); /** * This method for getting spoofed code for the given keyboard event. * * @param aDoc [in] the owner's document for getting content language. * @param aKeyboardEvent [in] the keyboard event that needs to be spoofed. * @param aOut [out] the spoofed code. * @return true if there is a spoofed code in the fake keyboard layout. */ static bool GetSpoofedCode(const nsIDocument* aDoc, const WidgetKeyboardEvent* aKeyboardEvent, nsAString& aOut); /** * This method for getting spoofed keyCode for the given keyboard event. * * @param aDoc [in] the owner's document for getting content language. * @param aKeyboardEvent [in] the keyboard event that needs to be spoofed. * @param aOut [out] the spoofed keyCode. * @return true if there is a spoofed keyCode in the fake keyboard layout. */ static bool GetSpoofedKeyCode(const nsIDocument* aDoc, const WidgetKeyboardEvent* aKeyboardEvent, uint32_t& aOut); private: nsresult Init(); nsRFPService() {} ~nsRFPService() {} void UpdateTimers(); void UpdateRFPPref(); void StartShutdown(); static void MaybeCreateSpoofingKeyCodes(const KeyboardLangs aLang, const KeyboardRegions aRegion); static void MaybeCreateSpoofingKeyCodesForEnUS(); static void GetKeyboardLangAndRegion(const nsAString& aLanguage, KeyboardLangs& aLang, KeyboardRegions& aRegion); static bool GetSpoofedKeyCodeInfo(const nsIDocument* aDoc, const WidgetKeyboardEvent* aKeyboardEvent, SpoofingKeyboardCode& aOut); static Atomic sPrivacyResistFingerprinting; static Atomic sPrivacyTimerPrecisionReduction; static nsDataHashtable* sSpoofingKeyboardCodes; nsCString mInitialTZValue; }; } // mozilla namespace #endif /* __nsRFPService_h__ */