url_param_classification_component_installer.cc 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/component_updater/installer_policies/url_param_classification_component_installer.h"
  5. #include "base/bind.h"
  6. #include "base/callback.h"
  7. #include "base/files/file_path.h"
  8. #include "base/files/file_util.h"
  9. #include "base/logging.h"
  10. #include "base/memory/ref_counted.h"
  11. #include "base/metrics/histogram_functions.h"
  12. #include "base/path_service.h"
  13. #include "base/task/task_traits.h"
  14. #include "base/task/thread_pool.h"
  15. #include "base/version.h"
  16. #include "components/component_updater/component_updater_paths.h"
  17. #include "components/url_param_filter/core/features.h"
  18. #include "components/url_param_filter/core/url_param_classifications_loader.h"
  19. #include "third_party/abseil-cpp/absl/types/optional.h"
  20. using component_updater::ComponentUpdateService;
  21. namespace {
  22. const base::FilePath::CharType kUrlParamClassificationsFileName[] =
  23. FILE_PATH_LITERAL("list.pb");
  24. // The SHA256 of the SubjectPublicKeyInfo used to sign the extension.
  25. // The extension id is: dnhnnofocefcglhjeigmkhcgfoaipbaa
  26. const uint8_t kUrlParamClassificationsPublicKeySHA256[32] = {
  27. 0x3d, 0x7d, 0xde, 0x5e, 0x24, 0x52, 0x6b, 0x79, 0x48, 0x6c, 0xa7,
  28. 0x26, 0x5e, 0x08, 0xf1, 0x00, 0x82, 0x56, 0x69, 0xb1, 0xca, 0xfc,
  29. 0x8a, 0x25, 0x50, 0x06, 0x6b, 0x5f, 0xa1, 0xd5, 0xeb, 0x80};
  30. const char kUrlParamClassificationManifestName[] = "Url Param Classifications";
  31. // Runs on a thread pool.
  32. absl::optional<std::string> LoadFileFromDisk(const base::FilePath& pb_path) {
  33. if (!base::FeatureList::IsEnabled(
  34. url_param_filter::features::kIncognitoParamFilterEnabled))
  35. return absl::nullopt;
  36. VLOG(1) << "Reading Url Param Classifications from file: " << pb_path.value();
  37. std::string file_contents;
  38. if (!base::ReadFileToString(pb_path, &file_contents)) {
  39. // The file won't exist on new installations, so this is not always an
  40. // error.
  41. VLOG(1) << "Failed reading from " << pb_path.value();
  42. return absl::nullopt;
  43. }
  44. return file_contents;
  45. }
  46. // Writes a metric denoting the |result| of validating a classification list.
  47. //
  48. // This method is called in VerifyInstallation which returns false (on an error)
  49. // or true (if the whole list is valid), so the metrics will be populated at
  50. // most once per version installed.
  51. void WriteMetrics(
  52. component_updater::UrlParamClassificationComponentInstallerPolicy::
  53. ClassificationListValidationResult result) {
  54. base::UmaHistogramEnumeration(
  55. "Navigation.UrlParamFilter.ClassificationListValidationResult", result);
  56. }
  57. absl::optional<base::FilePath>& GetConfigPathInstance() {
  58. // Contains nullopt until registration is complete. Afterward, contains the
  59. // FilePath for the component file, or an empty FilePath if no component was
  60. // installed at startup.
  61. static base::NoDestructor<absl::optional<base::FilePath>> instance;
  62. return *instance;
  63. }
  64. } // namespace
  65. namespace component_updater {
  66. UrlParamClassificationComponentInstallerPolicy::
  67. UrlParamClassificationComponentInstallerPolicy(
  68. component_updater::OnUrlParamClassificationComponentReady
  69. on_component_ready)
  70. : on_component_ready_(on_component_ready) {}
  71. UrlParamClassificationComponentInstallerPolicy::
  72. ~UrlParamClassificationComponentInstallerPolicy() = default;
  73. bool UrlParamClassificationComponentInstallerPolicy::
  74. SupportsGroupPolicyEnabledComponentUpdates() const {
  75. return true;
  76. }
  77. bool UrlParamClassificationComponentInstallerPolicy::RequiresNetworkEncryption()
  78. const {
  79. return false;
  80. }
  81. update_client::CrxInstaller::Result
  82. UrlParamClassificationComponentInstallerPolicy::OnCustomInstall(
  83. const base::Value& manifest,
  84. const base::FilePath& install_dir) {
  85. return update_client::CrxInstaller::Result(0); // Nothing custom here.
  86. }
  87. void UrlParamClassificationComponentInstallerPolicy::OnCustomUninstall() {}
  88. base::FilePath UrlParamClassificationComponentInstallerPolicy::GetInstalledPath(
  89. const base::FilePath& base) {
  90. return base.Append(kUrlParamClassificationsFileName);
  91. }
  92. void UrlParamClassificationComponentInstallerPolicy::ComponentReady(
  93. const base::Version& version,
  94. const base::FilePath& install_dir,
  95. base::Value manifest) {
  96. VLOG(1) << "Component ready, version " << version.GetString() << " in "
  97. << install_dir.value();
  98. // Given BEST_EFFORT since we don't need to be USER_BLOCKING.
  99. base::ThreadPool::PostTaskAndReplyWithResult(
  100. FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
  101. base::BindOnce(&LoadFileFromDisk, GetInstalledPath(install_dir)),
  102. base::BindOnce(
  103. [](OnUrlParamClassificationComponentReady callback,
  104. const absl::optional<std::string>& maybe_file) {
  105. if (maybe_file.has_value())
  106. callback.Run(maybe_file.value());
  107. },
  108. on_component_ready_));
  109. }
  110. // Called during startup and installation before ComponentReady().
  111. bool UrlParamClassificationComponentInstallerPolicy::VerifyInstallation(
  112. const base::Value& manifest,
  113. const base::FilePath& install_dir) const {
  114. if (!base::PathExists(GetInstalledPath(install_dir))) {
  115. WriteMetrics(
  116. ClassificationListValidationResult::kMissingClassificationsFile);
  117. return false;
  118. }
  119. std::string file_contents;
  120. if (!base::ReadFileToString(GetInstalledPath(install_dir), &file_contents)) {
  121. WriteMetrics(
  122. ClassificationListValidationResult::kReadingClassificationsFileFailed);
  123. return false;
  124. }
  125. url_param_filter::FilterClassifications classification_list;
  126. if (!classification_list.ParseFromString(file_contents)) {
  127. WriteMetrics(ClassificationListValidationResult::kParsingToProtoFailed);
  128. return false;
  129. }
  130. for (const url_param_filter::FilterClassification& fc :
  131. classification_list.classifications()) {
  132. if (!fc.has_site()) {
  133. WriteMetrics(
  134. ClassificationListValidationResult::kClassificationMissingSite);
  135. return false;
  136. }
  137. if (!fc.has_site_role()) {
  138. WriteMetrics(
  139. ClassificationListValidationResult::kClassificationMissingSiteRole);
  140. return false;
  141. }
  142. }
  143. WriteMetrics(ClassificationListValidationResult::kSuccessful);
  144. return true;
  145. }
  146. base::FilePath
  147. UrlParamClassificationComponentInstallerPolicy::GetRelativeInstallDir() const {
  148. return base::FilePath(FILE_PATH_LITERAL("UrlParamClassifications"));
  149. }
  150. void UrlParamClassificationComponentInstallerPolicy::GetHash(
  151. std::vector<uint8_t>* hash) const {
  152. hash->assign(std::begin(kUrlParamClassificationsPublicKeySHA256),
  153. std::end(kUrlParamClassificationsPublicKeySHA256));
  154. }
  155. std::string UrlParamClassificationComponentInstallerPolicy::GetName() const {
  156. return kUrlParamClassificationManifestName;
  157. }
  158. update_client::InstallerAttributes
  159. UrlParamClassificationComponentInstallerPolicy::GetInstallerAttributes() const {
  160. return update_client::InstallerAttributes();
  161. }
  162. // static
  163. void UrlParamClassificationComponentInstallerPolicy::WriteComponentForTesting(
  164. const base::FilePath& install_dir,
  165. base::StringPiece contents) {
  166. CHECK(base::WriteFile(GetInstalledPath(install_dir), contents));
  167. GetConfigPathInstance() = GetInstalledPath(install_dir);
  168. }
  169. // static
  170. void UrlParamClassificationComponentInstallerPolicy::ResetForTesting() {
  171. GetConfigPathInstance().reset();
  172. }
  173. void RegisterUrlParamClassificationComponent(ComponentUpdateService* cus) {
  174. // Register the component even if feature isn't enabled so that when it is
  175. // enabled in the future, the component is already installed.
  176. VLOG(1) << "Registering Url Param Classifications component.";
  177. auto installer = base::MakeRefCounted<ComponentInstaller>(
  178. std::make_unique<UrlParamClassificationComponentInstallerPolicy>(
  179. base::BindRepeating([](std::string raw_classifications) {
  180. url_param_filter::ClassificationsLoader::GetInstance()
  181. ->ReadClassifications(raw_classifications);
  182. })));
  183. installer->Register(
  184. cus, base::BindOnce([]() {
  185. if (GetConfigPathInstance().has_value()) {
  186. absl::optional<std::string> file_contents =
  187. LoadFileFromDisk(GetConfigPathInstance().value());
  188. if (file_contents.has_value()) {
  189. // Only read classifications after registration if
  190. // needed for testing.
  191. url_param_filter::ClassificationsLoader::GetInstance()
  192. ->ReadClassifications(file_contents.value());
  193. }
  194. }
  195. }));
  196. }
  197. } // namespace component_updater