blob: 07e70acc5e9be323dd1e343354ddd335c139a055 [file] [log] [blame]
evliu7b9481b32019-12-20 19:39:551// Copyright 2019 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 "chrome/browser/component_updater/soda_component_installer.h"
6
7#include "base/bind.h"
8#include "base/files/file_util.h"
Abigail Klein82807c552020-04-06 19:58:079#include "build/build_config.h"
evliu7b9481b32019-12-20 19:39:5510#include "chrome/browser/browser_process.h"
11#include "chrome/common/pref_names.h"
evliu8b3cee92020-07-28 17:17:2112#include "chrome/services/speech/buildflags.h"
evliu7b9481b32019-12-20 19:39:5513#include "components/component_updater/component_updater_service.h"
14#include "components/crx_file/id_util.h"
evliu415179ab2020-01-24 20:50:5315#include "components/soda/constants.h"
evliu7b9481b32019-12-20 19:39:5516#include "components/update_client/update_client_errors.h"
17#include "content/public/browser/browser_task_traits.h"
Gabriel Charettee7cdc5cd2020-05-27 23:35:0518#include "content/public/browser/browser_thread.h"
evliu7b9481b32019-12-20 19:39:5519#include "crypto/sha2.h"
20
21using content::BrowserThread;
22
23namespace component_updater {
24
25namespace {
26
evliu7be3c7d2020-01-10 20:17:0627// The SHA256 of the SubjectPublicKeyInfo used to sign the component.
28// The component id is: icnkogojpkfjeajonkmlplionaamopkf
evliu7b9481b32019-12-20 19:39:5529const uint8_t kSODAPublicKeySHA256[32] = {
evliu7be3c7d2020-01-10 20:17:0630 0x82, 0xda, 0xe6, 0xe9, 0xfa, 0x59, 0x40, 0x9e, 0xda, 0xcb, 0xfb,
31 0x8e, 0xd0, 0x0c, 0xef, 0xa5, 0xc0, 0x97, 0x00, 0x84, 0x1c, 0x21,
32 0xa6, 0xae, 0xc8, 0x1b, 0x87, 0xfb, 0x12, 0x27, 0x28, 0xb1};
evliu7b9481b32019-12-20 19:39:5533
evliu7b9481b32019-12-20 19:39:5534static_assert(base::size(kSODAPublicKeySHA256) == crypto::kSHA256Length,
35 "Wrong hash length");
36
37const char kSODAManifestName[] = "SODA Library";
38
evliu14d897af2020-07-30 22:17:2139constexpr base::FilePath::CharType kSodaEnUsConfigFileRelativePath[] =
40 FILE_PATH_LITERAL("SODAFiles/en_us/dictation.ascii_proto");
41
evliu7b9481b32019-12-20 19:39:5542} // namespace
43
44SODAComponentInstallerPolicy::SODAComponentInstallerPolicy(
Xida Chenb38f3f76a2020-07-02 02:11:1445 OnSODAComponentReadyCallback callback)
evliu7b9481b32019-12-20 19:39:5546 : on_component_ready_callback_(callback) {}
47
48SODAComponentInstallerPolicy::~SODAComponentInstallerPolicy() = default;
49
50const std::string SODAComponentInstallerPolicy::GetExtensionId() {
51 return crx_file::id_util::GenerateIdFromHash(kSODAPublicKeySHA256,
52 sizeof(kSODAPublicKeySHA256));
53}
54
55void SODAComponentInstallerPolicy::UpdateSODAComponentOnDemand() {
56 const std::string crx_id =
57 component_updater::SODAComponentInstallerPolicy::GetExtensionId();
58 g_browser_process->component_updater()->GetOnDemandUpdater().OnDemandUpdate(
59 crx_id, component_updater::OnDemandUpdater::Priority::FOREGROUND,
60 base::BindOnce([](update_client::Error error) {
61 if (error != update_client::Error::NONE &&
62 error != update_client::Error::UPDATE_IN_PROGRESS)
63 LOG(ERROR) << "On demand update of the SODA component failed "
64 "with error: "
65 << static_cast<int>(error);
66 }));
67}
68
69bool SODAComponentInstallerPolicy::VerifyInstallation(
70 const base::DictionaryValue& manifest,
71 const base::FilePath& install_dir) const {
evliu2e5dbee42020-04-09 23:35:2972 return base::PathExists(install_dir.Append(speech::kSodaBinaryRelativePath));
evliu7b9481b32019-12-20 19:39:5573}
74
75bool SODAComponentInstallerPolicy::SupportsGroupPolicyEnabledComponentUpdates()
76 const {
77 return true;
78}
79
80bool SODAComponentInstallerPolicy::RequiresNetworkEncryption() const {
81 return false;
82}
83
84update_client::CrxInstaller::Result
85SODAComponentInstallerPolicy::OnCustomInstall(
86 const base::DictionaryValue& manifest,
87 const base::FilePath& install_dir) {
88 return update_client::CrxInstaller::Result(0); // Nothing custom here.
89}
90
91void SODAComponentInstallerPolicy::OnCustomUninstall() {}
92
93void SODAComponentInstallerPolicy::ComponentReady(
94 const base::Version& version,
95 const base::FilePath& install_dir,
96 std::unique_ptr<base::DictionaryValue> manifest) {
97 VLOG(1) << "Component ready, version " << version.GetString() << " in "
98 << install_dir.value();
99
100 on_component_ready_callback_.Run(install_dir);
101}
102
103base::FilePath SODAComponentInstallerPolicy::GetRelativeInstallDir() const {
evliu2e5dbee42020-04-09 23:35:29104 return base::FilePath(speech::kSodaInstallationRelativePath);
evliu7b9481b32019-12-20 19:39:55105}
106
107void SODAComponentInstallerPolicy::GetHash(std::vector<uint8_t>* hash) const {
108 hash->assign(kSODAPublicKeySHA256,
109 kSODAPublicKeySHA256 + base::size(kSODAPublicKeySHA256));
110}
111
112std::string SODAComponentInstallerPolicy::GetName() const {
113 return kSODAManifestName;
114}
115
116update_client::InstallerAttributes
117SODAComponentInstallerPolicy::GetInstallerAttributes() const {
118 return update_client::InstallerAttributes();
119}
120
121std::vector<std::string> SODAComponentInstallerPolicy::GetMimeTypes() const {
122 return std::vector<std::string>();
123}
124
evliu7be3c7d2020-01-10 20:17:06125void UpdateSODAInstallDirPref(PrefService* prefs,
126 const base::FilePath& install_dir) {
Abigail Klein82807c552020-04-06 19:58:07127#if !defined(OS_ANDROID)
evliu14d897af2020-07-30 22:17:21128 prefs->SetFilePath(prefs::kSodaBinaryPath,
evliud498bd82020-08-12 19:06:02129 install_dir.Append(speech::kSodaBinaryRelativePath));
evliu14d897af2020-07-30 22:17:21130 prefs->SetFilePath(prefs::kSodaEnUsConfigPath,
131 install_dir.Append(kSodaEnUsConfigFileRelativePath));
Abigail Klein82807c552020-04-06 19:58:07132#endif
evliu7be3c7d2020-01-10 20:17:06133}
134
evliu7b9481b32019-12-20 19:39:55135void RegisterSODAComponent(ComponentUpdateService* cus,
136 PrefService* prefs,
137 base::OnceClosure callback) {
138 DCHECK_CURRENTLY_ON(BrowserThread::UI);
evliu8b3cee92020-07-28 17:17:21139#if BUILDFLAG(ENABLE_SODA)
evliu7be3c7d2020-01-10 20:17:06140 auto installer = base::MakeRefCounted<ComponentInstaller>(
141 std::make_unique<SODAComponentInstallerPolicy>(base::BindRepeating(
evliu552d1052020-06-24 16:27:46142 [](ComponentUpdateService* cus, PrefService* prefs,
143 const base::FilePath& install_dir) {
144 if (prefs->GetBoolean(prefs::kLiveCaptionEnabled)) {
145 content::GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
146 ->PostTask(FROM_HERE,
147 base::BindOnce(&UpdateSODAInstallDirPref, prefs,
148 install_dir));
149 }
evliu7be3c7d2020-01-10 20:17:06150 },
evliu552d1052020-06-24 16:27:46151 cus, prefs)));
152
153 if (prefs->GetBoolean(prefs::kLiveCaptionEnabled)) {
154 installer->Register(cus, std::move(callback));
155 } else {
156 // Register and uninstall the SODA component to delete the previously
157 // installed SODA files.
evliu14d897af2020-07-30 22:17:21158 if (!prefs->GetFilePath(prefs::kSodaBinaryPath).empty()) {
evliu552d1052020-06-24 16:27:46159 installer->Register(
160 cus,
161 base::BindOnce(
162 [](ComponentUpdateService* cus, PrefService* prefs) {
163 if (component_updater::UninstallSODAComponent(cus, prefs)) {
evliu14d897af2020-07-30 22:17:21164 prefs->SetFilePath(prefs::kSodaBinaryPath, base::FilePath());
165 prefs->SetFilePath(prefs::kSodaEnUsConfigPath,
166 base::FilePath());
evliu552d1052020-06-24 16:27:46167 }
168 },
169 cus, prefs));
170 }
171 }
evliu8b3cee92020-07-28 17:17:21172#endif
evliu552d1052020-06-24 16:27:46173}
174
175bool UninstallSODAComponent(ComponentUpdateService* cus, PrefService* prefs) {
176 return cus->UnregisterComponent(
177 SODAComponentInstallerPolicy::GetExtensionId());
evliu7b9481b32019-12-20 19:39:55178}
179} // namespace component_updater