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