summaryrefslogtreecommitdiffstats
path: root/toolkit/components/antitracking/StorageAccessAPIHelper.h
blob: dd6f326604e5e1edc579ca3bb58d19f8cb01a57b (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
/* -*- 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_antitrackingservice_h
#define mozilla_antitrackingservice_h

#include "nsString.h"
#include "mozilla/ContentBlockingNotifier.h"
#include "mozilla/MozPromise.h"
#include "mozilla/RefPtr.h"
#include "mozilla/StaticPrefs_privacy.h"

#include "nsIUrlClassifierFeature.h"

class nsIChannel;
class nsICookieJarSettings;
class nsIPermission;
class nsIPrincipal;
class nsIURI;
class nsPIDOMWindowInner;
class nsPIDOMWindowOuter;

namespace mozilla {

class OriginAttributes;

namespace dom {
class BrowsingContext;
class ContentParent;
class Document;
}  // namespace dom

class StorageAccessAPIHelper final {
 public:
  enum StorageAccessPromptChoices { eAllow, eAllowAutoGrant };

  // Grant the permission for aOrigin to have access to the first party storage.
  // This methods can handle 2 different scenarios:
  // - aParentContext is a 3rd party context, it opens an aOrigin window and the
  //   user interacts with it. We want to grant the permission at the
  //   combination: top-level + aParentWindow + aOrigin.
  //   Ex: example.net loads an iframe tracker.com, which opens a popup
  //   tracker.org and the user interacts with it. tracker.org is allowed if
  //   loaded by tracker.com when loaded by example.net.
  // - aParentContext is a first party context and a 3rd party resource
  //   (probably becuase of a script) opens a popup and the user interacts with
  //   it. We want to grant the permission for the 3rd party context to have
  //   access to the first party stoage when loaded in aParentWindow. Ex:
  //   example.net import tracker.com/script.js which does opens a popup and the
  //   user interacts with it. tracker.com is allowed when loaded by
  //   example.net.
  typedef MozPromise<int, bool, true> StorageAccessPermissionGrantPromise;
  typedef std::function<RefPtr<StorageAccessPermissionGrantPromise>()>
      PerformPermissionGrant;
  [[nodiscard]] static RefPtr<StorageAccessPermissionGrantPromise>
  AllowAccessForOnParentProcess(
      nsIPrincipal* aPrincipal, dom::BrowsingContext* aParentContext,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
      const PerformPermissionGrant& aPerformFinalChecks = nullptr);

  [[nodiscard]] static RefPtr<StorageAccessPermissionGrantPromise>
  AllowAccessForOnChildProcess(
      nsIPrincipal* aPrincipal, dom::BrowsingContext* aParentContext,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
      const PerformPermissionGrant& aPerformFinalChecks = nullptr);

  // This function handles tasks that have to be done in the process
  // of the window that we just grant permission for.
  static void OnAllowAccessFor(
      dom::BrowsingContext* aParentContext, const nsACString& aTrackingOrigin,
      uint32_t aCookieBehavior,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason);

  // For IPC only.
  typedef MozPromise<nsresult, bool, true> ParentAccessGrantPromise;
  static RefPtr<ParentAccessGrantPromise> SaveAccessForOriginOnParentProcess(
      nsIPrincipal* aParentPrincipal, nsIPrincipal* aTrackingPrincipal,
      int aAllowMode, bool aFrameOnly,
      uint64_t aExpirationTime =
          StaticPrefs::privacy_restrict3rdpartystorage_expiration());

  static RefPtr<ParentAccessGrantPromise> SaveAccessForOriginOnParentProcess(
      uint64_t aTopLevelWindowId, dom::BrowsingContext* aParentContext,
      nsIPrincipal* aTrackingPrincipal, int aAllowMode, bool aFrameOnly,
      uint64_t aExpirationTime =
          StaticPrefs::privacy_restrict3rdpartystorage_expiration());

  // This function checks if the document has explicit permission either to
  // allow or deny access to cookies. This may be because of the "cookie"
  // permission or because the domain is on the ContentBlockingAllowList
  // e.g. because the user flipped the sheild.
  // This returns:
  //   Some(true) if unpartitioned cookies will be permitted
  //   Some(false) if unpartitioned cookies will be blocked
  //   None if it is not clear from permission alone what to do
  static Maybe<bool> CheckCookiesPermittedDecidesStorageAccessAPI(
      nsICookieJarSettings* aCookieJarSettings,
      nsIPrincipal* aRequestingPrincipal);

  // Calls CheckCookiesPermittedDecidesStorageAccessAPI in the Content Parent
  // using aBrowsingContext's Top's Window Global's CookieJarSettings.
  static RefPtr<MozPromise<Maybe<bool>, nsresult, true>>
  AsyncCheckCookiesPermittedDecidesStorageAccessAPIOnChildProcess(
      dom::BrowsingContext* aBrowsingContext,
      nsIPrincipal* aRequestingPrincipal);

  // This function checks if the browser settings give explicit permission
  // either to allow or deny access to cookies. This only checks the
  // cookieBehavior setting. This requires an additional bool to indicate
  // whether or not the context considered is third-party. This returns:
  //   Some(true) if unpartitioned cookies will be permitted
  //   Some(false) if unpartitioned cookies will be blocked
  //   None if it is not clear from settings alone what to do
  static Maybe<bool> CheckBrowserSettingsDecidesStorageAccessAPI(
      nsICookieJarSettings* aCookieJarSettings, bool aThirdParty,
      bool aIsOnThirdPartySkipList, bool aIsThirdPartyTracker);

  // This function checks if the document's context (like if it is third-party
  // or an iframe) gives an answer of how a the StorageAccessAPI call, that is
  // meant to be called by an embedded third party, should return.
  // This requires an argument that allows some checks to be run only if the
  // caller of this function is performing a request for storage access.
  // This returns:
  //   Some(true) if the calling context has access to cookies if it is not
  //              disallowed by the browser settings and cookie permissions
  //   Some(false) if the calling context should not have access to cookies if
  //               it is not expressly allowed by the browser settings and
  //               cookie permissions
  //   None if the calling context does not determine the document's access to
  //        unpartitioned cookies
  static Maybe<bool> CheckCallingContextDecidesStorageAccessAPI(
      dom::Document* aDocument, bool aRequestingStorageAccess);

  // This function checks if the document's context (like if it is third-party
  // or an iframe) gives an answer of how a the StorageAccessAPI call that is
  // meant to be called in a top-level context, should return.
  // This returns:
  //   Some(true) if the calling context indicates calls to the top-level
  //              API must resolve if it is not
  //              disallowed by the browser settings and cookie permissions
  //   Some(false) if the calling context must reject when calling top level
  //               portions of the API if it is not expressly allowed by the
  //               browser settings and cookie permissions
  //   None if the calling context does not determine the outcome of the
  //        document's use of the top-level portions of the Storage Access API.
  static Maybe<bool> CheckSameSiteCallingContextDecidesStorageAccessAPI(
      dom::Document* aDocument, bool aRequireUserActivation);

  // This function checks if the document has already been granted or denied
  // access to its unpartitioned cookies by the StorageAccessAPI
  // This returns:
  //   Some(true) if the document has been granted access by the Storage Access
  //              API before
  //   Some(false) if the document has been denied access by the Storage Access
  //               API before
  //   None if the document has not been granted or denied access by the Storage
  //        Access API before
  static Maybe<bool> CheckExistingPermissionDecidesStorageAccessAPI(
      dom::Document* aDocument, bool aRequestingStorageAccess);

  // This function performs the asynchronous portion of checking if requests
  // for storage access will be successful or not. This includes calling
  // Document member functions that creating a permission prompt request and
  // trying to perform an "autogrant" if aRequireGrant is true.
  // This will return a promise whose values correspond to those of a
  // ContentBlocking::AllowAccessFor call that ends the function.
  static RefPtr<StorageAccessPermissionGrantPromise>
  RequestStorageAccessAsyncHelper(
      dom::Document* aDocument, nsPIDOMWindowInner* aInnerWindow,
      dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
      bool aHasUserInteraction, bool aRequireUserInteraction, bool aFrameOnly,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aNotifier,
      bool aRequireGrant);

 private:
  friend class dom::ContentParent;

  // This function performs browser setting, cookie behavior and requesting
  // context checks that might grant/reject storage access immediately using
  // information provided by the inputs aPrincipal and aParentContext. To reduce
  // redundancy the following out parameters with information also required in
  // AllowAccessFor() are set in the function: aTrackingPrinciple,
  // aTrackingOrigin, aTopLevelWindowId, aBehavior. If storage access can be
  // granted/rejected due to settings/behavior returns a promise, else returns
  // nullptr.
  [[nodiscard]] static RefPtr<
      StorageAccessAPIHelper::StorageAccessPermissionGrantPromise>
  AllowAccessForHelper(
      nsIPrincipal* aPrincipal, dom::BrowsingContext* aParentContext,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
      nsCOMPtr<nsIPrincipal>* aTrackingPrincipal, nsACString& aTrackingOrigin,
      uint64_t* aTopLevelWindowId, uint32_t* aBehavior);

  [[nodiscard]] static RefPtr<StorageAccessPermissionGrantPromise>
  CompleteAllowAccessForOnParentProcess(
      dom::BrowsingContext* aParentContext, uint64_t aTopLevelWindowId,
      nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
      uint32_t aCookieBehavior,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
      const PerformPermissionGrant& aPerformFinalChecks = nullptr);

  [[nodiscard]] static RefPtr<StorageAccessPermissionGrantPromise>
  CompleteAllowAccessForOnChildProcess(
      dom::BrowsingContext* aParentContext, uint64_t aTopLevelWindowId,
      nsIPrincipal* aTrackingPrincipal, const nsACString& aTrackingOrigin,
      uint32_t aCookieBehavior,
      ContentBlockingNotifier::StorageAccessPermissionGrantedReason aReason,
      const PerformPermissionGrant& aPerformFinalChecks = nullptr);

  static void UpdateAllowAccessOnCurrentProcess(
      dom::BrowsingContext* aParentContext, const nsACString& aTrackingOrigin);

  static void UpdateAllowAccessOnParentProcess(
      dom::BrowsingContext* aParentContext, const nsACString& aTrackingOrigin);
};

}  // namespace mozilla

#endif  // mozilla_antitrackingservice_h