Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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 https://mozilla.org/MPL/2.0/. */
#ifndef _nsRFPService_h_
#define _nsRFPService_h_
#include <cstdint>
#include <bitset>
#include "ErrorList.h"
#include "PLDHashTable.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/TypedEnumBits.h"
#include "mozilla/dom/MediaDeviceInfoBinding.h"
#include "mozilla/dom/ScreenOrientationBinding.h"
#include "js/RealmOptions.h"
#include "nsHashtablesFwd.h"
#include "nsICookieJarSettings.h"
#include "nsIFingerprintingWebCompatService.h"
#include "nsIObserver.h"
#include "nsISupports.h"
#include "nsIRFPService.h"
#include "nsStringFwd.h"
#include <queue>
// 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 macOS if we spoof it as a Windows platform.
// We use this value for Desktop mode in Android.
// That's why it is defined here, outside of
// the platform-specific definitions.
#define SPOOFED_UA_OS_OTHER "X11; Linux x86_64"
#ifdef XP_WIN
# define SPOOFED_UA_OS "Windows NT 10.0; Win64; x64"
# define SPOOFED_APPVERSION "5.0 (Windows)"
# define SPOOFED_OSCPU "Windows NT 10.0; Win64; x64"
# define SPOOFED_MAX_TOUCH_POINTS 10
#elif defined(XP_MACOSX)
# define SPOOFED_UA_OS "Macintosh; Intel Mac OS X 10.15"
# define SPOOFED_APPVERSION "5.0 (Macintosh)"
# define SPOOFED_OSCPU "Intel Mac OS X 10.15"
# define SPOOFED_MAX_TOUCH_POINTS 0
#elif defined(MOZ_WIDGET_ANDROID)
# define SPOOFED_UA_OS "Android 10; Mobile"
# define SPOOFED_APPVERSION "5.0 (Android 10)"
# define SPOOFED_OSCPU "Linux armv81"
# define SPOOFED_MAX_TOUCH_POINTS 5
#else
// For Linux and other platforms, like BSDs, SunOS and etc, we will use Linux
// platform.
# define SPOOFED_UA_OS SPOOFED_UA_OS_OTHER
# define SPOOFED_APPVERSION "5.0 (X11)"
# define SPOOFED_OSCPU "Linux x86_64"
# define SPOOFED_MAX_TOUCH_POINTS 5
#endif
#define LEGACY_BUILD_ID "20181001000000"
#define LEGACY_UA_GECKO_TRAIL "20100101"
#define SPOOFED_POINTER_INTERFACE MouseEvent_Binding::MOZ_SOURCE_MOUSE
struct JSContext;
class nsIChannel;
class nsICanvasRenderingContextInternal;
namespace mozilla {
class WidgetKeyboardEvent;
class OriginAttributes;
class OriginAttributesPattern;
namespace dom {
class Document;
enum class CanvasContextType : uint8_t;
} // namespace dom
namespace gfx {
class DataSourceSurface;
} // namespace gfx
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 {
nsString mKey;
KeyNameIndex mKeyIdx;
SpoofingKeyboardCode mSpoofingCode;
};
class KeyboardHashKey : public PLDHashEntryHdr {
public:
typedef const KeyboardHashKey& KeyType;
typedef const KeyboardHashKey* KeyTypePointer;
KeyboardHashKey(const KeyboardLangs aLang, const KeyboardRegions aRegion,
const KeyNameIndex aKeyIdx, const nsAString& aKey);
explicit KeyboardHashKey(KeyTypePointer aOther);
KeyboardHashKey(KeyboardHashKey&& aOther) noexcept;
~KeyboardHashKey();
bool KeyEquals(KeyTypePointer aOther) const;
static KeyTypePointer KeyToPointer(KeyType aKey);
static PLDHashNumber HashKey(KeyTypePointer aKey);
enum { ALLOW_MEMMOVE = true };
KeyboardLangs mLang;
KeyboardRegions mRegion;
KeyNameIndex mKeyIdx;
nsString mKey;
};
// ============================================================================
// Reduce Timer Precision (RTP) Caller Type
enum class RTPCallerType : uint8_t {
Normal = 0,
SystemPrincipal = (1 << 0),
ResistFingerprinting = (1 << 1),
CrossOriginIsolated = (1 << 2)
};
inline JS::RTPCallerTypeToken RTPCallerTypeToToken(RTPCallerType aType) {
return JS::RTPCallerTypeToken{uint8_t(aType)};
}
inline RTPCallerType RTPCallerTypeFromToken(JS::RTPCallerTypeToken aToken) {
MOZ_RELEASE_ASSERT(
aToken.value == uint8_t(RTPCallerType::Normal) ||
aToken.value == uint8_t(RTPCallerType::SystemPrincipal) ||
aToken.value == uint8_t(RTPCallerType::ResistFingerprinting) ||
aToken.value == uint8_t(RTPCallerType::CrossOriginIsolated));
return static_cast<RTPCallerType>(aToken.value);
}
enum TimerPrecisionType {
DangerouslyNone = 1,
UnconditionalAKAHighRes = 2,
Normal = 3,
RFP = 4,
};
// ============================================================================
enum class CanvasFeatureUsage : uint64_t {
None = 0,
KnownText_1 = 1llu << 0,
KnownText_2 = 1llu << 1,
KnownText_3 = 1llu << 2,
KnownText_4 = 1llu << 3,
KnownText_5 = 1llu << 4,
KnownText_6 = 1llu << 5,
KnownText_7 = 1llu << 6,
KnownText_8 = 1llu << 7,
KnownText_9 = 1llu << 8,
KnownText_10 = 1llu << 9,
KnownText_11 = 1llu << 10,
KnownText_12 = 1llu << 11,
KnownText_13 = 1llu << 12,
KnownText_14 = 1llu << 13,
KnownText_15 = 1llu << 14,
KnownText_16 = 1llu << 15,
KnownText_17 = 1llu << 16,
KnownText_18 = 1llu << 17,
KnownText_19 = 1llu << 18,
KnownText_20 = 1llu << 19,
KnownText_21 = 1llu << 20,
KnownText_22 = 1llu << 21,
KnownText_23 = 1llu << 22,
KnownText_24 = 1llu << 23,
KnownText_25 = 1llu << 24,
KnownText_26 = 1llu << 25,
KnownText_27 = 1llu << 26,
KnownText_28 = 1llu << 27,
KnownText_29 = 1llu << 28,
KnownText_30 = 1llu << 29,
KnownText_31 = 1llu << 30,
KnownText_32 = 1llu << 31,
SetFont = 1llu << 32,
FillRect = 1llu << 33,
LineTo = 1llu << 34,
Stroke = 1llu << 35,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CanvasFeatureUsage);
// We try to classify observed canvas fingerprinting scripts into different
// classes, but we don't usually know the source/vendor of those scripts. The
// classification is based on a behavioral analysis covering things like the
// functions called and size of the canvas. The alias given is a guess and
// should not be considered definitive. The entity identified may not be doing
// this behavior at all, they may be doing a diferent or additional behaviors.
enum CanvasFingerprinterAlias {
eNoneIdentified = 0,
eFingerprintJS = 1,
eAkamai = 2,
eOzoki = 3,
ePerimeterX = 4,
eSignifyd = 5,
eClaydar = 6,
eForter = 7,
// Variants are unknown but distinct types of fingerprinters
eVariant1 = 8,
eVariant2 = 9,
eVariant3 = 10,
eVariant4 = 11,
eVariant5 = 12,
eVariant6 = 13,
eVariant7 = 14,
eVariant8 = 15,
eClientGear = 16,
eImperva = 17,
eLastAlias = eImperva
};
enum CanvasExtractionAPI : uint8_t {
ToDataURL = 0,
ToBlob = 1,
GetImageData = 2,
ReadPixels = 3
};
enum CanvasUsageSource : uint64_t {
Unknown = 0,
Impossible =
1llu << 0, // This represents API calls that I don't believe are possible
MainThread_Canvas_ImageBitmap_toDataURL = 1llu << 1,
MainThread_Canvas_ImageBitmap_toBlob = 1llu << 2,
MainThread_Canvas_ImageBitmap_getImageData = 1llu << 3,
MainThread_Canvas_Canvas2D_toDataURL = 1llu << 4,
MainThread_Canvas_Canvas2D_toBlob = 1llu << 5,
MainThread_Canvas_Canvas2D_getImageData = 1llu << 6,
MainThread_Canvas_WebGL_toDataURL = 1llu << 7,
MainThread_Canvas_WebGL_toBlob = 1llu << 8,
MainThread_Canvas_WebGL_getImageData = 1llu << 9,
MainThread_Canvas_WebGL_readPixels = 1llu << 10,
MainThread_Canvas_WebGPU_toDataURL = 1llu << 11,
MainThread_Canvas_WebGPU_toBlob = 1llu << 12,
MainThread_Canvas_WebGPU_getImageData = 1llu << 13,
MainThread_OffscreenCanvas_ImageBitmap_toDataURL = 1llu << 14,
MainThread_OffscreenCanvas_ImageBitmap_toBlob = 1llu << 15,
MainThread_OffscreenCanvas_ImageBitmap_getImageData = 1llu << 16,
MainThread_OffscreenCanvas_Canvas2D_toDataURL = 1llu << 17,
MainThread_OffscreenCanvas_Canvas2D_toBlob = 1llu << 18,
MainThread_OffscreenCanvas_Canvas2D_getImageData = 1llu << 19,
MainThread_OffscreenCanvas_WebGL_toDataURL = 1llu << 20,
MainThread_OffscreenCanvas_WebGL_toBlob = 1llu << 21,
MainThread_OffscreenCanvas_WebGL_getImageData = 1llu << 22,
MainThread_OffscreenCanvas_WebGL_readPixels = 1llu << 23,
MainThread_OffscreenCanvas_WebGPU_toDataURL = 1llu << 24,
MainThread_OffscreenCanvas_WebGPU_toBlob = 1llu << 25,
MainThread_OffscreenCanvas_WebGPU_getImageData = 1llu << 26,
Worker_OffscreenCanvas_ImageBitmap_toBlob = 1llu << 27,
Worker_OffscreenCanvas_ImageBitmap_getImageData = 1llu << 28,
Worker_OffscreenCanvas_Canvas2D_toBlob = 1llu << 29,
Worker_OffscreenCanvas_Canvas2D_getImageData = 1llu << 30,
Worker_OffscreenCanvasCanvas2D_Canvas2D_toBlob = 1llu << 31,
Worker_OffscreenCanvasCanvas2D_Canvas2D_getImageData = 1llu << 32,
Worker_OffscreenCanvas_WebGL_toBlob = 1llu << 33,
Worker_OffscreenCanvas_WebGL_getImageData = 1llu << 34,
Worker_OffscreenCanvas_WebGL_readPixels = 1llu << 35,
Worker_OffscreenCanvas_WebGPU_toBlob = 1llu << 36,
Worker_OffscreenCanvas_WebGPU_getImageData = 1llu << 37,
// --- New entires added here to preserve original values (no reordering!)
MainThread_Canvas_OffscreenCanvas2D_getImageData = 1llu << 38,
MainThread_Canvas_OffscreenCanvas2D_toBlob = 1llu << 39,
// After you go past 40 - metrics.yaml will need to be updated
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CanvasUsageSource);
nsCString CanvasUsageSourceToString(CanvasUsageSource aSource);
class CanvasUsage {
public:
CSSIntSize mSize;
dom::CanvasContextType mType;
CanvasUsageSource mUsageSource;
CanvasFeatureUsage mFeatureUsage;
CanvasUsage(CSSIntSize aSize, dom::CanvasContextType aType,
CanvasUsageSource aUsageSource, CanvasFeatureUsage aFeatureUsage)
: mSize(aSize),
mType(aType),
mUsageSource(aUsageSource),
mFeatureUsage(aFeatureUsage) {}
static CanvasUsage CreateUsage(
bool aIsOffscreen, dom::CanvasContextType aContextType,
CanvasExtractionAPI aApi, CSSIntSize aSize,
const nsICanvasRenderingContextInternal* aContext);
static inline CanvasUsageSource GetCanvasUsageSource(
bool isOffscreen, dom::CanvasContextType contextType,
CanvasExtractionAPI api);
};
struct CanvasFingerprintingEvent {
// The identity or alias of the entity doing the fingerprinting.
CanvasFingerprinterAlias alias;
// A bitmask of all of the known canvas fingerprinting texts
// non-zero indicates some known fingerprinting text was used, making the
// event highly likely to be fingerprinting.
uint32_t knownTextBitmask;
// A bitmap of all the sources that were used to extract canvas data
uint64_t sourcesBitmask;
CanvasFingerprintingEvent()
: alias(CanvasFingerprinterAlias::eNoneIdentified),
knownTextBitmask(0),
sourcesBitmask(0) {}
CanvasFingerprintingEvent(CanvasFingerprinterAlias aAlias,
uint32_t aKnownTextBitmask,
uint64_t aSourcesBitmask)
: alias(aAlias),
knownTextBitmask(aKnownTextBitmask),
sourcesBitmask(aSourcesBitmask) {}
bool operator==(const CanvasFingerprintingEvent& other) const {
return alias == other.alias && knownTextBitmask == other.knownTextBitmask &&
sourcesBitmask == other.sourcesBitmask;
}
};
// ============================================================================
// NOLINTNEXTLINE(bugprone-macro-parentheses)
#define ITEM_VALUE(name, val) name = val,
// The definition for fingerprinting protections. Each enum represents one
// fingerprinting protection that targets one specific WebAPI our fingerprinting
// surface. The enums can be found in RFPTargets.inc.
enum class RFPTarget : uint64_t {
#include "RFPTargets.inc"
};
#undef ITEM_VALUE
using RFPTargetSet = EnumSet<RFPTarget, std::bitset<128>>;
template <>
struct MaxEnumValue<RFPTarget> {
static constexpr unsigned int value = 127;
};
// ============================================================================
class nsRFPService final : public nsIObserver, public nsIRFPService {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIRFPSERVICE
static already_AddRefed<nsRFPService> GetOrCreate();
// _Rarely_ you will need to know if RFP is enabled, or if FPP is enabled.
// 98% of the time you should use nsContentUtils::ShouldResistFingerprinting
// as the difference will not matter to you.
static bool IsRFPPrefEnabled(bool aIsPrivateMode);
static bool IsRFPEnabledFor(
bool aIsPrivateMode, RFPTarget aTarget,
const Maybe<RFPTargetSet>& aOverriddenFingerprintingSettings);
static bool IsSystemPrincipalOrAboutFingerprintingProtection(JSContext*,
JSObject*);
// --------------------------------------------------------------------------
static double TimerResolution(RTPCallerType aRTPCallerType);
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,
RTPCallerType aRTPCallerType);
static double ReduceTimePrecisionAsMSecs(double aTime, int64_t aContextMixin,
RTPCallerType aRTPCallerType);
static double ReduceTimePrecisionAsMSecsRFPOnly(double aTime,
int64_t aContextMixin,
RTPCallerType aRTPCallerType);
static double ReduceTimePrecisionAsSecs(double aTime, int64_t aContextMixin,
RTPCallerType aRTPCallerType);
static double ReduceTimePrecisionAsSecsRFPOnly(double aTime,
int64_t aContextMixin,
RTPCallerType aRTPCallerType);
// 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 void GetSpoofedUserAgent(nsACString& userAgent,
bool aAndroidDesktopMode = false);
// --------------------------------------------------------------------------
// This method generates the locale string (e.g. "en-US") that should be
// spoofed by the JavaScript engine.
static nsCString GetSpoofedJSLocale();
// --------------------------------------------------------------------------
// This method generates the time zone string (e.g. "Atlantic/Reykjavik") that
// should be spoofed by the JavaScript engine.
static nsCString GetSpoofedJSTimeZone();
// --------------------------------------------------------------------------
/**
* 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 mozilla::dom::Document* 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 dom::Document* 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 mozilla::dom::Document* aDoc,
const WidgetKeyboardEvent* aKeyboardEvent,
uint32_t& aOut);
// --------------------------------------------------------------------------
// The method to generate the key for randomization. It can return nothing if
// the session key is not available due to the randomization is disabled.
static Maybe<nsTArray<uint8_t>> GenerateKey(nsIChannel* aChannel);
static Maybe<nsTArray<uint8_t>> GenerateKeyForServiceWorker(
nsIURI* aFirstPartyURI, nsIPrincipal* aPrincipal,
bool aForeignByAncestorContext);
static void PotentiallyDumpImage(nsIPrincipal* aPrincipal,
gfx::DataSourceSurface* aSurface);
static void PotentiallyDumpImage(nsIPrincipal* aPrincipal, uint8_t* aData,
uint32_t aWidth, uint32_t aHeight,
uint32_t aSize);
// This function is plumbed to RandomizeElements function.
static nsresult RandomizePixels(nsICookieJarSettings* aCookieJarSettings,
nsIPrincipal* aPrincipal, uint8_t* aData,
uint32_t aWidth, uint32_t aHeight,
uint32_t aSize,
mozilla::gfx::SurfaceFormat aSurfaceFormat);
// This function is used to randomize the elements in the given data
// according to the given parameters. For example, for an RGBA pixel, by group
// in this context, we refer to a single pixel and by element, we refer to
// channels. So, if we have an RGBA pixel, we have 4 elements per group, i.e.
// 4 channels per pixel. We use aElementsPerGroup to randomize at most one of
// elements per group, i.e. one channel per pixel.
static nsresult RandomizeElements(
nsICookieJarSettings* aCookieJarSettings, nsIPrincipal* aPrincipal,
uint8_t* aData, uint32_t aSizeInBytes, uint8_t aElementsPerGroup,
uint8_t aBytesPerElement, uint8_t aElementOffset, bool aSkipLastElement);
// --------------------------------------------------------------------------
// The method for getting the granular fingerprinting protection override of
// the given channel. Due to WebCompat reason, there can be a granular
// overrides to replace default enabled RFPTargets for the context of the
// channel. The method will return Nothing() to indicate using the default
// RFPTargets
static Maybe<RFPTargetSet> GetOverriddenFingerprintingSettingsForChannel(
nsIChannel* aChannel);
// The method for getting the granular fingerprinting protection override of
// the given first-party and third-party URIs. It will return the granular
// overrides if there is one defined for the context of the first-party URI
// and third-party URI. Otherwise, it will return Nothing() to indicate using
// the default RFPTargets.
static Maybe<RFPTargetSet> GetOverriddenFingerprintingSettingsForURI(
nsIURI* aFirstPartyURI, nsIURI* aThirdPartyURI, bool aIsPrivate);
// --------------------------------------------------------------------------
static void MaybeReportCanvasFingerprinter(nsTArray<CanvasUsage>& aUses,
nsIChannel* aChannel, nsIURI* aURI,
const nsACString& aOriginNoSuffix);
static void MaybeReportFontFingerprinter(nsIChannel* aChannel, nsIURI* aURI,
const nsACString& aOriginNoSuffix);
// --------------------------------------------------------------------------
// Generates a fake media device name with given kind and index.
// Example: Internal Microphone
static void GetMediaDeviceName(nsString& aName,
mozilla::dom::MediaDeviceKind aKind);
// Generates a fake media device group name with given kind and index.
// Example: Audio Group
static void GetMediaDeviceGroup(nsString& aGroup,
mozilla::dom::MediaDeviceKind aKind);
// Converts the viewport size to the angle.
static uint16_t ViewportSizeToAngle(int32_t aWidth, int32_t aHeight);
// Converts the viewport size to the orientation type.
static dom::OrientationType ViewportSizeToOrientationType(int32_t aWidth,
int32_t aHeight);
// Returns the default orientation type for the given platform.
static dom::OrientationType GetDefaultOrientationType();
// Returns the default pixel density for RFP.
static float GetDefaultPixelDensity();
// Returns the device pixel ratio at the given zoom level.
static double GetDevicePixelRatioAtZoom(float aZoom);
// Returns the value of privacy.resistFingerprinting.exemptedDomains pref
static void GetExemptedDomainsLowercase(nsCString& aExemptedDomains);
static CSSIntRect GetSpoofedScreenAvailSize(const nsRect& aRect, float aScale,
bool aIsFullscreen);
static uint64_t GetSpoofedStorageLimit();
static bool ExposeWebCodecsAPI(JSContext* aCx, JSObject* aObj);
static bool ExposeWebCodecsAPIImageDecoder(JSContext* aCx, JSObject* aObj);
static bool IsWebCodecsRFPTargetEnabled(JSContext* aCx);
static uint32_t CollapseMaxTouchPoints(uint32_t aMaxTouchPoints);
static void CalculateFontLocaleAllowlist();
static bool FontIsAllowedByLocale(const nsACString& aName);
static Maybe<RFPTarget> TextToRFPTarget(const nsAString& aText);
static void GetFingerprintingRandomizationKeyAsString(
nsICookieJarSettings* aCookieJarSettings,
nsACString& aRandomizationKeyStr);
static nsresult GenerateRandomizationKeyFromHash(
const nsACString& aRandomizationKeyStr, uint32_t aContentHash,
nsACString& aHex);
private:
nsresult Init();
nsRFPService() = default;
~nsRFPService() = default;
void UpdateFPPOverrideList();
void StartShutdown();
void PrefChanged(const char* aPref);
static void PrefChanged(const char* aPref, void* aSelf);
// --------------------------------------------------------------------------
static void MaybeCreateSpoofingKeyCodes(const KeyboardLangs aLang,
const KeyboardRegions aRegion);
static void MaybeCreateSpoofingKeyCodesForEnUS();
static void GetKeyboardLangAndRegion(const nsAString& aLanguage,
KeyboardLangs& aLocale,
KeyboardRegions& aRegion);
static bool GetSpoofedKeyCodeInfo(const mozilla::dom::Document* aDoc,
const WidgetKeyboardEvent* aKeyboardEvent,
SpoofingKeyboardCode& aOut);
static nsTHashMap<KeyboardHashKey, const SpoofingKeyboardCode*>*
sSpoofingKeyboardCodes;
// --------------------------------------------------------------------------
// Used by the JS Engine
static double ReduceTimePrecisionAsUSecsWrapper(
double aTime, JS::RTPCallerTypeToken aCallerType, JSContext* aCx);
static TimerPrecisionType GetTimerPrecisionType(RTPCallerType aRTPCallerType);
static TimerPrecisionType GetTimerPrecisionTypeRFPOnly(
RTPCallerType aRTPCallerType);
static void TypeToText(TimerPrecisionType aType, nsACString& aText);
// --------------------------------------------------------------------------
// A helper function to generate canvas key from the given image data and
// randomization key.
static nsresult GenerateCanvasKeyFromImageData(
nsICookieJarSettings* aCookieJarSettings, uint8_t* aImageData,
uint32_t aSize, nsTArray<uint8_t>& aCanvasKey);
// Generate the session key if it hasn't been generated.
nsresult GetBrowsingSessionKey(const OriginAttributes& aOriginAttributes,
nsID& aBrowsingSessionKey);
void ClearBrowsingSessionKey(const OriginAttributesPattern& aPattern);
void ClearBrowsingSessionKey(const OriginAttributes& aOriginAttributes);
// The keys that represent the browsing session. The lifetime of the key ties
// to the browsing session. For normal windows, the key is generated when
// loading the first http channel after the browser startup and persists until
// the browser shuts down. For private windows, the key is generated when
// opening a http channel on a private window and reset after all private
// windows close, i.e. private browsing session ends.
//
// The key will be used to generate the randomization noise used to fiddle the
// browser fingerprints. Note that this key lives and can only be accessed in
// the parent process.
nsTHashMap<nsCStringHashKey, nsID> mBrowsingSessionKeys;
nsCOMPtr<nsIFingerprintingWebCompatService> mWebCompatService;
nsTHashMap<nsCStringHashKey, RFPTargetSet> mFingerprintingOverrides;
// A helper function to create the domain key for the fingerprinting
// overrides. The key can be in the following five formats.
// 1. {first-party domain}: The override only apply to the first-party domain.
// 2. {first-party domain, *}: The overrides apply to every contexts under the
// top-level domain, including itself.
// 3. {*, third-party domain}: The overrides apply to the third-party domain
// under any top-level domain.
// 4. {first-party domain, third-party domain}: the overrides apply to the
// specific third-party domain under the given first-party domain.
// 5. {*}: A global overrides that will apply to every context.
static nsresult CreateOverrideDomainKey(nsIFingerprintingOverride* aOverride,
nsACString& aDomainKey);
// A helper function to create the RFPTarget bitfield based on the given
// overrides text and the based overrides bitfield. The function will parse
// the text and update the based overrides bitfield accordingly. Then, it will
// return the updated bitfield.
static RFPTargetSet CreateOverridesFromText(
const nsString& aOverridesText,
RFPTargetSet aBaseOverrides = RFPTargetSet());
enum FingerprintingProtectionType : uint8_t {
RFP,
FPP,
Baseline,
None,
};
static FingerprintingProtectionType GetFingerprintingProtectionType(
bool aIsPrivateMode);
static Maybe<bool> HandleExceptionalRFPTargets(
RFPTarget aTarget, bool aIsPrivateMode,
FingerprintingProtectionType aMode);
static bool IsTargetActiveForMode(RFPTarget aTarget,
FingerprintingProtectionType aMode);
static nsCString* sExemptedDomainsLowercase;
};
} // namespace mozilla
#endif /* _nsRFPService_h_ */