910e62b5创建于 1月15日历史提交
// Copyright 2022 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_K_ANONYMITY_MANAGER_H_
#define CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_K_ANONYMITY_MANAGER_H_

#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "content/browser/interest_group/interest_group_caching_storage.h"
#include "content/browser/interest_group/interest_group_update.h"
#include "content/browser/interest_group/storage_interest_group.h"
#include "content/common/content_export.h"
#include "content/public/browser/k_anonymity_service_delegate.h"
#include "third_party/blink/public/common/interest_group/interest_group.h"

namespace content {
class InterestGroupManagerImpl;

// Maximum number of IDs to send in a single query call. Public for testing.
constexpr size_t kQueryBatchSizeLimit = 1000;

// Returns whether `last_updated` is less than 7 days ago.
bool CONTENT_EXPORT IsKAnonDataExpired(const base::Time last_updated,
                                       const base::Time now);

// Manages k-anonymity updates. Checks last updated times in the database
// to limit updates (joins and queries) to once per day. Called by the
// InterestGroupManagerImpl for interest group k-anonymity updates. Calls
// The InterestGroupManagerImpl to access interest group storage to perform
// interest group updates.
class CONTENT_EXPORT InterestGroupKAnonymityManager {
 public:
  using GetKAnonymityServiceDelegateCallback =
      base::RepeatingCallback<KAnonymityServiceDelegate*()>;

  InterestGroupKAnonymityManager(
      InterestGroupManagerImpl* interest_group_manager,
      InterestGroupCachingStorage* caching_storage,
      GetKAnonymityServiceDelegateCallback k_anonymity_service_callback);
  ~InterestGroupKAnonymityManager();

  // Requests k-anonymity updates for all interest groups owned by `owners` that
  // haven't been updated in 24 hours or more. Results are passed to
  // interest_group_manager_->UpdateKAnonymity.
  void QueryKAnonymityOfOwners(base::span<const url::Origin> owners);

  // Requests the k-anonymity status of elements of `k_anon_data` that
  // haven't been updated in 24 hours or more. Results are passed to
  // interest_group_manager_->UpdateKAnonymity.
  void QueryKAnonymityData(
      const blink::InterestGroupKey& interest_group_key,
      const InterestGroupKanonUpdateParameter& k_anon_data);

  // Notify the k-anonymity service that these ad keys won an auction.
  // Internally this calls RegisterIDAsJoined().
  void RegisterAdKeysAsJoined(base::flat_set<std::string> hashed_keys);

 private:
  friend class InterestGroupKAnonymityManagerTestPeer;

  struct InProgressQueryState {
    InProgressQueryState(base::Time update_time, bool replace_existing_values);
    InProgressQueryState(const InProgressQueryState&);
    ~InProgressQueryState();
    base::Time update_time;
    bool replace_existing_values;
    size_t remaining_responses{0};
    std::vector<std::string> positive_hashed_keys_from_received_responses;
  };

  // Callback from QueryKAnonymityOfOwners
  void OnGotInterestGroupsOfOwner(scoped_refptr<StorageInterestGroups> groups);

  // Callback from LoadPositiveHashedKAnonymityKeysFromCache
  void FetchUncachedKAnonymityData(
      base::Time update_time,
      const blink::InterestGroupKey& interest_group_key,
      InterestGroupStorage::KAnonymityCacheResponse cache_response);

  // Callback from k-anonymity service QuerySets().
  void QuerySetsCallback(std::vector<std::string> query,
                         base::Time update_time,
                         const blink::InterestGroupKey& interest_group_key,
                         std::vector<bool> status);

  // Starts fetching the LastKAnonymityReported time for `url` from the
  // database.
  void RegisterIDAsJoined(const std::string& hashed_key);

  // Called by the database when the update time for `url` has been retrieved.
  // If the last reported time is too long ago, calls JoinSet() on the
  // k-anonymity service.
  void OnGotLastReportedTime(std::string hashed_key,
                             std::optional<base::Time> last_update_time);

  // Callback from k-anonymity service JoinSet(). Updates the LastReported time
  // for key in the database, regardless of status (fail close).
  void JoinSetCallback(std::string hashed_key, bool status);

  // An unowned pointer to the InterestGroupManagerImpl that owns this
  // InterestGroupUpdateManager. Used as an intermediary to talk to the
  // database.
  raw_ptr<InterestGroupManagerImpl> interest_group_manager_;

  // An unowned pointer to the interest_group_manager_'s
  // InterestGroupCachingStorage. Used to talk to the database directly for
  // fetching and storing cached hashed keys only.
  raw_ptr<InterestGroupCachingStorage> caching_storage_;

  GetKAnonymityServiceDelegateCallback k_anonymity_service_callback_;

  // We keep track of joins in progress because the joins that haven't completed
  // are still marked as eligible but it would be incorrect to join them
  // multiple times. We don't do this for query because the
  // size of the request could expose membership in overlapping groups through
  // traffic analysis.
  base::flat_set<std::string> joins_in_progress_;

  // Keep track of updates for which we have not yet written values back to the
  // database. When we receive a new QueryKAnonymityData for an interest group
  // while there's an outstanding query for the same interest group, we may
  // choose to replace the query in progress or add more k-anonymity keys onto
  // it.
  base::flat_map<blink::InterestGroupKey, InProgressQueryState>
      queries_in_progress_;

  base::WeakPtrFactory<InterestGroupKAnonymityManager> weak_ptr_factory_;
};

}  // namespace content

#endif  // CONTENT_BROWSER_INTEREST_GROUP_INTEREST_GROUP_K_ANONYMITY_MANAGER_H_