blob: cc1dd9b87b8fdc9e4669a43cee6dff04612a9442 [file] [log] [blame]
[email protected]8e4560b62011-01-14 10:09:141// Copyright (c) 2011 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/extensions/external_extension_provider_impl.h"
6
[email protected]83b59325a2011-10-14 15:58:077#include "base/command_line.h"
[email protected]8e4560b62011-01-14 10:09:148#include "base/file_path.h"
9#include "base/logging.h"
[email protected]3b63f8f42011-03-28 01:54:1510#include "base/memory/linked_ptr.h"
[email protected]51a7a9d2011-09-27 17:21:4111#include "base/metrics/field_trial.h"
[email protected]8e4560b62011-01-14 10:09:1412#include "base/path_service.h"
[email protected]e601e822011-10-05 19:25:3713#include "base/string_util.h"
[email protected]8e4560b62011-01-14 10:09:1414#include "base/values.h"
15#include "base/version.h"
[email protected]e601e822011-10-05 19:25:3716#include "chrome/browser/browser_process.h"
[email protected]51a7a9d2011-09-27 17:21:4117#include "chrome/browser/extensions/extension_service.h"
[email protected]8e4560b62011-01-14 10:09:1418#include "chrome/browser/extensions/external_extension_provider_interface.h"
19#include "chrome/browser/extensions/external_policy_extension_loader.h"
20#include "chrome/browser/extensions/external_pref_extension_loader.h"
21#include "chrome/browser/profiles/profile.h"
[email protected]f0841cd2011-01-19 15:07:2422#include "chrome/common/chrome_paths.h"
[email protected]83b59325a2011-10-14 15:58:0723#include "chrome/common/chrome_switches.h"
24#include "chrome/common/pref_names.h"
[email protected]c38831a12011-10-28 12:44:4925#include "content/public/browser/browser_thread.h"
[email protected]9d32ded072011-10-11 16:31:0526#include "ui/base/l10n/l10n_util.h"
[email protected]8e4560b62011-01-14 10:09:1427
[email protected]86c6b9e32011-10-25 17:09:1028#if !defined(OS_CHROMEOS)
29#include "chrome/browser/extensions/default_apps.h"
30#endif
31
[email protected]8e4560b62011-01-14 10:09:1432#if defined(OS_WIN)
33#include "chrome/browser/extensions/external_registry_extension_loader_win.h"
34#endif
35
[email protected]631bb742011-11-02 11:29:3936using content::BrowserThread;
37
[email protected]8e4560b62011-01-14 10:09:1438// Constants for keeping track of extension preferences in a dictionary.
[email protected]8e4560b62011-01-14 10:09:1439const char ExternalExtensionProviderImpl::kExternalCrx[] = "external_crx";
40const char ExternalExtensionProviderImpl::kExternalVersion[] =
41 "external_version";
42const char ExternalExtensionProviderImpl::kExternalUpdateUrl[] =
43 "external_update_url";
[email protected]9d32ded072011-10-11 16:31:0544const char ExternalExtensionProviderImpl::kSupportedLocales[] =
45 "supported_locales";
[email protected]8e4560b62011-01-14 10:09:1446
[email protected]8e4560b62011-01-14 10:09:1447ExternalExtensionProviderImpl::ExternalExtensionProviderImpl(
48 VisitorInterface* service,
49 ExternalExtensionLoader* loader,
50 Extension::Location crx_location,
[email protected]1bf73cc2011-10-26 22:38:3151 Extension::Location download_location,
52 int creation_flags)
[email protected]8e4560b62011-01-14 10:09:1453 : crx_location_(crx_location),
54 download_location_(download_location),
55 service_(service),
56 prefs_(NULL),
57 ready_(false),
[email protected]1bf73cc2011-10-26 22:38:3158 loader_(loader),
[email protected]47fc70c2011-12-06 07:29:5159 creation_flags_(creation_flags),
60 auto_acknowledge_(false) {
[email protected]8e4560b62011-01-14 10:09:1461 loader_->Init(this);
62}
63
64ExternalExtensionProviderImpl::~ExternalExtensionProviderImpl() {
65 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66 loader_->OwnerShutdown();
67}
68
[email protected]d190cef2011-11-09 02:09:2469void ExternalExtensionProviderImpl::VisitRegisteredExtension() {
[email protected]8e4560b62011-01-14 10:09:1470 // The loader will call back to SetPrefs.
71 loader_->StartLoading();
72}
73
74void ExternalExtensionProviderImpl::SetPrefs(DictionaryValue* prefs) {
75 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
76
[email protected]47fc70c2011-12-06 07:29:5177 // Check if the service is still alive. It is possible that it went
[email protected]8e4560b62011-01-14 10:09:1478 // away while |loader_| was working on the FILE thread.
79 if (!service_) return;
80
81 prefs_.reset(prefs);
82 ready_ = true; // Queries for extensions are allowed from this point.
83
[email protected]9d32ded072011-10-11 16:31:0584 // Set of unsupported extensions that need to be deleted from prefs_.
85 std::set<std::string> unsupported_extensions;
86
[email protected]8e4560b62011-01-14 10:09:1487 // Notify ExtensionService about all the extensions this provider has.
88 for (DictionaryValue::key_iterator i = prefs_->begin_keys();
89 i != prefs_->end_keys(); ++i) {
90 const std::string& extension_id = *i;
91 DictionaryValue* extension;
[email protected]ab22ba42011-01-14 16:36:3892
93 if (!Extension::IdIsValid(extension_id)) {
94 LOG(WARNING) << "Malformed extension dictionary: key "
95 << extension_id.c_str() << " is not a valid id.";
[email protected]8e4560b62011-01-14 10:09:1496 continue;
[email protected]ab22ba42011-01-14 16:36:3897 }
98
99 if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension)) {
100 LOG(WARNING) << "Malformed extension dictionary: key "
101 << extension_id.c_str()
102 << " has a value that is not a dictionary.";
103 continue;
104 }
[email protected]8e4560b62011-01-14 10:09:14105
106 FilePath::StringType external_crx;
107 std::string external_version;
108 std::string external_update_url;
109
110 bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
111 bool has_external_version = extension->GetString(kExternalVersion,
112 &external_version);
113 bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
114 &external_update_url);
115 if (has_external_crx != has_external_version) {
116 LOG(WARNING) << "Malformed extension dictionary for extension: "
117 << extension_id.c_str() << ". " << kExternalCrx
118 << " and " << kExternalVersion << " must be used together.";
119 continue;
120 }
121
122 if (has_external_crx == has_external_update_url) {
123 LOG(WARNING) << "Malformed extension dictionary for extension: "
124 << extension_id.c_str() << ". Exactly one of the "
125 << "followng keys should be used: " << kExternalCrx
126 << ", " << kExternalUpdateUrl << ".";
127 continue;
128 }
129
[email protected]9d32ded072011-10-11 16:31:05130 // Check that extension supports current browser locale.
131 ListValue* supported_locales = NULL;
132 if (extension->GetList(kSupportedLocales, &supported_locales)) {
133 std::vector<std::string> browser_locales;
134 l10n_util::GetParentLocales(g_browser_process->GetApplicationLocale(),
135 &browser_locales);
136
137 size_t num_locales = supported_locales->GetSize();
138 bool locale_supported = false;
139 for (size_t j = 0; j < num_locales; j++) {
140 std::string current_locale;
141 if (supported_locales->GetString(j, &current_locale) &&
142 l10n_util::IsValidLocaleSyntax(current_locale)) {
143 current_locale = l10n_util::NormalizeLocale(current_locale);
144 if (std::find(browser_locales.begin(), browser_locales.end(),
145 current_locale) != browser_locales.end()) {
146 locale_supported = true;
147 break;
148 }
149 } else {
150 LOG(WARNING) << "Unrecognized locale '" << current_locale
151 << "' found as supported locale for extension: "
152 << extension_id;
153 }
154 }
155
156 if (!locale_supported) {
157 unsupported_extensions.insert(extension_id);
158 LOG(INFO) << "Skip installing (or uninstall) external extension: "
159 << extension_id << " because the extension doesn't support "
160 << "the browser locale.";
161 continue;
162 }
163 }
164
[email protected]8e4560b62011-01-14 10:09:14165 if (has_external_crx) {
166 if (crx_location_ == Extension::INVALID) {
167 LOG(WARNING) << "This provider does not support installing external "
168 << "extensions from crx files.";
169 continue;
170 }
171 if (external_crx.find(FilePath::kParentDirectory) !=
172 base::StringPiece::npos) {
173 LOG(WARNING) << "Path traversal not allowed in path: "
174 << external_crx.c_str();
175 continue;
176 }
177
[email protected]f0841cd2011-01-19 15:07:24178 // If the path is relative, and the provider has a base path,
179 // build the absolute path to the crx file.
[email protected]8e4560b62011-01-14 10:09:14180 FilePath path(external_crx);
181 if (!path.IsAbsolute()) {
[email protected]f0841cd2011-01-19 15:07:24182 FilePath base_path = loader_->GetBaseCrxFilePath();
183 if (base_path.empty()) {
184 LOG(WARNING) << "File path " << external_crx.c_str()
185 << " is relative. An absolute path is required.";
186 continue;
187 }
[email protected]8e4560b62011-01-14 10:09:14188 path = base_path.Append(external_crx);
189 }
190
191 scoped_ptr<Version> version;
192 version.reset(Version::GetVersionFromString(external_version));
193 if (!version.get()) {
194 LOG(WARNING) << "Malformed extension dictionary for extension: "
195 << extension_id.c_str() << ". Invalid version string \""
196 << external_version << "\".";
197 continue;
198 }
199 service_->OnExternalExtensionFileFound(extension_id, version.get(), path,
[email protected]47fc70c2011-12-06 07:29:51200 crx_location_, creation_flags_,
201 auto_acknowledge_);
[email protected]8e4560b62011-01-14 10:09:14202 } else { // if (has_external_update_url)
203 CHECK(has_external_update_url); // Checking of keys above ensures this.
204 if (download_location_ == Extension::INVALID) {
205 LOG(WARNING) << "This provider does not support installing external "
206 << "extensions from update URLs.";
207 continue;
208 }
209 GURL update_url(external_update_url);
210 if (!update_url.is_valid()) {
211 LOG(WARNING) << "Malformed extension dictionary for extension: "
[email protected]ab22ba42011-01-14 16:36:38212 << extension_id.c_str() << ". Key " << kExternalUpdateUrl
213 << " has value \"" << external_update_url
214 << "\", which is not a valid URL.";
[email protected]8e4560b62011-01-14 10:09:14215 continue;
216 }
217 service_->OnExternalExtensionUpdateUrlFound(
218 extension_id, update_url, download_location_);
219 }
220 }
221
[email protected]9d32ded072011-10-11 16:31:05222 for (std::set<std::string>::iterator it = unsupported_extensions.begin();
223 it != unsupported_extensions.end(); ++it) {
224 // Remove extension for the list of know external extensions. The extension
225 // will be uninstalled later because provider doesn't provide it anymore.
226 prefs_->Remove(*it, NULL);
227 }
228
[email protected]50067e52011-10-20 23:17:07229 service_->OnExternalProviderReady(this);
[email protected]8e4560b62011-01-14 10:09:14230}
231
232void ExternalExtensionProviderImpl::ServiceShutdown() {
233 service_ = NULL;
234}
235
[email protected]50067e52011-10-20 23:17:07236bool ExternalExtensionProviderImpl::IsReady() const {
[email protected]8e4560b62011-01-14 10:09:14237 return ready_;
238}
239
240bool ExternalExtensionProviderImpl::HasExtension(
241 const std::string& id) const {
242 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
243 CHECK(prefs_.get());
244 CHECK(ready_);
245 return prefs_->HasKey(id);
246}
247
248bool ExternalExtensionProviderImpl::GetExtensionDetails(
249 const std::string& id, Extension::Location* location,
250 scoped_ptr<Version>* version) const {
251 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
252 CHECK(prefs_.get());
253 CHECK(ready_);
254 DictionaryValue* extension = NULL;
255 if (!prefs_->GetDictionary(id, &extension))
256 return false;
257
258 Extension::Location loc = Extension::INVALID;
259 if (extension->HasKey(kExternalUpdateUrl)) {
260 loc = download_location_;
261
262 } else if (extension->HasKey(kExternalCrx)) {
263 loc = crx_location_;
264
265 std::string external_version;
266 if (!extension->GetString(kExternalVersion, &external_version))
267 return false;
268
269 if (version)
270 version->reset(Version::GetVersionFromString(external_version));
271
272 } else {
273 NOTREACHED(); // Chrome should not allow prefs to get into this state.
274 return false;
275 }
276
277 if (location)
278 *location = loc;
279
280 return true;
281}
282
283// static
284void ExternalExtensionProviderImpl::CreateExternalProviders(
285 VisitorInterface* service,
286 Profile* profile,
287 ProviderCollection* provider_list) {
[email protected]73e4c362011-09-22 14:47:18288
289 // On Mac OS, items in /Library/... should be written by the superuser.
290 // Check that all components of the path are writable by root only.
[email protected]0edc55412011-11-07 16:47:33291 ExternalPrefExtensionLoader::Options check_admin_permissions_on_mac;
[email protected]73e4c362011-09-22 14:47:18292#if defined(OS_MACOSX)
[email protected]0edc55412011-11-07 16:47:33293 check_admin_permissions_on_mac =
294 ExternalPrefExtensionLoader::ENSURE_PATH_CONTROLLED_BY_ADMIN;
[email protected]73e4c362011-09-22 14:47:18295#else
[email protected]0edc55412011-11-07 16:47:33296 check_admin_permissions_on_mac = ExternalPrefExtensionLoader::NONE;
[email protected]73e4c362011-09-22 14:47:18297#endif
298
[email protected]8e4560b62011-01-14 10:09:14299 provider_list->push_back(
300 linked_ptr<ExternalExtensionProviderInterface>(
301 new ExternalExtensionProviderImpl(
302 service,
[email protected]a29a517a2011-01-21 21:11:12303 new ExternalPrefExtensionLoader(
[email protected]0edc55412011-11-07 16:47:33304 chrome::DIR_EXTERNAL_EXTENSIONS,
305 check_admin_permissions_on_mac),
[email protected]8e4560b62011-01-14 10:09:14306 Extension::EXTERNAL_PREF,
[email protected]1bf73cc2011-10-26 22:38:31307 Extension::EXTERNAL_PREF_DOWNLOAD,
308 Extension::NO_FLAGS)));
[email protected]a29a517a2011-01-21 21:11:12309
[email protected]73e4c362011-09-22 14:47:18310#if defined(OS_MACOSX)
311 // Support old path to external extensions file as we migrate to the
312 // new one. See crbug/67203.
313 provider_list->push_back(
314 linked_ptr<ExternalExtensionProviderInterface>(
315 new ExternalExtensionProviderImpl(
316 service,
317 new ExternalPrefExtensionLoader(
[email protected]23b00972011-10-04 17:17:26318 chrome::DIR_DEPRECATED_EXTERNAL_EXTENSIONS,
[email protected]73e4c362011-09-22 14:47:18319 ExternalPrefExtensionLoader::NONE),
320 Extension::EXTERNAL_PREF,
[email protected]1bf73cc2011-10-26 22:38:31321 Extension::EXTERNAL_PREF_DOWNLOAD,
322 Extension::NO_FLAGS)));
[email protected]73e4c362011-09-22 14:47:18323#endif
324
[email protected]0edc55412011-11-07 16:47:33325#if defined(OS_CHROMEOS) || defined (OS_MACOSX)
326 // Define a per-user source of external extensions.
327 // On Chrome OS, this serves as a source for OEM customization.
[email protected]a29a517a2011-01-21 21:11:12328 provider_list->push_back(
329 linked_ptr<ExternalExtensionProviderInterface>(
330 new ExternalExtensionProviderImpl(
331 service,
332 new ExternalPrefExtensionLoader(
[email protected]998e8b92011-09-22 15:07:24333 chrome::DIR_USER_EXTERNAL_EXTENSIONS,
334 ExternalPrefExtensionLoader::NONE),
[email protected]a29a517a2011-01-21 21:11:12335 Extension::EXTERNAL_PREF,
[email protected]1bf73cc2011-10-26 22:38:31336 Extension::EXTERNAL_PREF_DOWNLOAD,
337 Extension::NO_FLAGS)));
[email protected]a29a517a2011-01-21 21:11:12338#endif
[email protected]8e4560b62011-01-14 10:09:14339#if defined(OS_WIN)
340 provider_list->push_back(
341 linked_ptr<ExternalExtensionProviderInterface>(
342 new ExternalExtensionProviderImpl(
343 service,
344 new ExternalRegistryExtensionLoader,
345 Extension::EXTERNAL_REGISTRY,
[email protected]1bf73cc2011-10-26 22:38:31346 Extension::INVALID,
347 Extension::NO_FLAGS)));
[email protected]8e4560b62011-01-14 10:09:14348#endif
349 provider_list->push_back(
350 linked_ptr<ExternalExtensionProviderInterface>(
351 new ExternalExtensionProviderImpl(
352 service,
353 new ExternalPolicyExtensionLoader(profile),
354 Extension::INVALID,
[email protected]1bf73cc2011-10-26 22:38:31355 Extension::EXTERNAL_POLICY_DOWNLOAD,
356 Extension::NO_FLAGS)));
[email protected]51a7a9d2011-09-27 17:21:41357
[email protected]98b4aca62011-09-28 01:27:23358#if !defined(OS_CHROMEOS)
[email protected]d190cef2011-11-09 02:09:24359 provider_list->push_back(
360 linked_ptr<ExternalExtensionProviderInterface>(
361 new default_apps::Provider(
362 profile,
363 service,
364 new ExternalPrefExtensionLoader(
365 chrome::DIR_DEFAULT_APPS,
366 ExternalPrefExtensionLoader::NONE),
367 Extension::EXTERNAL_PREF,
368 Extension::INVALID,
369 Extension::FROM_BOOKMARK)));
[email protected]98b4aca62011-09-28 01:27:23370#endif
[email protected]8e4560b62011-01-14 10:09:14371}