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_
|