mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
c89fa7c1ae
Differential Revision: https://phabricator.services.mozilla.com/D172213
273 lines
10 KiB
C++
273 lines
10 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 mozilla_net_CookieJarSettings_h
|
|
#define mozilla_net_CookieJarSettings_h
|
|
|
|
#include "mozilla/Maybe.h"
|
|
|
|
#include "nsICookieJarSettings.h"
|
|
#include "nsTArray.h"
|
|
|
|
#define COOKIEJARSETTINGS_CONTRACTID "@mozilla.org/cookieJarSettings;1"
|
|
// 4ce234f1-52e8-47a9-8c8d-b02f815733c7
|
|
#define COOKIEJARSETTINGS_CID \
|
|
{ \
|
|
0x4ce234f1, 0x52e8, 0x47a9, { \
|
|
0x8c, 0x8d, 0xb0, 0x2f, 0x81, 0x57, 0x33, 0xc7 \
|
|
} \
|
|
}
|
|
|
|
class nsIPermission;
|
|
|
|
namespace mozilla {
|
|
namespace net {
|
|
|
|
class CookieJarSettingsArgs;
|
|
|
|
/**
|
|
* CookieJarSettings
|
|
* ~~~~~~~~~~~~~~
|
|
*
|
|
* CookieJarSettings is a snapshot of the cookie jar's configurations in a
|
|
* precise moment of time, such as the cookie policy and cookie permissions.
|
|
* This object is used by top-level documents to have a consistent cookie jar
|
|
* configuration also in case the user changes it. New configurations will apply
|
|
* only to new top-level documents.
|
|
*
|
|
* CookieJarSettings creation
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* CookieJarSettings is created when the top-level document's nsIChannel's
|
|
* nsILoadInfo is constructed. Any sub-resource and any sub-document inherits it
|
|
* from that nsILoadInfo. Also dedicated workers and their resources inherit it
|
|
* from the parent document.
|
|
*
|
|
* SharedWorkers and ServiceWorkers have their own CookieJarSettings because
|
|
* they don't have a single parent document (SharedWorkers could have more than
|
|
* one, ServiceWorkers have none).
|
|
*
|
|
* In Chrome code, we have a new CookieJarSettings when we download resources
|
|
* via 'Save-as...' and we also have a new CookieJarSettings for favicon
|
|
* downloading.
|
|
*
|
|
* Content-scripts WebExtensions also have their own CookieJarSettings because
|
|
* they don't have a direct access to the document they are running into.
|
|
*
|
|
* Anything else will have a special CookieJarSettings which blocks everything
|
|
* (CookieJarSettings::GetBlockingAll()) by forcing BEHAVIOR_REJECT as policy.
|
|
* When this happens, that context will not have access to the cookie jar and no
|
|
* cookies are sent or received.
|
|
*
|
|
* Propagation of CookieJarSettings
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* CookieJarSettings are shared inside the same top-level document via its
|
|
* nsIChannel's nsILoadInfo. This is done automatically if you pass a nsINode
|
|
* to NS_NewChannel(), and it must be done manually if you use a different
|
|
* channel constructor. For instance, this happens for any worker networking
|
|
* operation.
|
|
*
|
|
* We use the same CookieJarSettings for any resource belonging to the top-level
|
|
* document even if cross-origin. This makes the browser behave consistently a
|
|
* scenario where A loads B which loads A again, and cookie policy/permission
|
|
* changes in the meantime.
|
|
*
|
|
* Cookie Permissions propagation
|
|
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* CookieJarSettings populates the known cookie permissions only when required.
|
|
* Initially the list is empty, but when CookieJarSettings::CookiePermission()
|
|
* is called, the requested permission is stored in the internal list if it
|
|
* doesn't exist yet.
|
|
*
|
|
* This is actually nice because it relies on the permission propagation from
|
|
* parent to content process. No extra IPC is required.
|
|
*
|
|
* Note that we store permissions with UNKNOWN_ACTION values too because they
|
|
* can be set after the loading of the top-level document and we don't want to
|
|
* return a different value when this happens.
|
|
*
|
|
* Use of CookieJarSettings
|
|
* ~~~~~~~~~~~~~~~~~~~~~
|
|
*
|
|
* In theory, there should not be direct access to cookie permissions or
|
|
* cookieBehavior pref. Everything should pass through CookieJarSettings.
|
|
*
|
|
* A reference to CookieJarSettings can be obtained from
|
|
* nsILoadInfo::GetCookieJarSettings(), from Document::CookieJarSettings() and
|
|
* from the WorkerPrivate::CookieJarSettings().
|
|
*
|
|
* CookieJarSettings is thread-safe, but the permission list must be touched
|
|
* only on the main-thread.
|
|
*
|
|
* Testing
|
|
* ~~~~~~~
|
|
*
|
|
* If you need to test the changing of cookie policy or a cookie permission, you
|
|
* need to workaround CookieJarSettings. This can be done opening a new window
|
|
* and running the test into that new global.
|
|
*/
|
|
|
|
/**
|
|
* Class that provides an nsICookieJarSettings implementation.
|
|
*/
|
|
class CookieJarSettings final : public nsICookieJarSettings {
|
|
public:
|
|
typedef nsTArray<RefPtr<nsIPermission>> CookiePermissionList;
|
|
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
NS_DECL_NSICOOKIEJARSETTINGS
|
|
NS_DECL_NSISERIALIZABLE
|
|
|
|
static already_AddRefed<nsICookieJarSettings> GetBlockingAll(
|
|
bool aShouldResistFingerprinting);
|
|
|
|
enum CreateMode { eRegular, ePrivate };
|
|
|
|
static already_AddRefed<nsICookieJarSettings> Create(
|
|
CreateMode aMode, bool aShouldResistFingerprinting);
|
|
|
|
static already_AddRefed<nsICookieJarSettings> Create(
|
|
nsIPrincipal* aPrincipal);
|
|
|
|
// This function should be only called for XPCOM. You should never use this
|
|
// for other purposes.
|
|
static already_AddRefed<nsICookieJarSettings> CreateForXPCOM();
|
|
|
|
static already_AddRefed<nsICookieJarSettings> Create(
|
|
uint32_t aCookieBehavior, const nsAString& aPartitionKey,
|
|
bool aIsFirstPartyIsolated, bool aIsOnContentBlockingAllowList,
|
|
bool aShouldResistFingerprinting);
|
|
|
|
static CookieJarSettings* Cast(nsICookieJarSettings* aCS) {
|
|
return static_cast<CookieJarSettings*>(aCS);
|
|
}
|
|
|
|
void Serialize(CookieJarSettingsArgs& aData);
|
|
|
|
static void Deserialize(const CookieJarSettingsArgs& aData,
|
|
nsICookieJarSettings** aCookieJarSettings);
|
|
|
|
void Merge(const CookieJarSettingsArgs& aData);
|
|
|
|
// We don't want to send this object from parent to child process if there are
|
|
// no reasons. HasBeenChanged() returns true if the object has changed its
|
|
// internal state and it must be sent beck to the content process.
|
|
bool HasBeenChanged() const { return mToBeMerged; }
|
|
|
|
void UpdateIsOnContentBlockingAllowList(nsIChannel* aChannel);
|
|
|
|
void SetPartitionKey(nsIURI* aURI);
|
|
void SetPartitionKey(const nsAString& aPartitionKey) {
|
|
mPartitionKey = aPartitionKey;
|
|
}
|
|
const nsAString& GetPartitionKey() { return mPartitionKey; };
|
|
|
|
void SetFingerprintingRandomizationKey(const nsTArray<uint8_t>& aKey) {
|
|
mFingerprintingRandomKey.reset();
|
|
|
|
mFingerprintingRandomKey.emplace(aKey.Clone());
|
|
}
|
|
|
|
// Utility function to test if the passed cookiebahvior is
|
|
// BEHAVIOR_REJECT_TRACKER, BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN or
|
|
// BEHAVIOR_REJECT_FOREIGN when
|
|
// network.cookie.rejectForeignWithExceptions.enabled pref is set to true.
|
|
static bool IsRejectThirdPartyContexts(uint32_t aCookieBehavior);
|
|
|
|
// This static method returns true if aCookieBehavior is
|
|
// BEHAVIOR_REJECT_FOREIGN and
|
|
// network.cookie.rejectForeignWithExceptions.enabled pref is set to true.
|
|
static bool IsRejectThirdPartyWithExceptions(uint32_t aCookieBehavior);
|
|
|
|
private:
|
|
enum State {
|
|
// No cookie permissions are allowed to be stored in this object.
|
|
eFixed,
|
|
|
|
// Cookie permissions can be stored in case they are unknown when they are
|
|
// asked or when they are sent from the parent process.
|
|
eProgressive,
|
|
};
|
|
|
|
CookieJarSettings(uint32_t aCookieBehavior, bool aIsFirstPartyIsolated,
|
|
bool aShouldResistFingerprinting, State aState);
|
|
~CookieJarSettings();
|
|
|
|
uint32_t mCookieBehavior;
|
|
bool mIsFirstPartyIsolated;
|
|
CookiePermissionList mCookiePermissions;
|
|
bool mIsOnContentBlockingAllowList;
|
|
bool mIsOnContentBlockingAllowListUpdated;
|
|
nsString mPartitionKey;
|
|
|
|
State mState;
|
|
|
|
bool mToBeMerged;
|
|
|
|
// DO NOT USE THIS MEMBER TO CHECK IF YOU SHOULD RESIST FINGERPRINTING.
|
|
// USE THE nsContentUtils::ShouldResistFingerprinting() METHODS ONLY.
|
|
//
|
|
// As we move to fine-grained RFP control, we want to support per-domain
|
|
// exemptions from ResistFingerprinting. Specifically the behavior should be
|
|
// as such:
|
|
//
|
|
// Top-Level Document is on an Exempted Domain
|
|
// - RFP is disabled.
|
|
//
|
|
// Top-Level Document on an Exempted Domain embedding a non-exempted
|
|
// cross-origin iframe
|
|
// - RFP in the iframe is enabled (NOT exempted). (**)
|
|
//
|
|
// Top-Level Document on an Exempted Domain embedding an exempted cross-origin
|
|
// iframe
|
|
// - RFP in the iframe is disabled (exempted).
|
|
//
|
|
// Top-Level Document on a Non-Exempted Domain
|
|
// - RFP is enabled (NOT exempted).
|
|
//
|
|
// Top-Level Document on a Non-Exempted Domain embeds an exempted cross-origin
|
|
// iframe
|
|
// - RFP in the iframe is enabled (NOT exempted). (*)
|
|
//
|
|
// Exempted Document (top-level or iframe) contacts any cross-origin domain
|
|
// (exempted or non-exempted)
|
|
// - RFP is disabled (exempted) for the request
|
|
//
|
|
// Non-Exempted Document (top-level or iframe) contacts any cross-origin
|
|
// domain
|
|
// (exempted or non-exempted)
|
|
// - RFP is enabled (NOT exempted) for the request
|
|
//
|
|
// This boolean on CookieJarSettings will enable us to apply the most
|
|
// difficult rule, marked in (*). (It is difficult because the
|
|
// subdocument's loadinfo will look like it should be exempted.)
|
|
// However if we trusted this member blindly, it would not correctly apply
|
|
// the one marked with (**). (Because it would inherit an exemption into
|
|
// a subdocument that should not be exempted.)
|
|
// To handle this case, we only trust a CookieJar's ShouldRFP value if it
|
|
// says we should resist fingerprinting. If it says that we _should not_,
|
|
// we continue and check the channel's URI or LoadInfo and if
|
|
// the domain specified there is not an exempted domain, enforce RFP anyway.
|
|
// This all occurrs in the nscontentUtils::ShouldResistFingerprinting
|
|
// functions which you should be using.
|
|
bool mShouldResistFingerprinting;
|
|
|
|
// The key used to generate the random noise for randomizing the browser
|
|
// fingerprint. The key is decided by the session key and the top-level site.
|
|
// So, the browse fingerprint will look different to the same tracker
|
|
// under different top-level sites. Also, the fingerprint will change as
|
|
// browsing session changes. This can prevent trackers to identify individuals
|
|
// by using browser fingerprints.
|
|
Maybe<nsTArray<uint8_t>> mFingerprintingRandomKey;
|
|
};
|
|
|
|
} // namespace net
|
|
} // namespace mozilla
|
|
|
|
#endif // mozilla_net_CookieJarSettings_h
|