1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef __nsRFPService_h__ 7 #define __nsRFPService_h__ 8 9 #include <cstdint> 10 #include "ErrorList.h" 11 #include "PLDHashTable.h" 12 #include "mozilla/BasicEvents.h" 13 #include "nsHashtablesFwd.h" 14 #include "nsIObserver.h" 15 #include "nsISupports.h" 16 #include "nsStringFwd.h" 17 18 // Defines regarding spoofed values of Navigator object. These spoofed values 19 // are returned when 'privacy.resistFingerprinting' is true. 20 // We decided to give different spoofed values according to the platform. The 21 // reason is that it is easy to detect the real platform. So there is no benefit 22 // for hiding the platform: it only brings breakages, like keyboard shortcuts 23 // won't work in macOS if we spoof it as a Windows platform. 24 #ifdef XP_WIN 25 # define SPOOFED_UA_OS "Windows NT 10.0; Win64; x64" 26 # define SPOOFED_APPVERSION "5.0 (Windows)" 27 # define SPOOFED_OSCPU "Windows NT 10.0; Win64; x64" 28 # define SPOOFED_PLATFORM "Win32" 29 #elif defined(XP_MACOSX) 30 # define SPOOFED_UA_OS "Macintosh; Intel Mac OS X 10.15" 31 # define SPOOFED_APPVERSION "5.0 (Macintosh)" 32 # define SPOOFED_OSCPU "Intel Mac OS X 10.15" 33 # define SPOOFED_PLATFORM "MacIntel" 34 #elif defined(MOZ_WIDGET_ANDROID) 35 # define SPOOFED_UA_OS "Android 10; Mobile" 36 # define SPOOFED_APPVERSION "5.0 (Android 10)" 37 # define SPOOFED_OSCPU "Linux aarch64" 38 # define SPOOFED_PLATFORM "Linux aarch64" 39 #else 40 // For Linux and other platforms, like BSDs, SunOS and etc, we will use Linux 41 // platform. 42 # define SPOOFED_UA_OS "X11; Linux x86_64" 43 # define SPOOFED_APPVERSION "5.0 (X11)" 44 # define SPOOFED_OSCPU "Linux x86_64" 45 # define SPOOFED_PLATFORM "Linux x86_64" 46 #endif 47 48 #define SPOOFED_APPNAME "Netscape" 49 #define LEGACY_BUILD_ID "20181001000000" 50 #define LEGACY_UA_GECKO_TRAIL "20100101" 51 52 #define SPOOFED_POINTER_INTERFACE MouseEvent_Binding::MOZ_SOURCE_MOUSE 53 54 // For the HTTP User-Agent header, we use a simpler set of spoofed values 55 // that do not reveal the specific desktop platform. 56 #if defined(MOZ_WIDGET_ANDROID) 57 # define SPOOFED_HTTP_UA_OS "Android 10; Mobile" 58 #else 59 # define SPOOFED_HTTP_UA_OS "Windows NT 10.0" 60 #endif 61 62 struct JSContext; 63 64 namespace mozilla { 65 class WidgetKeyboardEvent; 66 namespace dom { 67 class Document; 68 } 69 70 enum KeyboardLang { EN = 0x01 }; 71 72 #define RFP_KEYBOARD_LANG_STRING_EN "en" 73 74 typedef uint8_t KeyboardLangs; 75 76 enum KeyboardRegion { US = 0x01 }; 77 78 #define RFP_KEYBOARD_REGION_STRING_US "US" 79 80 typedef uint8_t KeyboardRegions; 81 82 // This struct has the information about how to spoof the keyboardEvent.code, 83 // keyboardEvent.keycode and modifier states. 84 struct SpoofingKeyboardCode { 85 CodeNameIndex mCode; 86 uint8_t mKeyCode; 87 Modifiers mModifierStates; 88 }; 89 90 struct SpoofingKeyboardInfo { 91 nsString mKey; 92 KeyNameIndex mKeyIdx; 93 SpoofingKeyboardCode mSpoofingCode; 94 }; 95 96 class KeyboardHashKey : public PLDHashEntryHdr { 97 public: 98 typedef const KeyboardHashKey& KeyType; 99 typedef const KeyboardHashKey* KeyTypePointer; 100 101 KeyboardHashKey(const KeyboardLangs aLang, const KeyboardRegions aRegion, 102 const KeyNameIndexType aKeyIdx, const nsAString& aKey); 103 104 explicit KeyboardHashKey(KeyTypePointer aOther); 105 106 KeyboardHashKey(KeyboardHashKey&& aOther); 107 108 ~KeyboardHashKey(); 109 110 bool KeyEquals(KeyTypePointer aOther) const; 111 112 static KeyTypePointer KeyToPointer(KeyType aKey); 113 114 static PLDHashNumber HashKey(KeyTypePointer aKey); 115 116 enum { ALLOW_MEMMOVE = true }; 117 118 KeyboardLangs mLang; 119 KeyboardRegions mRegion; 120 KeyNameIndexType mKeyIdx; 121 nsString mKey; 122 }; 123 124 enum TimerPrecisionType { 125 DangerouslyNone = 1, 126 UnconditionalAKAHighRes = 2, 127 Normal = 3, 128 RFP = 4, 129 }; 130 131 class nsRFPService final : public nsIObserver { 132 public: 133 NS_DECL_ISUPPORTS 134 NS_DECL_NSIOBSERVER 135 136 static nsRFPService* GetOrCreate(); 137 static double TimerResolution(); 138 139 enum TimeScale { Seconds = 1, MilliSeconds = 1000, MicroSeconds = 1000000 }; 140 141 // The following Reduce methods can be called off main thread. 142 static double ReduceTimePrecisionAsUSecs(double aTime, int64_t aContextMixin, 143 bool aIsSystemPrincipal, 144 bool aCrossOriginIsolated); 145 static double ReduceTimePrecisionAsMSecs(double aTime, int64_t aContextMixin, 146 bool aIsSystemPrincipal, 147 bool aCrossOriginIsolated); 148 static double ReduceTimePrecisionAsMSecsRFPOnly(double aTime, 149 int64_t aContextMixin); 150 static double ReduceTimePrecisionAsSecs(double aTime, int64_t aContextMixin, 151 bool aIsSystemPrincipal, 152 bool aCrossOriginIsolated); 153 static double ReduceTimePrecisionAsSecsRFPOnly(double aTime, 154 int64_t aContextMixin); 155 156 // Used by the JS Engine, as it doesn't know about the TimerPrecisionType enum 157 static double ReduceTimePrecisionAsUSecsWrapper(double aTime, JSContext* aCx); 158 159 // Public only for testing purposes 160 static double ReduceTimePrecisionImpl(double aTime, TimeScale aTimeScale, 161 double aResolutionUSec, 162 int64_t aContextMixin, 163 TimerPrecisionType aType); 164 static nsresult RandomMidpoint(long long aClampedTimeUSec, 165 long long aResolutionUSec, 166 int64_t aContextMixin, long long* aMidpointOut, 167 uint8_t* aSecretSeed = nullptr); 168 169 // This method calculates the video resolution (i.e. height x width) based 170 // on the video quality (480p, 720p, etc). 171 static uint32_t CalculateTargetVideoResolution(uint32_t aVideoQuality); 172 173 // Methods for getting spoofed media statistics and the return value will 174 // depend on the video resolution. 175 static uint32_t GetSpoofedTotalFrames(double aTime); 176 static uint32_t GetSpoofedDroppedFrames(double aTime, uint32_t aWidth, 177 uint32_t aHeight); 178 static uint32_t GetSpoofedPresentedFrames(double aTime, uint32_t aWidth, 179 uint32_t aHeight); 180 181 // This method generates the spoofed value of User Agent. 182 static void GetSpoofedUserAgent(nsACString& userAgent, bool isForHTTPHeader); 183 184 /** 185 * This method for getting spoofed modifier states for the given keyboard 186 * event. 187 * 188 * @param aDoc [in] the owner's document for getting content 189 * language. 190 * @param aKeyboardEvent [in] the keyboard event that needs to be spoofed. 191 * @param aModifier [in] the modifier that needs to be spoofed. 192 * @param aOut [out] the spoofed state for the given modifier. 193 * @return true if there is a spoofed state for the modifier. 194 */ 195 static bool GetSpoofedModifierStates( 196 const mozilla::dom::Document* aDoc, 197 const WidgetKeyboardEvent* aKeyboardEvent, const Modifiers aModifier, 198 bool& aOut); 199 200 /** 201 * This method for getting spoofed code for the given keyboard event. 202 * 203 * @param aDoc [in] the owner's document for getting content 204 * language. 205 * @param aKeyboardEvent [in] the keyboard event that needs to be spoofed. 206 * @param aOut [out] the spoofed code. 207 * @return true if there is a spoofed code in the fake keyboard 208 * layout. 209 */ 210 static bool GetSpoofedCode(const dom::Document* aDoc, 211 const WidgetKeyboardEvent* aKeyboardEvent, 212 nsAString& aOut); 213 214 /** 215 * This method for getting spoofed keyCode for the given keyboard event. 216 * 217 * @param aDoc [in] the owner's document for getting content 218 * language. 219 * @param aKeyboardEvent [in] the keyboard event that needs to be spoofed. 220 * @param aOut [out] the spoofed keyCode. 221 * @return true if there is a spoofed keyCode in the fake 222 * keyboard layout. 223 */ 224 static bool GetSpoofedKeyCode(const mozilla::dom::Document* aDoc, 225 const WidgetKeyboardEvent* aKeyboardEvent, 226 uint32_t& aOut); 227 228 private: 229 nsresult Init(); 230 231 nsRFPService() = default; 232 233 ~nsRFPService() = default; 234 235 void UpdateTimers(); 236 void UpdateRFPPref(); 237 void StartShutdown(); 238 239 void PrefChanged(const char* aPref); 240 static void PrefChanged(const char* aPref, void* aSelf); 241 242 static void MaybeCreateSpoofingKeyCodes(const KeyboardLangs aLang, 243 const KeyboardRegions aRegion); 244 static void MaybeCreateSpoofingKeyCodesForEnUS(); 245 246 static void GetKeyboardLangAndRegion(const nsAString& aLanguage, 247 KeyboardLangs& aLocale, 248 KeyboardRegions& aRegion); 249 static bool GetSpoofedKeyCodeInfo(const mozilla::dom::Document* aDoc, 250 const WidgetKeyboardEvent* aKeyboardEvent, 251 SpoofingKeyboardCode& aOut); 252 253 static nsTHashMap<KeyboardHashKey, const SpoofingKeyboardCode*>* 254 sSpoofingKeyboardCodes; 255 256 static TimerPrecisionType GetTimerPrecisionType(bool aIsSystemPrincipal, 257 bool aCrossOriginIsolated); 258 259 static TimerPrecisionType GetTimerPrecisionTypeRFPOnly(); 260 261 static void TypeToText(TimerPrecisionType aType, nsACString& aText); 262 263 nsCString mInitialTZValue; 264 }; 265 266 } // namespace mozilla 267 268 #endif /* __nsRFPService_h__ */ 269