532 lines
21 KiB
C++
532 lines
21 KiB
C++
/* -*- 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 <tuple>
|
|
#include <bitset>
|
|
#include "ErrorList.h"
|
|
#include "PLDHashTable.h"
|
|
#include "mozilla/BasicEvents.h"
|
|
#include "mozilla/ContentBlockingLog.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"
|
|
|
|
// 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 10
|
|
#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 10
|
|
#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;
|
|
|
|
namespace mozilla {
|
|
class WidgetKeyboardEvent;
|
|
class OriginAttributes;
|
|
class OriginAttributesPattern;
|
|
namespace dom {
|
|
class Document;
|
|
enum class CanvasContextType : uint8_t;
|
|
} // namespace dom
|
|
|
|
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 KeyNameIndexType 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;
|
|
KeyNameIndexType 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 : uint8_t {
|
|
None = 0,
|
|
KnownFingerprintText = 1 << 0,
|
|
SetFont = 1 << 1,
|
|
FillRect = 1 << 2,
|
|
LineTo = 1 << 3,
|
|
Stroke = 1 << 4
|
|
};
|
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CanvasFeatureUsage);
|
|
|
|
class CanvasUsage {
|
|
public:
|
|
CSSIntSize mSize;
|
|
dom::CanvasContextType mType;
|
|
CanvasFeatureUsage mFeatureUsage;
|
|
|
|
CanvasUsage(CSSIntSize aSize, dom::CanvasContextType aType,
|
|
CanvasFeatureUsage aFeatureUsage)
|
|
: mSize(aSize), mType(aType), mFeatureUsage(aFeatureUsage) {}
|
|
};
|
|
|
|
// ============================================================================
|
|
|
|
// 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 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);
|
|
|
|
// The method to add random noises to the image data based on the random key
|
|
// of the given cookieJarSettings.
|
|
static nsresult RandomizePixels(nsICookieJarSettings* aCookieJarSettings,
|
|
uint8_t* aData, uint32_t aWidth,
|
|
uint32_t aHeight, uint32_t aSize,
|
|
mozilla::gfx::SurfaceFormat aSurfaceFormat);
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// 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,
|
|
nsACString& aOriginNoSuffix);
|
|
|
|
static void MaybeReportFontFingerprinter(nsIChannel* aChannel,
|
|
const nsACString& aOriginNoSuffix);
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
// A helper function to check if there is a suspicious fingerprinting
|
|
// activity from given content blocking origin logs. It returns true if we
|
|
// detect suspicious fingerprinting activities.
|
|
static bool CheckSuspiciousFingerprintingActivity(
|
|
nsTArray<ContentBlockingLog::LogEntry>& aLogs);
|
|
|
|
// 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);
|
|
|
|
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 Maybe<RFPTarget> TextToRFPTarget(const nsAString& aText);
|
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
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> HandleExeptionalRFPTargets(
|
|
RFPTarget aTarget, bool aIsPrivateMode,
|
|
FingerprintingProtectionType aMode);
|
|
|
|
static bool IsTargetActiveForMode(RFPTarget aTarget,
|
|
FingerprintingProtectionType aMode);
|
|
|
|
static nsCString* sExemptedDomainsLowercase;
|
|
};
|
|
|
|
} // namespace mozilla
|
|
|
|
#endif /* __nsRFPService_h__ */
|