1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
// Copyright 2023 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_IP_PROTECTION_COMMON_IP_PROTECTION_TOKEN_MANAGER_IMPL_H_
#define COMPONENTS_IP_PROTECTION_COMMON_IP_PROTECTION_TOKEN_MANAGER_IMPL_H_
#include <cstddef>
#include <cstdint>
#include <deque>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/ip_protection/common/ip_protection_token_manager.h"
namespace ip_protection {
class IpProtectionTokenFetcher;
class IpProtectionCore;
enum class ProxyLayer;
// An implementation of IpProtectionTokenManager that populates itself
// using a passed in IpProtectionTokenFetcher pointer from the cache.
class IpProtectionTokenManagerImpl : public IpProtectionTokenManager {
public:
explicit IpProtectionTokenManagerImpl(
IpProtectionCore* core,
std::unique_ptr<IpProtectionTokenFetcher> fetcher,
ProxyLayer proxy_layer,
bool disable_cache_management_for_testing = false);
~IpProtectionTokenManagerImpl() override;
// IpProtectionTokenManager implementation.
bool IsAuthTokenAvailable() override;
bool IsAuthTokenAvailable(const std::string& geo_id) override;
bool WasTokenCacheEverFilled() override;
std::optional<BlindSignedAuthToken> GetAuthToken() override;
std::optional<BlindSignedAuthToken> GetAuthToken(
const std::string& geo_id) override;
std::string CurrentGeo() const override;
void SetCurrentGeo(const std::string& geo_id) override;
void InvalidateTryAgainAfterTime() override;
// Set a callback that will be run after the next call to `TryGetAuthTokens()`
// has completed.
void SetOnTryGetAuthTokensCompletedForTesting(
base::OnceClosure on_try_get_auth_tokens_completed) {
on_try_get_auth_tokens_completed_for_testing_ =
std::move(on_try_get_auth_tokens_completed);
}
// Enable active cache management in the background, if it was disabled
// (either via the constructor or via a call to
// `DisableCacheManagementForTesting()`).
void EnableCacheManagementForTesting() {
disable_cache_management_for_testing_ = false;
ScheduleMaybeRefillCache();
}
bool IsCacheManagementEnabledForTesting() {
return !disable_cache_management_for_testing_;
}
// Disable active cache management and reset the manager back to its base
// state: no tokens, no backoff, no active token fetches, no pending timers.
void DisableCacheManagementForTesting(
base::OnceClosure on_cache_management_disabled);
void EnableTokenExpirationFuzzingForTesting(bool enable);
// Requests tokens from the browser process and executes the provided callback
// after the response is received.
void CallTryGetAuthTokensForTesting();
base::Time try_get_auth_tokens_after_for_testing() {
return try_get_auth_tokens_after_;
}
bool fetching_auth_tokens_for_testing() { return fetching_auth_tokens_; }
private:
void OnGotAuthTokens(base::TimeTicks attempt_start_time_for_metrics,
std::optional<std::vector<BlindSignedAuthToken>> tokens,
std::optional<base::Time> try_again_after);
void RemoveExpiredTokens();
void MeasureTokenRates();
void MaybeRefillCache();
void ScheduleMaybeRefillCache();
bool NeedsRefill(const std::string& geo_id) const;
bool IsTokenLimitExceeded(const std::string& geo_id) const;
// Current geo of the client.
// This value should only be set by the `IpProtectionCore` using the
// `IpProtectionTokenManager::SetCurrentGeo()` function.
std::string current_geo_id_ = "";
// Batch size and cache low-water mark as determined from feature params at
// construction time.
const int batch_size_;
const size_t cache_low_water_mark_;
// The last time token rates were measured and the counts since then.
base::TimeTicks last_token_rate_measurement_;
int64_t tokens_spent_ = 0;
int64_t tokens_expired_ = 0;
// Map for caches of tokens keyed by geo id. For each geo entry, tokens are
// sorted by their expiration time.
std::map<std::string, std::deque<BlindSignedAuthToken>> cache_by_geo_;
// Source of proxy list, when needed.
std::unique_ptr<IpProtectionTokenFetcher> fetcher_;
// The proxy layer which the cache of tokens will be used for.
ProxyLayer proxy_layer_;
// Pointer to the `IpProtectionCore` that holds the proxy list and
// tokens. Required to observe geo changes from retrieved tokens.
// The lifetime of the `IpProtectionCore` object WILL ALWAYS outlive
// this class b/c `ip_protection_core_` owns this (at least outside of
// testing).
const raw_ptr<IpProtectionCore> ip_protection_core_;
// True if an attempt to fetch tokens is outstanding.
bool fetching_auth_tokens_ = false;
// True if the cache has been filled at least once.
bool cache_has_been_filled_ = false;
// True if the "NetworkService.IpProtection.GeoChangeTokenPresence" metric
// needs to be sampled. False if the presence has already been sampled. This
// value should be reset to true after `SetCurrentGeo` is called after a token
// refill.
// A boolean flag is crucial to prevent duplicate or incorrect histogram
// measurements. By tracking whether a histogram has already been logged for a
// given geo change, we can avoid redundant or misleading data which could be
// caused b/c a cache is filled with tokens before a call to `SetCurrentGeo`
// is made.
bool emitted_geo_presence_histogram_before_refill_ = true;
// If not null, this is the `try_again_after` time from the last call to
// `TryGetAuthTokens()`, and no calls should be made until this time.
base::Time try_get_auth_tokens_after_;
// A timer to run `MaybeRefillCache()` when necessary, such as when the next
// token expires or the cache is able to fetch more tokens.
base::OneShotTimer next_maybe_refill_cache_;
// A callback triggered when the next call to `TryGetAuthTokens()` occurs, for
// use in testing.
base::OnceClosure on_try_get_auth_tokens_completed_for_testing_;
// If true, do not try to automatically refill the cache.
bool disable_cache_management_for_testing_ = false;
// If false, token expiration is not fuzzed.
bool enable_token_expiration_fuzzing_= true;
base::RepeatingTimer measurement_timer_;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<IpProtectionTokenManagerImpl> weak_ptr_factory_{this};
};
} // namespace ip_protection
#endif // COMPONENTS_IP_PROTECTION_COMMON_IP_PROTECTION_TOKEN_MANAGER_IMPL_H_
|