summaryrefslogtreecommitdiffstats
path: root/caps/OriginAttributes.h
blob: 52f7afa9427de0856fa5d235cc459ddff09d1527 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/* -*- 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_OriginAttributes_h
#define mozilla_OriginAttributes_h

#include "mozilla/dom/ChromeUtilsBinding.h"
#include "mozilla/StaticPrefs_privacy.h"
#include "nsIScriptSecurityManager.h"

namespace mozilla {

class OriginAttributes : public dom::OriginAttributesDictionary {
 public:
  OriginAttributes() = default;

  explicit OriginAttributes(const OriginAttributesDictionary& aOther)
      : OriginAttributesDictionary(aOther) {}

  void SetFirstPartyDomain(const bool aIsTopLevelDocument, nsIURI* aURI,
                           bool aForced = false);
  void SetFirstPartyDomain(const bool aIsTopLevelDocument,
                           const nsACString& aDomain);
  void SetFirstPartyDomain(const bool aIsTopLevelDocument,
                           const nsAString& aDomain, bool aForced = false);

  void SetPartitionKey(nsIURI* aURI, bool aForeignByAncestorContext);
  void SetPartitionKey(const nsACString& aOther);
  void SetPartitionKey(const nsAString& aOther);

  enum {
    STRIP_FIRST_PARTY_DOMAIN = 0x01,
    STRIP_USER_CONTEXT_ID = 0x02,
    STRIP_PRIVATE_BROWSING_ID = 0x04,
    STRIP_PARITION_KEY = 0x08,
  };

  inline void StripAttributes(uint32_t aFlags) {
    if (aFlags & STRIP_FIRST_PARTY_DOMAIN) {
      mFirstPartyDomain.Truncate();
    }

    if (aFlags & STRIP_USER_CONTEXT_ID) {
      mUserContextId = nsIScriptSecurityManager::DEFAULT_USER_CONTEXT_ID;
    }

    if (aFlags & STRIP_PRIVATE_BROWSING_ID) {
      mPrivateBrowsingId =
          nsIScriptSecurityManager::DEFAULT_PRIVATE_BROWSING_ID;
    }

    if (aFlags & STRIP_PARITION_KEY) {
      mPartitionKey.Truncate();
    }
  }

  bool operator==(const OriginAttributes& aOther) const {
    return EqualsIgnoringFPD(aOther) &&
           mFirstPartyDomain == aOther.mFirstPartyDomain &&
           // FIXME(emilio, bug 1667440): Should this be part of
           // EqualsIgnoringFPD instead?
           mPartitionKey == aOther.mPartitionKey;
  }

  bool operator!=(const OriginAttributes& aOther) const {
    return !(*this == aOther);
  }

  [[nodiscard]] bool EqualsIgnoringFPD(const OriginAttributes& aOther) const {
    return mUserContextId == aOther.mUserContextId &&
           mPrivateBrowsingId == aOther.mPrivateBrowsingId &&
           mGeckoViewSessionContextId == aOther.mGeckoViewSessionContextId;
  }

  [[nodiscard]] bool EqualsIgnoringPartitionKey(
      const OriginAttributes& aOther) const {
    return EqualsIgnoringFPD(aOther) &&
           mFirstPartyDomain == aOther.mFirstPartyDomain;
  }

  // Serializes/Deserializes non-default values into the suffix format, i.e.
  // |^key1=value1&key2=value2|. If there are no non-default attributes, this
  // returns an empty string.
  void CreateSuffix(nsACString& aStr) const;

  // Like CreateSuffix, but returns an atom instead of producing a string.
  already_AddRefed<nsAtom> CreateSuffixAtom() const;

  // Don't use this method for anything else than debugging!
  void CreateAnonymizedSuffix(nsACString& aStr) const;

  [[nodiscard]] bool PopulateFromSuffix(const nsACString& aStr);

  // Populates the attributes from a string like
  // |uri^key1=value1&key2=value2| and returns the uri without the suffix.
  [[nodiscard]] bool PopulateFromOrigin(const nsACString& aOrigin,
                                        nsACString& aOriginNoSuffix);

  // Helper function to match mIsPrivateBrowsing to existing private browsing
  // flags. Once all other flags are removed, this can be removed too.
  void SyncAttributesWithPrivateBrowsing(bool aInPrivateBrowsing);

  // check if "privacy.firstparty.isolate" is enabled.
  static inline bool IsFirstPartyEnabled() {
    return StaticPrefs::privacy_firstparty_isolate();
  }

  // check if the access of window.opener across different FPDs is restricted.
  // We only restrict the access of window.opener when first party isolation
  // is enabled and "privacy.firstparty.isolate.restrict_opener_access" is on.
  static inline bool IsRestrictOpenerAccessForFPI() {
    // We always want to restrict window.opener if first party isolation is
    // disabled.
    return !StaticPrefs::privacy_firstparty_isolate() ||
           StaticPrefs::privacy_firstparty_isolate_restrict_opener_access();
  }

  // Check whether we block the postMessage across different FPDs when the
  // targetOrigin is '*'.
  [[nodiscard]] static inline bool IsBlockPostMessageForFPI() {
    return StaticPrefs::privacy_firstparty_isolate() &&
           StaticPrefs::privacy_firstparty_isolate_block_post_message();
  }

  // returns true if the originAttributes suffix has mPrivateBrowsingId value
  // different than 0.
  static bool IsPrivateBrowsing(const nsACString& aOrigin);

  // Parse a partitionKey of the format
  // "(<scheme>,<baseDomain>,[port],[ancestorbit])" into its components. Returns
  // false if the partitionKey cannot be parsed because the format is invalid.
  static bool ParsePartitionKey(const nsAString& aPartitionKey,
                                nsAString& outScheme, nsAString& outBaseDomain,
                                int32_t& outPort,
                                bool& outForeignByAncestorContext);
};

class OriginAttributesPattern : public dom::OriginAttributesPatternDictionary {
 public:
  // To convert a JSON string to an OriginAttributesPattern, do the following:
  //
  // OriginAttributesPattern pattern;
  // if (!pattern.Init(aJSONString)) {
  //   ... // handle failure.
  // }
  OriginAttributesPattern() = default;

  explicit OriginAttributesPattern(
      const OriginAttributesPatternDictionary& aOther)
      : OriginAttributesPatternDictionary(aOther) {}

  // Performs a match of |aAttrs| against this pattern.
  bool Matches(const OriginAttributes& aAttrs) const {
    if (mUserContextId.WasPassed() &&
        mUserContextId.Value() != aAttrs.mUserContextId) {
      return false;
    }

    if (mPrivateBrowsingId.WasPassed() &&
        mPrivateBrowsingId.Value() != aAttrs.mPrivateBrowsingId) {
      return false;
    }

    if (mFirstPartyDomain.WasPassed() &&
        mFirstPartyDomain.Value() != aAttrs.mFirstPartyDomain) {
      return false;
    }

    if (mGeckoViewSessionContextId.WasPassed() &&
        mGeckoViewSessionContextId.Value() !=
            aAttrs.mGeckoViewSessionContextId) {
      return false;
    }

    // If both mPartitionKey and mPartitionKeyPattern are passed, mPartitionKey
    // takes precedence.
    if (mPartitionKey.WasPassed()) {
      if (mPartitionKey.Value() != aAttrs.mPartitionKey) {
        return false;
      }
    } else if (mPartitionKeyPattern.WasPassed()) {
      auto& pkPattern = mPartitionKeyPattern.Value();

      if (pkPattern.mScheme.WasPassed() || pkPattern.mBaseDomain.WasPassed() ||
          pkPattern.mPort.WasPassed()) {
        if (aAttrs.mPartitionKey.IsEmpty()) {
          return false;
        }

        nsString scheme;
        nsString baseDomain;
        int32_t port;
        bool ancestor;
        bool success = OriginAttributes::ParsePartitionKey(
            aAttrs.mPartitionKey, scheme, baseDomain, port, ancestor);
        if (!success) {
          return false;
        }

        if (pkPattern.mScheme.WasPassed() &&
            pkPattern.mScheme.Value() != scheme) {
          return false;
        }
        if (pkPattern.mBaseDomain.WasPassed() &&
            pkPattern.mBaseDomain.Value() != baseDomain) {
          return false;
        }
        if (pkPattern.mPort.WasPassed() && pkPattern.mPort.Value() != port) {
          return false;
        }
        if (pkPattern.mForeignByAncestorContext.WasPassed() &&
            pkPattern.mForeignByAncestorContext.Value() != ancestor) {
          return false;
        }
      }
    }

    return true;
  }

  bool Overlaps(const OriginAttributesPattern& aOther) const {
    if (mUserContextId.WasPassed() && aOther.mUserContextId.WasPassed() &&
        mUserContextId.Value() != aOther.mUserContextId.Value()) {
      return false;
    }

    if (mPrivateBrowsingId.WasPassed() &&
        aOther.mPrivateBrowsingId.WasPassed() &&
        mPrivateBrowsingId.Value() != aOther.mPrivateBrowsingId.Value()) {
      return false;
    }

    if (mFirstPartyDomain.WasPassed() && aOther.mFirstPartyDomain.WasPassed() &&
        mFirstPartyDomain.Value() != aOther.mFirstPartyDomain.Value()) {
      return false;
    }

    if (mGeckoViewSessionContextId.WasPassed() &&
        aOther.mGeckoViewSessionContextId.WasPassed() &&
        mGeckoViewSessionContextId.Value() !=
            aOther.mGeckoViewSessionContextId.Value()) {
      return false;
    }

    if (mPartitionKey.WasPassed() && aOther.mPartitionKey.WasPassed() &&
        mPartitionKey.Value() != aOther.mPartitionKey.Value()) {
      return false;
    }

    if (mPartitionKeyPattern.WasPassed() &&
        aOther.mPartitionKeyPattern.WasPassed()) {
      auto& self = mPartitionKeyPattern.Value();
      auto& other = aOther.mPartitionKeyPattern.Value();

      if (self.mScheme.WasPassed() && other.mScheme.WasPassed() &&
          self.mScheme.Value() != other.mScheme.Value()) {
        return false;
      }
      if (self.mBaseDomain.WasPassed() && other.mBaseDomain.WasPassed() &&
          self.mBaseDomain.Value() != other.mBaseDomain.Value()) {
        return false;
      }
      if (self.mPort.WasPassed() && other.mPort.WasPassed() &&
          self.mPort.Value() != other.mPort.Value()) {
        return false;
      }
      if (self.mForeignByAncestorContext.WasPassed() &&
          other.mForeignByAncestorContext.WasPassed() &&
          self.mForeignByAncestorContext.Value() !=
              other.mForeignByAncestorContext.Value()) {
        return false;
      }
    }

    return true;
  }
};

}  // namespace mozilla

#endif /* mozilla_OriginAttributes_h */