blob: e6f3f44bd83f5b2d09fbe4ccefd388b70a81fb2d [file] [log] [blame]
// 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_