diff options
Diffstat (limited to '')
-rw-r--r-- | netwerk/cookie/CookieJarSettings.h | 267 |
1 files changed, 267 insertions, 0 deletions
diff --git a/netwerk/cookie/CookieJarSettings.h b/netwerk/cookie/CookieJarSettings.h new file mode 100644 index 0000000000..97f8528a55 --- /dev/null +++ b/netwerk/cookie/CookieJarSettings.h @@ -0,0 +1,267 @@ +/* -*- 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); + + 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 |