File: privacy_sandbox_attestations.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (260 lines) | stat: -rw-r--r-- 11,663 bytes parent folder | download | duplicates (6)
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
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_ATTESTATIONS_PRIVACY_SANDBOX_ATTESTATIONS_H_
#define COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_ATTESTATIONS_PRIVACY_SANDBOX_ATTESTATIONS_H_

#include <memory>
#include <optional>
#include <vector>

#include "base/containers/enum_set.h"
#include "base/containers/flat_map.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/thread_annotations.h"
#include "base/types/expected.h"
#include "base/version.h"
#include "components/privacy_sandbox/privacy_sandbox_settings_impl.h"
#include "net/base/schemeful_site.h"

namespace privacy_sandbox {

enum class ParsingStatus;

using PrivacySandboxAttestationsGatedAPISet =
    base::EnumSet<PrivacySandboxAttestationsGatedAPI,
                  PrivacySandboxAttestationsGatedAPI::kTopics,
                  PrivacySandboxAttestationsGatedAPI::kMaxValue>;

// TODO(crbug.com/40272506): Add a concise representation for "this site is
// attested for all APIs".
using PrivacySandboxAttestationsMap =
    base::flat_map<net::SchemefulSite, PrivacySandboxAttestationsGatedAPISet>;

// The default behavior when attestations are not yet ready.
enum class AttestationsDefaultBehavior {
  kAllow,
  kDeny,
};

class PrivacySandboxAttestations {
 public:
  // Describes the status of attestations file parsing.
  enum Progress {
    // Before we have started any parsing tasks on the attestation file.
    kNotStarted,

    // During the time when a new parsing task is running off of the main
    // thread.
    // TODO(crbug.com/40941689): This will no longer be true when there are two
    // parsing tasks posted to the thread pool at the same time, in which case
    // the progress will be `kFinished` after the first one completes. This
    // could be fixed by keeping a counter of pending tasks, and moving the
    // progress to kFinished when the counter reaches 0.
    kStarted,

    // When we have finished parsing the attestation file (resulting in either
    // success or failure). See the TODO above for edge cases.
    kFinished,
  };

  // Returns the singleton instance. If there is a test instance present, return
  // the test instance.
  static PrivacySandboxAttestations* GetInstance();

  // This function constructs a `PrivacySandboxAttestations` and returns a
  // unique pointer to it. Test should use this with
  // `ScopedPrivacySandboxAttestations` to install a scoped test instance, for
  // example:
  //
  // ScopedPrivacySandboxAttestations(
  //   PrivacySandboxAttestations::CreateForTesting())
  //
  // The destructor of `ScopedPrivacySandboxAttestations` will reset the
  // `g_test_instance` back to the previous one. If tests are testing APIs that
  // rely on `GetInstance()`, they must use `ScopedPrivacySandboxAttestations`
  // to set up the test instance first.
  // Note: `PrivacySandboxAttestations` requires that tests have a properly set
  // up task environment. For unit-tests, ensure
  // `content::BrowserTaskEnvironment` is initialized. This is required because
  // the final move assignment of the attestations map is done using the UI
  // thread. For browser tests, wait until the main thread is initialized before
  // calling `CreateForTesting()`.
  static std::unique_ptr<PrivacySandboxAttestations> CreateForTesting();

  static void SetInstanceForTesting(PrivacySandboxAttestations* test_instance);

  ~PrivacySandboxAttestations();

  PrivacySandboxAttestations(const PrivacySandboxAttestations&) = delete;
  PrivacySandboxAttestations(PrivacySandboxAttestations&&);

  PrivacySandboxAttestations& operator=(const PrivacySandboxAttestations&) =
      delete;
  PrivacySandboxAttestations& operator=(PrivacySandboxAttestations&&);

  // Record the status returned by `IsSiteAttestedInternal` to a histogram, then
  // return the status.
  // `attestations_default_behavior` optionally specifies the behavior when
  // attestations are not yet ready. By default it depends on the feature
  // `kDefaultAllowPrivacySandboxAttestations`, and when specified this
  // parameter takes precedence over the feature status.
  // TODO(crbug.com/40940888): This method will occasionally return false
  // positives i.e. it may mark some sites as attested even when they are not.
  // This will occur for example, if the attestations file is corrupted on-disk,
  // or the file is otherwise unavailable.
  PrivacySandboxSettingsImpl::Status IsSiteAttested(
      const net::SchemefulSite& site,
      PrivacySandboxAttestationsGatedAPI invoking_api,
      std::optional<AttestationsDefaultBehavior> attestations_default_behavior =
          std::nullopt) const;

  // Invoke `LoadAttestationsInternal()` to parse the attestations file
  // asynchronously on the SequencedTaskRunner `task_runner_` in the thread
  // pool. This function should only be invoked with a valid version and
  // `kEnforcePrivacySandboxAttestations` enabled. `installed_file_path` should
  // be the path to the attestations list file. If there is an existing
  // attestations map, only posts the parsing task if the incoming attestations
  // file has a newer version. This function also validates the existing version
  // and attestations map are in valid states.
  void LoadAttestations(base::Version version,
                        base::FilePath installed_file_path,
                        bool is_pre_installed);

  // Override the site to be attested for all the Privacy Sandbox APIs, even if
  // it is not officially enrolled. This allows developers to test Privacy
  // Sandbox APIs. The overriding is done using the devtools procotol.
  void AddOverride(const net::SchemefulSite& site);
  bool IsOverridden(const net::SchemefulSite& site) const;

