privacy_sandbox_settings.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/privacy_sandbox/privacy_sandbox_settings.h"
  5. #include "base/feature_list.h"
  6. #include "base/json/values_util.h"
  7. #include "base/observer_list.h"
  8. #include "base/ranges/algorithm.h"
  9. #include "base/time/time.h"
  10. #include "components/content_settings/core/browser/cookie_settings.h"
  11. #include "components/content_settings/core/browser/host_content_settings_map.h"
  12. #include "components/content_settings/core/common/pref_names.h"
  13. #include "components/prefs/pref_service.h"
  14. #include "components/prefs/scoped_user_pref_update.h"
  15. #include "components/privacy_sandbox/privacy_sandbox_features.h"
  16. #include "components/privacy_sandbox/privacy_sandbox_prefs.h"
  17. #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
  18. #include "net/cookies/site_for_cookies.h"
  19. #include "url/gurl.h"
  20. #include "url/origin.h"
  21. namespace privacy_sandbox {
  22. namespace {
  23. constexpr char kBlockedTopicsTopicKey[] = "topic";
  24. constexpr char kBlockedTopicsBlockTimeKey[] = "blockedOn";
  25. bool IsCookiesClearOnExitEnabled(HostContentSettingsMap* map) {
  26. return map->GetDefaultContentSetting(ContentSettingsType::COOKIES,
  27. /*provider_id=*/nullptr) ==
  28. ContentSetting::CONTENT_SETTING_SESSION_ONLY;
  29. }
  30. // Convert a stored FLEDGE block eTLD+1 into applicable content settings
  31. // patterns. This ensures that if Public Suffix List membership changes, the
  32. // stored item continues to match as when it was set. Multiple patterns are set
  33. // to support IP address fallbacks, which do not support [*.] prefixes.
  34. // TODO (crbug.com/1287153): This is somewhat hacky and can be removed when
  35. // FLEDGE is controlled by a content setting directly.
  36. std::vector<ContentSettingsPattern> FledgeBlockToContentSettingsPatterns(
  37. const std::string& entry) {
  38. return {ContentSettingsPattern::FromString("[*.]" + entry),
  39. ContentSettingsPattern::FromString(entry)};
  40. }
  41. // Returns a base::Value for storage in prefs that represents |topic| blocked
  42. // at the current time.
  43. base::Value CreateBlockedTopicEntry(const CanonicalTopic& topic) {
  44. base::Value entry(base::Value::Type::DICTIONARY);
  45. entry.SetKey(kBlockedTopicsTopicKey, topic.ToValue());
  46. entry.SetKey(kBlockedTopicsBlockTimeKey,
  47. base::TimeToValue(base::Time::Now()));
  48. return entry;
  49. }
  50. } // namespace
  51. PrivacySandboxSettings::PrivacySandboxSettings(
  52. std::unique_ptr<Delegate> delegate,
  53. HostContentSettingsMap* host_content_settings_map,
  54. scoped_refptr<content_settings::CookieSettings> cookie_settings,
  55. PrefService* pref_service,
  56. bool incognito_profile)
  57. : delegate_(std::move(delegate)),
  58. host_content_settings_map_(host_content_settings_map),
  59. cookie_settings_(cookie_settings),
  60. pref_service_(pref_service),
  61. incognito_profile_(incognito_profile) {
  62. DCHECK(pref_service_);
  63. DCHECK(host_content_settings_map_);
  64. DCHECK(cookie_settings_);
  65. // "Clear on exit" causes a cookie deletion on shutdown. But for practical
  66. // purposes, we're notifying the observers on startup (which should be
  67. // equivalent, as no cookie operations could have happened while the profile
  68. // was shut down).
  69. if (IsCookiesClearOnExitEnabled(host_content_settings_map_))
  70. OnCookiesCleared();
  71. pref_change_registrar_.Init(pref_service_);
  72. pref_change_registrar_.Add(
  73. prefs::kPrivacySandboxApisEnabledV2,
  74. base::BindRepeating(&PrivacySandboxSettings::OnPrivacySandboxPrefChanged,
  75. base::Unretained(this)));
  76. }
  77. PrivacySandboxSettings::~PrivacySandboxSettings() = default;
  78. bool PrivacySandboxSettings::IsTopicsAllowed() const {
  79. // Topics API calculation should be prevented if the user has blocked 3PC
  80. // cookies, as there will be no context specific check.
  81. const auto cookie_controls_mode =
  82. static_cast<content_settings::CookieControlsMode>(
  83. pref_service_->GetInteger(prefs::kCookieControlsMode));
  84. const auto default_content_setting =
  85. cookie_settings_->GetDefaultCookieSetting(/*provider_id=*/nullptr);
  86. const bool third_party_cookies_blocked =
  87. default_content_setting == ContentSetting::CONTENT_SETTING_BLOCK ||
  88. cookie_controls_mode ==
  89. content_settings::CookieControlsMode::kBlockThirdParty;
  90. return IsPrivacySandboxEnabled() && !third_party_cookies_blocked;
  91. }
  92. bool PrivacySandboxSettings::IsTopicsAllowedForContext(
  93. const GURL& url,
  94. const absl::optional<url::Origin>& top_frame_origin) const {
  95. // If the Topics API is disabled completely, it is not available in any
  96. // context.
  97. return IsTopicsAllowed() &&
  98. IsPrivacySandboxEnabledForContext(url, top_frame_origin);
  99. }
  100. bool PrivacySandboxSettings::IsTopicAllowed(const CanonicalTopic& topic) {
  101. auto* blocked_topics =
  102. pref_service_->GetList(prefs::kPrivacySandboxBlockedTopics);
  103. for (const auto& item : blocked_topics->GetList()) {
  104. auto blocked_topic =
  105. CanonicalTopic::FromValue(*item.GetDict().Find(kBlockedTopicsTopicKey));
  106. if (!blocked_topic)
  107. continue;
  108. if (topic == *blocked_topic)
  109. return false;
  110. }
  111. return true;
  112. }
  113. void PrivacySandboxSettings::SetTopicAllowed(const CanonicalTopic& topic,
  114. bool allowed) {
  115. ListPrefUpdate scoped_pref_update(pref_service_,
  116. prefs::kPrivacySandboxBlockedTopics);
  117. // Presence in the preference list indicates that a topic is blocked, as
  118. // there is no concept of explicitly allowed topics. Thus, allowing a topic
  119. // is the same as removing it, if it exists, from the blocklist. Blocking
  120. // a topic is the same as adding it to the blocklist, but as duplicate entries
  121. // are undesireable, removing any existing reference first is desireable.
  122. // Thus, regardless of |allowed|, removing any existing reference is the
  123. // first step.
  124. scoped_pref_update->GetList().EraseIf([&](const base::Value& value) {
  125. auto* blocked_topic_value = value.GetDict().Find(kBlockedTopicsTopicKey);
  126. auto converted_topic = CanonicalTopic::FromValue(*blocked_topic_value);
  127. return converted_topic && *converted_topic == topic;
  128. });
  129. // If the topic is being blocked, it can be (re)added to the blocklist. If the
  130. // topic was removed from the blocklist above, this is equivalent to updating
  131. // the modified time associated with the entry to the current time. As data
  132. // deletions are typically from the current time backwards, this makes it
  133. // more likely to be removed - a privacy improvement.
  134. if (!allowed)
  135. scoped_pref_update->Append(CreateBlockedTopicEntry(topic));
  136. }
  137. void PrivacySandboxSettings::ClearTopicSettings(base::Time start_time,
  138. base::Time end_time) {
  139. ListPrefUpdate scoped_pref_update(pref_service_,
  140. prefs::kPrivacySandboxBlockedTopics);
  141. // Shortcut for maximum time range deletion.
  142. if (start_time == base::Time() && end_time == base::Time::Max()) {
  143. scoped_pref_update->GetList().clear();
  144. return;
  145. }
  146. scoped_pref_update->GetList().EraseIf([&](const base::Value& value) {
  147. auto blocked_time =
  148. base::ValueToTime(value.GetDict().Find(kBlockedTopicsBlockTimeKey));
  149. return start_time <= blocked_time && blocked_time <= end_time;
  150. });
  151. }
  152. base::Time PrivacySandboxSettings::TopicsDataAccessibleSince() const {
  153. return pref_service_->GetTime(
  154. prefs::kPrivacySandboxTopicsDataAccessibleSince);
  155. }
  156. bool PrivacySandboxSettings::IsConversionMeasurementAllowed(
  157. const url::Origin& top_frame_origin,
  158. const url::Origin& reporting_origin) const {
  159. return IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(),
  160. top_frame_origin);
  161. }
  162. bool PrivacySandboxSettings::ShouldSendConversionReport(
  163. const url::Origin& impression_origin,
  164. const url::Origin& conversion_origin,
  165. const url::Origin& reporting_origin) const {
  166. // The |reporting_origin| needs to have been accessible in both impression
  167. // and conversion contexts. These are both checked when they occur, but
  168. // user settings may have changed between then and when the conversion report
  169. // is sent.
  170. return IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(),
  171. impression_origin) &&
  172. IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(),
  173. conversion_origin);
  174. }
  175. void PrivacySandboxSettings::SetFledgeJoiningAllowed(
  176. const std::string& top_frame_etld_plus1,
  177. bool allowed) {
  178. DictionaryPrefUpdate scoped_pref_update(
  179. pref_service_, prefs::kPrivacySandboxFledgeJoinBlocked);
  180. auto* pref_data = scoped_pref_update.Get();
  181. DCHECK(pref_data);
  182. DCHECK(pref_data->is_dict());
  183. // Ensure that the provided etld_plus1 actually is an etld+1.
  184. auto effective_top_frame_etld_plus1 =
  185. net::registry_controlled_domains::GetDomainAndRegistry(
  186. top_frame_etld_plus1,
  187. net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
  188. // Hosts are also accepted as a fallback. This may occur if the private
  189. // registry has changed, and what the caller may be assuming is an eTLD+1 no
  190. // longer is. Simply ignoring non-eTLD+1's may thus result in unexpected
  191. // access.
  192. if (effective_top_frame_etld_plus1 != top_frame_etld_plus1) {
  193. // Add a dummy scheme and use GURL to confirm the provided string is a valid
  194. // host.
  195. const GURL url("https://" + top_frame_etld_plus1);
  196. effective_top_frame_etld_plus1 = url.host();
  197. }
  198. // Ignore attempts to configure an empty etld+1. This will also catch the
  199. // case where the eTLD+1 was not even a host, as GURL will have canonicalised
  200. // it to empty.
  201. if (effective_top_frame_etld_plus1.length() == 0) {
  202. NOTREACHED() << "Cannot control FLEDGE joining for empty eTLD+1";
  203. return;
  204. }
  205. if (allowed) {
  206. // Existence of the key implies blocking, so simply removing the key is
  207. // sufficient. If the key wasn't already present, the following is a no-op.
  208. pref_data->RemoveKey(effective_top_frame_etld_plus1);
  209. } else {
  210. // Overriding the creation date for keys which already exist is acceptable.
  211. // Time range based deletions are typically started from the current time,
  212. // and so this will be more aggressively removed. This decreases the chance
  213. // a potentially sensitive website remains in preferences.
  214. pref_data->SetKey(effective_top_frame_etld_plus1,
  215. base::TimeToValue(base::Time::Now()));
  216. }
  217. }
  218. void PrivacySandboxSettings::ClearFledgeJoiningAllowedSettings(
  219. base::Time start_time,
  220. base::Time end_time) {
  221. DictionaryPrefUpdate scoped_pref_update(
  222. pref_service_, prefs::kPrivacySandboxFledgeJoinBlocked);
  223. auto* pref_data = scoped_pref_update.Get();
  224. DCHECK(pref_data);
  225. DCHECK(pref_data->is_dict());
  226. // Shortcut for maximum time range deletion
  227. if (start_time == base::Time() && end_time == base::Time::Max()) {
  228. pref_data->DictClear();
  229. return;
  230. }
  231. std::vector<std::string> keys_to_remove;
  232. for (auto entry : pref_data->DictItems()) {
  233. absl::optional<base::Time> created_time = base::ValueToTime(entry.second);
  234. if (created_time.has_value() && start_time <= created_time &&
  235. created_time <= end_time) {
  236. keys_to_remove.push_back(entry.first);
  237. }
  238. }
  239. for (const auto& key : keys_to_remove)
  240. pref_data->RemoveKey(key);
  241. }
  242. bool PrivacySandboxSettings::IsFledgeJoiningAllowed(
  243. const url::Origin& top_frame_origin) const {
  244. DictionaryPrefUpdate scoped_pref_update(
  245. pref_service_, prefs::kPrivacySandboxFledgeJoinBlocked);
  246. auto* pref_data = scoped_pref_update.Get();
  247. DCHECK(pref_data);
  248. DCHECK(pref_data->is_dict());
  249. for (auto entry : pref_data->DictItems()) {
  250. if (base::ranges::any_of(FledgeBlockToContentSettingsPatterns(entry.first),
  251. [&](const auto& pattern) {
  252. return pattern.Matches(
  253. top_frame_origin.GetURL());
  254. })) {
  255. return false;
  256. }
  257. }
  258. return true;
  259. }
  260. bool PrivacySandboxSettings::IsFledgeAllowed(
  261. const url::Origin& top_frame_origin,
  262. const url::Origin& auction_party) {
  263. return IsPrivacySandboxEnabledForContext(auction_party.GetURL(),
  264. top_frame_origin);
  265. }
  266. std::vector<GURL> PrivacySandboxSettings::FilterFledgeAllowedParties(
  267. const url::Origin& top_frame_origin,
  268. const std::vector<GURL>& auction_parties) {
  269. // If the sandbox is disabled, then no parties are allowed and we can avoid
  270. // even iterating over them.
  271. if (!IsPrivacySandboxEnabled())
  272. return {};
  273. std::vector<GURL> allowed_parties;
  274. for (const auto& party : auction_parties) {
  275. if (IsPrivacySandboxEnabledForContext(party, top_frame_origin)) {
  276. allowed_parties.push_back(party);
  277. }
  278. }
  279. return allowed_parties;
  280. }
  281. bool PrivacySandboxSettings::IsSharedStorageAllowed(
  282. const url::Origin& top_frame_origin,
  283. const url::Origin& accessing_origin) const {
  284. // Ensures that Shared Storage is only allowed if both Privacy Sandbox is
  285. // enabled and full cookie access is enabled for this context.
  286. return IsPrivacySandboxEnabledForContext(accessing_origin.GetURL(),
  287. top_frame_origin);
  288. }
  289. bool PrivacySandboxSettings::IsPrivateAggregationAllowed(
  290. const url::Origin& top_frame_origin,
  291. const url::Origin& reporting_origin) const {
  292. return IsPrivacySandboxEnabledForContext(reporting_origin.GetURL(),
  293. top_frame_origin);
  294. }
  295. bool PrivacySandboxSettings::IsPrivacySandboxEnabled() const {
  296. // If the delegate is restricting access the Privacy Sandbox is disabled.
  297. if (delegate_->IsPrivacySandboxRestricted())
  298. return false;
  299. // For Measurement and Relevance APIs, we explicitly do not require the
  300. // underlying pref to be enabled if there is a local flag enabling the APIs to
  301. // allow for local testing.
  302. bool should_override_setting_for_local_testing = base::FeatureList::IsEnabled(
  303. privacy_sandbox::kOverridePrivacySandboxSettingsLocalTesting);
  304. // Which preference is consulted is dependent on whether release 3 of the
  305. // settings is available.
  306. if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) {
  307. // For Privacy Sandbox Settings 3, APIs are disabled in incognito.
  308. if (incognito_profile_)
  309. return false;
  310. if (should_override_setting_for_local_testing) {
  311. return true;
  312. }
  313. // For Privacy Sandbox Settings 3, APIs may be restricted via the delegate.
  314. // The V2 pref was introduced with the 3rd Privacy Sandbox release.
  315. return pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabledV2);
  316. }
  317. if (should_override_setting_for_local_testing)
  318. return true;
  319. return pref_service_->GetBoolean(prefs::kPrivacySandboxApisEnabled);
  320. }
  321. void PrivacySandboxSettings::SetPrivacySandboxEnabled(bool enabled) {
  322. // Only apply the decision to the appropriate preference.
  323. if (base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3)) {
  324. pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabledV2, enabled);
  325. } else {
  326. pref_service_->SetBoolean(prefs::kPrivacySandboxApisEnabled, enabled);
  327. }
  328. }
  329. bool PrivacySandboxSettings::IsTrustTokensAllowed() {
  330. // The PrivacySandboxSettings is only involved in Trust Token access
  331. // decisions when the Release 3 flag is enabled.
  332. if (!base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3))
  333. return true;
  334. return IsPrivacySandboxEnabled();
  335. }
  336. bool PrivacySandboxSettings::IsPrivacySandboxRestricted() {
  337. return delegate_->IsPrivacySandboxRestricted();
  338. }
  339. void PrivacySandboxSettings::OnCookiesCleared() {
  340. SetTopicsDataAccessibleFromNow();
  341. }
  342. void PrivacySandboxSettings::OnPrivacySandboxPrefChanged() {
  343. // The PrivacySandboxSettings is only involved in Trust Token access
  344. // decisions when the Release 3 flag is enabled.
  345. if (!base::FeatureList::IsEnabled(privacy_sandbox::kPrivacySandboxSettings3))
  346. return;
  347. for (auto& observer : observers_)
  348. observer.OnTrustTokenBlockingChanged(!IsTrustTokensAllowed());
  349. }
  350. void PrivacySandboxSettings::AddObserver(Observer* observer) {
  351. observers_.AddObserver(observer);
  352. }
  353. void PrivacySandboxSettings::RemoveObserver(Observer* observer) {
  354. observers_.RemoveObserver(observer);
  355. }
  356. void PrivacySandboxSettings::SetDelegateForTesting(
  357. std::unique_ptr<Delegate> delegate) {
  358. delegate_ = std::move(delegate);
  359. }
  360. PrivacySandboxSettings::PrivacySandboxSettings() = default;
  361. bool PrivacySandboxSettings::IsPrivacySandboxEnabledForContext(
  362. const GURL& url,
  363. const absl::optional<url::Origin>& top_frame_origin) const {
  364. if (!IsPrivacySandboxEnabled())
  365. return false;
  366. // Third party cookies must also be available for this context. An empty site
  367. // for cookies is provided so the context is always treated as a third party.
  368. return cookie_settings_->IsFullCookieAccessAllowed(
  369. url, net::SiteForCookies(), top_frame_origin,
  370. content_settings::CookieSettings::QueryReason::kPrivacySandbox);
  371. }
  372. void PrivacySandboxSettings::SetTopicsDataAccessibleFromNow() const {
  373. pref_service_->SetTime(prefs::kPrivacySandboxTopicsDataAccessibleSince,
  374. base::Time::Now());
  375. for (auto& observer : observers_)
  376. observer.OnTopicsDataAccessibleSinceUpdated();
  377. }
  378. } // namespace privacy_sandbox