1 // Copyright 2015 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
5 #include "extensions/browser/updater/update_data_provider.h"
6
7 #include <utility>
8
9 #include "base/base64.h"
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/optional.h"
14 #include "base/strings/string_util.h"
15 #include "base/task/thread_pool.h"
16 #include "components/crx_file/crx_verifier.h"
17 #include "components/update_client/utils.h"
18 #include "content/public/browser/browser_task_traits.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "crypto/sha2.h"
21 #include "extensions/browser/content_verifier.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/browser/extensions_browser_client.h"
26 #include "extensions/browser/install/crx_install_error.h"
27 #include "extensions/browser/updater/manifest_fetch_data.h"
28 #include "extensions/common/extension.h"
29 #include "extensions/common/extension_urls.h"
30 #include "extensions/common/verifier_formats.h"
31
32 namespace extensions {
33
34 namespace {
35
36 using UpdateClientCallback = UpdateDataProvider::UpdateClientCallback;
37
InstallUpdateCallback(content::BrowserContext * context,const std::string & extension_id,const std::string & public_key,const base::FilePath & unpacked_dir,bool install_immediately,UpdateClientCallback update_client_callback)38 void InstallUpdateCallback(content::BrowserContext* context,
39 const std::string& extension_id,
40 const std::string& public_key,
41 const base::FilePath& unpacked_dir,
42 bool install_immediately,
43 UpdateClientCallback update_client_callback) {
44 // Note that error codes are converted into custom error codes, which are all
45 // based on a constant (see ToInstallerResult). This means that custom codes
46 // from different embedders may collide. However, for any given extension ID,
47 // there should be only one embedder, so this should be OK from Omaha.
48 ExtensionSystem::Get(context)->InstallUpdate(
49 extension_id, public_key, unpacked_dir, install_immediately,
50 base::BindOnce(
51 [](UpdateClientCallback callback,
52 const base::Optional<CrxInstallError>& error) {
53 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
54 update_client::CrxInstaller::Result result(0);
55 if (error.has_value()) {
56 int detail =
57 error->type() ==
58 CrxInstallErrorType::SANDBOXED_UNPACKER_FAILURE
59 ? static_cast<int>(error->sandbox_failure_detail())
60 : static_cast<int>(error->detail());
61 result = update_client::ToInstallerResult(error->type(), detail);
62 }
63 std::move(callback).Run(result);
64 },
65 std::move(update_client_callback)));
66 }
67
68 } // namespace
69
UpdateDataProvider(content::BrowserContext * browser_context)70 UpdateDataProvider::UpdateDataProvider(content::BrowserContext* browser_context)
71 : browser_context_(browser_context) {}
72
73 UpdateDataProvider::~UpdateDataProvider() = default;
74
Shutdown()75 void UpdateDataProvider::Shutdown() {
76 browser_context_ = nullptr;
77 }
78
79 std::vector<base::Optional<update_client::CrxComponent>>
GetData(bool install_immediately,const ExtensionUpdateDataMap & update_crx_component,const std::vector<std::string> & ids)80 UpdateDataProvider::GetData(bool install_immediately,
81 const ExtensionUpdateDataMap& update_crx_component,
82 const std::vector<std::string>& ids) {
83 std::vector<base::Optional<update_client::CrxComponent>> data;
84 if (!browser_context_)
85 return data;
86 const ExtensionRegistry* registry = ExtensionRegistry::Get(browser_context_);
87 const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser_context_);
88 for (const auto& id : ids) {
89 const Extension* extension = registry->GetInstalledExtension(id);
90 data.push_back(extension
91 ? base::make_optional<update_client::CrxComponent>()
92 : base::nullopt);
93 if (!extension)
94 continue;
95 DCHECK_NE(0u, update_crx_component.count(id));
96 const ExtensionUpdateData& extension_data = update_crx_component.at(id);
97 auto& crx_component = data.back();
98 std::string pubkey_bytes;
99 base::Base64Decode(extension->public_key(), &pubkey_bytes);
100 crx_component->pk_hash.resize(crypto::kSHA256Length, 0);
101 crypto::SHA256HashString(pubkey_bytes, crx_component->pk_hash.data(),
102 crx_component->pk_hash.size());
103 crx_component->app_id =
104 update_client::GetCrxIdFromPublicKeyHash(crx_component->pk_hash);
105 if (extension_data.is_corrupt_reinstall) {
106 crx_component->version = base::Version("0.0.0.0");
107 } else {
108 crx_component->version = extension->version();
109 crx_component->fingerprint = extension->DifferentialFingerprint();
110 }
111 crx_component->allows_background_download = false;
112 bool allow_dev = extension_urls::GetWebstoreUpdateUrl() !=
113 extension_urls::GetDefaultWebstoreUpdateUrl();
114 crx_component->requires_network_encryption = !allow_dev;
115 crx_component->crx_format_requirement =
116 extension->from_webstore() ? GetWebstoreVerifierFormat(allow_dev)
117 : GetPolicyVerifierFormat();
118 crx_component->installer = base::MakeRefCounted<ExtensionInstaller>(
119 id, extension->path(), install_immediately,
120 base::BindRepeating(&UpdateDataProvider::RunInstallCallback, this));
121 if (!ExtensionsBrowserClient::Get()->IsExtensionEnabled(id,
122 browser_context_)) {
123 int disabled_reasons = extension_prefs->GetDisableReasons(id);
124 if (disabled_reasons == extensions::disable_reason::DISABLE_NONE ||
125 disabled_reasons >= extensions::disable_reason::DISABLE_REASON_LAST) {
126 crx_component->disabled_reasons.push_back(0);
127 }
128 for (int enum_value = 1;
129 enum_value < extensions::disable_reason::DISABLE_REASON_LAST;
130 enum_value <<= 1) {
131 if (disabled_reasons & enum_value)
132 crx_component->disabled_reasons.push_back(enum_value);
133 }
134 }
135 crx_component->install_source = extension_data.is_corrupt_reinstall
136 ? "reinstall"
137 : extension_data.install_source;
138 crx_component->install_location =
139 ManifestFetchData::GetSimpleLocationString(extension->location());
140 }
141 return data;
142 }
143
RunInstallCallback(const std::string & extension_id,const std::string & public_key,const base::FilePath & unpacked_dir,bool install_immediately,UpdateClientCallback update_client_callback)144 void UpdateDataProvider::RunInstallCallback(
145 const std::string& extension_id,
146 const std::string& public_key,
147 const base::FilePath& unpacked_dir,
148 bool install_immediately,
149 UpdateClientCallback update_client_callback) {
150 VLOG(3) << "UpdateDataProvider::RunInstallCallback " << extension_id << " "
151 << public_key;
152
153 if (!browser_context_) {
154 base::ThreadPool::PostTask(
155 FROM_HERE, {base::TaskPriority::BEST_EFFORT, base::MayBlock()},
156 base::BindOnce(base::GetDeletePathRecursivelyCallback(), unpacked_dir));
157 content::GetUIThreadTaskRunner({})->PostTask(
158 FROM_HERE,
159 base::BindOnce(std::move(update_client_callback),
160 update_client::CrxInstaller::Result(
161 update_client::InstallError::GENERIC_ERROR)));
162 return;
163 }
164
165 content::GetUIThreadTaskRunner({})->PostTask(
166 FROM_HERE,
167 base::BindOnce(InstallUpdateCallback, browser_context_, extension_id,
168 public_key, unpacked_dir, install_immediately,
169 std::move(update_client_callback)));
170 }
171
172 } // namespace extensions
173