| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_MANAGER_IMPL_H_ |
| #define CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_MANAGER_IMPL_H_ |
| |
| #include <sys/types.h> |
| |
| #include <cstddef> |
| #include <list> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/flat_map.h" |
| #include "base/containers/flat_set.h" |
| #include "base/containers/span.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/observer_list.h" |
| #include "base/threading/sequence_bound.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "base/types/expected.h" |
| #include "content/browser/interest_group/auction_process_manager.h" |
| #include "content/browser/interest_group/bidding_and_auction_serializer.h" |
| #include "content/browser/interest_group/bidding_and_auction_server_key_fetcher.h" |
| #include "content/browser/interest_group/data_decoder_manager.h" |
| #include "content/browser/interest_group/for_debugging_only_report_util.h" |
| #include "content/browser/interest_group/interest_group_caching_storage.h" |
| #include "content/browser/interest_group/interest_group_k_anonymity_manager.h" |
| #include "content/browser/interest_group/interest_group_permissions_checker.h" |
| #include "content/browser/interest_group/interest_group_update.h" |
| #include "content/browser/interest_group/interest_group_update_manager.h" |
| #include "content/browser/interest_group/storage_interest_group.h" |
| #include "content/common/content_export.h" |
| #include "content/public/browser/frame_tree_node_id.h" |
| #include "content/public/browser/interest_group_manager.h" |
| #include "content/public/browser/k_anonymity_service_delegate.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "content/services/auction_worklet/public/mojom/bidder_worklet.mojom-forward.h" |
| #include "content/services/auction_worklet/public/mojom/real_time_reporting.mojom.h" |
| #include "services/network/public/cpp/resource_request.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/simple_url_loader.h" |
| #include "services/network/public/cpp/wrapper_shared_url_loader_factory.h" |
| #include "services/network/public/mojom/client_security_state.mojom.h" |
| #include "third_party/blink/public/common/interest_group/interest_group.h" |
| #include "third_party/blink/public/mojom/interest_group/ad_auction_service.mojom.h" |
| #include "url/origin.h" |
| |
| namespace base { |
| |
| class FilePath; |
| |
| } // namespace base |
| |
| namespace content { |
| |
| class AdAuctionPageData; |
| class BrowserContext; |
| class InterestGroupStorage; |
| class NavigationOrDocumentHandle; |
| class TrustedSignalsCacheImpl; |
| struct DebugReportLockoutAndCooldowns; |
| |
| // InterestGroupManager is a per-StoragePartition class that owns shared |
| // state needed to run FLEDGE auctions. It lives on the UI thread. |
| // |
| // It acts as a proxy to access an InterestGroupStorage, which lives off-thread |
| // as it performs blocking file IO when backed by on-disk storage. |
| class CONTENT_EXPORT InterestGroupManagerImpl : public InterestGroupManager { |
| public: |
| using AreReportingOriginsAttestedCallback = |
| base::RepeatingCallback<bool(const std::vector<url::Origin>&)>; |
| using GetKAnonymityServiceDelegateCallback = |
| InterestGroupKAnonymityManager::GetKAnonymityServiceDelegateCallback; |
| using RealTimeReportingContributions = |
| std::vector<auction_worklet::mojom::RealTimeReportingContributionPtr>; |
| using AdAuctionPageDataCallback = |
| base::RepeatingCallback<AdAuctionPageData*()>; |
| |
| // Controls how auction worklets will be run. kDedicated will use |
| // fully-isolated utility processes solely for worklet. kInRenderer will |
| // re-use regular renderers following the normal site isolation policy. |
| enum class ProcessMode { kDedicated, kInRenderer }; |
| |
| // Types of even-level reports, for use with EnqueueReports(). Currently only |
| // used for histograms. Raw values are not logged directly in histograms, so |
| // values do not need to be consistent across versions. |
| enum class ReportType { |
| kSendReportTo, |
| kDebugWin, |
| kDebugLoss, |
| }; |
| |
| // Creates an interest group manager using the provided directory path for |
| // persistent storage. If `in_memory` is true the path is ignored and only |
| // in-memory storage is used. |
| explicit InterestGroupManagerImpl( |
| const base::FilePath& path, |
| bool in_memory, |
| ProcessMode process_mode, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, |
| GetKAnonymityServiceDelegateCallback k_anonymity_service_callback); |
| ~InterestGroupManagerImpl() override; |
| InterestGroupManagerImpl(const InterestGroupManagerImpl& other) = delete; |
| InterestGroupManagerImpl& operator=(const InterestGroupManagerImpl& other) = |
| delete; |
| |
| class CONTENT_EXPORT InterestGroupObserver : public base::CheckedObserver { |
| public: |
| enum AccessType { |
| kJoin, |
| kLeave, |
| kUpdate, |
| kLoaded, |
| kBid, |
| kAdditionalBid, |
| kWin, |
| kAdditionalBidWin, |
| kClear, |
| kTopLevelBid, |
| kTopLevelAdditionalBid |
| }; |
| |
| virtual void OnInterestGroupAccessed( |
| base::optional_ref<const std::string> devtools_auction_id, |
| base::Time access_time, |
| AccessType type, |
| const url::Origin& owner_origin, |
| const std::string& name, |
| base::optional_ref<const url::Origin> component_seller_origin, |
| std::optional<double> bid, |
| base::optional_ref<const std::string> bid_currency) = 0; |
| }; |
| |
| // InterestGroupManager overrides: |
| void GetAllInterestGroupJoiningOrigins( |
| base::OnceCallback<void(std::vector<url::Origin>)> callback) override; |
| void GetAllInterestGroupDataKeys( |
| base::OnceCallback<void(std::vector<InterestGroupDataKey>)> callback) |
| override; |
| void RemoveInterestGroupsByDataKey(InterestGroupDataKey data_key, |
| base::OnceClosure callback) override; |
| void AddTrustedServerKeysDebugOverride( |
| TrustedServerAPIType api, |
| const url::Origin& coordinator, |
| std::string serialized_keys, |
| base::OnceCallback<void(std::optional<std::string>)> callback) override; |
| |
| /******** Proxy function calls to InterestGroupsStorage **********/ |
| |
| // Checks if `frame_origin` can join the specified InterestGroup, performing |
| // .well-known fetches if needed. If joining is allowed, then joins the |
| // interest group. |
| // |
| // `network_isolation_key` must be the NetworkIsolationKey associated with |
| // `url_loader_factory`. |
| // |
| // `url_loader_factory` is the factory for renderer frame where |
| // navigator.joinAdInterestGroup() was invoked, and will be used for the |
| // .well-known fetch if one is needed. |
| // |
| // `report_result_only`, if true, results in calling `callback` with the |
| // result of the permissions check, but not actually joining the interest |
| // group, regardless of success or failure. This is used to avoid leaking |
| // fingerprinting information if the join operation is disallowed by the |
| // browser configuration (e.g., 3P cookie blocking). |
| // |
| // See JoinInterestGroup() for more details on how the join operation is |
| // performed. |
| void CheckPermissionsAndJoinInterestGroup( |
| blink::InterestGroup group, |
| const GURL& joining_url, |
| const url::Origin& frame_origin, |
| const net::NetworkIsolationKey& network_isolation_key, |
| bool report_result_only, |
| network::mojom::URLLoaderFactory& url_loader_factory, |
| AreReportingOriginsAttestedCallback attestation_callback, |
| blink::mojom::AdAuctionService::JoinInterestGroupCallback callback); |
| |
| // Same as CheckPermissionsAndJoinInterestGroup(), except for a leave |
| // operation. |
| void CheckPermissionsAndLeaveInterestGroup( |
| const blink::InterestGroupKey& group_key, |
| const url::Origin& main_frame, |
| const url::Origin& frame_origin, |
| const net::NetworkIsolationKey& network_isolation_key, |
| bool report_result_only, |
| network::mojom::URLLoaderFactory& url_loader_factory, |
| blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback); |
| |
| // Much like CheckPermissionsAndJoinInterestGroup(), except for an operation |
| // that leaves all interest groups previously joined from the main frame |
| // origin, except those listed in `interest_groups_to_keep`. |
| void CheckPermissionsAndClearOriginJoinedInterestGroups( |
| const url::Origin& owner, |
| const std::vector<std::string>& interest_groups_to_keep, |
| const url::Origin& main_frame_origin, |
| const url::Origin& frame_origin, |
| const net::NetworkIsolationKey& network_isolation_key, |
| bool report_result_only, |
| network::mojom::URLLoaderFactory& url_loader_factory, |
| blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback); |
| |
| // Joins an interest group. If the interest group does not exist, a new one |
| // is created based on the provided group information. If the interest group |
| // exists, the existing interest group is overwritten. In either case a join |
| // record for this interest group is created. |
| void JoinInterestGroup(blink::InterestGroup group, const GURL& joining_url); |
| // Remove the interest group if it exists. |
| void LeaveInterestGroup(const blink::InterestGroupKey& group_key, |
| const url::Origin& main_frame); |
| // Removes all interest groups owned by `owner` joined from |
| // `main_frame_origin` except `interest_groups_to_keep`, if they exist. |
| void ClearOriginJoinedInterestGroups( |
| const url::Origin& owner, |
| std::set<std::string> interest_groups_to_keep, |
| url::Origin main_frame_origin); |
| // Loads all interest groups owned by `owners`, then updates their |
| // definitions by fetching their `updateURL`. Interest group updates |
| // that fail to load or validate are skipped, but other updates will |
| // proceed. |
| // The list is shuffled in-place to ensure fairness. |
| void UpdateInterestGroupsOfOwners( |
| std::vector<url::Origin> owners, |
| network::mojom::ClientSecurityStatePtr client_security_state, |
| std::optional<std::string> user_agent_override, |
| AreReportingOriginsAttestedCallback callback); |
| |
| void UpdateInterestGroupsOfOwnersWithDelay( |
| std::vector<url::Origin> owners, |
| network::mojom::ClientSecurityStatePtr client_security_state, |
| std::optional<std::string> user_agent_override, |
| AreReportingOriginsAttestedCallback callback, |
| const base::TimeDelta& delay); |
| |
| // Allows the interest group specified by `group_key` to be updated if it was |
| // last updated before `update_if_older_than`. |
| void AllowUpdateIfOlderThan(blink::InterestGroupKey group_key, |
| base::TimeDelta update_if_older_than); |
| |
| // For testing *only*; changes the maximum amount of time that the update |
| // process can run before it gets cancelled for taking too long. |
| void set_max_update_round_duration_for_testing(base::TimeDelta delta) { |
| update_manager_.set_max_update_round_duration_for_testing( |
| delta); // IN-TEST |
| } |
| |
| // For testing *only*; changes the maximum number of groups that can be |
| // updated at the same time. |
| void set_max_parallel_updates_for_testing(int max_parallel_updates) { |
| update_manager_.set_max_parallel_updates_for_testing( // IN-TEST |
| max_parallel_updates); |
| } |
| |
| // Adds an entry to the bidding history for this interest group. |
| void RecordInterestGroupBids(const blink::InterestGroupSet& groups); |
| |
| // Adds an entry to the win history for this interest group. `ad_json` is a |
| // piece of opaque data to identify the winning ad. |
| void RecordInterestGroupWin(const blink::InterestGroupKey& group_key, |
| const std::string& ad_json); |
| // Adds an entry to forDebuggingOnly report lockout table if the table is |
| // empty. Otherwise replaces the existing entry. |
| void RecordDebugReportLockout(base::Time starting_time, |
| base::TimeDelta duration); |
| // Adds an entry with random duration to forDebuggingOnly report lockout |
| // table. This is used to avoid new user bias when changing from allowing 3PC |
| // to disallowing 3PC. |
| void RecordRandomDebugReportLockout(base::Time starting_time); |
| // Adds an entry to forDebuggingOnly report cooldown table for `origin` if it |
| // does not exist, otherwise replaces the existing entry. |
| void RecordDebugReportCooldown(const url::Origin& origin, |
| base::Time cooldown_start, |
| DebugReportCooldownType cooldown_type); |
| |
| // Records a view or a click event. Aggregate time bucketed view and click |
| // information is provided to bidder's browsing signals in generateBid(). |
| // |
| // `navigation_or_document_handle` may be null -- in that case, the top-frame |
| // origin for the IsInterestGroupAPIAllowed() check is an opaque origin. |
| void RecordViewClick( |
| BrowserContext& browser_context, |
| const NavigationOrDocumentHandle* navigation_or_document_handle, |
| const std::optional<url::Origin>& maybe_top_frame_origin, |
| network::AdAuctionEventRecord event_record); |
| |
| // Test-only variant; this lacks permission & attestation checks (so tests |
| // don't need to set up things they need to operate). |
| void RecordViewClickForTesting(network::AdAuctionEventRecord event_record); |
| |
| // Invokes `callback` with whether the database has a record of view/click |
| // events for given combination of provider & eligible origins. |
| // |
| // nullopt will be passed in case of some sort of database error. |
| void CheckViewClickInfoInDbForTesting( |
| url::Origin provider_origin, |
| url::Origin eligible_origin, |
| base::OnceCallback<void(std::optional<bool>)> callback); |
| |
| // Reports the ad keys to the k-anonymity service. Should be called when |
| // FLEDGE selects an ad. |
| void RegisterAdKeysAsJoined(base::flat_set<std::string> hashed_keys); |
| |
| // Gets a single interest group. |
| void GetInterestGroup( |
| const blink::InterestGroupKey& group_key, |
| base::OnceCallback<void(std::optional<SingleStorageInterestGroup>)> |
| callback); |
| |
| // Gets a single interest group. |
| void GetInterestGroup( |
| const url::Origin& owner, |
| const std::string& name, |
| base::OnceCallback<void(std::optional<SingleStorageInterestGroup>)> |
| callback); |
| |
| // Gets a list of all interest group owners. Each owner will only appear |
| // once. |
| void GetAllInterestGroupOwners( |
| base::OnceCallback<void(std::vector<url::Origin>)> callback); |
| |
| // Gets a list of all interest groups with their bidding information |
| // associated with the provided owner. |
| void GetInterestGroupsForOwner( |
| const std::optional<std::string>& devtools_auction_id, |
| const url::Origin& owner, |
| base::OnceCallback<void(scoped_refptr<StorageInterestGroups>)> callback); |
| |
| // For a given `owner`, return whether the owner origin and bidding signal |
| // origin were cached in-memory via UpdateCachedOriginsIfEnabled. If the |
| // `owner` origin was cached, update `signals_origin` to the one that was |
| // cached -- or set to nullopt if no bidding signals origin was cached or if |
| // it would be the same as the owner origin. The cache includes at most one |
| // entry per origin, and may not reflect the results of interest group |
| // updates. It's intended to be used for best-effort preconnecting, and should |
| // not be considered authoritative. It is guaranteed not to contain interest |
| // groups that have are beyond the max expiration time limit, so preconnecting |
| // should not leak data the bidder would otherwise have access to, if it so |
| // desired. That is, manual voluntarily removing or expiring of an interest |
| // group may not be reflected in the result, but hitting the the global |
| // interest group lifetime cap will be respected. |
| bool GetCachedOwnerAndSignalsOrigins( |
| const url::Origin& owner, |
| std::optional<url::Origin>& signals_origin); |
| |
| // Update the cached owner and signal origins for an owner's interest groups |
| // if kFledgeUsePreconnectCache or kFledgeStartAnticipatoryProcesses are |
| // enabled and the owner's IGs are still in memory. |
| void UpdateCachedOriginsIfEnabled(const url::Origin& owner); |
| |
| // Clear out storage for the matching owning storage key. If the matcher is |
| // empty then apply to all storage keys. |
| void DeleteInterestGroupData( |
| StoragePartition::StorageKeyMatcherFunction storage_key_matcher, |
| bool user_initiated_deletion, |
| base::OnceClosure completion_callback); |
| |
| // Completely delete all interest group data, including k-anonymity data that |
| // is not cleared by DeleteInterestGroupData. |
| void DeleteAllInterestGroupData(base::OnceClosure completion_callback); |
| |
| // Get the last maintenance time from the underlying InterestGroupStorage. |
| void GetLastMaintenanceTimeForTesting( |
| base::RepeatingCallback<void(base::Time)> callback) const; |
| |
| // Enqueues reports for the specified URLs. Virtual for testing. |
| virtual void EnqueueReports( |
| ReportType report_type, |
| std::vector<GURL> report_urls, |
| FrameTreeNodeId frame_tree_node_id, |
| const url::Origin& frame_origin, |
| const network::mojom::ClientSecurityState& client_security_state, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); |
| |
| // Similar to EnqueueReports(), but enqueues real time reporting |
| // contributions. Contributions will be sampled and converted to histograms by |
| // calling CalculateRealTimeReportingHistograms() before added to queue. |
| // Virtual for testing. |
| virtual void EnqueueRealTimeReports( |
| std::map<url::Origin, RealTimeReportingContributions> contributions, |
| AdAuctionPageDataCallback ad_auction_page_data_callback, |
| FrameTreeNodeId frame_tree_node_id, |
| const url::Origin& frame_origin, |
| const network::mojom::ClientSecurityState& client_security_state, |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory); |
| |
| // Update the interest group priority. |
| void SetInterestGroupPriority(const blink::InterestGroupKey& group, |
| double priority); |
| |
| // Merges `update_priority_signals_overrides` with the previous priority |
| // signals of `group`. |
| void UpdateInterestGroupPriorityOverrides( |
| const blink::InterestGroupKey& group_key, |
| base::flat_map<std::string, |
| auction_worklet::mojom::PrioritySignalsDoublePtr> |
| update_priority_signals_overrides); |
| |
| // Update B&A keys for a coordinator. This function will overwrite any |
| // existing keys for the coordinator. |
| void SetBiddingAndAuctionServerKeys(const url::Origin& coordinator, |
| std::string serialized_keys, |
| base::Time expiration); |
| |
| // Load stored B&A server keys for a coordinator along with the keys' |
| // expiration. |
| void GetBiddingAndAuctionServerKeys( |
| const url::Origin& coordinator, |
| base::OnceCallback<void(std::pair<base::Time, std::string>)> callback); |
| |
| // Clears the InterestGroupPermissionsChecker's cache of the results of |
| // .well-known fetches. |
| void ClearPermissionsCache(); |
| |
| AuctionProcessManager& auction_process_manager() { |
| return *auction_process_manager_; |
| } |
| |
| DataDecoderManager& data_decoder_manager() { return data_decoder_manager_; } |
| |
| void AddInterestGroupObserver(InterestGroupObserver* observer) { |
| observers_.AddObserver(observer); |
| } |
| |
| void RemoveInterestGroupObserver(InterestGroupObserver* observer) { |
| observers_.RemoveObserver(observer); |
| } |
| |
| // Allows the AuctionProcessManager to be overridden in unit tests, both to |
| // allow not creating a new process, and mocking out the Mojo service |
| // interface. |
| void set_auction_process_manager_for_testing( |
| std::unique_ptr<AuctionProcessManager> auction_process_manager) { |
| auction_process_manager_ = std::move(auction_process_manager); |
| } |
| |
| // Allows the AuctionProcessManager to be overridden in unit tests, to mock |
| // out its behavior. Note that the automatically created built-in |
| // AuctionProcessManager may have raw pointers to the old cache, |
| // set_auction_process_manager_for_testing() should typically be called before |
| // this method. |
| void set_trusted_signals_cache_for_testing( |
| std::unique_ptr<TrustedSignalsCacheImpl> trusted_signals_cache); |
| |
| // For testing *only*; changes the maximum number of active report requests |
| // at a time. |
| void set_max_active_report_requests_for_testing( |
| int max_active_report_requests) { |
| max_active_report_requests_ = max_active_report_requests; |
| } |
| |
| // For testing *only*; changes the maximum number of report requests that can |
| // be stored in `report_requests_` queue. |
| void set_max_report_queue_length_for_testing(int max_queue_length) { |
| max_report_queue_length_ = max_queue_length; |
| } |
| |
| // For testing *only*; changes `max_reporting_round_duration_`. |
| void set_max_reporting_round_duration_for_testing( |
| base::TimeDelta max_reporting_round_duration) { |
| max_reporting_round_duration_ = max_reporting_round_duration; |
| } |
| |
| // For testing *only*; changes the time interval to wait before sending the |
| // next report after sending one. |
| void set_reporting_interval_for_testing(base::TimeDelta interval) { |
| reporting_interval_ = interval; |
| } |
| |
| // For testing *only*; changes `real_time_reporting_window_`. |
| void set_real_time_reporting_window_for_testing(base::TimeDelta window) { |
| real_time_reporting_window_ = window; |
| } |
| |
| // For testing *only*; changes `max_real_time_reports_`. |
| void set_max_real_time_reports_for_testing(int max_num_reports) { |
| max_real_time_reports_ = max_num_reports; |
| } |
| |
| size_t report_queue_length_for_testing() const { |
| return report_requests_.size(); |
| } |
| |
| // Handles daily k-anonymity updates for the interest group. Triggers an |
| // update request for the k-anonymity of all parts of the interest group |
| // (including ads). Also reports membership in the interest group to the |
| // k-anonymity of interest-group service. |
| void QueueKAnonymityUpdateForInterestGroup( |
| const blink::InterestGroupKey& group_key, |
| const std::optional<InterestGroupKanonUpdateParameter> update_parameter); |
| // Records a K-anonymity update for an interest group. If |
| // `replace_existing_values` is true, this update will store the new |
| // `update_time` and `positive_hashed_values`, replacing the interest |
| // group's existing update time and keys. If `replace_existing_values` is |
| // false, `positive_hashed_keys` will be added to the existing positive keys |
| // without updating the stored update time. No value is stored if |
| // `update_time` is older than the `update_time` already stored in the |
| // database. |
| void UpdateKAnonymity(const blink::InterestGroupKey& interest_group_key, |
| const std::vector<std::string>& positive_hashed_keys, |
| const base::Time update_time, |
| bool replace_existing_values); |
| |
| // Gets lockout and cooldowns of `origins` for sending forDebuggingOnly |
| // reports. |
| void GetDebugReportLockoutAndCooldowns( |
| base::flat_set<url::Origin> origins, |
| base::OnceCallback<void(std::optional<DebugReportLockoutAndCooldowns>)> |
| callback); |
| |
| // Gets lockout and all cooldowns for sending forDebuggingOnly reports. |
| void GetDebugReportLockoutAndAllCooldowns( |
| base::OnceCallback<void(std::optional<DebugReportLockoutAndCooldowns>)> |
| callback); |
| |
| // Gets the last time that the key was reported to the k-anonymity server. |
| void GetLastKAnonymityReported( |
| const std::string& hashed_key, |
| base::OnceCallback<void(std::optional<base::Time>)> callback); |
| // Updates the last time that the key was reported to the k-anonymity server. |
| void UpdateLastKAnonymityReported(const std::string& hashed_key); |
| |
| void GetInterestGroupAdAuctionData( |
| url::Origin top_level_origin, |
| base::Uuid generation_id, |
| base::Time timestamp, |
| blink::mojom::AuctionDataConfigPtr config, |
| std::vector<url::Origin> sellers, |
| base::OnceCallback<void(BiddingAndAuctionData)> callback); |
| |
| // Get the public key to use for the auction data. The `callback` may be |
| // called synchronously if the key is already available or the coordinator is |
| // not recognized. |
| void GetTrustedServerKey( |
| TrustedServerAPIType api, |
| const url::Origin& seller, |
| const std::optional<url::Origin>& coordinator, |
| base::OnceCallback<void( |
| base::expected<BiddingAndAuctionServerKey, std::string>)> callback); |
| |
| InterestGroupPermissionsChecker& permissions_checker_for_testing() { |
| return permissions_checker_; |
| } |
| |
| void set_k_anonymity_manager_for_testing( |
| std::unique_ptr<InterestGroupKAnonymityManager> k_anonymity_manager) { |
| k_anonymity_manager_ = std::move(k_anonymity_manager); |
| } |
| |
| // Notifies an interest group has been accessed. Used for devtools interest |
| // group view and testing. |
| // |
| // For calls that affect the database, should be invoked after the database |
| // update, so that the calls are all in the same order they're applied to the |
| // database (can't log them all before the database update, since for, e.g., |
| // calls to retrieve all interest groups for an owner, the name may not be |
| // known until after the database has been accessed). |
| void NotifyInterestGroupAccessed( |
| base::optional_ref<const std::string> devtools_auction_id, |
| InterestGroupObserver::AccessType type, |
| const url::Origin& owner_origin, |
| const std::string& name, |
| base::optional_ref<const url::Origin> component_seller_origin, |
| std::optional<double> bid, |
| base::optional_ref<const std::string> bid_currency); |
| |
| // Cache for trusted browser signals version 2. Returns nullptr if relevant |
| // features have not been enabled. |
| TrustedSignalsCacheImpl* trusted_signals_cache() { |
| return trusted_signals_cache_.get(); |
| } |
| |
| InterestGroupCachingStorage* GetCachingStorageForTesting() { |
| return &caching_storage_; |
| } |
| |
| private: |
| friend class InterestGroupManagerImplTestPeer; |
| |
| // InterestGroupUpdateManager calls private members to write updates to the |
| // database. |
| friend class InterestGroupUpdateManager; |
| |
| struct ReportRequest { |
| ReportRequest(); |
| ~ReportRequest(); |
| |
| GURL report_url; |
| // Real time reporting histograms to be sent in POST request's body. Null |
| // for other report types. |
| std::optional<std::vector<uint8_t>> real_time_histogram; |
| |
| // The flip probability that was used to calculate the real time report's |
| // noise using RAPPOR. |
| std::optional<double> real_time_report_flip_probability; |
| |
| url::Origin frame_origin; |
| network::mojom::ClientSecurityState client_security_state; |
| |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory; |
| |
| // This optional string holds a user agent value that can override the |
| // default one for reporting requests. If no override is needed, it remains |
| // std::nullopt. |
| std::optional<std::string> user_agent_override; |
| |
| // Used for Uma histograms. These are build-time constants contained within |
| // the binary, so no need for anything to own them. |
| const char* name; |
| int request_url_size_bytes; |
| FrameTreeNodeId frame_tree_node_id; |
| }; |
| |
| struct AdAuctionDataLoaderState { |
| AdAuctionDataLoaderState(); |
| ~AdAuctionDataLoaderState(); |
| AdAuctionDataLoaderState(AdAuctionDataLoaderState&& state); |
| BiddingAndAuctionSerializer serializer; |
| std::vector<url::Origin> sellers; |
| base::OnceCallback<void(BiddingAndAuctionData)> callback; |
| base::TimeTicks start_time; |
| }; |
| |
| // Callbacks for CheckPermissionsAndJoinInterestGroup(), |
| // CheckPermissionsAndLeaveInterestGroup(), and |
| // CheckPermissionsAndClearOriginJoinedInterestGroups(), respectively. Perform |
| // requested operation if the results of the permissions check allows it. |
| void OnJoinInterestGroupPermissionsChecked( |
| blink::InterestGroup group, |
| const GURL& joining_url, |
| bool report_result_only, |
| AreReportingOriginsAttestedCallback attestation_callback, |
| blink::mojom::AdAuctionService::JoinInterestGroupCallback callback, |
| bool can_join); |
| void OnLeaveInterestGroupPermissionsChecked( |
| const blink::InterestGroupKey& group_key, |
| const url::Origin& main_frame, |
| bool report_result_only, |
| blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback, |
| bool can_leave); |
| void OnClearOriginJoinedInterestGroupsPermissionsChecked( |
| url::Origin owner, |
| std::set<std::string> interest_groups_to_keep, |
| url::Origin main_frame_origin, |
| bool report_result_only, |
| blink::mojom::AdAuctionService::LeaveInterestGroupCallback callback, |
| bool can_leave); |
| void OnClearOriginJoinedInterestGroupsComplete( |
| const url::Origin& owner, |
| std::vector<std::string> left_interest_group_names); |
| |
| // Gets a list of `InterestGroupUpdateParameter` for all interest groups |
| // associated with the provided owner. |
| // |
| // `groups_limit` sets a limit on the maximum number of interest group keys |
| // that may be returned. |
| // |
| // To be called only by `update_manager_`. |
| void GetInterestGroupsForUpdate( |
| const url::Origin& owner, |
| int groups_limit, |
| base::OnceCallback<void(std::vector<InterestGroupUpdateParameter>)> |
| callback); |
| |
| // Updates the interest group of the same name based on the information in |
| // the provided group. This does not update the interest group expiration |
| // time or user bidding signals. |
| // |
| // `callback` is invoked asynchronously on completion, with a bool indicating |
| // success or failure. |
| // |
| // To be called only by `update_manager_`. |
| void UpdateInterestGroup(const blink::InterestGroupKey& group_key, |
| InterestGroupUpdate update, |
| base::OnceCallback<void(bool)> callback); |
| |
| // Called when a call to UpdateInterestGroup() completes. Sends a notification |
| // about the update and invokes `callback` with `success`. Queues a |
| // k-anonymity update with `kanon_update_parameter`. |
| void OnUpdateComplete( |
| const blink::InterestGroupKey& group_key, |
| base::OnceCallback<void(bool)> callback, |
| std::optional<InterestGroupKanonUpdateParameter> kanon_update_parameter); |
| |
| // Modifies the update rate limits stored in the database, with a longer delay |
| // for parse failure. |
| // |
| // To be called only by `update_manager_`. |
| void ReportUpdateFailed(const blink::InterestGroupKey& group_key, |
| bool parse_failure); |
| |
| void OnGetInterestGroupsComplete( |
| base::OnceCallback<void(scoped_refptr<StorageInterestGroups>)> callback, |
| const std::optional<std::string>& devtools_auction_id, |
| scoped_refptr<StorageInterestGroups> groups); |
| |
| // Dequeues and sends the first report request in `report_requests_` queue, |
| // if the queue is not empty. |
| void TrySendingOneReport(); |
| |
| // Invoked when a report request completed. |
| void OnOneReportSent( |
| std::unique_ptr<network::SimpleURLLoader> simple_url_loader, |
| FrameTreeNodeId frame_tree_node_id, |
| const std::string& devtools_request_id, |
| scoped_refptr<net::HttpResponseHeaders> response_headers); |
| |
| // Clears `report_requests_`. Does not abort currently pending requests. |
| void TimeoutReports(); |
| |
| // Shuffles the owners then calls `LoadNextInterestGroupAdAuctionData()`. |
| // We need the shuffle so that interest group owners are not included in the |
| // auction data in the same order every time. Our serialization only solves |
| // an approximation of the "knapsack" problem, so the amount of interest |
| // groups we can fit for each owner may depend on the order in which |
| // they are processed. Shuffling helps guarantee fairness. |
| void ShuffleOwnersThenLoadInterestGroupAdAuctionData( |
| AdAuctionDataLoaderState state, |
| std::vector<url::Origin> owners); |
| |
| // Loads the next owner's interest group data. If there are no more owners |
| // whose interest groups need to be loaded, calls OnAdAuctionDataLoadComplete. |
| void LoadNextInterestGroupAdAuctionData(AdAuctionDataLoaderState state, |
| std::vector<url::Origin> owners); |
| |
| // Serializes the loaded auction data and then calls |
| // LoadNextInterestGroupAdAuctionData to continue loading. |
| void OnLoadedNextInterestGroupAdAuctionData( |
| AdAuctionDataLoaderState state, |
| std::vector<url::Origin> owners, |
| url::Origin owner, |
| scoped_refptr<StorageInterestGroups> groups); |
| |
| // Invoked when loading interest groups is completed. Load debug report |
| // lockout information if sampling debug report is enabled, otherwise invoke |
| // `OnAdAuctionDataLoadComplete()` directly. |
| void OnInterestGroupAdAuctionDataLoadComplete(AdAuctionDataLoaderState state); |
| |
| // Constructs the AdAuctionData when the load is complete and calls the |
| // provided callback. |
| void OnAdAuctionDataLoadComplete( |
| AdAuctionDataLoaderState state, |
| std::optional<DebugReportLockoutAndCooldowns> lockout); |
| |
| // Helper to that returns bound NotifyInterestGroupAccessed() callbacks to |
| // allow notifications to be sent after a database update. |
| base::OnceClosure CreateNotifyInterestGroupAccessedCallback( |
| InterestGroupObserver::AccessType type, |
| const url::Origin& owner_origin, |
| const std::string& name); |
| |
| // Controls access to the Interest Group Database through its owned |
| // InterestGroupStorage. Returns cached values for GetInterestGroupsForOwner |
| // when available. |
| InterestGroupCachingStorage caching_storage_; |
| |
| // This must be above the `trusted_signals_cache_`, which depends on it. |
| DataDecoderManager data_decoder_manager_; |
| |
| // Cache for trusted browser signals version 2. Only populated if |
| // kFledgeTrustedSignalsKVv2Support and kFledgeUseKvv2SignalsCache features |
| // are enabled. Rather than check for those features, consumers should check |
| // if this has been populated. Must be declared before |
| // `auction_process_manager_`, which depends on this. |
| std::unique_ptr<TrustedSignalsCacheImpl> trusted_signals_cache_; |
| |
| // Stored as pointer so that tests can override it. |
| std::unique_ptr<AuctionProcessManager> auction_process_manager_; |
| |
| base::ObserverList<InterestGroupObserver> observers_; |
| |
| // Manages the logic required to support UpdateInterestGroupsOfOwner(). |
| // |
| // InterestGroupUpdateManager keeps a pointer to this InterestGroupManagerImpl |
| // to make database writes via calls to GetInterestGroupsForUpdate(), |
| // UpdateInterestGroup(), and ReportUpdateFailed(). |
| // |
| // Therefore, `update_manager_` *must* be declared after fields used by those |
| // methods so that updates are cancelled before those fields are destroyed. |
| InterestGroupUpdateManager update_manager_; |
| |
| // Manages the logic required to support k-anonymity updates. |
| // |
| // InterestGroupKAnonymityManager keeps a pointer to this |
| // InterestGroupManagerImpl to make database reads and writes.... |
| // |
| // Therefore, `k_anonymity_manager_` *must* be declared after fields used by |
| // those methods so that k-anonymity operations are cancelled before those |
| // fields are destroyed. |
| // Stored as pointer so that tests can override it. |
| std::unique_ptr<InterestGroupKAnonymityManager> k_anonymity_manager_; |
| |
| // Checks if a frame can join or leave an interest group. Global so that |
| // pending operations can continue after a page has been navigate away from. |
| InterestGroupPermissionsChecker permissions_checker_; |
| |
| // The queue of report requests. Empty the queue if it's size is larger than |
| // `max_report_queue_length` at the time of adding new entries. |
| base::circular_deque<std::unique_ptr<ReportRequest>> report_requests_; |
| |
| // Current number of active report requests. Includes requests that completed |
| // within the last `kReportingInterval`, each of which should have a pending |
| // delayed task to invoke TrySendingOneReport(). |
| int num_active_ = 0; |
| |
| // The maximum number of active report requests at a time. |
| // |
| // Should *only* be changed by tests. |
| int max_active_report_requests_; |
| |
| // The maximum number of report requests that can be stored in queue |
| // `report_requests_`. |
| // |
| // Should *only* be changed by tests. |
| int max_report_queue_length_; |
| |
| // The time interval to wait before sending the next batch of report requests |
| // after sending one batch. |
| // |
| // Should *only* be changed by tests. |
| base::TimeDelta reporting_interval_; |
| |
| // The maximum amount of time that the reporting process can run before the |
| // report queue is cleared due to taking too long. |
| // |
| // Should *only* be changed by tests. |
| base::TimeDelta max_reporting_round_duration_; |
| |
| // The number of real time reports (`max_real_time_reports_`) per reporting |
| // origin per page per `real_time_reporting_window_`. |
| // |
| // Should *only* be changed by tests. |
| base::TimeDelta real_time_reporting_window_; |
| double max_real_time_reports_; |
| |
| // Used to clear all pending reports in the queue if reporting takes too long. |
| // Started when sending reports starts. Stopped once all reports are sent. |
| // When the timer triggers, all reports are aborted. |
| // |
| // The resulting behavior is that if reports are continuously being sent for |
| // too long, possibly from multiple auctions, all reports are timed out. |
| base::OneShotTimer timeout_timer_; |
| |
| // Used to fetch the key for encrypting the request to the bidding and auction |
| // server. |
| BiddingAndAuctionServerKeyFetcher ba_key_fetcher_; |
| |
| base::WeakPtrFactory<InterestGroupManagerImpl> weak_factory_{this}; |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_MANAGER_IMPL_H_ |