blob: aae153b0781edd0a6704e192b8d3e74f00a847cf [file] [log] [blame]
[email protected]ce5c4502009-05-06 16:46:111// Copyright (c) 2009 The Chromium Authors. All rights reserved.
[email protected]6014d672008-12-05 00:38:252// 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/extensions_service.h"
6
[email protected]e2eb43112009-05-29 21:19:547#include "app/l10n_util.h"
8#include "base/command_line.h"
[email protected]fbcc40302009-06-12 20:45:459#include "base/crypto/signature_verifier.h"
[email protected]6014d672008-12-05 00:38:2510#include "base/file_util.h"
[email protected]902f7cd2009-05-22 19:02:1911#include "base/gfx/png_encoder.h"
[email protected]cc655912009-01-29 23:19:1912#include "base/scoped_handle.h"
13#include "base/scoped_temp_dir.h"
[email protected]5c238752009-06-13 10:29:0714#include "base/stl_util-inl.h"
[email protected]6014d672008-12-05 00:38:2515#include "base/string_util.h"
[email protected]cc655912009-01-29 23:19:1916#include "base/third_party/nss/blapi.h"
17#include "base/third_party/nss/sha256.h"
[email protected]6014d672008-12-05 00:38:2518#include "base/thread.h"
[email protected]cc655912009-01-29 23:19:1919#include "base/values.h"
20#include "net/base/file_stream.h"
[email protected]a57209872009-05-04 22:53:1421#include "chrome/browser/browser.h"
22#include "chrome/browser/browser_list.h"
[email protected]6014d672008-12-05 00:38:2523#include "chrome/browser/browser_process.h"
[email protected]1fca1492009-05-15 22:23:4324#include "chrome/browser/chrome_thread.h"
[email protected]fbcc40302009-06-12 20:45:4525#include "chrome/browser/extensions/extension_creator.h"
[email protected]b68d5ed2009-04-16 02:41:2826#include "chrome/browser/extensions/extension_browser_event_router.h"
[email protected]481e1a42009-05-06 20:56:0527#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]a1257b12009-06-12 02:51:3428#include "chrome/browser/extensions/external_extension_provider.h"
29#include "chrome/browser/extensions/external_pref_extension_provider.h"
[email protected]81e63782009-02-27 19:35:0930#include "chrome/browser/profile.h"
[email protected]1fca1492009-05-15 22:23:4331#include "chrome/browser/utility_process_host.h"
[email protected]e2eb43112009-05-29 21:19:5432#include "chrome/common/chrome_switches.h"
[email protected]5b1a0e22009-05-26 19:00:5833#include "chrome/common/extensions/extension.h"
34#include "chrome/common/extensions/extension_error_reporter.h"
[email protected]1fca1492009-05-15 22:23:4335#include "chrome/common/extensions/extension_unpacker.h"
[email protected]6014d672008-12-05 00:38:2536#include "chrome/common/json_value_serializer.h"
[email protected]82891262008-12-24 00:21:2637#include "chrome/common/notification_service.h"
[email protected]25b34332009-06-05 21:53:1938#include "chrome/common/pref_names.h"
[email protected]894bb502009-05-21 22:39:5739#include "chrome/common/pref_service.h"
[email protected]4777bc562009-06-01 02:53:0040#include "chrome/common/zip.h"
[email protected]a57209872009-05-04 22:53:1441#include "chrome/common/url_constants.h"
[email protected]e2eb43112009-05-29 21:19:5442#include "grit/chromium_strings.h"
43#include "grit/generated_resources.h"
[email protected]fbcc40302009-06-12 20:45:4544#include "net/base/base64.h"
[email protected]902f7cd2009-05-22 19:02:1945#include "third_party/skia/include/core/SkBitmap.h"
[email protected]c64631652009-04-29 22:24:3146
[email protected]79db6232009-02-13 20:51:2047#if defined(OS_WIN)
[email protected]e2eb43112009-05-29 21:19:5448#include "app/win_util.h"
[email protected]e2eb43112009-05-29 21:19:5449#include "base/win_util.h"
[email protected]a1257b12009-06-12 02:51:3450#include "chrome/browser/extensions/external_registry_extension_provider_win.h"
[email protected]79db6232009-02-13 20:51:2051#endif
[email protected]6014d672008-12-05 00:38:2552
[email protected]25b34332009-06-05 21:53:1953// ExtensionsService.
[email protected]6014d672008-12-05 00:38:2554
[email protected]fbcc40302009-06-12 20:45:4555const char ExtensionsService::kExtensionHeaderMagic[] = "Cr24";
56
[email protected]cc655912009-01-29 23:19:1957const char* ExtensionsService::kInstallDirectoryName = "Extensions";
58const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
59const char* ExtensionsServiceBackend::kTempExtensionName = "TEMP_INSTALL";
[email protected]b0beaa662009-02-26 00:04:1560
61namespace {
[email protected]6014d672008-12-05 00:38:2562
[email protected]25b34332009-06-05 21:53:1963// A preference that keeps track of extension settings. This is a dictionary
64// object read from the Preferences file, keyed off of extension id's.
65const wchar_t kExternalExtensionsPref[] = L"extensions.settings";
66
67// A preference keeping track of how the extension was installed.
68const wchar_t kLocation[] = L"location";
69const wchar_t kState[] = L"state";
[email protected]b0beaa662009-02-26 00:04:1570
[email protected]1fca1492009-05-15 22:23:4371// A temporary subdirectory where we unpack extensions.
72const char* kUnpackExtensionDir = "TEMP_UNPACK";
73
[email protected]fbcc40302009-06-12 20:45:4574// Unpacking errors
75const char* kBadMagicNumberError = "Bad magic number";
76const char* kBadHeaderSizeError = "Excessively large key or signature";
77const char* kBadVersionNumberError = "Bad version number";
78const char* kInvalidExtensionHeaderError = "Invalid extension header";
79const char* kInvalidPublicKeyError = "Invalid public key";
80const char* kInvalidSignatureError = "Invalid signature";
81const char* kSignatureVerificationFailed = "Signature verification failed";
82const char* kSignatureVerificationInitFailed =
83 "Signature verification initialization failed. This is most likely "
84 "caused by a public key in the wrong format (should encode algorithm).";
[email protected]b0beaa662009-02-26 00:04:1585}
86
[email protected]1fca1492009-05-15 22:23:4387// This class coordinates an extension unpack task which is run in a separate
88// process. Results are sent back to this class, which we route to the
89// ExtensionServiceBackend.
90class ExtensionsServiceBackend::UnpackerClient
91 : public UtilityProcessHost::Client {
92 public:
93 UnpackerClient(ExtensionsServiceBackend* backend,
94 const FilePath& extension_path,
[email protected]fbcc40302009-06-12 20:45:4595 const std::string& public_key,
[email protected]1fca1492009-05-15 22:23:4396 const std::string& expected_id,
97 bool from_external)
98 : backend_(backend), extension_path_(extension_path),
[email protected]fbcc40302009-06-12 20:45:4599 public_key_(public_key), expected_id_(expected_id),
100 from_external_(from_external), got_response_(false) {
[email protected]1fca1492009-05-15 22:23:43101 }
102
103 // Starts the unpack task. We call back to the backend when the task is done,
104 // or a problem occurs.
105 void Start() {
106 AddRef(); // balanced in OnUnpackExtensionReply()
107
108 // TODO(mpcomplete): handle multiple installs
109 FilePath temp_dir = backend_->install_directory_.AppendASCII(
110 kUnpackExtensionDir);
111 if (!file_util::CreateDirectory(temp_dir)) {
112 backend_->ReportExtensionInstallError(extension_path_,
113 "Failed to create temporary directory.");
114 return;
115 }
116
117 temp_extension_path_ = temp_dir.Append(extension_path_.BaseName());
118 if (!file_util::CopyFile(extension_path_, temp_extension_path_)) {
119 backend_->ReportExtensionInstallError(extension_path_,
120 "Failed to copy extension file to temporary directory.");
121 return;
122 }
123
124 if (backend_->resource_dispatcher_host_) {
125 ChromeThread::GetMessageLoop(ChromeThread::IO)->PostTask(FROM_HERE,
126 NewRunnableMethod(this, &UnpackerClient::StartProcessOnIOThread,
127 backend_->resource_dispatcher_host_,
128 MessageLoop::current()));
129 } else {
130 // Cheesy... but if we don't have a ResourceDispatcherHost, assume we're
131 // in a unit test and run the unpacker directly in-process.
132 ExtensionUnpacker unpacker(temp_extension_path_);
[email protected]902f7cd2009-05-22 19:02:19133 if (unpacker.Run()) {
[email protected]facd7a7652009-06-05 23:15:02134 OnUnpackExtensionSucceededImpl(*unpacker.parsed_manifest(),
135 unpacker.decoded_images());
[email protected]902f7cd2009-05-22 19:02:19136 } else {
137 OnUnpackExtensionFailed(unpacker.error_message());
138 }
[email protected]1fca1492009-05-15 22:23:43139 }
140 }
141
142 private:
143 // UtilityProcessHost::Client
144 virtual void OnProcessCrashed() {
[email protected]2b4053c2009-05-29 20:28:09145 // Don't report crashes if they happen after we got a response.
146 if (got_response_)
147 return;
148
149 OnUnpackExtensionFailed("Chrome crashed while trying to install.");
[email protected]1fca1492009-05-15 22:23:43150 }
151
[email protected]facd7a7652009-06-05 23:15:02152 virtual void OnUnpackExtensionSucceeded(const DictionaryValue& manifest) {
153 ExtensionUnpacker::DecodedImages images;
154 if (!ExtensionUnpacker::ReadImagesFromFile(temp_extension_path_,
155 &images)) {
156 OnUnpackExtensionFailed("Couldn't read image data from disk.");
157 } else {
158 OnUnpackExtensionSucceededImpl(manifest, images);
159 }
160 }
161
162 void OnUnpackExtensionSucceededImpl(
[email protected]902f7cd2009-05-22 19:02:19163 const DictionaryValue& manifest,
[email protected]facd7a7652009-06-05 23:15:02164 const ExtensionUnpacker::DecodedImages& images) {
[email protected]fbcc40302009-06-12 20:45:45165 // Add our public key into the parsed manifest. We want it to be saved so
166 // that we can later refer to it (eg for generating ids, validating
167 // signatures, etc).
168 // The const_cast is hacky, but seems like the right thing here, rather than
169 // making a full copy just to make this change.
170 const_cast<DictionaryValue*>(&manifest)->SetString(
171 Extension::kPublicKeyKey, public_key_);
172
[email protected]902f7cd2009-05-22 19:02:19173 // The extension was unpacked to the temp dir inside our unpacking dir.
174 FilePath extension_dir = temp_extension_path_.DirName().AppendASCII(
175 ExtensionsServiceBackend::kTempExtensionName);
176 backend_->OnExtensionUnpacked(extension_path_, extension_dir,
177 expected_id_, from_external_,
178 manifest, images);
[email protected]1fca1492009-05-15 22:23:43179 Cleanup();
[email protected]902f7cd2009-05-22 19:02:19180 }
181
182 virtual void OnUnpackExtensionFailed(const std::string& error_message) {
183 backend_->ReportExtensionInstallError(extension_path_, error_message);
184 Cleanup();
[email protected]1fca1492009-05-15 22:23:43185 }
186
187 // Cleans up our temp directory.
188 void Cleanup() {
[email protected]2b4053c2009-05-29 20:28:09189 if (got_response_)
190 return;
191
192 got_response_ = true;
[email protected]1fca1492009-05-15 22:23:43193 file_util::Delete(temp_extension_path_.DirName(), true);
[email protected]902f7cd2009-05-22 19:02:19194 Release(); // balanced in Run()
[email protected]1fca1492009-05-15 22:23:43195 }
196
197 // Starts the utility process that unpacks our extension.
198 void StartProcessOnIOThread(ResourceDispatcherHost* rdh,
199 MessageLoop* file_loop) {
200 UtilityProcessHost* host = new UtilityProcessHost(rdh, this, file_loop);
201 host->StartExtensionUnpacker(temp_extension_path_);
202 }
203
204 scoped_refptr<ExtensionsServiceBackend> backend_;
205
206 // The path to the crx file that we're installing.
207 FilePath extension_path_;
208
[email protected]fbcc40302009-06-12 20:45:45209 // The public key of the extension we're installing.
210 std::string public_key_;
211
[email protected]1fca1492009-05-15 22:23:43212 // The path to the copy of the crx file in the temporary directory where we're
213 // unpacking it.
214 FilePath temp_extension_path_;
215
216 // The ID we expect this extension to have, if any.
217 std::string expected_id_;
218
219 // True if this is being installed from an external source.
220 bool from_external_;
[email protected]2b4053c2009-05-29 20:28:09221
222 // True if we got a response from the utility process and have cleaned up
223 // already.
224 bool got_response_;
[email protected]1fca1492009-05-15 22:23:43225};
226
[email protected]81e63782009-02-27 19:35:09227ExtensionsService::ExtensionsService(Profile* profile,
[email protected]894bb502009-05-21 22:39:57228 MessageLoop* frontend_loop,
[email protected]a1257b12009-06-12 02:51:34229 MessageLoop* backend_loop)
[email protected]894bb502009-05-21 22:39:57230 : prefs_(profile->GetPrefs()),
231 backend_loop_(backend_loop),
[email protected]81e63782009-02-27 19:35:09232 install_directory_(profile->GetPath().AppendASCII(kInstallDirectoryName)),
[email protected]e2eb43112009-05-29 21:19:54233 extensions_enabled_(
234 CommandLine::ForCurrentProcess()->
235 HasSwitch(switches::kEnableExtensions)),
[email protected]a1257b12009-06-12 02:51:34236 show_extensions_prompts_(true) {
237 // We pass ownership of this object to the Backend.
238 DictionaryValue* external_extensions = new DictionaryValue;
[email protected]25b34332009-06-05 21:53:19239 prefs_->RegisterDictionaryPref(kExternalExtensionsPref);
[email protected]a1257b12009-06-12 02:51:34240 GetExternalExtensions(external_extensions, NULL);
241 backend_ = new ExtensionsServiceBackend(
242 install_directory_, g_browser_process->resource_dispatcher_host(),
243 frontend_loop, external_extensions);
[email protected]6014d672008-12-05 00:38:25244}
245
246ExtensionsService::~ExtensionsService() {
247 for (ExtensionList::iterator iter = extensions_.begin();
248 iter != extensions_.end(); ++iter) {
249 delete *iter;
250 }
251}
252
253bool ExtensionsService::Init() {
[email protected]b68d5ed2009-04-16 02:41:28254 // Start up the extension event routers.
255 ExtensionBrowserEventRouter::GetInstance()->Init();
256
[email protected]25b34332009-06-05 21:53:19257 scoped_ptr<DictionaryValue> external_extensions(new DictionaryValue);
258 GetExternalExtensions(external_extensions.get(), NULL);
[email protected]894bb502009-05-21 22:39:57259
[email protected]25b34332009-06-05 21:53:19260 scoped_ptr< std::set<std::string> >
261 killed_extensions(new std::set<std::string>);
262 GetExternalExtensions(NULL, killed_extensions.get());
[email protected]894bb502009-05-21 22:39:57263
[email protected]894bb502009-05-21 22:39:57264 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
265 &ExtensionsServiceBackend::CheckForExternalUpdates,
[email protected]25b34332009-06-05 21:53:19266 *killed_extensions.get(),
[email protected]25b34332009-06-05 21:53:19267 scoped_refptr<ExtensionsService>(this)));
[email protected]b0beaa662009-02-26 00:04:15268
[email protected]894bb502009-05-21 22:39:57269 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
270 &ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory,
[email protected]25b34332009-06-05 21:53:19271 scoped_refptr<ExtensionsService>(this),
272 external_extensions.release()));
[email protected]6014d672008-12-05 00:38:25273
274 return true;
275}
276
[email protected]3cf4f0992009-02-03 23:00:30277void ExtensionsService::InstallExtension(const FilePath& extension_path) {
[email protected]894bb502009-05-21 22:39:57278 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
279 &ExtensionsServiceBackend::InstallExtension,
280 extension_path,
281 scoped_refptr<ExtensionsService>(this)));
[email protected]3cf4f0992009-02-03 23:00:30282}
283
[email protected]631cf822009-05-15 07:01:25284void ExtensionsService::UninstallExtension(const std::string& extension_id) {
285 Extension* extension = NULL;
286
287 ExtensionList::iterator iter;
288 for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
289 if ((*iter)->id() == extension_id) {
290 extension = *iter;
291 break;
292 }
293 }
294
[email protected]894bb502009-05-21 22:39:57295 // Callers should not send us nonexistant extensions.
296 CHECK(extension);
297
[email protected]631cf822009-05-15 07:01:25298 // Remove the extension from our list.
299 extensions_.erase(iter);
300
[email protected]631cf822009-05-15 07:01:25301 // Tell other services the extension is gone.
302 NotificationService::current()->Notify(NotificationType::EXTENSION_UNLOADED,
303 NotificationService::AllSources(),
304 Details<Extension>(extension));
305
[email protected]894bb502009-05-21 22:39:57306 // For external extensions, we save a preference reminding ourself not to try
307 // and install the extension anymore.
[email protected]25b34332009-06-05 21:53:19308 if (Extension::IsExternalLocation(extension->location())) {
309 UpdateExtensionPref(ASCIIToWide(extension->id()), kState,
310 Value::CreateIntegerValue(Extension::KILLBIT), true);
311 } else {
312 UpdateExtensionPref(ASCIIToWide(extension->id()), kState,
313 Value::CreateIntegerValue(Extension::DISABLED), true);
[email protected]894bb502009-05-21 22:39:57314 }
315
316 // Tell the backend to start deleting installed extensions on the file thread.
317 if (extension->location() == Extension::INTERNAL ||
[email protected]25b34332009-06-05 21:53:19318 Extension::IsExternalLocation(extension->location())) {
[email protected]894bb502009-05-21 22:39:57319 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
320 &ExtensionsServiceBackend::UninstallExtension, extension_id));
321 }
[email protected]631cf822009-05-15 07:01:25322
323 delete extension;
324}
325
[email protected]3cf4f0992009-02-03 23:00:30326void ExtensionsService::LoadExtension(const FilePath& extension_path) {
[email protected]894bb502009-05-21 22:39:57327 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
328 &ExtensionsServiceBackend::LoadSingleExtension,
329 extension_path, scoped_refptr<ExtensionsService>(this)));
[email protected]3cf4f0992009-02-03 23:00:30330}
331
[email protected]4a8d3272009-03-10 19:15:08332void ExtensionsService::OnExtensionsLoaded(ExtensionList* new_extensions) {
[email protected]86a274072009-06-11 02:06:45333 // Filter out any extensions we don't want to enable. Themes are always
334 // enabled, but other extensions are only loaded if --enable-extensions is
335 // present.
[email protected]a1257b12009-06-12 02:51:34336 ExtensionList enabled_extensions;
[email protected]86a274072009-06-11 02:06:45337 for (ExtensionList::iterator iter = new_extensions->begin();
[email protected]25b34332009-06-05 21:53:19338 iter != new_extensions->end(); ++iter) {
[email protected]ba74f352009-06-11 18:54:45339 if (extensions_enabled() || (*iter)->IsTheme()) {
[email protected]86a274072009-06-11 02:06:45340 enabled_extensions.push_back(*iter);
[email protected]ba74f352009-06-11 18:54:45341 } else {
342 // Extensions that get enabled get added to extensions_ and deleted later.
343 // Anything skipped must be deleted now so we don't leak.
344 delete *iter;
345 }
[email protected]86a274072009-06-11 02:06:45346 }
347
348 for (ExtensionList::const_iterator iter = enabled_extensions.begin();
349 iter != enabled_extensions.end(); ++iter) {
[email protected]25b34332009-06-05 21:53:19350 std::wstring extension_id = ASCIIToWide((*iter)->id());
[email protected]86a274072009-06-11 02:06:45351 DictionaryValue* pref = GetOrCreateExtensionPref(extension_id);
[email protected]dd19d64a2009-06-05 22:10:01352 int location;
353 int state;
[email protected]a1257b12009-06-12 02:51:34354
[email protected]86a274072009-06-11 02:06:45355 // Ensure all loaded extensions have a preference set. This deals with a
356 // legacy problem where some extensions were installed before we were
357 // storing state in the preferences.
358 // TODO(aa): We should remove this eventually.
[email protected]dd19d64a2009-06-05 22:10:01359 if (!pref->GetInteger(kLocation, &location) ||
360 !pref->GetInteger(kState, &state)) {
[email protected]25b34332009-06-05 21:53:19361 UpdateExtensionPref(extension_id,
362 kLocation, Value::CreateIntegerValue(Extension::INTERNAL), false);
363 UpdateExtensionPref(extension_id,
364 kState, Value::CreateIntegerValue(Extension::ENABLED), false);
365 } else {
[email protected]86a274072009-06-11 02:06:45366 // Sanity check: The kill-bit should only ever be set on external
367 // extensions.
[email protected]25b34332009-06-05 21:53:19368 DCHECK(state != Extension::KILLBIT ||
[email protected]86a274072009-06-11 02:06:45369 Extension::IsExternalLocation(
370 static_cast<Extension::Location>(location)));
[email protected]25b34332009-06-05 21:53:19371 }
[email protected]25b34332009-06-05 21:53:19372
[email protected]86a274072009-06-11 02:06:45373 extensions_.push_back(*iter);
[email protected]9197f3b2009-06-02 00:49:27374 }
375
[email protected]d2d89d82009-06-08 21:01:53376 NotificationService::current()->Notify(
377 NotificationType::EXTENSIONS_LOADED,
378 NotificationService::AllSources(),
[email protected]86a274072009-06-11 02:06:45379 Details<ExtensionList>(&enabled_extensions));
[email protected]d2d89d82009-06-08 21:01:53380
[email protected]82891262008-12-24 00:21:26381 delete new_extensions;
[email protected]6014d672008-12-05 00:38:25382}
383
[email protected]a57209872009-05-04 22:53:14384void ExtensionsService::OnExtensionInstalled(Extension* extension,
[email protected]fbcc40302009-06-12 20:45:45385 Extension::InstallType install_type) {
[email protected]25b34332009-06-05 21:53:19386 UpdateExtensionPref(ASCIIToWide(extension->id()), kState,
387 Value::CreateIntegerValue(Extension::ENABLED), false);
388 UpdateExtensionPref(ASCIIToWide(extension->id()), kLocation,
389 Value::CreateIntegerValue(Extension::INTERNAL), true);
390
[email protected]4a190632009-05-09 01:07:42391 // If the extension is a theme, tell the profile (and therefore ThemeProvider)
392 // to apply it.
393 if (extension->IsTheme()) {
394 NotificationService::current()->Notify(
395 NotificationType::THEME_INSTALLED,
396 NotificationService::AllSources(),
397 Details<Extension>(extension));
[email protected]9197f3b2009-06-02 00:49:27398 } else {
399 NotificationService::current()->Notify(
400 NotificationType::EXTENSION_INSTALLED,
401 NotificationService::AllSources(),
402 Details<Extension>(extension));
[email protected]4a190632009-05-09 01:07:42403 }
404}
405
[email protected]25b34332009-06-05 21:53:19406void ExtensionsService::OnExternalExtensionInstalled(
407 const std::string& id, Extension::Location location) {
408 DCHECK(Extension::IsExternalLocation(location));
409 UpdateExtensionPref(ASCIIToWide(id), kState,
410 Value::CreateIntegerValue(Extension::ENABLED), false);
411 UpdateExtensionPref(ASCIIToWide(id), kLocation,
412 Value::CreateIntegerValue(location), true);
413}
414
[email protected]fbcc40302009-06-12 20:45:45415void ExtensionsService::OnExtensionOverinstallAttempted(const std::string& id) {
[email protected]4a190632009-05-09 01:07:42416 Extension* extension = GetExtensionByID(id);
417 if (extension && extension->IsTheme()) {
418 NotificationService::current()->Notify(
419 NotificationType::THEME_INSTALLED,
420 NotificationService::AllSources(),
421 Details<Extension>(extension));
422 }
[email protected]cc655912009-01-29 23:19:19423}
424
[email protected]ce5c4502009-05-06 16:46:11425Extension* ExtensionsService::GetExtensionByID(std::string id) {
426 for (ExtensionList::const_iterator iter = extensions_.begin();
[email protected]4a190632009-05-09 01:07:42427 iter != extensions_.end(); ++iter) {
[email protected]ce5c4502009-05-06 16:46:11428 if ((*iter)->id() == id)
429 return *iter;
430 }
431 return NULL;
432}
433
[email protected]25b34332009-06-05 21:53:19434void ExtensionsService::GetExternalExtensions(
435 DictionaryValue* external_extensions,
436 std::set<std::string>* killed_extensions) {
437 const DictionaryValue* dict = prefs_->GetDictionary(kExternalExtensionsPref);
438 if (!dict || dict->GetSize() == 0)
439 return;
440
441 for (DictionaryValue::key_iterator i = dict->begin_keys();
442 i != dict->end_keys(); ++i) {
443 std::wstring key_name = *i;
[email protected]5a2721f62009-06-13 07:08:20444 if (!Extension::IdIsValid(WideToASCII(key_name))) {
445 LOG(WARNING) << "Invalid external extension ID encountered: "
446 << WideToASCII(key_name);
447 continue;
448 }
449
[email protected]25b34332009-06-05 21:53:19450 DictionaryValue* extension = NULL;
451 if (!dict->GetDictionary(key_name, &extension)) {
452 NOTREACHED();
453 continue;
454 }
455
456 // Check to see if the extension has been killed.
[email protected]dd19d64a2009-06-05 22:10:01457 int state;
458 if (extension->GetInteger(kState, &state) &&
[email protected]25b34332009-06-05 21:53:19459 state == static_cast<int>(Extension::KILLBIT)) {
460 if (killed_extensions) {
461 StringToLowerASCII(&key_name);
462 killed_extensions->insert(WideToASCII(key_name));
463 }
464 }
465 // Return all extensions found.
466 if (external_extensions) {
467 DictionaryValue* result =
468 static_cast<DictionaryValue*>(extension->DeepCopy());
469 StringToLowerASCII(&key_name);
470 external_extensions->Set(key_name, result);
471 }
472 }
473}
474
475DictionaryValue* ExtensionsService::GetOrCreateExtensionPref(
476 const std::wstring& extension_id) {
477 DictionaryValue* dict = prefs_->GetMutableDictionary(kExternalExtensionsPref);
478 DictionaryValue* extension = NULL;
479 if (!dict->GetDictionary(extension_id, &extension)) {
480 // Extension pref does not exist, create it.
481 extension = new DictionaryValue();
482 dict->Set(extension_id, extension);
483 }
484
485 return extension;
486}
487
[email protected]a1257b12009-06-12 02:51:34488void ExtensionsService::ClearProvidersForTesting() {
489 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
490 &ExtensionsServiceBackend::ClearProvidersForTesting));
491}
492
493void ExtensionsService::SetProviderForTesting(
494 Extension::Location location, ExternalExtensionProvider* test_provider) {
495 backend_loop_->PostTask(FROM_HERE, NewRunnableMethod(backend_.get(),
496 &ExtensionsServiceBackend::SetProviderForTesting,
497 location, test_provider));
498}
499
[email protected]25b34332009-06-05 21:53:19500bool ExtensionsService::UpdateExtensionPref(const std::wstring& extension_id,
501 const std::wstring& key,
502 Value* data_value,
503 bool schedule_save) {
504 DictionaryValue* extension = GetOrCreateExtensionPref(extension_id);
505 if (!extension->Set(key, data_value)) {
506 NOTREACHED() << L"Cannot modify key: '" << key.c_str()
507 << "' for extension: '" << extension_id.c_str() << "'";
508 return false;
509 }
510
511 if (schedule_save)
512 prefs_->ScheduleSavePersistentPrefs();
513 return true;
514}
[email protected]6014d672008-12-05 00:38:25515
516// ExtensionsServicesBackend
517
[email protected]894bb502009-05-21 22:39:57518ExtensionsServiceBackend::ExtensionsServiceBackend(
519 const FilePath& install_directory, ResourceDispatcherHost* rdh,
[email protected]a1257b12009-06-12 02:51:34520 MessageLoop* frontend_loop, DictionaryValue* extension_prefs)
[email protected]0c7bc4b2009-05-30 01:47:08521 : frontend_(NULL),
522 install_directory_(install_directory),
[email protected]894bb502009-05-21 22:39:57523 resource_dispatcher_host_(rdh),
[email protected]0c7bc4b2009-05-30 01:47:08524 alert_on_error_(false),
[email protected]a1257b12009-06-12 02:51:34525 frontend_loop_(frontend_loop) {
526 external_extension_providers_[Extension::EXTERNAL_PREF] =
527 new ExternalPrefExtensionProvider(extension_prefs);
528#if defined(OS_WIN)
529 external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
530 new ExternalRegistryExtensionProvider();
531#endif
532}
533
534ExtensionsServiceBackend::~ExtensionsServiceBackend() {
535 STLDeleteContainerPairSecondPointers(external_extension_providers_.begin(),
536 external_extension_providers_.end());
[email protected]894bb502009-05-21 22:39:57537}
538
[email protected]cc5da332009-03-04 08:02:51539void ExtensionsServiceBackend::LoadExtensionsFromInstallDirectory(
[email protected]25b34332009-06-05 21:53:19540 scoped_refptr<ExtensionsService> frontend,
541 DictionaryValue* extension_prefs) {
[email protected]b0beaa662009-02-26 00:04:15542 frontend_ = frontend;
543 alert_on_error_ = false;
[email protected]25b34332009-06-05 21:53:19544 scoped_ptr<DictionaryValue> external_extensions(extension_prefs);
[email protected]05eb0fa2009-02-21 00:05:48545
[email protected]540f91b2009-03-26 19:37:43546#if defined(OS_WIN)
547 // On POSIX, AbsolutePath() calls realpath() which returns NULL if
548 // it does not exist. Instead we absolute-ify after creation in
549 // case that is needed.
550 // TODO(port): does this really need to happen before
551 // CreateDirectory() on Windows?
[email protected]cc5da332009-03-04 08:02:51552 if (!file_util::AbsolutePath(&install_directory_))
[email protected]eab9b452009-01-23 20:48:59553 NOTREACHED();
[email protected]540f91b2009-03-26 19:37:43554#endif
[email protected]eab9b452009-01-23 20:48:59555
[email protected]b0beaa662009-02-26 00:04:15556 scoped_ptr<ExtensionList> extensions(new ExtensionList);
557
558 // Create the <Profile>/Extensions directory if it doesn't exist.
[email protected]cc5da332009-03-04 08:02:51559 if (!file_util::DirectoryExists(install_directory_)) {
560 file_util::CreateDirectory(install_directory_);
[email protected]b0beaa662009-02-26 00:04:15561 LOG(INFO) << "Created Extensions directory. No extensions to install.";
562 ReportExtensionsLoaded(extensions.release());
563 return;
564 }
565
[email protected]540f91b2009-03-26 19:37:43566#if !defined(OS_WIN)
567 if (!file_util::AbsolutePath(&install_directory_))
568 NOTREACHED();
569#endif
570
[email protected]bf24d2c2009-02-24 23:07:45571 LOG(INFO) << "Loading installed extensions...";
572
[email protected]6014d672008-12-05 00:38:25573 // Find all child directories in the install directory and load their
574 // manifests. Post errors and results to the frontend.
[email protected]cc5da332009-03-04 08:02:51575 file_util::FileEnumerator enumerator(install_directory_,
[email protected]a1257b12009-06-12 02:51:34576 false, // Not recursive.
[email protected]6014d672008-12-05 00:38:25577 file_util::FileEnumerator::DIRECTORIES);
[email protected]cc5da332009-03-04 08:02:51578 FilePath extension_path;
579 for (extension_path = enumerator.Next(); !extension_path.value().empty();
580 extension_path = enumerator.Next()) {
581 std::string extension_id = WideToASCII(
582 extension_path.BaseName().ToWStringHack());
[email protected]5a2721f62009-06-13 07:08:20583
[email protected]96088fb2009-05-26 19:08:13584 // The utility process might be in the middle of unpacking an extension, so
585 // ignore the temp unpacking directory.
586 if (extension_id == kUnpackExtensionDir)
587 continue;
[email protected]894bb502009-05-21 22:39:57588
[email protected]5a2721f62009-06-13 07:08:20589 // Ignore directories that aren't valid IDs.
590 if (!Extension::IdIsValid(extension_id)) {
591 LOG(WARNING) << "Invalid extension ID encountered in extensions "
592 "directory: " << extension_id;
593 continue;
594 }
595
[email protected]894bb502009-05-21 22:39:57596 // If there is no Current Version file, just delete the directory and move
597 // on. This can legitimately happen when an uninstall does not complete, for
598 // example, when a plugin is in use at uninstall time.
599 FilePath current_version_path = extension_path.AppendASCII(
600 ExtensionsService::kCurrentVersionFileName);
601 if (!file_util::PathExists(current_version_path)) {
602 LOG(INFO) << "Deleting incomplete install for directory "
603 << WideToASCII(extension_path.ToWStringHack()) << ".";
[email protected]25b34332009-06-05 21:53:19604 file_util::Delete(extension_path, true); // Recursive.
[email protected]894bb502009-05-21 22:39:57605 continue;
606 }
607
608 std::string current_version;
609 if (!ReadCurrentVersion(extension_path, &current_version))
610 continue;
611
[email protected]a1257b12009-06-12 02:51:34612 Extension::Location location = Extension::INVALID;
613 int location_value;
[email protected]25b34332009-06-05 21:53:19614 DictionaryValue* pref = NULL;
615 external_extensions->GetDictionary(ASCIIToWide(extension_id), &pref);
616 if (!pref ||
[email protected]a1257b12009-06-12 02:51:34617 !pref->GetInteger(kLocation, &location_value)) {
618 // Check with the external providers.
619 if (!LookupExternalExtension(extension_id, NULL, &location))
620 location = Extension::INTERNAL;
621 } else {
622 location = static_cast<Extension::Location>(location_value);
[email protected]25b34332009-06-05 21:53:19623 }
[email protected]a1257b12009-06-12 02:51:34624
[email protected]894bb502009-05-21 22:39:57625 FilePath version_path = extension_path.AppendASCII(current_version);
[email protected]a1257b12009-06-12 02:51:34626 if (Extension::IsExternalLocation(location) &&
[email protected]25b34332009-06-05 21:53:19627 CheckExternalUninstall(external_extensions.get(),
628 version_path, extension_id)) {
[email protected]cc5da332009-03-04 08:02:51629 // TODO(erikkay): Possibly defer this operation to avoid slowing initial
630 // load of extensions.
[email protected]631cf822009-05-15 07:01:25631 UninstallExtension(extension_id);
[email protected]cc5da332009-03-04 08:02:51632
633 // No error needs to be reported. The extension effectively doesn't
634 // exist.
635 continue;
636 }
637
[email protected]a1257b12009-06-12 02:51:34638 Extension* extension = LoadExtension(version_path,
639 location,
640 true); // require id
[email protected]0877fd92009-02-03 16:34:06641 if (extension)
642 extensions->push_back(extension);
[email protected]6014d672008-12-05 00:38:25643 }
644
[email protected]bf24d2c2009-02-24 23:07:45645 LOG(INFO) << "Done.";
[email protected]b0beaa662009-02-26 00:04:15646 ReportExtensionsLoaded(extensions.release());
[email protected]6014d672008-12-05 00:38:25647}
648
[email protected]b0beaa662009-02-26 00:04:15649void ExtensionsServiceBackend::LoadSingleExtension(
[email protected]894bb502009-05-21 22:39:57650 const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
[email protected]b0beaa662009-02-26 00:04:15651 frontend_ = frontend;
652
653 // Explicit UI loads are always noisy.
654 alert_on_error_ = true;
655
[email protected]cc5da332009-03-04 08:02:51656 FilePath extension_path = path_in;
657 if (!file_util::AbsolutePath(&extension_path))
[email protected]0877fd92009-02-03 16:34:06658 NOTREACHED();
[email protected]bf24d2c2009-02-24 23:07:45659
660 LOG(INFO) << "Loading single extension from " <<
[email protected]cc5da332009-03-04 08:02:51661 WideToASCII(extension_path.BaseName().ToWStringHack());
[email protected]bf24d2c2009-02-24 23:07:45662
[email protected]5bfb1eb0a2009-04-08 18:33:30663 Extension* extension = LoadExtension(extension_path,
[email protected]a1257b12009-06-12 02:51:34664 Extension::LOAD,
[email protected]5bfb1eb0a2009-04-08 18:33:30665 false); // don't require ID
[email protected]0877fd92009-02-03 16:34:06666 if (extension) {
667 ExtensionList* extensions = new ExtensionList;
668 extensions->push_back(extension);
[email protected]b0beaa662009-02-26 00:04:15669 ReportExtensionsLoaded(extensions);
[email protected]0877fd92009-02-03 16:34:06670 }
[email protected]0877fd92009-02-03 16:34:06671}
672
[email protected]fbcc40302009-06-12 20:45:45673DictionaryValue* ExtensionsServiceBackend::ReadManifest(FilePath manifest_path,
674 std::string* error) {
675 JSONFileValueSerializer serializer(manifest_path);
676 scoped_ptr<Value> root(serializer.Deserialize(error));
677 if (!root.get())
678 return NULL;
679
680 if (!root->IsType(Value::TYPE_DICTIONARY)) {
681 *error = Extension::kInvalidManifestError;
682 return NULL;
683 }
684
685 return static_cast<DictionaryValue*>(root.release());
686}
687
[email protected]cc5da332009-03-04 08:02:51688Extension* ExtensionsServiceBackend::LoadExtension(
[email protected]a1257b12009-06-12 02:51:34689 const FilePath& extension_path,
690 Extension::Location location,
691 bool require_id) {
[email protected]0877fd92009-02-03 16:34:06692 FilePath manifest_path =
[email protected]cc5da332009-03-04 08:02:51693 extension_path.AppendASCII(Extension::kManifestFilename);
[email protected]0877fd92009-02-03 16:34:06694 if (!file_util::PathExists(manifest_path)) {
[email protected]cc5da332009-03-04 08:02:51695 ReportExtensionLoadError(extension_path, Extension::kInvalidManifestError);
[email protected]0877fd92009-02-03 16:34:06696 return NULL;
697 }
698
[email protected]0877fd92009-02-03 16:34:06699 std::string error;
[email protected]fbcc40302009-06-12 20:45:45700 scoped_ptr<DictionaryValue> root(ReadManifest(manifest_path, &error));
[email protected]0877fd92009-02-03 16:34:06701 if (!root.get()) {
[email protected]cc5da332009-03-04 08:02:51702 ReportExtensionLoadError(extension_path, error);
[email protected]0877fd92009-02-03 16:34:06703 return NULL;
704 }
705
[email protected]cc5da332009-03-04 08:02:51706 scoped_ptr<Extension> extension(new Extension(extension_path));
[email protected]fbcc40302009-06-12 20:45:45707 if (!extension->InitFromValue(*root.get(), require_id, &error)) {
[email protected]cc5da332009-03-04 08:02:51708 ReportExtensionLoadError(extension_path, error);
[email protected]0877fd92009-02-03 16:34:06709 return NULL;
710 }
[email protected]8d6d9ff2009-02-20 08:14:39711
[email protected]a1257b12009-06-12 02:51:34712 extension->set_location(location);
[email protected]631cf822009-05-15 07:01:25713
[email protected]12198912009-06-05 03:41:22714 // Theme resource validation.
715 if (extension->IsTheme()) {
716 DictionaryValue* images_value = extension->GetThemeImages();
717 DictionaryValue::key_iterator iter = images_value->begin_keys();
718 while (iter != images_value->end_keys()) {
719 std::string val;
[email protected]25b34332009-06-05 21:53:19720 if (images_value->GetString(*iter , &val)) {
[email protected]12198912009-06-05 03:41:22721 FilePath image_path = extension->path().AppendASCII(val);
722 if (!file_util::PathExists(image_path)) {
723 ReportExtensionLoadError(extension_path,
724 StringPrintf("Could not load '%s' for theme.",
725 WideToUTF8(image_path.ToWStringHack()).c_str()));
726 return NULL;
727 }
728 }
729 ++iter;
730 }
731
732 // Themes cannot contain other extension types.
733 return extension.release();
734 }
735
[email protected]d24070e22009-05-21 19:26:59736 // Validate that claimed script resources actually exist.
[email protected]3cfbd0e2009-03-18 21:26:24737 for (size_t i = 0; i < extension->content_scripts().size(); ++i) {
738 const UserScript& script = extension->content_scripts()[i];
739
740 for (size_t j = 0; j < script.js_scripts().size(); j++) {
741 const FilePath& path = script.js_scripts()[j].path();
742 if (!file_util::PathExists(path)) {
743 ReportExtensionLoadError(extension_path,
[email protected]d24070e22009-05-21 19:26:59744 StringPrintf("Could not load '%s' for content script.",
745 WideToUTF8(path.ToWStringHack()).c_str()));
[email protected]3cfbd0e2009-03-18 21:26:24746 return NULL;
747 }
748 }
749
750 for (size_t j = 0; j < script.css_scripts().size(); j++) {
751 const FilePath& path = script.css_scripts()[j].path();
752 if (!file_util::PathExists(path)) {
753 ReportExtensionLoadError(extension_path,
[email protected]d24070e22009-05-21 19:26:59754 StringPrintf("Could not load '%s' for content script.",
755 WideToUTF8(path.ToWStringHack()).c_str()));
[email protected]3cfbd0e2009-03-18 21:26:24756 return NULL;
757 }
[email protected]8d6d9ff2009-02-20 08:14:39758 }
759 }
760
[email protected]c533bb22009-06-03 19:06:11761 for (size_t i = 0; i < extension->plugins().size(); ++i) {
762 const Extension::PluginInfo& plugin = extension->plugins()[i];
763 if (!file_util::PathExists(plugin.path)) {
764 ReportExtensionLoadError(extension_path,
765 StringPrintf("Could not load '%s' for plugin.",
766 WideToUTF8(plugin.path.ToWStringHack()).c_str()));
767 return NULL;
768 }
769 }
770
[email protected]d24070e22009-05-21 19:26:59771 // Validate icon location for page actions.
772 const PageActionMap& page_actions = extension->page_actions();
773 for (PageActionMap::const_iterator i(page_actions.begin());
774 i != page_actions.end(); ++i) {
775 PageAction* page_action = i->second;
776 FilePath path = page_action->icon_path();
777 if (!file_util::PathExists(path)) {
778 ReportExtensionLoadError(extension_path,
779 StringPrintf("Could not load icon '%s' for page action.",
780 WideToUTF8(path.ToWStringHack()).c_str()));
781 return NULL;
782 }
783 }
784
[email protected]0877fd92009-02-03 16:34:06785 return extension.release();
786}
787
[email protected]6014d672008-12-05 00:38:25788void ExtensionsServiceBackend::ReportExtensionLoadError(
[email protected]cc5da332009-03-04 08:02:51789 const FilePath& extension_path, const std::string &error) {
[email protected]b0beaa662009-02-26 00:04:15790 // TODO(port): note that this isn't guaranteed to work properly on Linux.
[email protected]cc5da332009-03-04 08:02:51791 std::string path_str = WideToASCII(extension_path.ToWStringHack());
[email protected]3acbd422008-12-08 18:25:00792 std::string message = StringPrintf("Could not load extension from '%s'. %s",
[email protected]cc655912009-01-29 23:19:19793 path_str.c_str(), error.c_str());
[email protected]bb28e062009-02-27 17:19:18794 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_);
[email protected]6014d672008-12-05 00:38:25795}
796
797void ExtensionsServiceBackend::ReportExtensionsLoaded(
[email protected]b0beaa662009-02-26 00:04:15798 ExtensionList* extensions) {
[email protected]894bb502009-05-21 22:39:57799 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
800 frontend_, &ExtensionsService::OnExtensionsLoaded, extensions));
[email protected]6014d672008-12-05 00:38:25801}
[email protected]cc655912009-01-29 23:19:19802
[email protected]b0beaa662009-02-26 00:04:15803bool ExtensionsServiceBackend::ReadCurrentVersion(const FilePath& dir,
804 std::string* version_string) {
[email protected]18a12352009-01-31 01:33:28805 FilePath current_version =
[email protected]b0beaa662009-02-26 00:04:15806 dir.AppendASCII(ExtensionsService::kCurrentVersionFileName);
[email protected]18a12352009-01-31 01:33:28807 if (file_util::PathExists(current_version)) {
808 if (file_util::ReadFileToString(current_version, version_string)) {
809 TrimWhitespace(*version_string, TRIM_ALL, version_string);
810 return true;
811 }
812 }
813 return false;
814}
815
[email protected]fbcc40302009-06-12 20:45:45816Extension::InstallType ExtensionsServiceBackend::CompareToInstalledVersion(
817 const std::string& id,
[email protected]b0beaa662009-02-26 00:04:15818 const std::string& new_version_str,
[email protected]fbcc40302009-06-12 20:45:45819 std::string *current_version_str) {
820 CHECK(current_version_str);
821 FilePath dir(install_directory_.AppendASCII(id.c_str()));
822 if (!ReadCurrentVersion(dir, current_version_str))
823 return Extension::NEW_INSTALL;
824
[email protected]b0beaa662009-02-26 00:04:15825 scoped_ptr<Version> current_version(
[email protected]fbcc40302009-06-12 20:45:45826 Version::GetVersionFromString(*current_version_str));
[email protected]b0beaa662009-02-26 00:04:15827 scoped_ptr<Version> new_version(
[email protected]fbcc40302009-06-12 20:45:45828 Version::GetVersionFromString(new_version_str));
829 int comp = new_version->CompareTo(*current_version);
830 if (comp > 0)
831 return Extension::UPGRADE;
832 else if (comp == 0)
833 return Extension::REINSTALL;
834 else
835 return Extension::DOWNGRADE;
836}
837
838bool ExtensionsServiceBackend::NeedsReinstall(const std::string& id,
839 const std::string& current_version) {
840 // Verify that the directory actually exists.
841 // TODO(erikkay): A further step would be to verify that the extension
842 // has actually loaded successfully.
843 FilePath dir(install_directory_.AppendASCII(id.c_str()));
844 FilePath version_dir(dir.AppendASCII(current_version));
845 return !file_util::PathExists(version_dir);
[email protected]cc655912009-01-29 23:19:19846}
847
[email protected]f0a51fb52009-03-05 12:46:38848bool ExtensionsServiceBackend::InstallDirSafely(const FilePath& source_dir,
[email protected]b0beaa662009-02-26 00:04:15849 const FilePath& dest_dir) {
[email protected]cc655912009-01-29 23:19:19850 if (file_util::PathExists(dest_dir)) {
851 // By the time we get here, it should be safe to assume that this directory
852 // is not currently in use (it's not the current active version).
853 if (!file_util::Delete(dest_dir, true)) {
[email protected]cc5da332009-03-04 08:02:51854 ReportExtensionInstallError(source_dir,
[email protected]cc655912009-01-29 23:19:19855 "Can't delete existing version directory.");
856 return false;
857 }
858 } else {
859 FilePath parent = dest_dir.DirName();
860 if (!file_util::DirectoryExists(parent)) {
861 if (!file_util::CreateDirectory(parent)) {
[email protected]cc5da332009-03-04 08:02:51862 ReportExtensionInstallError(source_dir,
863 "Couldn't create extension directory.");
[email protected]cc655912009-01-29 23:19:19864 return false;
865 }
866 }
867 }
868 if (!file_util::Move(source_dir, dest_dir)) {
[email protected]cc5da332009-03-04 08:02:51869 ReportExtensionInstallError(source_dir,
870 "Couldn't move temporary directory.");
[email protected]cc655912009-01-29 23:19:19871 return false;
872 }
873
874 return true;
875}
876
[email protected]b0beaa662009-02-26 00:04:15877bool ExtensionsServiceBackend::SetCurrentVersion(const FilePath& dest_dir,
878 std::string version) {
[email protected]cc655912009-01-29 23:19:19879 // Write out the new CurrentVersion file.
880 // <profile>/Extension/<name>/CurrentVersion
881 FilePath current_version =
882 dest_dir.AppendASCII(ExtensionsService::kCurrentVersionFileName);
883 FilePath current_version_old =
884 current_version.InsertBeforeExtension(FILE_PATH_LITERAL("_old"));
885 if (file_util::PathExists(current_version_old)) {
886 if (!file_util::Delete(current_version_old, false)) {
[email protected]cc5da332009-03-04 08:02:51887 ReportExtensionInstallError(dest_dir,
888 "Couldn't remove CurrentVersion_old file.");
[email protected]cc655912009-01-29 23:19:19889 return false;
890 }
891 }
892 if (file_util::PathExists(current_version)) {
893 if (!file_util::Move(current_version, current_version_old)) {
[email protected]cc5da332009-03-04 08:02:51894 ReportExtensionInstallError(dest_dir,
895 "Couldn't move CurrentVersion file.");
[email protected]cc655912009-01-29 23:19:19896 return false;
897 }
898 }
899 net::FileStream stream;
900 int flags = base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_WRITE;
901 if (stream.Open(current_version, flags) != 0)
902 return false;
903 if (stream.Write(version.c_str(), version.size(), NULL) < 0) {
904 // Restore the old CurrentVersion.
905 if (file_util::PathExists(current_version_old)) {
906 if (!file_util::Move(current_version_old, current_version)) {
[email protected]f0a51fb52009-03-05 12:46:38907 LOG(WARNING) << "couldn't restore " << current_version_old.value() <<
[email protected]cc655912009-01-29 23:19:19908 " to " << current_version.value();
[email protected]b0beaa662009-02-26 00:04:15909
[email protected]cc655912009-01-29 23:19:19910 // TODO(erikkay): This is an ugly state to be in. Try harder?
911 }
912 }
[email protected]f0a51fb52009-03-05 12:46:38913 ReportExtensionInstallError(dest_dir,
[email protected]cc5da332009-03-04 08:02:51914 "Couldn't create CurrentVersion file.");
[email protected]cc655912009-01-29 23:19:19915 return false;
916 }
917 return true;
918}
919
[email protected]b0beaa662009-02-26 00:04:15920void ExtensionsServiceBackend::InstallExtension(
[email protected]894bb502009-05-21 22:39:57921 const FilePath& extension_path, scoped_refptr<ExtensionsService> frontend) {
[email protected]cc655912009-01-29 23:19:19922 LOG(INFO) << "Installing extension " << extension_path.value();
923
[email protected]b0beaa662009-02-26 00:04:15924 frontend_ = frontend;
[email protected]0e34d7892009-06-05 19:17:40925 alert_on_error_ = true;
[email protected]b0beaa662009-02-26 00:04:15926
[email protected]1fca1492009-05-15 22:23:43927 bool from_external = false;
928 InstallOrUpdateExtension(extension_path, std::string(), from_external);
[email protected]b0beaa662009-02-26 00:04:15929}
930
[email protected]1fca1492009-05-15 22:23:43931void ExtensionsServiceBackend::InstallOrUpdateExtension(
[email protected]fbcc40302009-06-12 20:45:45932 const FilePath& extension_path,
933 const std::string& expected_id,
[email protected]1fca1492009-05-15 22:23:43934 bool from_external) {
[email protected]fbcc40302009-06-12 20:45:45935 std::string actual_public_key;
936 if (!ValidateSignature(extension_path, &actual_public_key))
937 return; // Failures reported within ValidateSignature().
938
939 UnpackerClient* client = new UnpackerClient(
940 this, extension_path, actual_public_key, expected_id, from_external);
[email protected]1fca1492009-05-15 22:23:43941 client->Start();
942}
[email protected]cc655912009-01-29 23:19:19943
[email protected]fbcc40302009-06-12 20:45:45944bool ExtensionsServiceBackend::ValidateSignature(const FilePath& extension_path,
945 std::string* key_out) {
946 ScopedStdioHandle file(file_util::OpenFile(extension_path, "rb"));
947 if (!file.get()) {
948 ReportExtensionInstallError(extension_path, "Could not open file.");
949 return NULL;
950 }
951
952 // Read and verify the header.
953 ExtensionsService::ExtensionHeader header;
954 size_t len;
955
956 // TODO(erikkay): Yuck. I'm not a big fan of this kind of code, but it
957 // appears that we don't have any endian/alignment aware serialization
958 // code in the code base. So for now, this assumes that we're running
959 // on a little endian machine with 4 byte alignment.
960 len = fread(&header, 1, sizeof(ExtensionsService::ExtensionHeader),
961 file.get());
962 if (len < sizeof(ExtensionsService::ExtensionHeader)) {
963 ReportExtensionInstallError(extension_path, kInvalidExtensionHeaderError);
964 return false;
965 }
966 if (strncmp(ExtensionsService::kExtensionHeaderMagic, header.magic,
967 sizeof(header.magic))) {
968 ReportExtensionInstallError(extension_path, kBadMagicNumberError);
969 return false;
970 }
971 if (header.version != ExtensionsService::kCurrentVersion) {
972 ReportExtensionInstallError(extension_path, kBadVersionNumberError);
973 return false;
974 }
975 if (header.key_size > ExtensionsService::kMaxPublicKeySize ||
976 header.signature_size > ExtensionsService::kMaxSignatureSize) {
977 ReportExtensionInstallError(extension_path, kBadHeaderSizeError);
978 return false;
979 }
980
981 std::vector<uint8> key;
982 key.resize(header.key_size);
983 len = fread(&key.front(), sizeof(uint8), header.key_size, file.get());
984 if (len < header.key_size) {
985 ReportExtensionInstallError(extension_path, kInvalidPublicKeyError);
986 return false;
987 }
988
989 std::vector<uint8> signature;
990 signature.resize(header.signature_size);
991 len = fread(&signature.front(), sizeof(uint8), header.signature_size,
992 file.get());
993 if (len < header.signature_size) {
994 ReportExtensionInstallError(extension_path, kInvalidSignatureError);
995 return false;
996 }
997
998 // Note: this structure is an ASN.1 which encodes the algorithm used
999 // with its parameters. This is defined in PKCS #1 v2.1 (RFC 3447).
1000 // It is encoding: { OID sha1WithRSAEncryption PARAMETERS NULL }
1001 // TODO(aa): This needs to be factored away someplace common.
1002 const uint8 signature_algorithm[15] = {
1003 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
1004 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00
1005 };
1006
1007 base::SignatureVerifier verifier;
1008 if (!verifier.VerifyInit(signature_algorithm,
1009 sizeof(signature_algorithm),
1010 &signature.front(),
1011 signature.size(),
1012 &key.front(),
1013 key.size())) {
1014 ReportExtensionInstallError(extension_path,
1015 kSignatureVerificationInitFailed);
1016 return false;
1017 }
1018
1019 unsigned char buf[1 << 12];
1020 while ((len = fread(buf, 1, sizeof(buf), file.get())) > 0)
1021 verifier.VerifyUpdate(buf, len);
1022
1023 if (!verifier.VerifyFinal()) {
1024 ReportExtensionInstallError(extension_path, kSignatureVerificationFailed);
1025 return false;
1026 }
1027
1028 net::Base64Encode(std::string(reinterpret_cast<char*>(&key.front()),
1029 key.size()), key_out);
1030 return true;
1031}
1032
[email protected]1fca1492009-05-15 22:23:431033void ExtensionsServiceBackend::OnExtensionUnpacked(
1034 const FilePath& extension_path,
1035 const FilePath& temp_extension_dir,
1036 const std::string expected_id,
[email protected]902f7cd2009-05-22 19:02:191037 bool from_external,
1038 const DictionaryValue& manifest,
1039 const std::vector< Tuple2<SkBitmap, FilePath> >& images) {
[email protected]1fca1492009-05-15 22:23:431040 Extension extension;
1041 std::string error;
[email protected]902f7cd2009-05-22 19:02:191042 if (!extension.InitFromValue(manifest,
[email protected]1fca1492009-05-15 22:23:431043 true, // require ID
1044 &error)) {
1045 ReportExtensionInstallError(extension_path, "Invalid extension manifest.");
1046 return;
[email protected]0b344962009-03-31 04:21:451047 }
1048
[email protected]e2eb43112009-05-29 21:19:541049 if (!frontend_->extensions_enabled() && !extension.IsTheme()) {
1050#if defined(OS_WIN)
[email protected]0e34d7892009-06-05 19:17:401051 if (frontend_->show_extensions_prompts()) {
[email protected]e2eb43112009-05-29 21:19:541052 win_util::MessageBox(GetActiveWindow(),
1053 L"Extensions are not enabled. Add --enable-extensions to the "
1054 L"command-line to enable extensions.\n\n"
1055 L"This is a temporary message and it will be removed when extensions "
1056 L"UI is finalized.",
1057 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(), MB_OK);
1058 }
1059#endif
1060 ReportExtensionInstallError(extension_path,
1061 "Extensions are not enabled.");
1062 return;
1063 }
1064
[email protected]0e34d7892009-06-05 19:17:401065#if defined(OS_WIN)
[email protected]a1257b12009-06-12 02:51:341066 if (!extension.IsTheme() && !from_external &&
[email protected]0e34d7892009-06-05 19:17:401067 frontend_->show_extensions_prompts() &&
1068 win_util::MessageBox(GetActiveWindow(),
1069 L"Are you sure you want to install this extension?\n\n"
1070 L"This is a temporary message and it will be removed when extensions "
1071 L"UI is finalized.",
1072 l10n_util::GetString(IDS_PRODUCT_NAME).c_str(),
[email protected]31e8a012009-06-06 08:13:341073 MB_OKCANCEL) != IDOK) {
[email protected]0e34d7892009-06-05 19:17:401074 ReportExtensionInstallError(extension_path,
1075 "User did not allow extension to be installed.");
1076 return;
1077 }
1078#endif
1079
[email protected]b0beaa662009-02-26 00:04:151080 // If an expected id was provided, make sure it matches.
[email protected]1fca1492009-05-15 22:23:431081 if (!expected_id.empty() && expected_id != extension.id()) {
[email protected]25b34332009-06-05 21:53:191082 std::string error_msg = "ID in new extension manifest (";
1083 error_msg += extension.id();
1084 error_msg += ") does not match expected ID (";
1085 error_msg += expected_id;
1086 error_msg += ")";
1087 ReportExtensionInstallError(extension_path, error_msg);
[email protected]1fca1492009-05-15 22:23:431088 return;
[email protected]cc655912009-01-29 23:19:191089 }
1090
1091 // <profile>/Extensions/<id>
[email protected]b0beaa662009-02-26 00:04:151092 FilePath dest_dir = install_directory_.AppendASCII(extension.id());
[email protected]cc655912009-01-29 23:19:191093 std::string version = extension.VersionString();
[email protected]b0beaa662009-02-26 00:04:151094 std::string current_version;
[email protected]fbcc40302009-06-12 20:45:451095 Extension::InstallType install_type =
1096 CompareToInstalledVersion(extension.id(), version, &current_version);
1097
1098 // Do not allow downgrade.
1099 if (install_type == Extension::DOWNGRADE) {
1100 ReportExtensionInstallError(extension_path,
1101 "Error: Attempt to downgrade extension from more recent version.");
1102 return;
1103 }
1104
1105 if (install_type == Extension::REINSTALL) {
1106 if (NeedsReinstall(extension.id(), current_version)) {
1107 // Treat corrupted existing installation as new install case.
1108 install_type = Extension::NEW_INSTALL;
1109 } else {
1110 // The client may use this as a signal (to switch themes, for instance).
1111 ReportExtensionOverinstallAttempted(extension.id());
[email protected]1fca1492009-05-15 22:23:431112 return;
[email protected]fbcc40302009-06-12 20:45:451113 }
[email protected]b0beaa662009-02-26 00:04:151114 }
[email protected]cc655912009-01-29 23:19:191115
[email protected]902f7cd2009-05-22 19:02:191116 // Write our parsed manifest back to disk, to ensure it doesn't contain an
1117 // exploitable bug that can be used to compromise the browser.
1118 std::string manifest_json;
1119 JSONStringValueSerializer serializer(&manifest_json);
1120 serializer.set_pretty_print(true);
1121 if (!serializer.Serialize(manifest)) {
1122 ReportExtensionInstallError(extension_path,
1123 "Error serializing manifest.json.");
1124 return;
1125 }
1126
1127 FilePath manifest_path =
1128 temp_extension_dir.AppendASCII(Extension::kManifestFilename);
1129 if (!file_util::WriteFile(manifest_path,
1130 manifest_json.data(), manifest_json.size())) {
1131 ReportExtensionInstallError(extension_path, "Error saving manifest.json.");
1132 return;
1133 }
1134
[email protected]facd7a7652009-06-05 23:15:021135 // Delete any images that may be used by the browser. We're going to write
1136 // out our own versions of the parsed images, and we want to make sure the
1137 // originals are gone for good.
1138 std::set<FilePath> image_paths = extension.GetBrowserImages();
1139 if (image_paths.size() != images.size()) {
1140 ReportExtensionInstallError(extension_path,
1141 "Decoded images don't match what's in the manifest.");
1142 return;
1143 }
1144
1145 for (std::set<FilePath>::iterator it = image_paths.begin();
1146 it != image_paths.end(); ++it) {
1147 if (!file_util::Delete(temp_extension_dir.Append(*it), false)) {
1148 ReportExtensionInstallError(extension_path,
1149 "Error removing old image file.");
1150 return;
1151 }
1152 }
1153
[email protected]902f7cd2009-05-22 19:02:191154 // Write our parsed images back to disk as well.
1155 for (size_t i = 0; i < images.size(); ++i) {
1156 const SkBitmap& image = images[i].a;
1157 FilePath path = temp_extension_dir.Append(images[i].b);
1158
1159 std::vector<unsigned char> image_data;
1160 // TODO(mpcomplete): It's lame that we're encoding all images as PNG, even
1161 // though they may originally be .jpg, etc. Figure something out.
1162 // http://code.google.com/p/chromium/issues/detail?id=12459
1163 if (!PNGEncoder::EncodeBGRASkBitmap(image, false, &image_data)) {
1164 ReportExtensionInstallError(extension_path,
1165 "Error re-encoding theme image.");
1166 return;
1167 }
1168
1169 // Note: we're overwriting existing files that the utility process wrote,
1170 // so we can be sure the directory exists.
1171 const char* image_data_ptr = reinterpret_cast<const char*>(&image_data[0]);
1172 if (!file_util::WriteFile(path, image_data_ptr, image_data.size())) {
1173 ReportExtensionInstallError(extension_path, "Error saving theme image.");
1174 return;
1175 }
1176 }
1177
[email protected]cc655912009-01-29 23:19:191178 // <profile>/Extensions/<dir_name>/<version>
[email protected]1fca1492009-05-15 22:23:431179 FilePath version_dir = dest_dir.AppendASCII(version);
[email protected]902f7cd2009-05-22 19:02:191180
1181 // If anything fails after this, we want to delete the extension dir.
1182 ScopedTempDir scoped_version_dir;
1183 scoped_version_dir.Set(version_dir);
1184
[email protected]1fca1492009-05-15 22:23:431185 if (!InstallDirSafely(temp_extension_dir, version_dir))
1186 return;
[email protected]cc655912009-01-29 23:19:191187
[email protected]902f7cd2009-05-22 19:02:191188 if (!SetCurrentVersion(dest_dir, version))
[email protected]1fca1492009-05-15 22:23:431189 return;
[email protected]cc655912009-01-29 23:19:191190
[email protected]a1257b12009-06-12 02:51:341191 Extension::Location location = Extension::INVALID;
1192 if (from_external)
1193 LookupExternalExtension(extension.id(), NULL, &location);
1194 else
1195 location = Extension::INTERNAL;
[email protected]1fca1492009-05-15 22:23:431196
[email protected]894bb502009-05-21 22:39:571197 // Load the extension immediately and then report installation success. We
1198 // don't load extensions for external installs because external installation
1199 // occurs before the normal startup so we just let startup pick them up. We
[email protected]25b34332009-06-05 21:53:191200 // notify on installation of external extensions because we need to update
1201 // the preferences for these extensions to reflect that they've just been
1202 // installed.
[email protected]894bb502009-05-21 22:39:571203 if (!from_external) {
[email protected]a1257b12009-06-12 02:51:341204 Extension* extension = LoadExtension(version_dir,
1205 location,
1206 true); // require id
[email protected]894bb502009-05-21 22:39:571207 CHECK(extension);
1208
1209 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
1210 frontend_, &ExtensionsService::OnExtensionInstalled, extension,
[email protected]fbcc40302009-06-12 20:45:451211 install_type));
[email protected]894bb502009-05-21 22:39:571212
1213 // Only one extension, but ReportExtensionsLoaded can handle multiple,
1214 // so we need to construct a list.
1215 scoped_ptr<ExtensionList> extensions(new ExtensionList);
1216 extensions->push_back(extension);
1217 LOG(INFO) << "Done.";
1218 // Hand off ownership of the loaded extensions to the frontend.
1219 ReportExtensionsLoaded(extensions.release());
[email protected]25b34332009-06-05 21:53:191220 } else {
1221 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
1222 frontend_, &ExtensionsService::OnExternalExtensionInstalled,
[email protected]a1257b12009-06-12 02:51:341223 extension.id(), location));
[email protected]894bb502009-05-21 22:39:571224 }
[email protected]902f7cd2009-05-22 19:02:191225
1226 scoped_version_dir.Take();
[email protected]cc655912009-01-29 23:19:191227}
1228
1229void ExtensionsServiceBackend::ReportExtensionInstallError(
[email protected]cc5da332009-03-04 08:02:511230 const FilePath& extension_path, const std::string &error) {
[email protected]b0beaa662009-02-26 00:04:151231
[email protected]cc655912009-01-29 23:19:191232 // TODO(erikkay): note that this isn't guaranteed to work properly on Linux.
[email protected]cc5da332009-03-04 08:02:511233 std::string path_str = WideToASCII(extension_path.ToWStringHack());
[email protected]cc655912009-01-29 23:19:191234 std::string message =
1235 StringPrintf("Could not install extension from '%s'. %s",
1236 path_str.c_str(), error.c_str());
[email protected]bb28e062009-02-27 17:19:181237 ExtensionErrorReporter::GetInstance()->ReportError(message, alert_on_error_);
[email protected]cc655912009-01-29 23:19:191238}
1239
[email protected]fbcc40302009-06-12 20:45:451240void ExtensionsServiceBackend::ReportExtensionOverinstallAttempted(
[email protected]4a190632009-05-09 01:07:421241 const std::string& id) {
[email protected]894bb502009-05-21 22:39:571242 frontend_loop_->PostTask(FROM_HERE, NewRunnableMethod(
[email protected]fbcc40302009-06-12 20:45:451243 frontend_, &ExtensionsService::OnExtensionOverinstallAttempted, id));
[email protected]b0beaa662009-02-26 00:04:151244}
1245
[email protected]25b34332009-06-05 21:53:191246bool ExtensionsServiceBackend::ShouldSkipInstallingExtension(
1247 const std::set<std::string>& ids_to_ignore,
1248 const std::string& id) {
1249 if (ids_to_ignore.find(id) != ids_to_ignore.end()) {
1250 LOG(INFO) << "Skipping uninstalled external extension " << id;
1251 return true;
1252 }
1253 return false;
1254}
1255
1256void ExtensionsServiceBackend::CheckVersionAndInstallExtension(
[email protected]a1257b12009-06-12 02:51:341257 const std::string& id, const Version* extension_version,
[email protected]25b34332009-06-05 21:53:191258 const FilePath& extension_path, bool from_external) {
1259 if (ShouldInstall(id, extension_version))
1260 InstallOrUpdateExtension(FilePath(extension_path), id, from_external);
1261}
1262
[email protected]a1257b12009-06-12 02:51:341263bool ExtensionsServiceBackend::LookupExternalExtension(
1264 const std::string& id, Version** version, Extension::Location* location) {
1265 scoped_ptr<Version> extension_version;
1266 for (ProviderMap::const_iterator i = external_extension_providers_.begin();
1267 i != external_extension_providers_.end(); ++i) {
1268 const ExternalExtensionProvider* provider = i->second;
1269 extension_version.reset(provider->RegisteredVersion(id, location));
1270 if (extension_version.get()) {
1271 if (version)
1272 *version = extension_version.release();
1273 return true;
1274 }
1275 }
1276 return false;
1277}
1278
[email protected]b0beaa662009-02-26 00:04:151279// Some extensions will autoupdate themselves externally from Chrome. These
1280// are typically part of some larger client application package. To support
[email protected]25b34332009-06-05 21:53:191281// these, the extension will register its location in the the preferences file
1282// (and also, on Windows, in the registry) and this code will periodically
[email protected]b0beaa662009-02-26 00:04:151283// check that location for a .crx file, which it will then install locally if
1284// a new version is available.
1285void ExtensionsServiceBackend::CheckForExternalUpdates(
[email protected]894bb502009-05-21 22:39:571286 std::set<std::string> ids_to_ignore,
1287 scoped_refptr<ExtensionsService> frontend) {
[email protected]b0beaa662009-02-26 00:04:151288 // Note that this installation is intentionally silent (since it didn't
1289 // go through the front-end). Extensions that are registered in this
1290 // way are effectively considered 'pre-bundled', and so implicitly
1291 // trusted. In general, if something has HKLM or filesystem access,
1292 // they could install an extension manually themselves anyway.
1293 alert_on_error_ = false;
1294 frontend_ = frontend;
[email protected]b0beaa662009-02-26 00:04:151295
[email protected]a1257b12009-06-12 02:51:341296 // Ask each external extension provider to give us a call back for each
1297 // extension they know about. See OnExternalExtensionFound.
1298 for (ProviderMap::const_iterator i = external_extension_providers_.begin();
1299 i != external_extension_providers_.end(); ++i) {
1300 ExternalExtensionProvider* provider = i->second;
1301 provider->VisitRegisteredExtension(this, ids_to_ignore);
[email protected]25b34332009-06-05 21:53:191302 }
[email protected]b0beaa662009-02-26 00:04:151303}
1304
[email protected]25b34332009-06-05 21:53:191305bool ExtensionsServiceBackend::CheckExternalUninstall(
1306 DictionaryValue* extension_prefs, const FilePath& version_path,
1307 const std::string& id) {
1308 // First check the preferences for the kill-bit.
[email protected]a1257b12009-06-12 02:51:341309 int location_value = Extension::INVALID;
[email protected]25b34332009-06-05 21:53:191310 DictionaryValue* extension = NULL;
[email protected]a1257b12009-06-12 02:51:341311 if (!extension_prefs->GetDictionary(ASCIIToWide(id), &extension))
1312 return false;
1313 int state;
1314 if (extension->GetInteger(kLocation, &location_value) &&
1315 location_value == Extension::EXTERNAL_PREF) {
1316 return extension->GetInteger(kState, &state) &&
1317 state == Extension::KILLBIT;
[email protected]25b34332009-06-05 21:53:191318 }
1319
[email protected]a1257b12009-06-12 02:51:341320 Extension::Location location =
1321 static_cast<Extension::Location>(location_value);
[email protected]b0beaa662009-02-26 00:04:151322
[email protected]a1257b12009-06-12 02:51:341323 // Check if the providers know about this extension.
1324 ProviderMap::const_iterator i = external_extension_providers_.find(location);
1325 if (i != external_extension_providers_.end()) {
1326 scoped_ptr<Version> version;
1327 version.reset(i->second->RegisteredVersion(id, NULL));
1328 if (version.get())
1329 return false; // Yup, known extension, don't uninstall.
[email protected]b0beaa662009-02-26 00:04:151330 }
[email protected]25b34332009-06-05 21:53:191331
[email protected]a1257b12009-06-12 02:51:341332 return true; // This is not a known extension, uninstall.
[email protected]b0beaa662009-02-26 00:04:151333}
1334
1335// Assumes that the extension isn't currently loaded or in use.
[email protected]631cf822009-05-15 07:01:251336void ExtensionsServiceBackend::UninstallExtension(
1337 const std::string& extension_id) {
1338 // First, delete the Current Version file. If the directory delete fails, then
1339 // at least the extension won't be loaded again.
1340 FilePath extension_directory = install_directory_.AppendASCII(extension_id);
1341
1342 if (!file_util::PathExists(extension_directory)) {
1343 LOG(WARNING) << "Asked to remove a non-existent extension " << extension_id;
[email protected]b0beaa662009-02-26 00:04:151344 return;
1345 }
[email protected]631cf822009-05-15 07:01:251346
1347 FilePath current_version_file = extension_directory.AppendASCII(
1348 ExtensionsService::kCurrentVersionFileName);
1349 if (!file_util::PathExists(current_version_file)) {
1350 LOG(WARNING) << "Extension " << extension_id
1351 << " does not have a Current Version file.";
1352 } else {
1353 if (!file_util::Delete(current_version_file, false)) {
1354 LOG(WARNING) << "Could not delete Current Version file for extension "
1355 << extension_id;
1356 return;
1357 }
1358 }
1359
[email protected]a1257b12009-06-12 02:51:341360 // OK, now try and delete the entire rest of the directory. One major place
[email protected]894bb502009-05-21 22:39:571361 // this can fail is if the extension contains a plugin (stupid plugins). It's
1362 // not a big deal though, because we'll notice next time we startup that the
1363 // Current Version file is gone and finish the delete then.
[email protected]631cf822009-05-15 07:01:251364 if (!file_util::Delete(extension_directory, true)) {
1365 LOG(WARNING) << "Could not delete directory for extension "
1366 << extension_id;
[email protected]b0beaa662009-02-26 00:04:151367 }
1368}
1369
[email protected]a1257b12009-06-12 02:51:341370void ExtensionsServiceBackend::ClearProvidersForTesting() {
[email protected]3e5f3e92009-06-12 05:05:411371 STLDeleteContainerPairSecondPointers(external_extension_providers_.begin(),
1372 external_extension_providers_.end());
[email protected]a1257b12009-06-12 02:51:341373 external_extension_providers_.clear();
1374}
1375
1376void ExtensionsServiceBackend::SetProviderForTesting(
1377 Extension::Location location,
1378 ExternalExtensionProvider* test_provider) {
1379 DCHECK(test_provider);
1380 external_extension_providers_[location] = test_provider;
1381}
1382
1383void ExtensionsServiceBackend::OnExternalExtensionFound(
1384 const std::string& id, const Version* version, const FilePath& path) {
1385 bool from_external = true;
1386 CheckVersionAndInstallExtension(id, version, path, from_external);
1387}
1388
[email protected]b0beaa662009-02-26 00:04:151389bool ExtensionsServiceBackend::ShouldInstall(const std::string& id,
[email protected]a1257b12009-06-12 02:51:341390 const Version* version) {
[email protected]b0beaa662009-02-26 00:04:151391 std::string current_version;
[email protected]fbcc40302009-06-12 20:45:451392 Extension::InstallType install_type =
1393 CompareToInstalledVersion(id, version->GetString(), &current_version);
1394
1395 if (install_type == Extension::DOWNGRADE)
1396 return false;
1397
1398 return (install_type == Extension::UPGRADE ||
1399 install_type == Extension::NEW_INSTALL ||
1400 NeedsReinstall(id, current_version));
[email protected]cc655912009-01-29 23:19:191401}