Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(247)

Side by Side Diff: chrome/browser/extensions/external_extension_provider_impl.cc

Issue 10692168: Moved ExternalExtensionLoaders/Providers into extensions namespace (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Even later master Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2012 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
7 #include "base/command_line.h"
8 #include "base/file_path.h"
9 #include "base/logging.h"
10 #include "base/memory/linked_ptr.h"
11 #include "base/metrics/field_trial.h"
12 #include "base/path_service.h"
13 #include "base/string_util.h"
14 #include "base/values.h"
15 #include "base/version.h"
16 #include "chrome/browser/browser_process.h"
17 #include "chrome/browser/extensions/extension_service.h"
18 #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"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/pref_names.h"
25 #include "content/public/browser/browser_thread.h"
26 #include "ui/base/l10n/l10n_util.h"
27
28 #if defined(OS_CHROMEOS)
29 #include "chrome/browser/chromeos/login/user_manager.h"
30 #include "chrome/browser/policy/app_pack_updater.h"
31 #include "chrome/browser/policy/browser_policy_connector.h"
32 #endif
33
34 #if !defined(OS_CHROMEOS)
35 #include "chrome/browser/extensions/default_apps.h"
36 #endif
37
38 #if defined(OS_WIN)
39 #include "chrome/browser/extensions/external_registry_extension_loader_win.h"
40 #endif
41
42 using content::BrowserThread;
43 using extensions::Extension;
44
45 // Constants for keeping track of extension preferences in a dictionary.
46 const char ExternalExtensionProviderImpl::kExternalCrx[] = "external_crx";
47 const char ExternalExtensionProviderImpl::kExternalVersion[] =
48 "external_version";
49 const char ExternalExtensionProviderImpl::kExternalUpdateUrl[] =
50 "external_update_url";
51 const char ExternalExtensionProviderImpl::kSupportedLocales[] =
52 "supported_locales";
53 const char ExternalExtensionProviderImpl::kIsBookmarkApp[] =
54 "is_bookmark_app";
55
56 ExternalExtensionProviderImpl::ExternalExtensionProviderImpl(
57 VisitorInterface* service,
58 ExternalExtensionLoader* loader,
59 Extension::Location crx_location,
60 Extension::Location download_location,
61 int creation_flags)
62 : crx_location_(crx_location),
63 download_location_(download_location),
64 service_(service),
65 prefs_(NULL),
66 ready_(false),
67 loader_(loader),
68 creation_flags_(creation_flags),
69 auto_acknowledge_(false) {
70 loader_->Init(this);
71 }
72
73 ExternalExtensionProviderImpl::~ExternalExtensionProviderImpl() {
74 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
75 loader_->OwnerShutdown();
76 }
77
78 void ExternalExtensionProviderImpl::VisitRegisteredExtension() {
79 // The loader will call back to SetPrefs.
80 loader_->StartLoading();
81 }
82
83 void ExternalExtensionProviderImpl::SetPrefs(DictionaryValue* prefs) {
84 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
85
86 // Check if the service is still alive. It is possible that it went
87 // away while |loader_| was working on the FILE thread.
88 if (!service_) return;
89
90 prefs_.reset(prefs);
91 ready_ = true; // Queries for extensions are allowed from this point.
92
93 // Set of unsupported extensions that need to be deleted from prefs_.
94 std::set<std::string> unsupported_extensions;
95
96 // Notify ExtensionService about all the extensions this provider has.
97 for (DictionaryValue::key_iterator i = prefs_->begin_keys();
98 i != prefs_->end_keys(); ++i) {
99 const std::string& extension_id = *i;
100 DictionaryValue* extension;
101
102 if (!Extension::IdIsValid(extension_id)) {
103 LOG(WARNING) << "Malformed extension dictionary: key "
104 << extension_id.c_str() << " is not a valid id.";
105 continue;
106 }
107
108 if (!prefs_->GetDictionaryWithoutPathExpansion(extension_id, &extension)) {
109 LOG(WARNING) << "Malformed extension dictionary: key "
110 << extension_id.c_str()
111 << " has a value that is not a dictionary.";
112 continue;
113 }
114
115 FilePath::StringType external_crx;
116 Value* external_version_value;
117 std::string external_version;
118 std::string external_update_url;
119
120 bool has_external_crx = extension->GetString(kExternalCrx, &external_crx);
121
122 bool has_external_version = false;
123 if (extension->Get(kExternalVersion, &external_version_value)) {
124 if (external_version_value->IsType(Value::TYPE_STRING)) {
125 external_version_value->GetAsString(&external_version);
126 has_external_version = true;
127 } else {
128 LOG(WARNING) << "Malformed extension dictionary for extension: "
129 << extension_id.c_str() << ". " << kExternalVersion
130 << " value must be a string.";
131 continue;
132 }
133 }
134
135 bool has_external_update_url = extension->GetString(kExternalUpdateUrl,
136 &external_update_url);
137 if (has_external_crx != has_external_version) {
138 LOG(WARNING) << "Malformed extension dictionary for extension: "
139 << extension_id.c_str() << ". " << kExternalCrx
140 << " and " << kExternalVersion << " must be used together.";
141 continue;
142 }
143
144 if (has_external_crx == has_external_update_url) {
145 LOG(WARNING) << "Malformed extension dictionary for extension: "
146 << extension_id.c_str() << ". Exactly one of the "
147 << "followng keys should be used: " << kExternalCrx
148 << ", " << kExternalUpdateUrl << ".";
149 continue;
150 }
151
152 // Check that extension supports current browser locale.
153 ListValue* supported_locales = NULL;
154 if (extension->GetList(kSupportedLocales, &supported_locales)) {
155 std::vector<std::string> browser_locales;
156 l10n_util::GetParentLocales(g_browser_process->GetApplicationLocale(),
157 &browser_locales);
158
159 size_t num_locales = supported_locales->GetSize();
160 bool locale_supported = false;
161 for (size_t j = 0; j < num_locales; j++) {
162 std::string current_locale;
163 if (supported_locales->GetString(j, &current_locale) &&
164 l10n_util::IsValidLocaleSyntax(current_locale)) {
165 current_locale = l10n_util::NormalizeLocale(current_locale);
166 if (std::find(browser_locales.begin(), browser_locales.end(),
167 current_locale) != browser_locales.end()) {
168 locale_supported = true;
169 break;
170 }
171 } else {
172 LOG(WARNING) << "Unrecognized locale '" << current_locale
173 << "' found as supported locale for extension: "
174 << extension_id;
175 }
176 }
177
178 if (!locale_supported) {
179 unsupported_extensions.insert(extension_id);
180 LOG(INFO) << "Skip installing (or uninstall) external extension: "
181 << extension_id << " because the extension doesn't support "
182 << "the browser locale.";
183 continue;
184 }
185 }
186
187 int creation_flags = creation_flags_;
188 bool is_bookmark_app;
189 if (extension->GetBoolean(kIsBookmarkApp, &is_bookmark_app) &&
190 is_bookmark_app) {
191 creation_flags |= Extension::FROM_BOOKMARK;
192 }
193
194 if (has_external_crx) {
195 if (crx_location_ == Extension::INVALID) {
196 LOG(WARNING) << "This provider does not support installing external "
197 << "extensions from crx files.";
198 continue;
199 }
200 if (external_crx.find(FilePath::kParentDirectory) !=
201 base::StringPiece::npos) {
202 LOG(WARNING) << "Path traversal not allowed in path: "
203 << external_crx.c_str();
204 continue;
205 }
206
207 // If the path is relative, and the provider has a base path,
208 // build the absolute path to the crx file.
209 FilePath path(external_crx);
210 if (!path.IsAbsolute()) {
211 FilePath base_path = loader_->GetBaseCrxFilePath();
212 if (base_path.empty()) {
213 LOG(WARNING) << "File path " << external_crx.c_str()
214 << " is relative. An absolute path is required.";
215 continue;
216 }
217 path = base_path.Append(external_crx);
218 }
219
220 Version version(external_version);
221 if (!version.IsValid()) {
222 LOG(WARNING) << "Malformed extension dictionary for extension: "
223 << extension_id.c_str() << ". Invalid version string \""
224 << external_version << "\".";
225 continue;
226 }
227 service_->OnExternalExtensionFileFound(extension_id, &version, path,
228 crx_location_, creation_flags,
229 auto_acknowledge_);
230 } else { // if (has_external_update_url)
231 CHECK(has_external_update_url); // Checking of keys above ensures this.
232 if (download_location_ == Extension::INVALID) {
233 LOG(WARNING) << "This provider does not support installing external "
234 << "extensions from update URLs.";
235 continue;
236 }
237 GURL update_url(external_update_url);
238 if (!update_url.is_valid()) {
239 LOG(WARNING) << "Malformed extension dictionary for extension: "
240 << extension_id.c_str() << ". Key " << kExternalUpdateUrl
241 << " has value \"" << external_update_url
242 << "\", which is not a valid URL.";
243 continue;
244 }
245 service_->OnExternalExtensionUpdateUrlFound(
246 extension_id, update_url, download_location_);
247 }
248 }
249
250 for (std::set<std::string>::iterator it = unsupported_extensions.begin();
251 it != unsupported_extensions.end(); ++it) {
252 // Remove extension for the list of know external extensions. The extension
253 // will be uninstalled later because provider doesn't provide it anymore.
254 prefs_->Remove(*it, NULL);
255 }
256
257 service_->OnExternalProviderReady(this);
258 }
259
260 void ExternalExtensionProviderImpl::ServiceShutdown() {
261 service_ = NULL;
262 }
263
264 bool ExternalExtensionProviderImpl::IsReady() const {
265 return ready_;
266 }
267
268 bool ExternalExtensionProviderImpl::HasExtension(
269 const std::string& id) const {
270 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
271 CHECK(prefs_.get());
272 CHECK(ready_);
273 return prefs_->HasKey(id);
274 }
275
276 bool ExternalExtensionProviderImpl::GetExtensionDetails(
277 const std::string& id, Extension::Location* location,
278 scoped_ptr<Version>* version) const {
279 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
280 CHECK(prefs_.get());
281 CHECK(ready_);
282 DictionaryValue* extension = NULL;
283 if (!prefs_->GetDictionary(id, &extension))
284 return false;
285
286 Extension::Location loc = Extension::INVALID;
287 if (extension->HasKey(kExternalUpdateUrl)) {
288 loc = download_location_;
289
290 } else if (extension->HasKey(kExternalCrx)) {
291 loc = crx_location_;
292
293 std::string external_version;
294 if (!extension->GetString(kExternalVersion, &external_version))
295 return false;
296
297 if (version)
298 version->reset(new Version(external_version));
299
300 } else {
301 NOTREACHED(); // Chrome should not allow prefs to get into this state.
302 return false;
303 }
304
305 if (location)
306 *location = loc;
307
308 return true;
309 }
310
311 // static
312 void ExternalExtensionProviderImpl::CreateExternalProviders(
313 VisitorInterface* service,
314 Profile* profile,
315 ProviderCollection* provider_list) {
316
317 // On Mac OS, items in /Library/... should be written by the superuser.
318 // Check that all components of the path are writable by root only.
319 ExternalPrefExtensionLoader::Options check_admin_permissions_on_mac;
320 #if defined(OS_MACOSX)
321 check_admin_permissions_on_mac =
322 ExternalPrefExtensionLoader::ENSURE_PATH_CONTROLLED_BY_ADMIN;
323 #else
324 check_admin_permissions_on_mac = ExternalPrefExtensionLoader::NONE;
325 #endif
326
327 bool is_chromeos_demo_session = false;
328 int bundled_extension_creation_flags = Extension::NO_FLAGS;
329 #if defined(OS_CHROMEOS)
330 chromeos::UserManager* user_manager = chromeos::UserManager::Get();
331 is_chromeos_demo_session =
332 user_manager && user_manager->IsLoggedInAsDemoUser() &&
333 g_browser_process->browser_policy_connector()->GetDeviceMode() ==
334 policy::DEVICE_MODE_KIOSK;
335 bundled_extension_creation_flags = Extension::FROM_WEBSTORE;
336 #endif
337
338 if (!is_chromeos_demo_session) {
339 provider_list->push_back(
340 linked_ptr<ExternalExtensionProviderInterface>(
341 new ExternalExtensionProviderImpl(
342 service,
343 new ExternalPrefExtensionLoader(
344 chrome::DIR_EXTERNAL_EXTENSIONS,
345 check_admin_permissions_on_mac),
346 Extension::EXTERNAL_PREF,
347 Extension::EXTERNAL_PREF_DOWNLOAD,
348 bundled_extension_creation_flags)));
349 }
350
351 #if defined(OS_CHROMEOS) || defined (OS_MACOSX)
352 // Define a per-user source of external extensions.
353 // On Chrome OS, this serves as a source for OEM customization.
354 provider_list->push_back(
355 linked_ptr<ExternalExtensionProviderInterface>(
356 new ExternalExtensionProviderImpl(
357 service,
358 new ExternalPrefExtensionLoader(
359 chrome::DIR_USER_EXTERNAL_EXTENSIONS,
360 ExternalPrefExtensionLoader::NONE),
361 Extension::EXTERNAL_PREF,
362 Extension::EXTERNAL_PREF_DOWNLOAD,
363 Extension::NO_FLAGS)));
364 #endif
365 #if defined(OS_WIN)
366 provider_list->push_back(
367 linked_ptr<ExternalExtensionProviderInterface>(
368 new ExternalExtensionProviderImpl(
369 service,
370 new ExternalRegistryExtensionLoader,
371 Extension::EXTERNAL_REGISTRY,
372 Extension::INVALID,
373 Extension::NO_FLAGS)));
374 #endif
375
376 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
377 provider_list->push_back(
378 linked_ptr<ExternalExtensionProviderInterface>(
379 new ExternalExtensionProviderImpl(
380 service,
381 new ExternalPrefExtensionLoader(
382 chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
383 ExternalPrefExtensionLoader::NONE),
384 Extension::EXTERNAL_PREF,
385 Extension::EXTERNAL_PREF_DOWNLOAD,
386 Extension::NO_FLAGS)));
387 #endif
388
389 provider_list->push_back(
390 linked_ptr<ExternalExtensionProviderInterface>(
391 new ExternalExtensionProviderImpl(
392 service,
393 new ExternalPolicyExtensionLoader(profile),
394 Extension::INVALID,
395 Extension::EXTERNAL_POLICY_DOWNLOAD,
396 Extension::NO_FLAGS)));
397
398 #if !defined(OS_CHROMEOS)
399 provider_list->push_back(
400 linked_ptr<ExternalExtensionProviderInterface>(
401 new default_apps::Provider(
402 profile,
403 service,
404 new ExternalPrefExtensionLoader(
405 chrome::DIR_DEFAULT_APPS,
406 ExternalPrefExtensionLoader::NONE),
407 Extension::EXTERNAL_PREF,
408 Extension::INVALID,
409 Extension::FROM_WEBSTORE)));
410 #endif
411
412 #if defined(OS_CHROMEOS)
413 policy::BrowserPolicyConnector* connector =
414 g_browser_process->browser_policy_connector();
415 if (is_chromeos_demo_session && connector->GetAppPackUpdater()) {
416 provider_list->push_back(
417 linked_ptr<ExternalExtensionProviderInterface>(
418 new ExternalExtensionProviderImpl(
419 service,
420 connector->GetAppPackUpdater()->CreateExternalExtensionLoader(),
421 Extension::EXTERNAL_PREF,
422 Extension::INVALID,
423 Extension::NO_FLAGS)));
424 }
425 #endif
426 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698