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 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
// 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 CHROME_BROWSER_EXTENSIONS_CWS_INFO_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_CWS_INFO_SERVICE_H_
#include <optional>
#include "base/feature_list.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "extensions/buildflags/buildflags.h"
#include "extensions/common/extension_id.h"
static_assert(BUILDFLAG(ENABLE_EXTENSIONS_CORE));
class PrefService;
class Profile;
namespace network {
class SharedURLLoaderFactory;
class SimpleURLLoader;
} // namespace network
namespace extensions {
class Extension;
class ExtensionPrefs;
class ExtensionRegistry;
class BatchGetStoreMetadatasResponse;
BASE_DECLARE_FEATURE(kCWSInfoFastCheck);
// This is an interface class to allow for easy mocking.
class CWSInfoServiceInterface {
public:
virtual ~CWSInfoServiceInterface() = default;
// Synchronously checks if the extension is currently live in CWS.
// If the information is not available immediately (i.e., not stored in local
// cache), does not return a value.
virtual std::optional<bool> IsLiveInCWS(const Extension& extension) const = 0;
enum class CWSViolationType {
kNone = 0,
kMalware = 1,
kPolicy = 2,
kMinorPolicy = 3,
// New enum values must go above here
kUnknown
};
struct CWSInfo {
// This extension is present in CWS.
bool is_present = false;
// This extension is currently published and downloadable from CWS.
bool is_live = false;
// The last time the extension was updated in CWS. Only valid if `is_live`
// is true.
base::Time last_update_time;
// The following fields are only valid if `is_present` is true.
// If the extension has been taken down, i.e., no longer live, this
// represents the violation type that caused the take-down.
CWSViolationType violation_type = CWSViolationType::kNone;
// The extension was unpublished from CWS by the developer a while ago.
bool unpublished_long_ago = false;
// The extension does not display proper privacy practice information in
// CWS.
bool no_privacy_practice = false;
};
virtual std::optional<CWSInfo> GetCWSInfo(
const Extension& extension) const = 0;
// Initiates a fetch from CWS if:
// - at least one installed extension is missing CWS metadata information
// - Enough time (default: 24 hours) has elapsed since the last time the
// metadata was fetched.
virtual void CheckAndMaybeFetchInfo() = 0;
class Observer : public base::CheckedObserver {
public:
// This callback is invoked when there is a change in store metadata
// saved by the service.
virtual void OnCWSInfoChanged() {}
};
// Use these methods to (de)register for changes in the CWS metadata retrieved
// by the service.
virtual void AddObserver(Observer* observer) = 0;
virtual void RemoveObserver(Observer* observer) = 0;
};
// This service retrieves information about installed extensions from CWS
// periodically (default: every 24 hours). It is used exclusively on the
// browser UI thread. The service also supports out-of-cycle fetch requests for
// use cases where waiting for up to 24 hours for fresh state is not desirable
// (for example, when the ExtensionsUnpublishedAvailability policy setting
// changes). Only extensions that update from CWS are queried.
class CWSInfoService : public CWSInfoServiceInterface, public KeyedService {
public:
// Convenience method to get the service for a profile.
static CWSInfoService* Get(Profile* profile);
explicit CWSInfoService(Profile* profile);
CWSInfoService(const CWSInfoService&) = delete;
CWSInfoService& operator=(const CWSInfoService&) = delete;
~CWSInfoService() override;
// CWSInfoServiceInterface:
std::optional<bool> IsLiveInCWS(const Extension& extension) const override;
std::optional<CWSInfo> GetCWSInfo(const Extension& extension) const override;
void CheckAndMaybeFetchInfo() override;
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
// KeyedService:
void Shutdown() override;
// Helpers
static CWSInfoService::CWSViolationType GetViolationTypeFromString(
const std::string& violation_type_str);
// Testing helpers
std::string GetRequestURLForTesting() const;
int GetStartupDelayForTesting() const;
int GetCheckIntervalForTesting() const;
int GetFetchIntervalForTesting() const;
base::Time GetCWSInfoTimestampForTesting() const;
base::Time GetCWSInfoFetchErrorTimestampForTesting() const;
void SetMaxExtensionIdsPerRequestForTesting(int max);
static void SetSkipApiCheckForTesting(bool skip_api_key_check);
protected:
// Only used for testing to create a fake derived class.
CWSInfoService();
// This method schedules an info check after specified `seconds`.
void ScheduleCheck(int seconds);
// This method prepares request protos to fetch CWS metadata. A CWS fetch
// operation can consist of multiple request protos when the number of
// installed extensions exceeds the max ids supported per request (100). The
// request protos, extension ids and other data associated with the fetch are
// returned in a `FetchContext`. The method also outputs a
// `new_info_requested` that indicates if at least one of the installed
// extensions is missing CWS metadata information.
struct FetchContext;
std::unique_ptr<FetchContext> CreateRequests(
bool& /*output=*/new_info_requested);
// Sends a single network request associated with a CWS info fetch.
void SendRequest();
// Handles the server response associated with a single network request.
void OnResponseReceived(std::unique_ptr<std::string> response);
// Saves data to prefs if the response data is different from the saved data.
// Returns true if the response data is saved, false otherwise.
bool MaybeSaveResponseToPrefs(
const BatchGetStoreMetadatasResponse& response_proto);
const raw_ptr<Profile> profile_ = nullptr;
const raw_ptr<PrefService> pref_service_ = nullptr;
const raw_ptr<ExtensionPrefs> extension_prefs_ = nullptr;
const raw_ptr<ExtensionRegistry> extension_registry_ = nullptr;
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
// Stores context about a fetch operation in progress. The service only
// supports one fetch operation at a time.
std::unique_ptr<FetchContext> active_fetch_;
// Each request associated with a fetch can have a maximum of 100 extension
// ids. This parameter can be changed for testing.
int max_ids_per_request_;
// Stats for requests, responses and errors.
uint32_t info_requests_ = 0;
uint32_t info_responses_ = 0;
uint32_t info_errors_ = 0;
// Counts the number of times the downloaded metadata was different from that
// currently saved.
uint32_t info_changes_ = 0;
// A timer used to periodically check if CWS information needs to be fetched.
base::OneShotTimer info_check_timer_;
// Time from startup to first check of CWS information.
int startup_delay_secs_ = 0;
// Time interval between fetches from CWS info server. The interval value
// varies +/-25% from default of 24 hours for every fetch.
int current_fetch_interval_secs_ = 0;
// List of observers that are notified whenever new CWS information is saved.
base::ObserverList<Observer> observers_;
friend class CWSInfoServiceTest;
base::WeakPtrFactory<CWSInfoService> weak_factory_{this};
};
} // namespace extensions
#endif // CHROME_BROWSER_EXTENSIONS_CWS_INFO_SERVICE_H_
|