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