OriginAttributes.h (10511B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_OriginAttributes_h 8 #define mozilla_OriginAttributes_h 9 10 #include "mozilla/dom/ChromeUtilsBinding.h" 11 #include "mozilla/StaticPrefs_privacy.h" 12 #include "nsIScriptSecurityManager.h" 13 14 namespace mozilla { 15 16 class OriginAttributes : public dom::OriginAttributesDictionary { 17 public: 18 OriginAttributes() = default; 19 20 explicit OriginAttributes(const OriginAttributesDictionary& aOther) 21 : OriginAttributesDictionary(aOther) {} 22 23 void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI, 24 bool aForced = false); 25 void SetFirstPartyDomain(const bool aIsTopLevelDocument, 26 const nsACString& aDomain); 27 void SetFirstPartyDomain(const bool aIsTopLevelDocument, 28 const nsAString& aDomain, bool aForced = false); 29 30 void SetPartitionKey(nsIURI* aURI, bool aForeignByAncestorContext); 31 void SetPartitionKey(const nsACString& aOther); 32 void SetPartitionKey(const nsAString& aOther); 33 34 enum { 35 STRIP_FIRST_PARTY_DOMAIN = 0x01, 36 STRIP_USER_CONTEXT_ID = 0x02, 37 STRIP_PRIVATE_BROWSING_ID = 0x04, 38 STRIP_PARITION_KEY = 0x08, 39 }; 40 41 inline void StripAttributes(uint32_t aFlags) { 42 if (aFlags & STRIP_FIRST_PARTY_DOMAIN) { 43 mFirstPartyDomain.Truncate(); 44 } 45 46 if (aFlags & STRIP_USER_CONTEXT_ID) { 47 mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID; 48 } 49 50 if (aFlags & STRIP_PRIVATE_BROWSING_ID) { 51 mPrivateBrowsingId = 52 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID; 53 } 54 55 if (aFlags & STRIP_PARITION_KEY) { 56 mPartitionKey.Truncate(); 57 } 58 } 59 60 bool operator==(const OriginAttributes& aOther) const { 61 return EqualsIgnoringFPD(aOther) && 62 mFirstPartyDomain == aOther.mFirstPartyDomain && 63 // FIXME(emilio, bug 1667440): Should this be part of 64 // EqualsIgnoringFPD instead? 65 mPartitionKey == aOther.mPartitionKey; 66 } 67 68 bool operator!=(const OriginAttributes& aOther) const { 69 return !(*this == aOther); 70 } 71 72 [[nodiscard]] bool EqualsIgnoringFPD(const OriginAttributes& aOther) const { 73 return mUserContextId == aOther.mUserContextId && 74 mPrivateBrowsingId == aOther.mPrivateBrowsingId && 75 mGeckoViewSessionContextId == aOther.mGeckoViewSessionContextId; 76 } 77 78 [[nodiscard]] bool EqualsIgnoringPartitionKey( 79 const OriginAttributes& aOther) const { 80 return EqualsIgnoringFPD(aOther) && 81 mFirstPartyDomain == aOther.mFirstPartyDomain; 82 } 83 84 [[nodiscard]] inline bool IsPrivateBrowsing() const { 85 return mPrivateBrowsingId != 86 nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID; 87 } 88 89 // Serializes/Deserializes non-default values into the suffix format, i.e. 90 // |^key1=value1&key2=value2|. If there are no non-default attributes, this 91 // returns an empty string. 92 void CreateSuffix(nsACString& aStr) const; 93 94 // Like CreateSuffix, but returns an atom instead of producing a string. 95 already_AddRefed<nsAtom> CreateSuffixAtom() const; 96 97 // Don't use this method for anything else than debugging! 98 void CreateAnonymizedSuffix(nsACString& aStr) const; 99 100 [[nodiscard]] bool PopulateFromSuffix(const nsACString& aStr); 101 102 // Populates the attributes from a string like 103 // |uri^key1=value1&key2=value2| and returns the uri without the suffix. 104 [[nodiscard]] bool PopulateFromOrigin(const nsACString& aOrigin, 105 nsACString& aOriginNoSuffix); 106 107 // Helper function to match mIsPrivateBrowsing to existing private browsing 108 // flags. Once all other flags are removed, this can be removed too. 109 void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing); 110 111 // check if "privacy.firstparty.isolate" is enabled. 112 static inline bool IsFirstPartyEnabled() { 113 return StaticPrefs::privacy_firstparty_isolate(); 114 } 115 116 // check if the access of window.opener across different FPDs is restricted. 117 // We only restrict the access of window.opener when first party isolation 118 // is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on. 119 static inline bool IsRestrictOpenerAccessForFPI() { 120 // We always want to restrict window.opener if first party isolation is 121 // disabled. 122 return !StaticPrefs::privacy_firstparty_isolate() || 123 StaticPrefs::privacy_firstparty_isolate_restrict_opener_access(); 124 } 125 126 // Check whether we block the postMessage across different FPDs when the 127 // targetOrigin is '*'. 128 [[nodiscard]] static inline bool IsBlockPostMessageForFPI() { 129 return StaticPrefs::privacy_firstparty_isolate() && 130 StaticPrefs::privacy_firstparty_isolate_block_post_message(); 131 } 132 133 // returns true if the originAttributes suffix has mPrivateBrowsingId value 134 // different than 0. 135 static bool IsPrivateBrowsing(const nsACString& aOrigin); 136 137 // Parse a partitionKey of the format 138 // "(<scheme>,<baseDomain>,[port],[ancestorbit])" into its components. Returns 139 // false if the partitionKey cannot be parsed because the format is invalid. 140 static bool ParsePartitionKey(const nsAString& aPartitionKey, 141 nsAString& outScheme, nsAString& outBaseDomain, 142 int32_t& outPort, 143 bool& outForeignByAncestorContext); 144 145 // Parse a partitionKey and extract the site from it. Returns false if the 146 // partitionKey cannot be parsed because the format is invalid. 147 static bool ExtractSiteFromPartitionKey(const nsAString& aPartitionKey, 148 nsAString& aOutSite); 149 }; 150 151 class OriginAttributesPattern : public dom::OriginAttributesPatternDictionary { 152 public: 153 // To convert a JSON string to an OriginAttributesPattern, do the following: 154 // 155 // OriginAttributesPattern pattern; 156 // if (!pattern.Init(aJSONString)) { 157 // ... // handle failure. 158 // } 159 OriginAttributesPattern() = default; 160 161 explicit OriginAttributesPattern( 162 const OriginAttributesPatternDictionary& aOther) 163 : OriginAttributesPatternDictionary(aOther) {} 164 165 // Performs a match of |aAttrs| against this pattern. 166 bool Matches(const OriginAttributes& aAttrs) const { 167 if (mUserContextId.WasPassed() && 168 mUserContextId.Value() != aAttrs.mUserContextId) { 169 return false; 170 } 171 172 if (mPrivateBrowsingId.WasPassed() && 173 mPrivateBrowsingId.Value() != aAttrs.mPrivateBrowsingId) { 174 return false; 175 } 176 177 if (mFirstPartyDomain.WasPassed() && 178 mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) { 179 return false; 180 } 181 182 if (mGeckoViewSessionContextId.WasPassed() && 183 mGeckoViewSessionContextId.Value() != 184 aAttrs.mGeckoViewSessionContextId) { 185 return false; 186 } 187 188 // If both mPartitionKey and mPartitionKeyPattern are passed, mPartitionKey 189 // takes precedence. 190 if (mPartitionKey.WasPassed()) { 191 if (mPartitionKey.Value() != aAttrs.mPartitionKey) { 192 return false; 193 } 194 } else if (mPartitionKeyPattern.WasPassed()) { 195 auto& pkPattern = mPartitionKeyPattern.Value(); 196 197 if (pkPattern.mScheme.WasPassed() || pkPattern.mBaseDomain.WasPassed() || 198 pkPattern.mPort.WasPassed()) { 199 if (aAttrs.mPartitionKey.IsEmpty()) { 200 return false; 201 } 202 203 nsString scheme; 204 nsString baseDomain; 205 int32_t port; 206 bool ancestor; 207 bool success = OriginAttributes::ParsePartitionKey( 208 aAttrs.mPartitionKey, scheme, baseDomain, port, ancestor); 209 if (!success) { 210 return false; 211 } 212 213 if (pkPattern.mScheme.WasPassed() && 214 pkPattern.mScheme.Value() != scheme) { 215 return false; 216 } 217 if (pkPattern.mBaseDomain.WasPassed() && 218 pkPattern.mBaseDomain.Value() != baseDomain) { 219 return false; 220 } 221 if (pkPattern.mPort.WasPassed() && pkPattern.mPort.Value() != port) { 222 return false; 223 } 224 if (pkPattern.mForeignByAncestorContext.WasPassed() && 225 pkPattern.mForeignByAncestorContext.Value() != ancestor) { 226 return false; 227 } 228 } 229 } 230 231 return true; 232 } 233 234 bool Overlaps(const OriginAttributesPattern& aOther) const { 235 if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() && 236 mUserContextId.Value() != aOther.mUserContextId.Value()) { 237 return false; 238 } 239 240 if (mPrivateBrowsingId.WasPassed() && 241 aOther.mPrivateBrowsingId.WasPassed() && 242 mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) { 243 return false; 244 } 245 246 if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() && 247 mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) { 248 return false; 249 } 250 251 if (mGeckoViewSessionContextId.WasPassed() && 252 aOther.mGeckoViewSessionContextId.WasPassed() && 253 mGeckoViewSessionContextId.Value() != 254 aOther.mGeckoViewSessionContextId.Value()) { 255 return false; 256 } 257 258 if (mPartitionKey.WasPassed() && aOther.mPartitionKey.WasPassed() && 259 mPartitionKey.Value() != aOther.mPartitionKey.Value()) { 260 return false; 261 } 262 263 if (mPartitionKeyPattern.WasPassed() && 264 aOther.mPartitionKeyPattern.WasPassed()) { 265 auto& self = mPartitionKeyPattern.Value(); 266 auto& other = aOther.mPartitionKeyPattern.Value(); 267 268 if (self.mScheme.WasPassed() && other.mScheme.WasPassed() && 269 self.mScheme.Value() != other.mScheme.Value()) { 270 return false; 271 } 272 if (self.mBaseDomain.WasPassed() && other.mBaseDomain.WasPassed() && 273 self.mBaseDomain.Value() != other.mBaseDomain.Value()) { 274 return false; 275 } 276 if (self.mPort.WasPassed() && other.mPort.WasPassed() && 277 self.mPort.Value() != other.mPort.Value()) { 278 return false; 279 } 280 if (self.mForeignByAncestorContext.WasPassed() && 281 other.mForeignByAncestorContext.WasPassed() && 282 self.mForeignByAncestorContext.Value() != 283 other.mForeignByAncestorContext.Value()) { 284 return false; 285 } 286 } 287 288 return true; 289 } 290 }; 291 292 } // namespace mozilla 293 294 #endif /* mozilla_OriginAttributes_h */