| // Copyright 2018 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_STRIKE_DATABASE_STRIKE_DATABASE_INTEGRATOR_BASE_H_ |
| #define COMPONENTS_STRIKE_DATABASE_STRIKE_DATABASE_INTEGRATOR_BASE_H_ |
| |
| #include <stdint.h> |
| |
| #include <map> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include "base/check.h" |
| #include "base/functional/function_ref.h" |
| #include "base/gtest_prod_util.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/time/time.h" |
| #include "components/strike_database/strike_database_base.h" |
| |
| namespace autofill { |
| class FakeCreditCardServer; |
| } // namespace autofill |
| |
| namespace strike_database { |
| |
| // Contains virtual functions for per-project implementations of StrikeDatabase |
| // to interface from, as well as a pointer to StrikeDatabase. This class is |
| // seperated from StrikeDatabase since we only want StrikeDatabase's cache to |
| // be loaded once per browser session. |
| class StrikeDatabaseIntegratorBase { |
| public: |
| // The StrikeDatabase's decision on whether the feature should be blocked or |
| // not, and if so, why. |
| enum StrikeDatabaseDecision { |
| // The feature should not be blocked. |
| kDoNotBlock = 0, |
| // Block feature: The maximum strike limit has been reached. |
| kMaxStrikeLimitReached = 1, |
| // Block feature: Not enough time has passed since the last strike. |
| kRequiredDelayNotPassed = 2, |
| }; |
| |
| static constexpr std::string_view kSharedId = "shared_id"; |
| |
| explicit StrikeDatabaseIntegratorBase(StrikeDatabaseBase* strike_database); |
| virtual ~StrikeDatabaseIntegratorBase(); |
| |
| // Returns the StrikeDatabase's decision on whether a particular feature |
| // should be blocked (not offered) for the given `id`. |
| StrikeDatabaseDecision GetStrikeDatabaseDecision(std::string_view id) const; |
| |
| // Returns the StrikeDatabase's decision on whether a particular feature |
| // should be blocked (not offered). |
| StrikeDatabaseDecision GetStrikeDatabaseDecision() const; |
| |
| // Returns whether a particular feature should be blocked (not offered) for |
| // the given `id`. Same as calling `GetStrikeDatabaseDecision`, where a result |
| // of `kDoNotBlock` returns false. |
| bool ShouldBlockFeature(std::string_view id) const; |
| |
| // Returns whether a particular feature should be blocked (not offered). Same |
| // as calling `GetStrikeDatabaseDecision`, where a result of `kDoNotBlock` |
| // returns false. |
| bool ShouldBlockFeature() const; |
| |
| // Increments in-memory cache and updates underlying ProtoDatabase. |
| int AddStrike(std::string_view id = kSharedId); |
| |
| // Increases in-memory cache by `strikes_increase` and updates underlying |
| // ProtoDatabase. |
| int AddStrikes(int strikes_increase, std::string_view id = kSharedId); |
| |
| // Removes an in-memory cache strike, updates last_update_timestamp, and |
| // updates underlying ProtoDatabase. |
| int RemoveStrike(std::string_view id = kSharedId); |
| |
| // Removes `strikes_decrease` in-memory cache strikes, updates |
| // `last_update_timestamp`, and updates underlying ProtoDatabase. |
| int RemoveStrikes(int strikes_decrease, std::string_view id = kSharedId); |
| |
| // Returns strike count from in-memory cache. |
| int GetStrikes(std::string_view id = kSharedId) const; |
| |
| // Removes all database entries from in-memory cache and underlying |
| // ProtoDatabase. |
| void ClearStrikes(std::string_view id = kSharedId); |
| |
| // Removes all database entries from in-memory cache and underlying |
| // ProtoDatabase for the whole project. |
| void ClearAllStrikes(); |
| |
| // Count strike entries for this project. |
| size_t CountEntries() const; |
| |
| protected: |
| // Runs a cleanup routine to remove the stored strike elements with the oldest |
| // update timestamps when `NumberOfEntriesExceedsLimits()`. The number of |
| // elements should be reduced to `GetMaximumEntriesAfterCleanup()`. |
| void LimitNumberOfStoredEntries(); |
| |
| // Returns true if the number of stored entries exceeds the limit. |
| bool NumberOfEntriesExceedsLimits() const; |
| |
| // Removes one strike for each key where it has been longer than |
| // GetExpiryTimeMicros() since `last_update_timestamp`. |
| void RemoveExpiredStrikes(); |
| |
| // Removes all database entries for which `id_map(ID)` is in `ids_to_delete`. |
| void ClearStrikesByIdMatching( |
| const std::set<std::string>& ids_to_delete, |
| base::FunctionRef<std::string(const std::string&)> id_map); |
| |
| // Removes all database entries from in-memory for which `id_map(ID)` is in |
| // `ids_to_delete` and were added between `delete_begin` and `delete_end`. |
| void ClearStrikesByIdMatchingAndTime( |
| const std::set<std::string>& ids_to_delete, |
| base::Time delete_begin, |
| base::Time delete_end, |
| base::FunctionRef<std::string(const std::string&)> id_map); |
| |
| // Removes all database entries from in-memory cache and underlying |
| // ProtoDatabase for keys in `keys`. |
| void ClearStrikesForKeys(const std::vector<std::string>& keys); |
| |
| // Get a readonly reference to the cache. |
| const std::map<std::string, StrikeData>& GetStrikeCache() const { |
| return strike_database_->GetStrikeCache(); |
| } |
| |
| // Returns the id the key was built from with `GetKey(id)`. |
| std::string_view GetIdFromKey(std::string_view key) const; |
| |
| // Returns the age of a strike entry. |
| static base::TimeDelta GetEntryAge(const StrikeData& strike_data); |
| |
| private: |
| FRIEND_TEST_ALL_PREFIXES(ChromeBrowsingDataRemoverDelegateTest, |
| StrikeDatabaseEmptyOnAutofillRemoveEverything); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| ClearStrikesForKeys); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| GetKeyForStrikeDatabaseIntegratorUniqueIdTest); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| IdFromKey); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| NonExpiringStrikesDoNotExpire); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| RemoveExpiredStrikesOnlyConsidersCurrentIntegrator); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| RemoveExpiredStrikesTest); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| RemoveExpiredStrikesTestLogsUMA); |
| FRIEND_TEST_ALL_PREFIXES(StrikeDatabaseIntegratorTestStrikeDatabaseTest, |
| RemoveExpiredStrikesUniqueIdTest); |
| friend autofill::FakeCreditCardServer; |
| friend class StrikeDatabaseTest; |
| |
| const raw_ptr<StrikeDatabaseBase> strike_database_; |
| |
| // For projects in which strikes don't have unique identifiers, the |
| // id suffix is set to `kSharedId`. This makes sure that projects requiring |
| // unique IDs always specify `id` instead of relying on the default shared |
| // value, while projects where unique IDs are unnecessary always fall back to |
| // the default shared value. |
| void CheckIdUniqueness(std::string_view id) const { |
| DCHECK(UniqueIdsRequired() == (id != kSharedId)); |
| } |
| |
| // Generates key based on project-specific string identifier. |
| std::string GetKey(std::string_view id) const; |
| |
| // Returns the maximum number of entries that should be stored for this |
| // project prefix. std::nullopt means that there is no limit. |
| virtual std::optional<size_t> GetMaximumEntries() const; |
| |
| // Returns the maximum number of entries that should remain after a cleanup. |
| // This number should be smaller then `GetMaximumEntries()` to create some |
| // headroom. std::nullopt means that `GetMaximumEntries()` should be used. |
| virtual std::optional<size_t> GetMaximumEntriesAfterCleanup() const; |
| |
| // Returns a prefix unique to each project, which will be used to create |
| // database key. |
| virtual std::string GetProjectPrefix() const = 0; |
| |
| // Returns the maximum number of strikes after which the project's Autofill |
| // opportunity stops being offered. |
| virtual int GetMaxStrikesLimit() const = 0; |
| |
| // Returns the time delta after which the most recent strike should expire. |
| // If the Optional is empty, then strikes don't expire. |
| virtual std::optional<base::TimeDelta> GetExpiryTimeDelta() const = 0; |
| |
| // Returns whether or not a unique string identifier is required for every |
| // strike in this project. |
| virtual bool UniqueIdsRequired() const = 0; |
| |
| // Returns the time delta to wait for before prompting the feature again. If |
| // the Optional is empty, then there is no required delay during which the |
| // feature is blocked. |
| virtual std::optional<base::TimeDelta> GetRequiredDelaySinceLastStrike() |
| const; |
| }; |
| |
| } // namespace strike_database |
| |
| #endif // COMPONENTS_STRIKE_DATABASE_STRIKE_DATABASE_INTEGRATOR_BASE_H_ |