  // Tests can call this function to make all privacy sandbox APIS to be
  // considered attested for any site. This is used to test APIs behaviors not
  // related to attestations.
  void SetAllPrivacySandboxAttestedForTesting(bool all_attested);

  // Tests can directly set the underlying `attestations_map_` through this test
  // only function. Note: tests should call `CreateAndSetForTesting()` before
  // calling this to make sure the attestations map is set to the testing
  // instance.
  void SetAttestationsForTesting(
      std::optional<PrivacySandboxAttestationsMap> attestations_map);

  base::Version GetVersionForTesting() const;

  // Set the callback to be invoked when attestations map is loaded. The typical
  // usage is to set the callback to `base::RunLoop::QuitClosure()`. Tests then
  // can use `base::RunLoop::Run()`, together with this callback, to make sure
  // the parsing and loading are completed.
  void SetLoadAttestationsDoneCallbackForTesting(base::OnceClosure callback);

  // Set the callback to be invoked when attestations map starts to be parsed.
  // (The parsing will be paused.) The typical usage is to set the callback to
  // `base::RunLoop::QuitClosure()`. Tests then can use `base::RunLoop::Run()`,
  // together with this callback, to inspect state once parsing starts.
  void SetLoadAttestationsParsingStartedCallbackForTesting(
      base::OnceClosure callback);

  // Set the callback to be invoked as part of the component registration
  // callback.
  void SetComponentRegistrationCallbackForTesting(base::OnceClosure callback);

  // Called when component installer finished registration and the check for
  // attestations file.
  void OnAttestationsFileCheckComplete();

  bool attestations_file_checked() const { return attestations_file_checked_; }

  void SetIsPreInstalled(bool is_pre_installed) {
    is_pre_installed_ = is_pre_installed;
  }

  bool is_pre_installed() const { return is_pre_installed_; }

 private:
  friend class base::NoDestructor<PrivacySandboxAttestations>;

  // The constructor is private to enforce the singleton requirement of this
  // class.
  PrivacySandboxAttestations();

  // Returns whether `site` is enrolled and attested for `invoking_api`.
  // This function returns `kAllowed` unconditionally if
  // 1. The `kEnforcePrivacySandboxAttestations` flag is disabled.
  // 2. Or `is_all_apis_attested_for_testing_` is set to true by
  // `SetAllPrivacySandboxAttestedForTesting()` for testing.
  PrivacySandboxSettingsImpl::Status IsSiteAttestedInternal(
      const net::SchemefulSite& site,
      PrivacySandboxAttestationsGatedAPI invoking_api) const;

  // Invoke the `attestations_loaded_callback_` registered by tests, if any.
  void RunLoadAttestationsDoneCallbackForTesting();

  // Invoke the `attestations_parsing_started_callback_` registered by tests,
  // if any. If this function returns true, parsing should be paused (because
  // we're in a test). If it returns false, do nothing.
  bool RunLoadAttestationsParsingStartedCallbackForTesting();

  // Invoke the `component_registration_callback_` registered by tests, if any.
  void RunComponentRegistrationCallbackForTesting();

  // Called when attestations parsing finishes. Stores the parsed attestations
  // map and its version.
  void OnAttestationsParsed(base::Version version,
                            bool is_pre_installed,
                            base::expected<PrivacySandboxAttestationsMap,
                                           ParsingStatus> attestations_map);

  // Task runner used to execute the file opening and parsing.
  scoped_refptr<base::SequencedTaskRunner> task_runner_;

  // This callback is invoked at the end of the loading of the attestations map.
  base::OnceClosure load_attestations_done_callback_;

  // This callback is invoked when parsing for the attestations map starts.
  base::OnceClosure load_attestations_parsing_started_callback_;

  // This callback is invoked as part of the component registration callback.
  base::OnceClosure component_registration_callback_;

  Progress attestations_parse_progress_ GUARDED_BY_CONTEXT(sequence_checker_) =
      kNotStarted;

  // The attestations file from the component updater should always carry a
  // valid version. If this is a `nullopt`, this implies the attestations list
  // has not been loaded yet.
  // The attestations file version uses a format of YYYY.MM.DD.VV. The last two
  // digits "VV" is used for multiple versions released in the same day. It has
  // a range from 0 to 99. It is usually 0.
  base::Version file_version_ GUARDED_BY_CONTEXT(sequence_checker_);

  // A data structure for storing and checking Privacy Sandbox attestations,
  // i.e. whether particular sites have opted in to using particular Privacy
  // Sandbox APIs. If this is a `nullopt`, this implies the attestations list
  // has not been loaded yet.
  std::optional<PrivacySandboxAttestationsMap> attestations_map_
      GUARDED_BY_CONTEXT(sequence_checker_);

  // Overridden sites by DevTools are considered attested.
  std::vector<net::SchemefulSite> overridden_sites_;

  // If true, all Privacy Sandbox APIs are considered attested for any site.
  bool is_all_apis_attested_for_testing_ = false;

  // Whether the component installer has checked the attestations file.
  bool attestations_file_checked_ = false;

  // Whether the attestation map is parsed from a pre-installed file.
  bool is_pre_installed_ = false;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace privacy_sandbox

#endif  // COMPONENTS_PRIVACY_SANDBOX_PRIVACY_SANDBOX_ATTESTATIONS_PRIVACY_SANDBOX_ATTESTATIONS_H_