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