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/api/management/management_api.h" 6 7 #include <string> 8 #include <vector> 9 10 #include "base/basictypes.h" 11 #include "base/bind.h" 12 #include "base/json/json_writer.h" 13 #include "base/lazy_instance.h" 14 #include "base/logging.h" 15 #include "base/memory/linked_ptr.h" 16 #include "base/memory/scoped_ptr.h" 17 #include "base/metrics/histogram.h" 18 #include "base/strings/string_number_conversions.h" 19 #include "base/strings/string_util.h" 20 #include "base/strings/utf_string_conversions.h" 21 #include "chrome/browser/extensions/api/management/management_api_constants.h" 22 #include "chrome/browser/extensions/extension_service.h" 23 #include "chrome/browser/extensions/extension_ui_util.h" 24 #include "chrome/browser/extensions/extension_uninstall_dialog.h" 25 #include "chrome/browser/extensions/launch_util.h" 26 #include "chrome/browser/favicon/favicon_service_factory.h" 27 #include "chrome/browser/profiles/profile.h" 28 #include "chrome/browser/ui/browser_dialogs.h" 29 #include "chrome/browser/ui/browser_finder.h" 30 #include "chrome/browser/ui/browser_window.h" 31 #include "chrome/browser/ui/extensions/application_launch.h" 32 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 33 #include "chrome/common/chrome_switches.h" 34 #include "chrome/common/chrome_utility_messages.h" 35 #include "chrome/common/extensions/api/management.h" 36 #include "chrome/common/extensions/extension_constants.h" 37 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h" 38 #include "chrome/common/extensions/manifest_url_handler.h" 39 #include "content/public/browser/utility_process_host.h" 40 #include "content/public/browser/utility_process_host_client.h" 41 #include "extensions/browser/event_router.h" 42 #include "extensions/browser/extension_prefs.h" 43 #include "extensions/browser/extension_registry.h" 44 #include "extensions/browser/extension_system.h" 45 #include "extensions/browser/management_policy.h" 46 #include "extensions/common/constants.h" 47 #include "extensions/common/error_utils.h" 48 #include "extensions/common/extension.h" 49 #include "extensions/common/extension_icon_set.h" 50 #include "extensions/common/manifest_handlers/icons_handler.h" 51 #include "extensions/common/manifest_handlers/offline_enabled_info.h" 52 #include "extensions/common/permissions/permission_set.h" 53 #include "extensions/common/permissions/permissions_data.h" 54 #include "extensions/common/url_pattern.h" 55 #include "ui/gfx/favicon_size.h" 56 57 #if !defined(OS_ANDROID) 58 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h" 59 #endif 60 61 using base::IntToString; 62 using content::BrowserThread; 63 using content::UtilityProcessHost; 64 using content::UtilityProcessHostClient; 65 66 namespace keys = extension_management_api_constants; 67 68 namespace extensions { 69 70 namespace management = api::management; 71 72 namespace { 73 74 typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList; 75 typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList; 76 77 enum AutoConfirmForTest { 78 DO_NOT_SKIP = 0, 79 PROCEED, 80 ABORT 81 }; 82 83 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP; 84 85 std::vector<std::string> CreateWarningsList(const Extension* extension) { 86 std::vector<std::string> warnings_list; 87 PermissionMessages warnings = 88 extension->permissions_data()->GetPermissionMessages(); 89 for (PermissionMessages::const_iterator iter = warnings.begin(); 90 iter != warnings.end(); ++iter) { 91 warnings_list.push_back(base::UTF16ToUTF8(iter->message())); 92 } 93 94 return warnings_list; 95 } 96 97 std::vector<management::LaunchType> GetAvailableLaunchTypes( 98 const Extension& extension) { 99 std::vector<management::LaunchType> launch_type_list; 100 if (extension.is_platform_app()) { 101 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW); 102 return launch_type_list; 103 } 104 105 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB); 106 107 #if !defined(OS_MACOSX) 108 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW); 109 #endif 110 111 if (!CommandLine::ForCurrentProcess()->HasSwitch( 112 switches::kEnableStreamlinedHostedApps)) { 113 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB); 114 launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN); 115 } 116 return launch_type_list; 117 } 118 119 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo( 120 const Extension& extension, 121 ExtensionSystem* system) { 122 scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo()); 123 ExtensionService* service = system->extension_service(); 124 125 info->id = extension.id(); 126 info->name = extension.name(); 127 info->short_name = extension.short_name(); 128 info->enabled = service->IsExtensionEnabled(info->id); 129 info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension); 130 info->version = extension.VersionString(); 131 info->description = extension.description(); 132 info->options_url = ManifestURL::GetOptionsPage(&extension).spec(); 133 info->homepage_url.reset(new std::string( 134 ManifestURL::GetHomepageURL(&extension).spec())); 135 info->may_disable = system->management_policy()-> 136 UserMayModifySettings(&extension, NULL); 137 info->is_app = extension.is_app(); 138 if (info->is_app) { 139 if (extension.is_legacy_packaged_app()) 140 info->type = management::ExtensionInfo::TYPE_LEGACY_PACKAGED_APP; 141 else if (extension.is_hosted_app()) 142 info->type = management::ExtensionInfo::TYPE_HOSTED_APP; 143 else 144 info->type = management::ExtensionInfo::TYPE_PACKAGED_APP; 145 } else if (extension.is_theme()) { 146 info->type = management::ExtensionInfo::TYPE_THEME; 147 } else { 148 info->type = management::ExtensionInfo::TYPE_EXTENSION; 149 } 150 151 if (info->enabled) { 152 info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE; 153 } else { 154 ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile()); 155 if (prefs->DidExtensionEscalatePermissions(extension.id())) { 156 info->disabled_reason = 157 management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE; 158 } else { 159 info->disabled_reason = 160 management::ExtensionInfo::DISABLED_REASON_UNKNOWN; 161 } 162 } 163 164 if (!ManifestURL::GetUpdateURL(&extension).is_empty()) { 165 info->update_url.reset(new std::string( 166 ManifestURL::GetUpdateURL(&extension).spec())); 167 } 168 169 if (extension.is_app()) { 170 info->app_launch_url.reset(new std::string( 171 AppLaunchInfo::GetFullLaunchURL(&extension).spec())); 172 } 173 174 const ExtensionIconSet::IconMap& icons = 175 IconsInfo::GetIcons(&extension).map(); 176 if (!icons.empty()) { 177 info->icons.reset(new IconInfoList()); 178 ExtensionIconSet::IconMap::const_iterator icon_iter; 179 for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) { 180 management::IconInfo* icon_info = new management::IconInfo(); 181 icon_info->size = icon_iter->first; 182 GURL url = ExtensionIconSource::GetIconURL( 183 &extension, icon_info->size, ExtensionIconSet::MATCH_EXACTLY, false, 184 NULL); 185 icon_info->url = url.spec(); 186 info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info)); 187 } 188 } 189 190 const std::set<std::string> perms = 191 extension.permissions_data()->active_permissions()->GetAPIsAsStrings(); 192 if (!perms.empty()) { 193 std::set<std::string>::const_iterator perms_iter; 194 for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter) 195 info->permissions.push_back(*perms_iter); 196 } 197 198 if (!extension.is_hosted_app()) { 199 // Skip host permissions for hosted apps. 200 const URLPatternSet host_perms = 201 extension.permissions_data()->active_permissions()->explicit_hosts(); 202 if (!host_perms.is_empty()) { 203 for (URLPatternSet::const_iterator iter = host_perms.begin(); 204 iter != host_perms.end(); ++iter) { 205 info->host_permissions.push_back(iter->GetAsString()); 206 } 207 } 208 } 209 210 switch (extension.location()) { 211 case Manifest::INTERNAL: 212 info->install_type = management::ExtensionInfo::INSTALL_TYPE_NORMAL; 213 break; 214 case Manifest::UNPACKED: 215 case Manifest::COMMAND_LINE: 216 info->install_type = management::ExtensionInfo::INSTALL_TYPE_DEVELOPMENT; 217 break; 218 case Manifest::EXTERNAL_PREF: 219 case Manifest::EXTERNAL_REGISTRY: 220 case Manifest::EXTERNAL_PREF_DOWNLOAD: 221 info->install_type = management::ExtensionInfo::INSTALL_TYPE_SIDELOAD; 222 break; 223 case Manifest::EXTERNAL_POLICY: 224 case Manifest::EXTERNAL_POLICY_DOWNLOAD: 225 info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN; 226 break; 227 case Manifest::NUM_LOCATIONS: 228 NOTREACHED(); 229 case Manifest::INVALID_LOCATION: 230 case Manifest::COMPONENT: 231 case Manifest::EXTERNAL_COMPONENT: 232 info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER; 233 break; 234 } 235 236 info->launch_type = management::LAUNCH_TYPE_NONE; 237 if (extension.is_app()) { 238 LaunchType launch_type; 239 if (extension.is_platform_app()) { 240 launch_type = LAUNCH_TYPE_WINDOW; 241 } else { 242 launch_type = 243 GetLaunchType(ExtensionPrefs::Get(service->profile()), &extension); 244 } 245 246 switch (launch_type) { 247 case LAUNCH_TYPE_PINNED: 248 info->launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB; 249 break; 250 case LAUNCH_TYPE_REGULAR: 251 info->launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB; 252 break; 253 case LAUNCH_TYPE_FULLSCREEN: 254 info->launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN; 255 break; 256 case LAUNCH_TYPE_WINDOW: 257 info->launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW; 258 break; 259 case LAUNCH_TYPE_INVALID: 260 case NUM_LAUNCH_TYPES: 261 NOTREACHED(); 262 } 263 264 info->available_launch_types.reset(new std::vector<management::LaunchType>( 265 GetAvailableLaunchTypes(extension))); 266 } 267 268 return info.Pass(); 269 } 270 271 void AddExtensionInfo(const ExtensionSet& extensions, 272 ExtensionSystem* system, 273 ExtensionInfoList* extension_list, 274 content::BrowserContext* context) { 275 for (ExtensionSet::const_iterator iter = extensions.begin(); 276 iter != extensions.end(); ++iter) { 277 const Extension& extension = *iter->get(); 278 279 if (ui_util::ShouldNotBeVisible(&extension, context)) 280 continue; // Skip built-in extensions/apps. 281 282 extension_list->push_back(make_linked_ptr<management::ExtensionInfo>( 283 CreateExtensionInfo(extension, system).release())); 284 } 285 } 286 287 } // namespace 288 289 ExtensionService* ManagementFunction::service() { 290 return GetProfile()->GetExtensionService(); 291 } 292 293 ExtensionService* AsyncManagementFunction::service() { 294 return GetProfile()->GetExtensionService(); 295 } 296 297 bool ManagementGetAllFunction::RunSync() { 298 ExtensionInfoList extensions; 299 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile()); 300 ExtensionSystem* system = ExtensionSystem::Get(GetProfile()); 301 302 AddExtensionInfo(registry->enabled_extensions(), 303 system, &extensions, browser_context()); 304 AddExtensionInfo(registry->disabled_extensions(), 305 system, &extensions, browser_context()); 306 AddExtensionInfo(registry->terminated_extensions(), 307 system, &extensions, browser_context()); 308 309 results_ = management::GetAll::Results::Create(extensions); 310 return true; 311 } 312 313 bool ManagementGetFunction::RunSync() { 314 scoped_ptr<management::Get::Params> params( 315 management::Get::Params::Create(*args_)); 316 EXTENSION_FUNCTION_VALIDATE(params.get()); 317 318 const Extension* extension = service()->GetExtensionById(params->id, true); 319 if (!extension) { 320 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 321 params->id); 322 return false; 323 } 324 325 scoped_ptr<management::ExtensionInfo> info = 326 CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile())); 327 results_ = management::Get::Results::Create(*info); 328 329 return true; 330 } 331 332 bool ManagementGetPermissionWarningsByIdFunction::RunSync() { 333 scoped_ptr<management::GetPermissionWarningsById::Params> params( 334 management::GetPermissionWarningsById::Params::Create(*args_)); 335 EXTENSION_FUNCTION_VALIDATE(params.get()); 336 337 const Extension* extension = service()->GetExtensionById(params->id, true); 338 if (!extension) { 339 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 340 params->id); 341 return false; 342 } 343 344 std::vector<std::string> warnings = CreateWarningsList(extension); 345 results_ = management::GetPermissionWarningsById::Results::Create(warnings); 346 return true; 347 } 348 349 namespace { 350 351 // This class helps ManagementGetPermissionWarningsByManifestFunction manage 352 // sending manifest JSON strings to the utility process for parsing. 353 class SafeManifestJSONParser : public UtilityProcessHostClient { 354 public: 355 SafeManifestJSONParser( 356 ManagementGetPermissionWarningsByManifestFunction* client, 357 const std::string& manifest) 358 : client_(client), 359 manifest_(manifest) {} 360 361 void Start() { 362 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 363 BrowserThread::PostTask( 364 BrowserThread::IO, 365 FROM_HERE, 366 base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this)); 367 } 368 369 void StartWorkOnIOThread() { 370 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 371 UtilityProcessHost* host = UtilityProcessHost::Create( 372 this, base::MessageLoopProxy::current().get()); 373 host->Send(new ChromeUtilityMsg_ParseJSON(manifest_)); 374 } 375 376 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 377 bool handled = true; 378 IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message) 379 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded, 380 OnJSONParseSucceeded) 381 IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed, 382 OnJSONParseFailed) 383 IPC_MESSAGE_UNHANDLED(handled = false) 384 IPC_END_MESSAGE_MAP() 385 return handled; 386 } 387 388 void OnJSONParseSucceeded(const base::ListValue& wrapper) { 389 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 390 const base::Value* value = NULL; 391 CHECK(wrapper.Get(0, &value)); 392 if (value->IsType(base::Value::TYPE_DICTIONARY)) 393 parsed_manifest_.reset( 394 static_cast<const base::DictionaryValue*>(value)->DeepCopy()); 395 else 396 error_ = keys::kManifestParseError; 397 398 BrowserThread::PostTask( 399 BrowserThread::UI, 400 FROM_HERE, 401 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this)); 402 } 403 404 void OnJSONParseFailed(const std::string& error) { 405 CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 406 error_ = error; 407 BrowserThread::PostTask( 408 BrowserThread::UI, 409 FROM_HERE, 410 base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this)); 411 } 412 413 void ReportResultFromUIThread() { 414 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 415 if (error_.empty() && parsed_manifest_.get()) 416 client_->OnParseSuccess(parsed_manifest_.Pass()); 417 else 418 client_->OnParseFailure(error_); 419 } 420 421 private: 422 virtual ~SafeManifestJSONParser() {} 423 424 // The client who we'll report results back to. 425 ManagementGetPermissionWarningsByManifestFunction* client_; 426 427 // Data to parse. 428 std::string manifest_; 429 430 // Results of parsing. 431 scoped_ptr<base::DictionaryValue> parsed_manifest_; 432 433 std::string error_; 434 }; 435 436 } // namespace 437 438 bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() { 439 scoped_ptr<management::GetPermissionWarningsByManifest::Params> params( 440 management::GetPermissionWarningsByManifest::Params::Create(*args_)); 441 EXTENSION_FUNCTION_VALIDATE(params.get()); 442 443 scoped_refptr<SafeManifestJSONParser> parser = 444 new SafeManifestJSONParser(this, params->manifest_str); 445 parser->Start(); 446 447 // Matched with a Release() in OnParseSuccess/Failure(). 448 AddRef(); 449 450 // Response is sent async in OnParseSuccess/Failure(). 451 return true; 452 } 453 454 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess( 455 scoped_ptr<base::DictionaryValue> parsed_manifest) { 456 CHECK(parsed_manifest.get()); 457 458 scoped_refptr<Extension> extension = Extension::Create( 459 base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest, 460 Extension::NO_FLAGS, &error_); 461 if (!extension.get()) { 462 OnParseFailure(keys::kExtensionCreateError); 463 return; 464 } 465 466 std::vector<std::string> warnings = CreateWarningsList(extension.get()); 467 results_ = 468 management::GetPermissionWarningsByManifest::Results::Create(warnings); 469 SendResponse(true); 470 471 // Matched with AddRef() in RunAsync(). 472 Release(); 473 } 474 475 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure( 476 const std::string& error) { 477 error_ = error; 478 SendResponse(false); 479 480 // Matched with AddRef() in RunAsync(). 481 Release(); 482 } 483 484 bool ManagementLaunchAppFunction::RunSync() { 485 scoped_ptr<management::LaunchApp::Params> params( 486 management::LaunchApp::Params::Create(*args_)); 487 EXTENSION_FUNCTION_VALIDATE(params.get()); 488 const Extension* extension = service()->GetExtensionById(params->id, true); 489 if (!extension) { 490 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 491 params->id); 492 return false; 493 } 494 if (!extension->is_app()) { 495 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, 496 params->id); 497 return false; 498 } 499 500 // Look at prefs to find the right launch container. 501 // If the user has not set a preference, the default launch value will be 502 // returned. 503 LaunchContainer launch_container = 504 GetLaunchContainer(ExtensionPrefs::Get(GetProfile()), extension); 505 OpenApplication(AppLaunchParams( 506 GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB)); 507 #if !defined(OS_ANDROID) 508 CoreAppLauncherHandler::RecordAppLaunchType( 509 extension_misc::APP_LAUNCH_EXTENSION_API, 510 extension->GetType()); 511 #endif 512 513 return true; 514 } 515 516 ManagementSetEnabledFunction::ManagementSetEnabledFunction() { 517 } 518 519 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() { 520 } 521 522 bool ManagementSetEnabledFunction::RunAsync() { 523 scoped_ptr<management::SetEnabled::Params> params( 524 management::SetEnabled::Params::Create(*args_)); 525 EXTENSION_FUNCTION_VALIDATE(params.get()); 526 527 extension_id_ = params->id; 528 529 const Extension* extension = 530 ExtensionRegistry::Get(GetProfile()) 531 ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING); 532 if (!extension || ui_util::ShouldNotBeVisible(extension, browser_context())) { 533 error_ = ErrorUtils::FormatErrorMessage( 534 keys::kNoExtensionError, extension_id_); 535 return false; 536 } 537 538 const ManagementPolicy* policy = 539 ExtensionSystem::Get(GetProfile())->management_policy(); 540 if (!policy->UserMayModifySettings(extension, NULL) || 541 (!params->enabled && policy->MustRemainEnabled(extension, NULL)) || 542 (params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) { 543 error_ = ErrorUtils::FormatErrorMessage( 544 keys::kUserCantModifyError, extension_id_); 545 return false; 546 } 547 548 bool currently_enabled = service()->IsExtensionEnabled(extension_id_); 549 550 if (!currently_enabled && params->enabled) { 551 ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile()); 552 if (prefs->DidExtensionEscalatePermissions(extension_id_)) { 553 if (!user_gesture()) { 554 error_ = keys::kGestureNeededForEscalationError; 555 return false; 556 } 557 AddRef(); // Matched in InstallUIProceed/InstallUIAbort 558 install_prompt_.reset( 559 new ExtensionInstallPrompt(GetAssociatedWebContents())); 560 install_prompt_->ConfirmReEnable(this, extension); 561 return true; 562 } 563 service()->EnableExtension(extension_id_); 564 } else if (currently_enabled && !params->enabled) { 565 service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION); 566 } 567 568 BrowserThread::PostTask( 569 BrowserThread::UI, 570 FROM_HERE, 571 base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true)); 572 573 return true; 574 } 575 576 void ManagementSetEnabledFunction::InstallUIProceed() { 577 service()->EnableExtension(extension_id_); 578 SendResponse(true); 579 Release(); 580 } 581 582 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) { 583 error_ = keys::kUserDidNotReEnableError; 584 SendResponse(false); 585 Release(); 586 } 587 588 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() { 589 } 590 591 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() { 592 } 593 594 bool ManagementUninstallFunctionBase::Uninstall( 595 const std::string& target_extension_id, 596 bool show_confirm_dialog) { 597 extension_id_ = target_extension_id; 598 const Extension* target_extension = 599 service()->GetExtensionById(extension_id_, true); 600 if (!target_extension || 601 ui_util::ShouldNotBeVisible(target_extension, browser_context())) { 602 error_ = ErrorUtils::FormatErrorMessage( 603 keys::kNoExtensionError, extension_id_); 604 return false; 605 } 606 607 if (!ExtensionSystem::Get(GetProfile()) 608 ->management_policy() 609 ->UserMayModifySettings(target_extension, NULL)) { 610 error_ = ErrorUtils::FormatErrorMessage( 611 keys::kUserCantModifyError, extension_id_); 612 return false; 613 } 614 615 if (auto_confirm_for_test == DO_NOT_SKIP) { 616 if (show_confirm_dialog) { 617 AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled 618 extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create( 619 GetProfile(), GetCurrentBrowser(), this)); 620 if (extension_id() != target_extension_id) { 621 extension_uninstall_dialog_->ConfirmProgrammaticUninstall( 622 target_extension, GetExtension()); 623 } else { 624 // If this is a self uninstall, show the generic uninstall dialog. 625 extension_uninstall_dialog_->ConfirmUninstall(target_extension); 626 } 627 } else { 628 Finish(true); 629 } 630 } else { 631 Finish(auto_confirm_for_test == PROCEED); 632 } 633 634 return true; 635 } 636 637 // static 638 void ManagementUninstallFunctionBase::SetAutoConfirmForTest( 639 bool should_proceed) { 640 auto_confirm_for_test = should_proceed ? PROCEED : ABORT; 641 } 642 643 void ManagementUninstallFunctionBase::Finish(bool should_uninstall) { 644 if (should_uninstall) { 645 // The extension can be uninstalled in another window while the UI was 646 // showing. Do nothing in that case. 647 ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile()); 648 const Extension* extension = registry->GetExtensionById( 649 extension_id_, ExtensionRegistry::EVERYTHING); 650 if (!extension) { 651 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 652 extension_id_); 653 SendResponse(false); 654 } else { 655 bool success = 656 service()->UninstallExtension(extension_id_, 657 false, /* external uninstall */ 658 NULL); 659 660 // TODO set error_ if !success 661 SendResponse(success); 662 } 663 } else { 664 error_ = ErrorUtils::FormatErrorMessage( 665 keys::kUninstallCanceledError, extension_id_); 666 SendResponse(false); 667 } 668 669 } 670 671 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() { 672 Finish(true); 673 Release(); 674 } 675 676 void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() { 677 Finish(false); 678 Release(); 679 } 680 681 ManagementUninstallFunction::ManagementUninstallFunction() { 682 } 683 684 ManagementUninstallFunction::~ManagementUninstallFunction() { 685 } 686 687 bool ManagementUninstallFunction::RunAsync() { 688 scoped_ptr<management::Uninstall::Params> params( 689 management::Uninstall::Params::Create(*args_)); 690 EXTENSION_FUNCTION_VALIDATE(extension_); 691 EXTENSION_FUNCTION_VALIDATE(params.get()); 692 693 bool show_confirm_dialog = true; 694 // By default confirmation dialog isn't shown when uninstalling self, but this 695 // can be overridden with showConfirmDialog. 696 if (params->id == extension_->id()) { 697 show_confirm_dialog = params->options.get() && 698 params->options->show_confirm_dialog.get() && 699 *params->options->show_confirm_dialog; 700 } 701 if (show_confirm_dialog && !user_gesture()) { 702 error_ = keys::kGestureNeededForUninstallError; 703 return false; 704 } 705 return Uninstall(params->id, show_confirm_dialog); 706 } 707 708 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() { 709 } 710 711 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() { 712 } 713 714 bool ManagementUninstallSelfFunction::RunAsync() { 715 scoped_ptr<management::UninstallSelf::Params> params( 716 management::UninstallSelf::Params::Create(*args_)); 717 EXTENSION_FUNCTION_VALIDATE(params.get()); 718 719 bool show_confirm_dialog = false; 720 if (params->options.get() && params->options->show_confirm_dialog.get()) 721 show_confirm_dialog = *params->options->show_confirm_dialog; 722 return Uninstall(extension_->id(), show_confirm_dialog); 723 } 724 725 ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() { 726 } 727 728 ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() { 729 } 730 731 // static 732 void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest( 733 bool should_proceed) { 734 auto_confirm_for_test = should_proceed ? PROCEED : ABORT; 735 } 736 737 void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) { 738 if (!created) 739 error_ = keys::kCreateShortcutCanceledError; 740 SendResponse(created); 741 Release(); 742 } 743 744 bool ManagementCreateAppShortcutFunction::RunAsync() { 745 if (!user_gesture()) { 746 error_ = keys::kGestureNeededForCreateAppShortcutError; 747 return false; 748 } 749 750 scoped_ptr<management::CreateAppShortcut::Params> params( 751 management::CreateAppShortcut::Params::Create(*args_)); 752 EXTENSION_FUNCTION_VALIDATE(params.get()); 753 const Extension* extension = service()->GetExtensionById(params->id, true); 754 if (!extension) { 755 error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, 756 params->id); 757 return false; 758 } 759 760 if (!extension->is_app()) { 761 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id); 762 return false; 763 } 764 765 #if defined(OS_MACOSX) 766 if (!extension->is_platform_app()) { 767 error_ = keys::kCreateOnlyPackagedAppShortcutMac; 768 return false; 769 } 770 #endif 771 772 Browser* browser = chrome::FindBrowserWithProfile( 773 GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE); 774 if (!browser) { 775 // Shouldn't happen if we have user gesture. 776 error_ = keys::kNoBrowserToCreateShortcut; 777 return false; 778 } 779 780 // Matched with a Release() in OnCloseShortcutPrompt(). 781 AddRef(); 782 783 if (auto_confirm_for_test == DO_NOT_SKIP) { 784 chrome::ShowCreateChromeAppShortcutsDialog( 785 browser->window()->GetNativeWindow(), browser->profile(), extension, 786 base::Bind(&ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt, 787 this)); 788 } else { 789 OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED); 790 } 791 792 // Response is sent async in OnCloseShortcutPrompt(). 793 return true; 794 } 795 796 bool ManagementSetLaunchTypeFunction::RunSync() { 797 if (!user_gesture()) { 798 error_ = keys::kGestureNeededForSetLaunchTypeError; 799 return false; 800 } 801 802 scoped_ptr<management::SetLaunchType::Params> params( 803 management::SetLaunchType::Params::Create(*args_)); 804 EXTENSION_FUNCTION_VALIDATE(params.get()); 805 const Extension* extension = service()->GetExtensionById(params->id, true); 806 if (!extension) { 807 error_ = 808 ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id); 809 return false; 810 } 811 812 if (!extension->is_app()) { 813 error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id); 814 return false; 815 } 816 817 std::vector<management::LaunchType> available_launch_types = 818 GetAvailableLaunchTypes(*extension); 819 820 management::LaunchType app_launch_type = params->launch_type; 821 if (std::find(available_launch_types.begin(), 822 available_launch_types.end(), 823 app_launch_type) == available_launch_types.end()) { 824 error_ = keys::kLaunchTypeNotAvailableError; 825 return false; 826 } 827 828 LaunchType launch_type = LAUNCH_TYPE_DEFAULT; 829 switch (app_launch_type) { 830 case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB: 831 launch_type = LAUNCH_TYPE_PINNED; 832 break; 833 case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB: 834 launch_type = LAUNCH_TYPE_REGULAR; 835 break; 836 case management::LAUNCH_TYPE_OPEN_FULL_SCREEN: 837 launch_type = LAUNCH_TYPE_FULLSCREEN; 838 break; 839 case management::LAUNCH_TYPE_OPEN_AS_WINDOW: 840 launch_type = LAUNCH_TYPE_WINDOW; 841 break; 842 case management::LAUNCH_TYPE_NONE: 843 NOTREACHED(); 844 } 845 846 SetLaunchType(service(), params->id, launch_type); 847 848 return true; 849 } 850 851 ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() { 852 } 853 854 ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() { 855 } 856 857 void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp( 858 const Extension* extension, 859 const WebApplicationInfo& web_app_info) { 860 if (extension) { 861 scoped_ptr<management::ExtensionInfo> info = 862 CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile())); 863 results_ = management::GenerateAppForLink::Results::Create(*info); 864 865 SendResponse(true); 866 Release(); 867 } else { 868 error_ = keys::kGenerateAppForLinkInstallError; 869 SendResponse(false); 870 Release(); 871 } 872 } 873 874 void ManagementGenerateAppForLinkFunction::OnFaviconForApp( 875 const favicon_base::FaviconImageResult& image_result) { 876 WebApplicationInfo web_app; 877 web_app.title = base::UTF8ToUTF16(title_); 878 web_app.app_url = launch_url_; 879 880 if (!image_result.image.IsEmpty()) { 881 WebApplicationInfo::IconInfo icon; 882 icon.data = image_result.image.AsBitmap(); 883 icon.width = icon.data.width(); 884 icon.height = icon.data.height(); 885 web_app.icons.push_back(icon); 886 } 887 888 bookmark_app_helper_.reset(new BookmarkAppHelper(service(), web_app, NULL)); 889 bookmark_app_helper_->Create(base::Bind( 890 &ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp, this)); 891 } 892 893 bool ManagementGenerateAppForLinkFunction::RunAsync() { 894 if (!user_gesture()) { 895 error_ = keys::kGestureNeededForGenerateAppForLinkError; 896 return false; 897 } 898 899 scoped_ptr<management::GenerateAppForLink::Params> params( 900 management::GenerateAppForLink::Params::Create(*args_)); 901 EXTENSION_FUNCTION_VALIDATE(params.get()); 902 903 GURL launch_url(params->url); 904 if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) { 905 error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidURLError, 906 params->url); 907 return false; 908 } 909 910 if (params->title.empty()) { 911 error_ = keys::kEmptyTitleError; 912 return false; 913 } 914 915 FaviconService* favicon_service = 916 FaviconServiceFactory::GetForProfile(GetProfile(), 917 Profile::EXPLICIT_ACCESS); 918 DCHECK(favicon_service); 919 920 title_ = params->title; 921 launch_url_ = launch_url; 922 923 favicon_service->GetFaviconImageForPageURL( 924 FaviconService::FaviconForPageURLParams( 925 launch_url, favicon_base::FAVICON, gfx::kFaviconSize), 926 base::Bind(&ManagementGenerateAppForLinkFunction::OnFaviconForApp, this), 927 &cancelable_task_tracker_); 928 929 // Matched with a Release() in OnExtensionLoaded(). 930 AddRef(); 931 932 // Response is sent async in OnExtensionLoaded(). 933 return true; 934 } 935 936 ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context) 937 : browser_context_(context), extension_registry_observer_(this) { 938 extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_)); 939 } 940 941 ManagementEventRouter::~ManagementEventRouter() {} 942 943 void ManagementEventRouter::OnExtensionLoaded( 944 content::BrowserContext* browser_context, 945 const Extension* extension) { 946 BroadcastEvent(extension, management::OnEnabled::kEventName); 947 } 948 949 void ManagementEventRouter::OnExtensionUnloaded( 950 content::BrowserContext* browser_context, 951 const Extension* extension, 952 UnloadedExtensionInfo::Reason reason) { 953 BroadcastEvent(extension, management::OnDisabled::kEventName); 954 } 955 956 void ManagementEventRouter::OnExtensionInstalled( 957 content::BrowserContext* browser_context, 958 const Extension* extension) { 959 BroadcastEvent(extension, management::OnInstalled::kEventName); 960 } 961 962 void ManagementEventRouter::OnExtensionUninstalled( 963 content::BrowserContext* browser_context, 964 const Extension* extension) { 965 BroadcastEvent(extension, management::OnUninstalled::kEventName); 966 } 967 968 void ManagementEventRouter::BroadcastEvent(const Extension* extension, 969 const char* event_name) { 970 if (ui_util::ShouldNotBeVisible(extension, browser_context_)) 971 return; // Don't dispatch events for built-in extenions. 972 scoped_ptr<base::ListValue> args(new base::ListValue()); 973 if (event_name == management::OnUninstalled::kEventName) { 974 args->Append(new base::StringValue(extension->id())); 975 } else { 976 scoped_ptr<management::ExtensionInfo> info = 977 CreateExtensionInfo(*extension, ExtensionSystem::Get(browser_context_)); 978 args->Append(info->ToValue().release()); 979 } 980 981 EventRouter::Get(browser_context_) 982 ->BroadcastEvent(scoped_ptr<Event>(new Event(event_name, args.Pass()))); 983 } 984 985 ManagementAPI::ManagementAPI(content::BrowserContext* context) 986 : browser_context_(context) { 987 EventRouter* event_router = EventRouter::Get(browser_context_); 988 event_router->RegisterObserver(this, management::OnInstalled::kEventName); 989 event_router->RegisterObserver(this, management::OnUninstalled::kEventName); 990 event_router->RegisterObserver(this, management::OnEnabled::kEventName); 991 event_router->RegisterObserver(this, management::OnDisabled::kEventName); 992 } 993 994 ManagementAPI::~ManagementAPI() { 995 } 996 997 void ManagementAPI::Shutdown() { 998 EventRouter::Get(browser_context_)->UnregisterObserver(this); 999 } 1000 1001 static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI> > 1002 g_factory = LAZY_INSTANCE_INITIALIZER; 1003 1004 // static 1005 BrowserContextKeyedAPIFactory<ManagementAPI>* 1006 ManagementAPI::GetFactoryInstance() { 1007 return g_factory.Pointer(); 1008 } 1009 1010 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) { 1011 management_event_router_.reset(new ManagementEventRouter(browser_context_)); 1012 EventRouter::Get(browser_context_)->UnregisterObserver(this); 1013 } 1014 1015 } // namespace extensions 1016