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/ui/webui/extensions/extension_settings_handler.h" 6 7 #include "apps/app_load_service.h" 8 #include "apps/saved_files_service.h" 9 #include "base/auto_reset.h" 10 #include "base/base64.h" 11 #include "base/bind.h" 12 #include "base/bind_helpers.h" 13 #include "base/command_line.h" 14 #include "base/location.h" 15 #include "base/message_loop/message_loop.h" 16 #include "base/metrics/histogram.h" 17 #include "base/prefs/pref_service.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 "base/values.h" 22 #include "base/version.h" 23 #include "chrome/browser/browser_process.h" 24 #include "chrome/browser/chrome_notification_types.h" 25 #include "chrome/browser/devtools/devtools_window.h" 26 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 27 #include "chrome/browser/extensions/component_loader.h" 28 #include "chrome/browser/extensions/crx_installer.h" 29 #include "chrome/browser/extensions/devtools_util.h" 30 #include "chrome/browser/extensions/error_console/error_console.h" 31 #include "chrome/browser/extensions/extension_action_manager.h" 32 #include "chrome/browser/extensions/extension_disabled_ui.h" 33 #include "chrome/browser/extensions/extension_error_reporter.h" 34 #include "chrome/browser/extensions/extension_management.h" 35 #include "chrome/browser/extensions/extension_service.h" 36 #include "chrome/browser/extensions/extension_tab_util.h" 37 #include "chrome/browser/extensions/extension_ui_util.h" 38 #include "chrome/browser/extensions/extension_util.h" 39 #include "chrome/browser/extensions/install_verifier.h" 40 #include "chrome/browser/extensions/path_util.h" 41 #include "chrome/browser/extensions/shared_module_service.h" 42 #include "chrome/browser/extensions/updater/extension_updater.h" 43 #include "chrome/browser/extensions/webstore_reinstaller.h" 44 #include "chrome/browser/platform_util.h" 45 #include "chrome/browser/prefs/incognito_mode_prefs.h" 46 #include "chrome/browser/profiles/profile.h" 47 #include "chrome/browser/supervised_user/supervised_user_service.h" 48 #include "chrome/browser/supervised_user/supervised_user_service_factory.h" 49 #include "chrome/browser/tab_contents/background_contents.h" 50 #include "chrome/browser/ui/browser.h" 51 #include "chrome/browser/ui/browser_finder.h" 52 #include "chrome/browser/ui/browser_window.h" 53 #include "chrome/browser/ui/extensions/application_launch.h" 54 #include "chrome/browser/ui/webui/extensions/extension_basic_info.h" 55 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 56 #include "chrome/common/chrome_switches.h" 57 #include "chrome/common/chrome_version_info.h" 58 #include "chrome/common/extensions/features/feature_channel.h" 59 #include "chrome/common/extensions/manifest_url_handler.h" 60 #include "chrome/common/pref_names.h" 61 #include "chrome/common/url_constants.h" 62 #include "chrome/grit/chromium_strings.h" 63 #include "chrome/grit/generated_resources.h" 64 #include "components/google/core/browser/google_util.h" 65 #include "components/pref_registry/pref_registry_syncable.h" 66 #include "content/public/browser/notification_service.h" 67 #include "content/public/browser/notification_source.h" 68 #include "content/public/browser/notification_types.h" 69 #include "content/public/browser/render_process_host.h" 70 #include "content/public/browser/render_view_host.h" 71 #include "content/public/browser/site_instance.h" 72 #include "content/public/browser/web_contents.h" 73 #include "content/public/browser/web_ui.h" 74 #include "content/public/browser/web_ui_data_source.h" 75 #include "extensions/browser/app_window/app_window.h" 76 #include "extensions/browser/app_window/app_window_registry.h" 77 #include "extensions/browser/blacklist_state.h" 78 #include "extensions/browser/extension_error.h" 79 #include "extensions/browser/extension_host.h" 80 #include "extensions/browser/extension_registry.h" 81 #include "extensions/browser/extension_system.h" 82 #include "extensions/browser/lazy_background_task_queue.h" 83 #include "extensions/browser/management_policy.h" 84 #include "extensions/browser/pref_names.h" 85 #include "extensions/browser/uninstall_reason.h" 86 #include "extensions/browser/view_type_utils.h" 87 #include "extensions/browser/warning_set.h" 88 #include "extensions/common/constants.h" 89 #include "extensions/common/extension.h" 90 #include "extensions/common/extension_icon_set.h" 91 #include "extensions/common/extension_set.h" 92 #include "extensions/common/extension_urls.h" 93 #include "extensions/common/feature_switch.h" 94 #include "extensions/common/manifest.h" 95 #include "extensions/common/manifest_handlers/background_info.h" 96 #include "extensions/common/manifest_handlers/incognito_info.h" 97 #include "extensions/common/manifest_handlers/options_page_info.h" 98 #include "extensions/common/permissions/permissions_data.h" 99 #include "extensions/common/switches.h" 100 #include "grit/components_strings.h" 101 #include "ui/base/l10n/l10n_util.h" 102 103 using base::DictionaryValue; 104 using base::ListValue; 105 using content::RenderViewHost; 106 using content::WebContents; 107 108 namespace { 109 const char kAppsDeveloperToolsExtensionId[] = 110 "ohmmkhmmmpcnpikjeljgnaoabkaalbgc"; 111 } 112 113 namespace extensions { 114 115 ExtensionPage::ExtensionPage(const GURL& url, 116 int render_process_id, 117 int render_view_id, 118 bool incognito, 119 bool generated_background_page) 120 : url(url), 121 render_process_id(render_process_id), 122 render_view_id(render_view_id), 123 incognito(incognito), 124 generated_background_page(generated_background_page) { 125 } 126 127 // On Mac, the install prompt is not modal. This means that the user can 128 // navigate while the dialog is up, causing the dialog handler to outlive the 129 // ExtensionSettingsHandler. That's a problem because the dialog framework will 130 // try to contact us back once the dialog is closed, which causes a crash. 131 // This class is designed to broker the message between the two objects, while 132 // managing its own lifetime so that it can outlive the ExtensionSettingsHandler 133 // and (when doing so) gracefully ignore the message from the dialog. 134 class BrokerDelegate : public ExtensionInstallPrompt::Delegate { 135 public: 136 explicit BrokerDelegate( 137 const base::WeakPtr<ExtensionSettingsHandler>& delegate) 138 : delegate_(delegate) {} 139 140 // ExtensionInstallPrompt::Delegate implementation. 141 virtual void InstallUIProceed() OVERRIDE { 142 if (delegate_) 143 delegate_->InstallUIProceed(); 144 delete this; 145 }; 146 147 virtual void InstallUIAbort(bool user_initiated) OVERRIDE { 148 if (delegate_) 149 delegate_->InstallUIAbort(user_initiated); 150 delete this; 151 }; 152 153 private: 154 base::WeakPtr<ExtensionSettingsHandler> delegate_; 155 156 DISALLOW_COPY_AND_ASSIGN(BrokerDelegate); 157 }; 158 159 /////////////////////////////////////////////////////////////////////////////// 160 // 161 // ExtensionSettingsHandler 162 // 163 /////////////////////////////////////////////////////////////////////////////// 164 165 ExtensionSettingsHandler::ExtensionSettingsHandler() 166 : extension_service_(NULL), 167 management_policy_(NULL), 168 ignore_notifications_(false), 169 deleting_rvh_(NULL), 170 deleting_rwh_id_(-1), 171 deleting_rph_id_(-1), 172 registered_for_notifications_(false), 173 warning_service_observer_(this), 174 error_console_observer_(this), 175 extension_prefs_observer_(this), 176 extension_registry_observer_(this), 177 extension_management_observer_(this), 178 should_do_verification_check_(false) { 179 } 180 181 ExtensionSettingsHandler::~ExtensionSettingsHandler() { 182 } 183 184 ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service, 185 ManagementPolicy* policy) 186 : extension_service_(service), 187 management_policy_(policy), 188 ignore_notifications_(false), 189 deleting_rvh_(NULL), 190 deleting_rwh_id_(-1), 191 deleting_rph_id_(-1), 192 registered_for_notifications_(false), 193 warning_service_observer_(this), 194 error_console_observer_(this), 195 extension_prefs_observer_(this), 196 extension_registry_observer_(this), 197 extension_management_observer_(this), 198 should_do_verification_check_(false) { 199 } 200 201 // static 202 void ExtensionSettingsHandler::RegisterProfilePrefs( 203 user_prefs::PrefRegistrySyncable* registry) { 204 registry->RegisterBooleanPref( 205 prefs::kExtensionsUIDeveloperMode, 206 false, 207 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 208 registry->RegisterBooleanPref( 209 prefs::kExtensionsUIDismissedADTPromo, 210 false, 211 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 212 } 213 214 base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue( 215 const Extension* extension, 216 const std::vector<ExtensionPage>& pages, 217 const WarningService* warning_service) { 218 // The items which are to be written into app_dict are also described in 219 // chrome/browser/resources/extensions/extension_list.js in @typedef for 220 // ExtensionData. Please update it whenever you add or remove any keys here. 221 base::DictionaryValue* extension_data = new base::DictionaryValue(); 222 bool enabled = extension_service_->IsExtensionEnabled(extension->id()); 223 GetExtensionBasicInfo(extension, enabled, extension_data); 224 225 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile()); 226 int disable_reasons = prefs->GetDisableReasons(extension->id()); 227 228 bool suspicious_install = 229 (disable_reasons & Extension::DISABLE_NOT_VERIFIED) != 0; 230 extension_data->SetBoolean("suspiciousInstall", suspicious_install); 231 if (suspicious_install) 232 should_do_verification_check_ = true; 233 234 bool corrupt_install = 235 (disable_reasons & Extension::DISABLE_CORRUPTED) != 0; 236 extension_data->SetBoolean("corruptInstall", corrupt_install); 237 238 bool managed_install = 239 !management_policy_->UserMayModifySettings(extension, NULL); 240 extension_data->SetBoolean("managedInstall", managed_install); 241 242 // We should not get into a state where both are true. 243 DCHECK(!managed_install || !suspicious_install); 244 245 GURL icon = 246 ExtensionIconSource::GetIconURL(extension, 247 extension_misc::EXTENSION_ICON_MEDIUM, 248 ExtensionIconSet::MATCH_BIGGER, 249 !enabled, NULL); 250 if (Manifest::IsUnpackedLocation(extension->location())) { 251 extension_data->SetString("path", extension->path().value()); 252 extension_data->SetString( 253 "prettifiedPath", 254 extensions::path_util::PrettifyPath(extension->path()).value()); 255 } 256 extension_data->SetString("icon", icon.spec()); 257 extension_data->SetBoolean("isUnpacked", 258 Manifest::IsUnpackedLocation(extension->location())); 259 extension_data->SetBoolean("isFromStore", 260 extension->location() == Manifest::INTERNAL && 261 ManifestURL::UpdatesFromGallery(extension)); 262 ExtensionRegistry* registry = 263 ExtensionRegistry::Get(extension_service_->profile()); 264 extension_data->SetBoolean( 265 "terminated", 266 registry->terminated_extensions().Contains(extension->id())); 267 extension_data->SetBoolean("enabledIncognito", 268 util::IsIncognitoEnabled(extension->id(), extension_service_->profile())); 269 extension_data->SetBoolean("incognitoCanBeEnabled", 270 extension->can_be_incognito_enabled()); 271 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access()); 272 extension_data->SetBoolean("allowFileAccess", 273 util::AllowFileAccess(extension->id(), extension_service_->profile())); 274 extension_data->SetBoolean("allow_reload", 275 Manifest::IsUnpackedLocation(extension->location())); 276 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app()); 277 extension_data->SetBoolean("is_platform_app", extension->is_platform_app()); 278 extension_data->SetBoolean("homepageProvided", 279 ManifestURL::SpecifiedHomepageURL(extension)); 280 extension_data->SetBoolean("optionsOpenInTab", 281 OptionsPageInfo::ShouldOpenInTab(extension)); 282 283 // Add dependent extensions. 284 base::ListValue* dependents_list = new base::ListValue; 285 if (extension->is_shared_module()) { 286 scoped_ptr<ExtensionSet> dependent_extensions = 287 extension_service_->shared_module_service()->GetDependentExtensions( 288 extension); 289 for (ExtensionSet::const_iterator i = dependent_extensions->begin(); 290 i != dependent_extensions->end(); 291 i++) { 292 base::DictionaryValue* dependent_entry = new base::DictionaryValue; 293 dependent_entry->SetString("id", (*i)->id()); 294 dependent_entry->SetString("name", (*i)->name()); 295 dependents_list->Append(dependent_entry); 296 } 297 } 298 extension_data->Set("dependentExtensions", dependents_list); 299 300 // Extensions only want all URL access if: 301 // - The feature is enabled for the given extension. 302 // - The extension has access to enough urls that we can't just let it run 303 // on those specified in the permissions. 304 bool wants_all_urls = 305 util::ScriptsMayRequireActionForExtension(extension) && 306 (extension->permissions_data()->HasWithheldImpliedAllHosts() || 307 util::AllowedScriptingOnAllUrls( 308 extension->id(), extension_service_->GetBrowserContext())); 309 extension_data->SetBoolean("wantsAllUrls", wants_all_urls); 310 extension_data->SetBoolean( 311 "allowAllUrls", 312 util::AllowedScriptingOnAllUrls( 313 extension->id(), 314 extension_service_->GetBrowserContext())); 315 316 base::string16 location_text; 317 if (Manifest::IsPolicyLocation(extension->location())) { 318 location_text = l10n_util::GetStringUTF16( 319 IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE); 320 } else if (extension->location() == Manifest::INTERNAL && 321 !ManifestURL::UpdatesFromGallery(extension)) { 322 location_text = l10n_util::GetStringUTF16( 323 IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN); 324 } else if (extension->location() == Manifest::EXTERNAL_REGISTRY) { 325 location_text = l10n_util::GetStringUTF16( 326 IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY); 327 } else if (extension->is_shared_module()) { 328 location_text = l10n_util::GetStringUTF16( 329 IDS_OPTIONS_INSTALL_LOCATION_SHARED_MODULE); 330 } 331 extension_data->SetString("locationText", location_text); 332 333 base::string16 blacklist_text; 334 switch (prefs->GetExtensionBlacklistState(extension->id())) { 335 case BLACKLISTED_SECURITY_VULNERABILITY: 336 blacklist_text = l10n_util::GetStringUTF16( 337 IDS_OPTIONS_BLACKLISTED_SECURITY_VULNERABILITY); 338 break; 339 340 case BLACKLISTED_CWS_POLICY_VIOLATION: 341 blacklist_text = l10n_util::GetStringUTF16( 342 IDS_OPTIONS_BLACKLISTED_CWS_POLICY_VIOLATION); 343 break; 344 345 case BLACKLISTED_POTENTIALLY_UNWANTED: 346 blacklist_text = l10n_util::GetStringUTF16( 347 IDS_OPTIONS_BLACKLISTED_POTENTIALLY_UNWANTED); 348 break; 349 350 default: 351 break; 352 } 353 extension_data->SetString("blacklistText", blacklist_text); 354 355 // Force unpacked extensions to show at the top. 356 if (Manifest::IsUnpackedLocation(extension->location())) 357 extension_data->SetInteger("order", 1); 358 else 359 extension_data->SetInteger("order", 2); 360 361 if (!ExtensionActionAPI::GetBrowserActionVisibility(prefs, extension->id())) { 362 extension_data->SetBoolean("enable_show_button", true); 363 } 364 365 // Add views 366 base::ListValue* views = new base::ListValue; 367 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin(); 368 iter != pages.end(); ++iter) { 369 base::DictionaryValue* view_value = new base::DictionaryValue; 370 if (iter->url.scheme() == kExtensionScheme) { 371 // No leading slash. 372 view_value->SetString("path", iter->url.path().substr(1)); 373 } else { 374 // For live pages, use the full URL. 375 view_value->SetString("path", iter->url.spec()); 376 } 377 view_value->SetInteger("renderViewId", iter->render_view_id); 378 view_value->SetInteger("renderProcessId", iter->render_process_id); 379 view_value->SetBoolean("incognito", iter->incognito); 380 view_value->SetBoolean("generatedBackgroundPage", 381 iter->generated_background_page); 382 views->Append(view_value); 383 } 384 extension_data->Set("views", views); 385 ExtensionActionManager* extension_action_manager = 386 ExtensionActionManager::Get(extension_service_->profile()); 387 extension_data->SetBoolean( 388 "hasPopupAction", 389 extension_action_manager->GetBrowserAction(*extension) || 390 extension_action_manager->GetPageAction(*extension)); 391 392 // Add warnings. 393 if (warning_service) { 394 std::vector<std::string> warnings = 395 warning_service->GetWarningMessagesForExtension(extension->id()); 396 397 if (!warnings.empty()) { 398 base::ListValue* warnings_list = new base::ListValue; 399 for (std::vector<std::string>::const_iterator iter = warnings.begin(); 400 iter != warnings.end(); ++iter) { 401 warnings_list->Append(new base::StringValue(*iter)); 402 } 403 extension_data->Set("warnings", warnings_list); 404 } 405 } 406 407 // If the ErrorConsole is enabled and the extension is unpacked, use the more 408 // detailed errors from the ErrorConsole. Otherwise, use the install warnings 409 // (using both is redundant). 410 ErrorConsole* error_console = 411 ErrorConsole::Get(extension_service_->profile()); 412 bool error_console_is_enabled = 413 error_console->IsEnabledForChromeExtensionsPage(); 414 extension_data->SetBoolean("wantsErrorCollection", error_console_is_enabled); 415 if (error_console_is_enabled) { 416 extension_data->SetBoolean("errorCollectionEnabled", 417 error_console->IsReportingEnabledForExtension( 418 extension->id())); 419 const ErrorList& errors = 420 error_console->GetErrorsForExtension(extension->id()); 421 if (!errors.empty()) { 422 scoped_ptr<base::ListValue> manifest_errors(new base::ListValue); 423 scoped_ptr<base::ListValue> runtime_errors(new base::ListValue); 424 for (ErrorList::const_iterator iter = errors.begin(); 425 iter != errors.end(); ++iter) { 426 if ((*iter)->type() == ExtensionError::MANIFEST_ERROR) { 427 manifest_errors->Append((*iter)->ToValue().release()); 428 } else { // Handle runtime error. 429 const RuntimeError* error = static_cast<const RuntimeError*>(*iter); 430 scoped_ptr<base::DictionaryValue> value = error->ToValue(); 431 bool can_inspect = 432 !(deleting_rwh_id_ == error->render_view_id() && 433 deleting_rph_id_ == error->render_process_id()) && 434 RenderViewHost::FromID(error->render_process_id(), 435 error->render_view_id()) != NULL; 436 value->SetBoolean("canInspect", can_inspect); 437 runtime_errors->Append(value.release()); 438 } 439 } 440 if (!manifest_errors->empty()) 441 extension_data->Set("manifestErrors", manifest_errors.release()); 442 if (!runtime_errors->empty()) 443 extension_data->Set("runtimeErrors", runtime_errors.release()); 444 } 445 } else if (Manifest::IsUnpackedLocation(extension->location())) { 446 const std::vector<InstallWarning>& install_warnings = 447 extension->install_warnings(); 448 if (!install_warnings.empty()) { 449 scoped_ptr<base::ListValue> list(new base::ListValue()); 450 for (std::vector<InstallWarning>::const_iterator it = 451 install_warnings.begin(); it != install_warnings.end(); ++it) { 452 base::DictionaryValue* item = new base::DictionaryValue(); 453 item->SetString("message", it->message); 454 list->Append(item); 455 } 456 extension_data->Set("installWarnings", list.release()); 457 } 458 } 459 460 return extension_data; 461 } 462 463 void ExtensionSettingsHandler::GetLocalizedValues( 464 content::WebUIDataSource* source) { 465 source->AddString("extensionSettings", 466 l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE)); 467 468 source->AddString("extensionSettingsDeveloperMode", 469 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK)); 470 source->AddString("extensionSettingsNoExtensions", 471 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED)); 472 source->AddString( 473 "extensionSettingsSuggestGallery", 474 l10n_util::GetStringFUTF16( 475 IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY, 476 base::ASCIIToUTF16( 477 google_util::AppendGoogleLocaleParam( 478 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()), 479 g_browser_process->GetApplicationLocale()).spec()))); 480 source->AddString("extensionSettingsGetMoreExtensions", 481 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS)); 482 source->AddString( 483 "extensionSettingsGetMoreExtensionsUrl", 484 base::ASCIIToUTF16( 485 google_util::AppendGoogleLocaleParam( 486 GURL(extension_urls::GetWebstoreExtensionsCategoryURL()), 487 g_browser_process->GetApplicationLocale()).spec())); 488 source->AddString("extensionSettingsExtensionId", 489 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID)); 490 source->AddString("extensionSettingsExtensionPath", 491 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH)); 492 source->AddString("extensionSettingsInspectViews", 493 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS)); 494 source->AddString("extensionSettingsInstallWarnings", 495 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS)); 496 source->AddString("viewIncognito", 497 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO)); 498 source->AddString("viewInactive", 499 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE)); 500 source->AddString("backgroundPage", 501 l10n_util::GetStringUTF16(IDS_EXTENSIONS_BACKGROUND_PAGE)); 502 source->AddString("extensionSettingsEnable", 503 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE)); 504 source->AddString("extensionSettingsEnabled", 505 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED)); 506 source->AddString("extensionSettingsRemove", 507 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE)); 508 source->AddString("extensionSettingsEnableIncognito", 509 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO)); 510 source->AddString("extensionSettingsEnableErrorCollection", 511 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_ERROR_COLLECTION)); 512 source->AddString("extensionSettingsAllowFileAccess", 513 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS)); 514 source->AddString("extensionSettingsAllowOnAllUrls", 515 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_ON_ALL_URLS)); 516 source->AddString("extensionSettingsIncognitoWarning", 517 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING)); 518 source->AddString("extensionSettingsReloadTerminated", 519 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED)); 520 source->AddString("extensionSettingsRepairCorrupted", 521 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REPAIR_CORRUPTED)); 522 source->AddString("extensionSettingsLaunch", 523 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH)); 524 source->AddString("extensionSettingsReloadUnpacked", 525 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED)); 526 source->AddString("extensionSettingsOptions", 527 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK)); 528 source->AddString("extensionSettingsPermissions", 529 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK)); 530 source->AddString("extensionSettingsVisitWebsite", 531 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE)); 532 source->AddString("extensionSettingsVisitWebStore", 533 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE)); 534 source->AddString("extensionSettingsPolicyControlled", 535 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED)); 536 source->AddString("extensionSettingsDependentExtensions", 537 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEPENDENT_EXTENSIONS)); 538 source->AddString("extensionSettingsSupervisedUser", 539 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_SUPERVISED_USER)); 540 source->AddString("extensionSettingsCorruptInstall", 541 l10n_util::GetStringUTF16( 542 IDS_EXTENSIONS_CORRUPTED_EXTENSION)); 543 source->AddString("extensionSettingsSuspiciousInstall", 544 l10n_util::GetStringFUTF16( 545 IDS_EXTENSIONS_ADDED_WITHOUT_KNOWLEDGE, 546 l10n_util::GetStringUTF16(IDS_EXTENSION_WEB_STORE_TITLE))); 547 source->AddString("extensionSettingsLearnMore", 548 l10n_util::GetStringUTF16(IDS_LEARN_MORE)); 549 source->AddString("extensionSettingsSuspiciousInstallHelpUrl", 550 base::ASCIIToUTF16( 551 google_util::AppendGoogleLocaleParam( 552 GURL(chrome::kRemoveNonCWSExtensionURL), 553 g_browser_process->GetApplicationLocale()).spec())); 554 source->AddString("extensionSettingsShowButton", 555 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON)); 556 source->AddString("extensionSettingsLoadUnpackedButton", 557 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON)); 558 source->AddString("extensionSettingsPackButton", 559 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON)); 560 source->AddString("extensionSettingsCommandsLink", 561 l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE)); 562 source->AddString("extensionSettingsUpdateButton", 563 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON)); 564 source->AddString( 565 "extensionSettingsAppsDevToolsPromoHTML", 566 l10n_util::GetStringFUTF16( 567 IDS_EXTENSIONS_APPS_DEV_TOOLS_PROMO_HTML, 568 base::ASCIIToUTF16( 569 google_util::AppendGoogleLocaleParam( 570 GURL(extension_urls::GetWebstoreItemDetailURLPrefix() + 571 kAppsDeveloperToolsExtensionId), 572 g_browser_process->GetApplicationLocale()).spec()))); 573 source->AddString( 574 "extensionSettingsAppDevToolsPromoClose", 575 l10n_util::GetStringUTF16(IDS_CLOSE)); 576 source->AddString("extensionSettingsCrashMessage", 577 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION)); 578 source->AddString("extensionSettingsInDevelopment", 579 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT)); 580 source->AddString("extensionSettingsWarningsTitle", 581 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE)); 582 source->AddString("extensionSettingsShowDetails", 583 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS)); 584 source->AddString("extensionSettingsHideDetails", 585 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS)); 586 587 // TODO(estade): comb through the above strings to find ones no longer used in 588 // uber extensions. 589 source->AddString("extensionUninstall", 590 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL)); 591 } 592 593 void ExtensionSettingsHandler::RenderViewDeleted( 594 RenderViewHost* render_view_host) { 595 deleting_rvh_ = render_view_host; 596 Profile* source_profile = Profile::FromBrowserContext( 597 render_view_host->GetSiteInstance()->GetBrowserContext()); 598 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile)) 599 return; 600 MaybeUpdateAfterNotification(); 601 } 602 603 void ExtensionSettingsHandler::DidStartNavigationToPendingEntry( 604 const GURL& url, 605 content::NavigationController::ReloadType reload_type) { 606 if (reload_type != content::NavigationController::NO_RELOAD) 607 ReloadUnpackedExtensions(); 608 } 609 610 void ExtensionSettingsHandler::RegisterMessages() { 611 // Don't override an |extension_service_| or |management_policy_| injected 612 // for testing. 613 if (!extension_service_) { 614 Profile* profile = Profile::FromWebUI(web_ui())->GetOriginalProfile(); 615 extension_service_ = 616 extensions::ExtensionSystem::Get(profile)->extension_service(); 617 } 618 if (!management_policy_) { 619 management_policy_ = ExtensionSystem::Get( 620 extension_service_->profile())->management_policy(); 621 } 622 623 web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData", 624 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData, 625 AsWeakPtr())); 626 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode", 627 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode, 628 AsWeakPtr())); 629 web_ui()->RegisterMessageCallback("extensionSettingsInspect", 630 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage, 631 AsWeakPtr())); 632 web_ui()->RegisterMessageCallback("extensionSettingsLaunch", 633 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage, 634 AsWeakPtr())); 635 web_ui()->RegisterMessageCallback("extensionSettingsReload", 636 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage, 637 AsWeakPtr())); 638 web_ui()->RegisterMessageCallback("extensionSettingsRepair", 639 base::Bind(&ExtensionSettingsHandler::HandleRepairMessage, 640 AsWeakPtr())); 641 web_ui()->RegisterMessageCallback("extensionSettingsEnable", 642 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage, 643 AsWeakPtr())); 644 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito", 645 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage, 646 AsWeakPtr())); 647 web_ui()->RegisterMessageCallback("extensionSettingsEnableErrorCollection", 648 base::Bind(&ExtensionSettingsHandler::HandleEnableErrorCollectionMessage, 649 AsWeakPtr())); 650 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess", 651 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage, 652 AsWeakPtr())); 653 web_ui()->RegisterMessageCallback("extensionSettingsAllowOnAllUrls", 654 base::Bind(&ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage, 655 AsWeakPtr())); 656 web_ui()->RegisterMessageCallback("extensionSettingsUninstall", 657 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage, 658 AsWeakPtr())); 659 web_ui()->RegisterMessageCallback("extensionSettingsOptions", 660 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage, 661 AsWeakPtr())); 662 web_ui()->RegisterMessageCallback("extensionSettingsPermissions", 663 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage, 664 AsWeakPtr())); 665 web_ui()->RegisterMessageCallback("extensionSettingsShowButton", 666 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage, 667 AsWeakPtr())); 668 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate", 669 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage, 670 AsWeakPtr())); 671 web_ui()->RegisterMessageCallback("extensionSettingsDismissADTPromo", 672 base::Bind(&ExtensionSettingsHandler::HandleDismissADTPromoMessage, 673 AsWeakPtr())); 674 web_ui()->RegisterMessageCallback("extensionSettingsShowPath", 675 base::Bind(&ExtensionSettingsHandler::HandleShowPath, 676 AsWeakPtr())); 677 } 678 679 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) { 680 MaybeUpdateAfterNotification(); 681 } 682 683 void ExtensionSettingsHandler::Observe( 684 int type, 685 const content::NotificationSource& source, 686 const content::NotificationDetails& details) { 687 Profile* profile = Profile::FromWebUI(web_ui()); 688 Profile* source_profile = NULL; 689 switch (type) { 690 // We listen for notifications that will result in the page being 691 // repopulated with data twice for the same event in certain cases. 692 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because 693 // we don't know about the views for an extension at EXTENSION_LOADED, but 694 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions 695 // that don't have a process at startup. 696 // 697 // Doing it this way gets everything but causes the page to be rendered 698 // more than we need. It doesn't seem to result in any noticeable flicker. 699 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: 700 deleting_rvh_ = content::Details<BackgroundContents>(details)-> 701 web_contents()->GetRenderViewHost(); 702 // Fall through. 703 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: 704 case extensions::NOTIFICATION_EXTENSION_HOST_CREATED: 705 source_profile = content::Source<Profile>(source).ptr(); 706 if (!profile->IsSameProfile(source_profile)) 707 return; 708 MaybeUpdateAfterNotification(); 709 break; 710 case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: { 711 content::RenderWidgetHost* rwh = 712 content::Source<content::RenderWidgetHost>(source).ptr(); 713 deleting_rwh_id_ = rwh->GetRoutingID(); 714 deleting_rph_id_ = rwh->GetProcess()->GetID(); 715 MaybeUpdateAfterNotification(); 716 break; 717 } 718 case extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED: 719 case extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: 720 MaybeUpdateAfterNotification(); 721 break; 722 case extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED: 723 // This notification is sent when the extension host destruction begins, 724 // not when it finishes. We use PostTask to delay the update until after 725 // the destruction finishes. 726 base::MessageLoop::current()->PostTask( 727 FROM_HERE, 728 base::Bind(&ExtensionSettingsHandler::MaybeUpdateAfterNotification, 729 AsWeakPtr())); 730 break; 731 default: 732 NOTREACHED(); 733 } 734 } 735 736 void ExtensionSettingsHandler::OnExtensionLoaded( 737 content::BrowserContext* browser_context, 738 const Extension* extension) { 739 MaybeUpdateAfterNotification(); 740 } 741 742 void ExtensionSettingsHandler::OnExtensionUnloaded( 743 content::BrowserContext* browser_context, 744 const Extension* extension, 745 UnloadedExtensionInfo::Reason reason) { 746 MaybeUpdateAfterNotification(); 747 } 748 749 void ExtensionSettingsHandler::OnExtensionUninstalled( 750 content::BrowserContext* browser_context, 751 const Extension* extension, 752 extensions::UninstallReason reason) { 753 MaybeUpdateAfterNotification(); 754 } 755 756 void ExtensionSettingsHandler::OnExtensionDisableReasonsChanged( 757 const std::string& extension_id, int disable_reasons) { 758 MaybeUpdateAfterNotification(); 759 } 760 761 void ExtensionSettingsHandler::OnExtensionManagementSettingsChanged() { 762 MaybeUpdateAfterNotification(); 763 } 764 765 void ExtensionSettingsHandler::ExtensionUninstallAccepted() { 766 DCHECK(!extension_id_prompting_.empty()); 767 768 bool was_terminated = false; 769 770 // The extension can be uninstalled in another window while the UI was 771 // showing. Do nothing in that case. 772 const Extension* extension = 773 extension_service_->GetExtensionById(extension_id_prompting_, true); 774 if (!extension) { 775 extension = 776 ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))->GetExtensionById( 777 extension_id_prompting_, ExtensionRegistry::TERMINATED); 778 was_terminated = true; 779 } 780 if (!extension) 781 return; 782 783 extension_service_->UninstallExtension( 784 extension_id_prompting_, 785 extensions::UNINSTALL_REASON_USER_INITIATED, 786 base::Bind(&base::DoNothing), 787 NULL); // Error. 788 extension_id_prompting_ = ""; 789 790 // There will be no EXTENSION_UNLOADED notification for terminated 791 // extensions as they were already unloaded. 792 if (was_terminated) 793 HandleRequestExtensionsData(NULL); 794 } 795 796 void ExtensionSettingsHandler::ExtensionUninstallCanceled() { 797 extension_id_prompting_ = ""; 798 } 799 800 void ExtensionSettingsHandler::ExtensionWarningsChanged() { 801 MaybeUpdateAfterNotification(); 802 } 803 804 // This is called when the user clicks "Revoke File Access." 805 void ExtensionSettingsHandler::InstallUIProceed() { 806 Profile* profile = Profile::FromWebUI(web_ui()); 807 apps::SavedFilesService::Get(profile)->ClearQueue( 808 extension_service_->GetExtensionById(extension_id_prompting_, true)); 809 apps::AppLoadService::Get(profile) 810 ->RestartApplicationIfRunning(extension_id_prompting_); 811 extension_id_prompting_.clear(); 812 } 813 814 void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) { 815 extension_id_prompting_.clear(); 816 } 817 818 void ExtensionSettingsHandler::ReloadUnpackedExtensions() { 819 const ExtensionSet* extensions = extension_service_->extensions(); 820 std::vector<const Extension*> unpacked_extensions; 821 for (ExtensionSet::const_iterator extension = extensions->begin(); 822 extension != extensions->end(); ++extension) { 823 if (Manifest::IsUnpackedLocation((*extension)->location())) 824 unpacked_extensions.push_back(extension->get()); 825 } 826 827 for (std::vector<const Extension*>::iterator iter = 828 unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) { 829 extension_service_->ReloadExtensionWithQuietFailure((*iter)->id()); 830 } 831 } 832 833 void ExtensionSettingsHandler::HandleRequestExtensionsData( 834 const base::ListValue* args) { 835 // The items which are to be written into results are also described in 836 // chrome/browser/resources/extensions/extensions.js in @typedef for 837 // ExtensionDataResponse. Please update it whenever you add or remove any keys 838 // here. 839 base::DictionaryValue results; 840 841 Profile* profile = Profile::FromWebUI(web_ui()); 842 843 // Add the extensions to the results structure. 844 base::ListValue* extensions_list = new base::ListValue(); 845 846 WarningService* warnings = ExtensionSystem::Get(profile)->warning_service(); 847 848 ExtensionRegistry* registry = ExtensionRegistry::Get(profile); 849 const ExtensionSet& enabled_set = registry->enabled_extensions(); 850 for (ExtensionSet::const_iterator extension = enabled_set.begin(); 851 extension != enabled_set.end(); ++extension) { 852 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) { 853 extensions_list->Append(CreateExtensionDetailValue( 854 extension->get(), 855 GetInspectablePagesForExtension(extension->get(), true), 856 warnings)); 857 } 858 } 859 const ExtensionSet& disabled_set = registry->disabled_extensions(); 860 for (ExtensionSet::const_iterator extension = disabled_set.begin(); 861 extension != disabled_set.end(); ++extension) { 862 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) { 863 extensions_list->Append(CreateExtensionDetailValue( 864 extension->get(), 865 GetInspectablePagesForExtension(extension->get(), false), 866 warnings)); 867 } 868 } 869 const ExtensionSet& terminated_set = registry->terminated_extensions(); 870 std::vector<ExtensionPage> empty_pages; 871 for (ExtensionSet::const_iterator extension = terminated_set.begin(); 872 extension != terminated_set.end(); ++extension) { 873 if (ui_util::ShouldDisplayInExtensionSettings(extension->get(), profile)) { 874 extensions_list->Append(CreateExtensionDetailValue( 875 extension->get(), 876 empty_pages, // Terminated process has no active pages. 877 warnings)); 878 } 879 } 880 results.Set("extensions", extensions_list); 881 882 bool is_supervised = profile->IsSupervised(); 883 bool incognito_available = 884 IncognitoModePrefs::GetAvailability(profile->GetPrefs()) != 885 IncognitoModePrefs::DISABLED; 886 bool developer_mode = 887 !is_supervised && 888 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); 889 results.SetBoolean("profileIsSupervised", is_supervised); 890 results.SetBoolean("incognitoAvailable", incognito_available); 891 results.SetBoolean("developerMode", developer_mode); 892 893 // Promote the Chrome Apps & Extensions Developer Tools if they are not 894 // installed and the user has not previously dismissed the warning. 895 bool promote_apps_dev_tools = false; 896 if (!ExtensionRegistry::Get(Profile::FromWebUI(web_ui()))-> 897 GetExtensionById(kAppsDeveloperToolsExtensionId, 898 ExtensionRegistry::EVERYTHING) && 899 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDismissedADTPromo)) { 900 promote_apps_dev_tools = true; 901 } 902 results.SetBoolean("promoteAppsDevTools", promote_apps_dev_tools); 903 904 const bool load_unpacked_disabled = 905 ExtensionManagementFactory::GetForBrowserContext(profile) 906 ->BlacklistedByDefault(); 907 results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled); 908 909 web_ui()->CallJavascriptFunction( 910 "extensions.ExtensionSettings.returnExtensionsData", results); 911 912 MaybeRegisterForNotifications(); 913 UMA_HISTOGRAM_BOOLEAN("ExtensionSettings.ShouldDoVerificationCheck", 914 should_do_verification_check_); 915 if (should_do_verification_check_) { 916 should_do_verification_check_ = false; 917 ExtensionSystem::Get(Profile::FromWebUI(web_ui())) 918 ->install_verifier() 919 ->VerifyAllExtensions(); 920 } 921 } 922 923 void ExtensionSettingsHandler::HandleToggleDeveloperMode( 924 const base::ListValue* args) { 925 Profile* profile = Profile::FromWebUI(web_ui()); 926 if (profile->IsSupervised()) 927 return; 928 929 bool developer_mode = 930 !profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); 931 profile->GetPrefs()->SetBoolean(prefs::kExtensionsUIDeveloperMode, 932 developer_mode); 933 } 934 935 void ExtensionSettingsHandler::HandleInspectMessage( 936 const base::ListValue* args) { 937 std::string extension_id; 938 std::string render_process_id_str; 939 std::string render_view_id_str; 940 int render_process_id; 941 int render_view_id; 942 bool incognito; 943 CHECK_EQ(4U, args->GetSize()); 944 CHECK(args->GetString(0, &extension_id)); 945 CHECK(args->GetString(1, &render_process_id_str)); 946 CHECK(args->GetString(2, &render_view_id_str)); 947 CHECK(args->GetBoolean(3, &incognito)); 948 CHECK(base::StringToInt(render_process_id_str, &render_process_id)); 949 CHECK(base::StringToInt(render_view_id_str, &render_view_id)); 950 951 if (render_process_id == -1) { 952 // This message is for a lazy background page. Start the page if necessary. 953 const Extension* extension = 954 extension_service_->extensions()->GetByID(extension_id); 955 DCHECK(extension); 956 Profile* profile = Profile::FromWebUI(web_ui()); 957 if (incognito) 958 profile = profile->GetOffTheRecordProfile(); 959 devtools_util::InspectBackgroundPage(extension, profile); 960 return; 961 } 962 963 RenderViewHost* host = RenderViewHost::FromID(render_process_id, 964 render_view_id); 965 if (!host || !WebContents::FromRenderViewHost(host)) { 966 // This can happen if the host has gone away since the page was displayed. 967 return; 968 } 969 970 DevToolsWindow::OpenDevToolsWindow(WebContents::FromRenderViewHost(host)); 971 } 972 973 void ExtensionSettingsHandler::HandleLaunchMessage( 974 const base::ListValue* args) { 975 CHECK_EQ(1U, args->GetSize()); 976 std::string extension_id; 977 CHECK(args->GetString(0, &extension_id)); 978 const Extension* extension = 979 extension_service_->GetExtensionById(extension_id, false); 980 OpenApplication(AppLaunchParams(extension_service_->profile(), extension, 981 extensions::LAUNCH_CONTAINER_WINDOW, 982 NEW_WINDOW)); 983 } 984 985 void ExtensionSettingsHandler::HandleReloadMessage( 986 const base::ListValue* args) { 987 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args)); 988 CHECK(!extension_id.empty()); 989 extension_service_->ReloadExtensionWithQuietFailure(extension_id); 990 } 991 992 void ExtensionSettingsHandler::HandleRepairMessage( 993 const base::ListValue* args) { 994 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args)); 995 CHECK(!extension_id.empty()); 996 scoped_refptr<WebstoreReinstaller> reinstaller(new WebstoreReinstaller( 997 web_contents(), 998 extension_id, 999 base::Bind(&ExtensionSettingsHandler::OnReinstallComplete, 1000 AsWeakPtr()))); 1001 reinstaller->BeginReinstall(); 1002 } 1003 1004 void ExtensionSettingsHandler::HandleEnableMessage( 1005 const base::ListValue* args) { 1006 CHECK_EQ(2U, args->GetSize()); 1007 std::string extension_id, enable_str; 1008 CHECK(args->GetString(0, &extension_id)); 1009 CHECK(args->GetString(1, &enable_str)); 1010 1011 const Extension* extension = 1012 extension_service_->GetInstalledExtension(extension_id); 1013 if (!extension) 1014 return; 1015 1016 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 1017 LOG(ERROR) << "An attempt was made to enable an extension that is " 1018 << "non-usermanagable. Extension id: " << extension->id(); 1019 return; 1020 } 1021 1022 if (enable_str == "true") { 1023 ExtensionPrefs* prefs = ExtensionPrefs::Get(extension_service_->profile()); 1024 if (prefs->DidExtensionEscalatePermissions(extension_id)) { 1025 ShowExtensionDisabledDialog( 1026 extension_service_, web_ui()->GetWebContents(), extension); 1027 } else if ((prefs->GetDisableReasons(extension_id) & 1028 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) && 1029 !requirements_checker_.get()) { 1030 // Recheck the requirements. 1031 scoped_refptr<const Extension> extension = 1032 extension_service_->GetExtensionById(extension_id, 1033 true /* include disabled */); 1034 requirements_checker_.reset(new RequirementsChecker); 1035 requirements_checker_->Check( 1036 extension, 1037 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked, 1038 AsWeakPtr(), extension_id)); 1039 } else { 1040 extension_service_->EnableExtension(extension_id); 1041 } 1042 } else { 1043 extension_service_->DisableExtension( 1044 extension_id, Extension::DISABLE_USER_ACTION); 1045 } 1046 } 1047 1048 void ExtensionSettingsHandler::HandleEnableIncognitoMessage( 1049 const base::ListValue* args) { 1050 CHECK_EQ(2U, args->GetSize()); 1051 std::string extension_id, enable_str; 1052 CHECK(args->GetString(0, &extension_id)); 1053 CHECK(args->GetString(1, &enable_str)); 1054 const Extension* extension = 1055 extension_service_->GetInstalledExtension(extension_id); 1056 if (!extension) 1057 return; 1058 1059 // Flipping the incognito bit will generate unload/load notifications for the 1060 // extension, but we don't want to reload the page, because a) we've already 1061 // updated the UI to reflect the change, and b) we want the yellow warning 1062 // text to stay until the user has left the page. 1063 // 1064 // TODO(aa): This creates crappiness in some cases. For example, in a main 1065 // window, when toggling this, the browser action will flicker because it gets 1066 // unloaded, then reloaded. It would be better to have a dedicated 1067 // notification for this case. 1068 // 1069 // Bug: http://crbug.com/41384 1070 base::AutoReset<bool> auto_reset_ignore_notifications( 1071 &ignore_notifications_, true); 1072 util::SetIsIncognitoEnabled(extension->id(), 1073 extension_service_->profile(), 1074 enable_str == "true"); 1075 } 1076 1077 void ExtensionSettingsHandler::HandleEnableErrorCollectionMessage( 1078 const base::ListValue* args) { 1079 CHECK_EQ(2u, args->GetSize()); 1080 std::string extension_id; 1081 std::string enable_str; 1082 CHECK(args->GetString(0, &extension_id)); 1083 CHECK(args->GetString(1, &enable_str)); 1084 bool enabled = enable_str == "true"; 1085 ErrorConsole::Get(Profile::FromWebUI(web_ui())) 1086 ->SetReportingAllForExtension(extension_id, enabled); 1087 } 1088 1089 void ExtensionSettingsHandler::HandleAllowFileAccessMessage( 1090 const base::ListValue* args) { 1091 CHECK_EQ(2U, args->GetSize()); 1092 std::string extension_id, allow_str; 1093 CHECK(args->GetString(0, &extension_id)); 1094 CHECK(args->GetString(1, &allow_str)); 1095 const Extension* extension = 1096 extension_service_->GetInstalledExtension(extension_id); 1097 if (!extension) 1098 return; 1099 1100 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 1101 LOG(ERROR) << "An attempt was made to change allow file access of an" 1102 << " extension that is non-usermanagable. Extension id : " 1103 << extension->id(); 1104 return; 1105 } 1106 1107 util::SetAllowFileAccess( 1108 extension_id, extension_service_->profile(), allow_str == "true"); 1109 } 1110 1111 void ExtensionSettingsHandler::HandleAllowOnAllUrlsMessage( 1112 const base::ListValue* args) { 1113 DCHECK(FeatureSwitch::scripts_require_action()->IsEnabled()); 1114 CHECK_EQ(2u, args->GetSize()); 1115 std::string extension_id; 1116 std::string allow_str; 1117 CHECK(args->GetString(0, &extension_id)); 1118 CHECK(args->GetString(1, &allow_str)); 1119 util::SetAllowedScriptingOnAllUrls(extension_id, 1120 extension_service_->GetBrowserContext(), 1121 allow_str == "true"); 1122 } 1123 1124 void ExtensionSettingsHandler::HandleUninstallMessage( 1125 const base::ListValue* args) { 1126 CHECK_EQ(1U, args->GetSize()); 1127 std::string extension_id; 1128 CHECK(args->GetString(0, &extension_id)); 1129 const Extension* extension = 1130 extension_service_->GetInstalledExtension(extension_id); 1131 if (!extension) 1132 return; 1133 1134 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 1135 LOG(ERROR) << "An attempt was made to uninstall an extension that is " 1136 << "non-usermanagable. Extension id : " << extension->id(); 1137 return; 1138 } 1139 1140 if (!extension_id_prompting_.empty()) 1141 return; // Only one prompt at a time. 1142 1143 extension_id_prompting_ = extension_id; 1144 1145 GetExtensionUninstallDialog()->ConfirmUninstall(extension); 1146 } 1147 1148 void ExtensionSettingsHandler::HandleOptionsMessage( 1149 const base::ListValue* args) { 1150 const Extension* extension = GetActiveExtension(args); 1151 if (!extension || OptionsPageInfo::GetOptionsPage(extension).is_empty()) 1152 return; 1153 ExtensionTabUtil::OpenOptionsPage(extension, 1154 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents())); 1155 } 1156 1157 void ExtensionSettingsHandler::HandlePermissionsMessage( 1158 const base::ListValue* args) { 1159 std::string extension_id(base::UTF16ToUTF8(ExtractStringValue(args))); 1160 CHECK(!extension_id.empty()); 1161 const Extension* extension = 1162 ExtensionRegistry::Get(Profile::FromWebUI(web_ui())) 1163 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 1164 if (!extension) 1165 return; 1166 1167 if (!extension_id_prompting_.empty()) 1168 return; // Only one prompt at a time. 1169 1170 extension_id_prompting_ = extension->id(); 1171 prompt_.reset(new ExtensionInstallPrompt(web_contents())); 1172 std::vector<base::FilePath> retained_file_paths; 1173 if (extension->permissions_data()->HasAPIPermission( 1174 APIPermission::kFileSystem)) { 1175 std::vector<apps::SavedFileEntry> retained_file_entries = 1176 apps::SavedFilesService::Get(Profile::FromWebUI( 1177 web_ui()))->GetAllFileEntries(extension_id_prompting_); 1178 for (size_t i = 0; i < retained_file_entries.size(); ++i) { 1179 retained_file_paths.push_back(retained_file_entries[i].path); 1180 } 1181 } 1182 // The BrokerDelegate manages its own lifetime. 1183 prompt_->ReviewPermissions( 1184 new BrokerDelegate(AsWeakPtr()), extension, retained_file_paths); 1185 } 1186 1187 void ExtensionSettingsHandler::HandleShowButtonMessage( 1188 const base::ListValue* args) { 1189 const Extension* extension = GetActiveExtension(args); 1190 if (!extension) 1191 return; 1192 ExtensionActionAPI::SetBrowserActionVisibility( 1193 ExtensionPrefs::Get(extension_service_->profile()), 1194 extension->id(), 1195 true); 1196 } 1197 1198 void ExtensionSettingsHandler::HandleAutoUpdateMessage( 1199 const base::ListValue* args) { 1200 ExtensionUpdater* updater = extension_service_->updater(); 1201 if (updater) { 1202 ExtensionUpdater::CheckParams params; 1203 params.install_immediately = true; 1204 updater->CheckNow(params); 1205 } 1206 } 1207 1208 void ExtensionSettingsHandler::HandleDismissADTPromoMessage( 1209 const base::ListValue* args) { 1210 DCHECK(args->empty()); 1211 Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean( 1212 prefs::kExtensionsUIDismissedADTPromo, true); 1213 } 1214 1215 void ExtensionSettingsHandler::HandleShowPath(const base::ListValue* args) { 1216 DCHECK(!args->empty()); 1217 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args)); 1218 1219 Profile* profile = Profile::FromWebUI(web_ui()); 1220 ExtensionRegistry* registry = ExtensionRegistry::Get(profile); 1221 const Extension* extension = registry->GetExtensionById( 1222 extension_id, 1223 ExtensionRegistry::EVERYTHING); 1224 CHECK(extension); 1225 // We explicitly show manifest.json in order to work around an issue in OSX 1226 // where opening the directory doesn't focus the Finder. 1227 platform_util::ShowItemInFolder(profile, 1228 extension->path().Append(kManifestFilename)); 1229 } 1230 1231 void ExtensionSettingsHandler::ShowAlert(const std::string& message) { 1232 base::ListValue arguments; 1233 arguments.Append(new base::StringValue(message)); 1234 web_ui()->CallJavascriptFunction("alert", arguments); 1235 } 1236 1237 const Extension* ExtensionSettingsHandler::GetActiveExtension( 1238 const base::ListValue* args) { 1239 std::string extension_id = base::UTF16ToUTF8(ExtractStringValue(args)); 1240 CHECK(!extension_id.empty()); 1241 return extension_service_->GetExtensionById(extension_id, false); 1242 } 1243 1244 void ExtensionSettingsHandler::MaybeUpdateAfterNotification() { 1245 WebContents* contents = web_ui()->GetWebContents(); 1246 if (!ignore_notifications_ && contents && contents->GetRenderViewHost()) 1247 HandleRequestExtensionsData(NULL); 1248 deleting_rvh_ = NULL; 1249 } 1250 1251 void ExtensionSettingsHandler::MaybeRegisterForNotifications() { 1252 if (registered_for_notifications_) 1253 return; 1254 1255 registered_for_notifications_ = true; 1256 Profile* profile = Profile::FromWebUI(web_ui()); 1257 1258 // Register for notifications that we need to reload the page. 1259 registrar_.Add(this, 1260 extensions::NOTIFICATION_EXTENSION_UPDATE_DISABLED, 1261 content::Source<Profile>(profile)); 1262 registrar_.Add(this, 1263 extensions::NOTIFICATION_EXTENSION_HOST_CREATED, 1264 content::NotificationService::AllBrowserContextsAndSources()); 1265 registrar_.Add(this, 1266 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, 1267 content::NotificationService::AllBrowserContextsAndSources()); 1268 registrar_.Add(this, 1269 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, 1270 content::NotificationService::AllBrowserContextsAndSources()); 1271 registrar_.Add( 1272 this, 1273 extensions::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, 1274 content::Source<ExtensionPrefs>(ExtensionPrefs::Get(profile))); 1275 registrar_.Add(this, 1276 extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED, 1277 content::NotificationService::AllBrowserContextsAndSources()); 1278 registrar_.Add(this, 1279 content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, 1280 content::NotificationService::AllBrowserContextsAndSources()); 1281 1282 extension_registry_observer_.Add(ExtensionRegistry::Get(profile)); 1283 1284 content::WebContentsObserver::Observe(web_ui()->GetWebContents()); 1285 1286 warning_service_observer_.Add( 1287 ExtensionSystem::Get(profile)->warning_service()); 1288 1289 error_console_observer_.Add(ErrorConsole::Get(profile)); 1290 1291 extension_management_observer_.Add( 1292 ExtensionManagementFactory::GetForBrowserContext(profile)); 1293 } 1294 1295 std::vector<ExtensionPage> 1296 ExtensionSettingsHandler::GetInspectablePagesForExtension( 1297 const Extension* extension, bool extension_is_enabled) { 1298 std::vector<ExtensionPage> result; 1299 1300 // Get the extension process's active views. 1301 extensions::ProcessManager* process_manager = 1302 ExtensionSystem::Get(extension_service_->profile())->process_manager(); 1303 GetInspectablePagesForExtensionProcess( 1304 extension, 1305 process_manager->GetRenderViewHostsForExtension(extension->id()), 1306 &result); 1307 1308 // Get app window views 1309 GetAppWindowPagesForExtensionProfile( 1310 extension, extension_service_->profile(), &result); 1311 1312 // Include a link to start the lazy background page, if applicable. 1313 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 1314 extension_is_enabled && 1315 !process_manager->GetBackgroundHostForExtension(extension->id())) { 1316 result.push_back(ExtensionPage( 1317 BackgroundInfo::GetBackgroundURL(extension), 1318 -1, 1319 -1, 1320 false, 1321 BackgroundInfo::HasGeneratedBackgroundPage(extension))); 1322 } 1323 1324 // Repeat for the incognito process, if applicable. Don't try to get 1325 // app windows for incognito processes. 1326 if (extension_service_->profile()->HasOffTheRecordProfile() && 1327 IncognitoInfo::IsSplitMode(extension) && 1328 util::IsIncognitoEnabled(extension->id(), 1329 extension_service_->profile())) { 1330 extensions::ProcessManager* process_manager = 1331 ExtensionSystem::Get(extension_service_->profile()-> 1332 GetOffTheRecordProfile())->process_manager(); 1333 GetInspectablePagesForExtensionProcess( 1334 extension, 1335 process_manager->GetRenderViewHostsForExtension(extension->id()), 1336 &result); 1337 1338 if (BackgroundInfo::HasLazyBackgroundPage(extension) && 1339 extension_is_enabled && 1340 !process_manager->GetBackgroundHostForExtension(extension->id())) { 1341 result.push_back(ExtensionPage( 1342 BackgroundInfo::GetBackgroundURL(extension), 1343 -1, 1344 -1, 1345 true, 1346 BackgroundInfo::HasGeneratedBackgroundPage(extension))); 1347 } 1348 } 1349 1350 return result; 1351 } 1352 1353 void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess( 1354 const Extension* extension, 1355 const std::set<RenderViewHost*>& views, 1356 std::vector<ExtensionPage>* result) { 1357 bool has_generated_background_page = 1358 BackgroundInfo::HasGeneratedBackgroundPage(extension); 1359 for (std::set<RenderViewHost*>::const_iterator iter = views.begin(); 1360 iter != views.end(); ++iter) { 1361 RenderViewHost* host = *iter; 1362 WebContents* web_contents = WebContents::FromRenderViewHost(host); 1363 ViewType host_type = GetViewType(web_contents); 1364 if (host == deleting_rvh_ || 1365 VIEW_TYPE_EXTENSION_POPUP == host_type || 1366 VIEW_TYPE_EXTENSION_DIALOG == host_type) 1367 continue; 1368 1369 GURL url = web_contents->GetURL(); 1370 content::RenderProcessHost* process = host->GetProcess(); 1371 bool is_background_page = 1372 (url == BackgroundInfo::GetBackgroundURL(extension)); 1373 result->push_back( 1374 ExtensionPage(url, 1375 process->GetID(), 1376 host->GetRoutingID(), 1377 process->GetBrowserContext()->IsOffTheRecord(), 1378 is_background_page && has_generated_background_page)); 1379 } 1380 } 1381 1382 void ExtensionSettingsHandler::GetAppWindowPagesForExtensionProfile( 1383 const Extension* extension, 1384 Profile* profile, 1385 std::vector<ExtensionPage>* result) { 1386 AppWindowRegistry* registry = AppWindowRegistry::Get(profile); 1387 if (!registry) return; 1388 1389 const AppWindowRegistry::AppWindowList windows = 1390 registry->GetAppWindowsForApp(extension->id()); 1391 1392 bool has_generated_background_page = 1393 BackgroundInfo::HasGeneratedBackgroundPage(extension); 1394 for (AppWindowRegistry::const_iterator it = windows.begin(); 1395 it != windows.end(); 1396 ++it) { 1397 WebContents* web_contents = (*it)->web_contents(); 1398 RenderViewHost* host = web_contents->GetRenderViewHost(); 1399 content::RenderProcessHost* process = host->GetProcess(); 1400 1401 bool is_background_page = 1402 (web_contents->GetURL() == BackgroundInfo::GetBackgroundURL(extension)); 1403 result->push_back( 1404 ExtensionPage(web_contents->GetURL(), 1405 process->GetID(), 1406 host->GetRoutingID(), 1407 process->GetBrowserContext()->IsOffTheRecord(), 1408 is_background_page && has_generated_background_page)); 1409 } 1410 } 1411 1412 ExtensionUninstallDialog* 1413 ExtensionSettingsHandler::GetExtensionUninstallDialog() { 1414 #if !defined(OS_ANDROID) 1415 if (!extension_uninstall_dialog_.get()) { 1416 Browser* browser = chrome::FindBrowserWithWebContents( 1417 web_ui()->GetWebContents()); 1418 extension_uninstall_dialog_.reset( 1419 ExtensionUninstallDialog::Create(extension_service_->profile(), 1420 browser->window()->GetNativeWindow(), 1421 this)); 1422 } 1423 return extension_uninstall_dialog_.get(); 1424 #else 1425 return NULL; 1426 #endif // !defined(OS_ANDROID) 1427 } 1428 1429 void ExtensionSettingsHandler::OnReinstallComplete( 1430 bool success, 1431 const std::string& error, 1432 webstore_install::Result result) { 1433 MaybeUpdateAfterNotification(); 1434 } 1435 1436 void ExtensionSettingsHandler::OnRequirementsChecked( 1437 std::string extension_id, 1438 std::vector<std::string> requirement_errors) { 1439 if (requirement_errors.empty()) { 1440 extension_service_->EnableExtension(extension_id); 1441 } else { 1442 ExtensionErrorReporter::GetInstance()->ReportError( 1443 base::UTF8ToUTF16(JoinString(requirement_errors, ' ')), 1444 true); // Be noisy. 1445 } 1446 requirements_checker_.reset(); 1447 } 1448 1449 } // namespace extensions 1450