| // 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 "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/common/extension_id.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| 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(kCWSInfoService); |
| 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 absl::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 absl::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: |
| absl::optional<bool> IsLiveInCWS(const Extension& extension) const override; |
| absl::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; |
| void SetMaxExtensionIdsPerRequestForTesting(int max); |
| |
| protected: |
| // Only used for testing to create a fake derived class. |
| CWSInfoService(); |
| |
| // Returns true if the service can perform fetch operations, false otherwise. |
| bool CanFetchInfo() const; |
| |
| // 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_ |