extension_settings_handler.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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 "base/auto_reset.h" 8#include "base/base64.h" 9#include "base/bind.h" 10#include "base/bind_helpers.h" 11#include "base/command_line.h" 12#include "base/prefs/pref_service.h" 13#include "base/string_util.h" 14#include "base/strings/string_number_conversions.h" 15#include "base/utf_string_conversions.h" 16#include "base/values.h" 17#include "base/version.h" 18#include "chrome/browser/browser_process.h" 19#include "chrome/browser/devtools/devtools_window.h" 20#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 21#include "chrome/browser/extensions/crx_installer.h" 22#include "chrome/browser/extensions/extension_action_manager.h" 23#include "chrome/browser/extensions/extension_disabled_ui.h" 24#include "chrome/browser/extensions/extension_error_reporter.h" 25#include "chrome/browser/extensions/extension_host.h" 26#include "chrome/browser/extensions/extension_service.h" 27#include "chrome/browser/extensions/extension_system.h" 28#include "chrome/browser/extensions/extension_tab_util.h" 29#include "chrome/browser/extensions/extension_warning_set.h" 30#include "chrome/browser/extensions/lazy_background_task_queue.h" 31#include "chrome/browser/extensions/management_policy.h" 32#include "chrome/browser/extensions/shell_window_registry.h" 33#include "chrome/browser/extensions/unpacked_installer.h" 34#include "chrome/browser/extensions/updater/extension_updater.h" 35#include "chrome/browser/google/google_util.h" 36#include "chrome/browser/managed_mode/managed_user_service.h" 37#include "chrome/browser/managed_mode/managed_user_service_factory.h" 38#include "chrome/browser/profiles/profile.h" 39#include "chrome/browser/tab_contents/background_contents.h" 40#include "chrome/browser/ui/browser_finder.h" 41#include "chrome/browser/ui/chrome_select_file_policy.h" 42#include "chrome/browser/ui/extensions/application_launch.h" 43#include "chrome/browser/ui/extensions/shell_window.h" 44#include "chrome/browser/ui/webui/extensions/extension_icon_source.h" 45#include "chrome/common/chrome_notification_types.h" 46#include "chrome/common/chrome_switches.h" 47#include "chrome/common/extensions/background_info.h" 48#include "chrome/common/extensions/extension.h" 49#include "chrome/common/extensions/extension_constants.h" 50#include "chrome/common/extensions/extension_icon_set.h" 51#include "chrome/common/extensions/extension_set.h" 52#include "chrome/common/extensions/feature_switch.h" 53#include "chrome/common/extensions/incognito_handler.h" 54#include "chrome/common/extensions/manifest_url_handler.h" 55#include "chrome/common/pref_names.h" 56#include "chrome/common/url_constants.h" 57#include "components/user_prefs/pref_registry_syncable.h" 58#include "content/public/browser/notification_service.h" 59#include "content/public/browser/notification_source.h" 60#include "content/public/browser/notification_types.h" 61#include "content/public/browser/render_process_host.h" 62#include "content/public/browser/render_view_host.h" 63#include "content/public/browser/site_instance.h" 64#include "content/public/browser/web_contents.h" 65#include "content/public/browser/web_contents_view.h" 66#include "content/public/browser/web_ui.h" 67#include "content/public/browser/web_ui_data_source.h" 68#include "extensions/browser/view_type_utils.h" 69#include "extensions/common/constants.h" 70#include "grit/browser_resources.h" 71#include "grit/chromium_strings.h" 72#include "grit/generated_resources.h" 73#include "grit/theme_resources.h" 74#include "ui/base/l10n/l10n_util.h" 75#include "ui/base/resource/resource_bundle.h" 76 77 78using content::RenderViewHost; 79using content::WebContents; 80using extensions::Extension; 81using extensions::ExtensionUpdater; 82using extensions::ExtensionWarning; 83using extensions::ManagementPolicy; 84using extensions::Manifest; 85 86/////////////////////////////////////////////////////////////////////////////// 87// 88// ExtensionSettingsHandler 89// 90/////////////////////////////////////////////////////////////////////////////// 91 92ExtensionSettingsHandler::ExtensionSettingsHandler() 93 : extension_service_(NULL), 94 management_policy_(NULL), 95 ignore_notifications_(false), 96 deleting_rvh_(NULL), 97 registered_for_notifications_(false), 98 rvh_created_callback_( 99 base::Bind(&ExtensionSettingsHandler::RenderViewHostCreated, 100 base::Unretained(this))), 101 warning_service_observer_(this) { 102} 103 104ExtensionSettingsHandler::~ExtensionSettingsHandler() { 105 content::RenderViewHost::RemoveCreatedCallback(rvh_created_callback_); 106 107 // There may be pending file dialogs, we need to tell them that we've gone 108 // away so they don't try and call back to us. 109 if (load_extension_dialog_) 110 load_extension_dialog_->ListenerDestroyed(); 111} 112 113ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service, 114 ManagementPolicy* policy) 115 : extension_service_(service), 116 management_policy_(policy), 117 ignore_notifications_(false), 118 deleting_rvh_(NULL), 119 registered_for_notifications_(false), 120 warning_service_observer_(this) { 121} 122 123// static 124void ExtensionSettingsHandler::RegisterUserPrefs( 125 user_prefs::PrefRegistrySyncable* registry) { 126 registry->RegisterBooleanPref( 127 prefs::kExtensionsUIDeveloperMode, 128 false, 129 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); 130} 131 132DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue( 133 const Extension* extension, 134 const std::vector<ExtensionPage>& pages, 135 const extensions::ExtensionWarningService* warning_service) { 136 DictionaryValue* extension_data = new DictionaryValue(); 137 bool enabled = extension_service_->IsExtensionEnabled(extension->id()); 138 extension->GetBasicInfo(enabled, extension_data); 139 140 extension_data->SetBoolean( 141 "userModifiable", 142 management_policy_->UserMayModifySettings(extension, NULL)); 143 144 GURL icon = 145 ExtensionIconSource::GetIconURL(extension, 146 extension_misc::EXTENSION_ICON_MEDIUM, 147 ExtensionIconSet::MATCH_BIGGER, 148 !enabled, NULL); 149 if (Manifest::IsUnpackedLocation(extension->location())) 150 extension_data->SetString("path", extension->path().value()); 151 extension_data->SetString("icon", icon.spec()); 152 extension_data->SetBoolean("isUnpacked", 153 Manifest::IsUnpackedLocation(extension->location())); 154 extension_data->SetBoolean("terminated", 155 extension_service_->terminated_extensions()->Contains(extension->id())); 156 extension_data->SetBoolean("enabledIncognito", 157 extension_service_->IsIncognitoEnabled(extension->id())); 158 extension_data->SetBoolean("incognitoCanBeEnabled", 159 extension->can_be_incognito_enabled()); 160 extension_data->SetBoolean("wantsFileAccess", extension->wants_file_access()); 161 extension_data->SetBoolean("allowFileAccess", 162 extension_service_->AllowFileAccess(extension)); 163 extension_data->SetBoolean("allow_activity", 164 enabled && CommandLine::ForCurrentProcess()->HasSwitch( 165 switches::kEnableExtensionActivityUI)); 166 extension_data->SetBoolean("allow_reload", 167 Manifest::IsUnpackedLocation(extension->location())); 168 extension_data->SetBoolean("is_hosted_app", extension->is_hosted_app()); 169 extension_data->SetBoolean("is_platform_app", extension->is_platform_app()); 170 extension_data->SetBoolean("homepageProvided", 171 extensions::ManifestURL::GetHomepageURL(extension).is_valid()); 172 173 string16 location_text; 174 if (extension->location() == Manifest::INTERNAL && 175 !extension->UpdatesFromGallery()) { 176 location_text = l10n_util::GetStringUTF16( 177 IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN); 178 } else if (extension->location() == Manifest::EXTERNAL_REGISTRY) { 179 location_text = l10n_util::GetStringUTF16( 180 IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY); 181 } 182 extension_data->SetString("locationText", location_text); 183 184 // Determine the sort order: Extensions loaded through --load-extensions show 185 // up at the top. Disabled extensions show up at the bottom. 186 if (Manifest::IsUnpackedLocation(extension->location())) 187 extension_data->SetInteger("order", 1); 188 else 189 extension_data->SetInteger("order", 2); 190 191 if (!extensions::ExtensionActionAPI::GetBrowserActionVisibility( 192 extension_service_->extension_prefs(), extension->id())) { 193 extension_data->SetBoolean("enable_show_button", true); 194 } 195 196 // Add views 197 ListValue* views = new ListValue; 198 for (std::vector<ExtensionPage>::const_iterator iter = pages.begin(); 199 iter != pages.end(); ++iter) { 200 DictionaryValue* view_value = new DictionaryValue; 201 if (iter->url.scheme() == extensions::kExtensionScheme) { 202 // No leading slash. 203 view_value->SetString("path", iter->url.path().substr(1)); 204 } else { 205 // For live pages, use the full URL. 206 view_value->SetString("path", iter->url.spec()); 207 } 208 view_value->SetInteger("renderViewId", iter->render_view_id); 209 view_value->SetInteger("renderProcessId", iter->render_process_id); 210 view_value->SetBoolean("incognito", iter->incognito); 211 views->Append(view_value); 212 } 213 extension_data->Set("views", views); 214 extensions::ExtensionActionManager* extension_action_manager = 215 extensions::ExtensionActionManager::Get(extension_service_->profile()); 216 extension_data->SetBoolean( 217 "hasPopupAction", 218 extension_action_manager->GetBrowserAction(*extension) || 219 extension_action_manager->GetPageAction(*extension)); 220 221 // Add warnings. 222 if (warning_service) { 223 std::vector<std::string> warnings = 224 warning_service->GetWarningMessagesForExtension(extension->id()); 225 226 if (!warnings.empty()) { 227 ListValue* warnings_list = new ListValue; 228 for (std::vector<std::string>::const_iterator iter = warnings.begin(); 229 iter != warnings.end(); ++iter) { 230 warnings_list->Append(Value::CreateStringValue(*iter)); 231 } 232 extension_data->Set("warnings", warnings_list); 233 } 234 } 235 236 // Add install warnings (these are not the same as warnings!). 237 if (Manifest::IsUnpackedLocation(extension->location())) { 238 const std::vector<extensions::InstallWarning>& install_warnings = 239 extension->install_warnings(); 240 if (!install_warnings.empty()) { 241 scoped_ptr<ListValue> list(new ListValue()); 242 for (std::vector<extensions::InstallWarning>::const_iterator it = 243 install_warnings.begin(); it != install_warnings.end(); ++it) { 244 DictionaryValue* item = new DictionaryValue(); 245 item->SetBoolean("isHTML", 246 it->format == extensions::InstallWarning::FORMAT_HTML); 247 item->SetString("message", it->message); 248 list->Append(item); 249 } 250 extension_data->Set("installWarnings", list.release()); 251 } 252 } 253 254 return extension_data; 255} 256 257void ExtensionSettingsHandler::GetLocalizedValues( 258 content::WebUIDataSource* source) { 259 source->AddString("extensionSettings", 260 l10n_util::GetStringUTF16(IDS_MANAGE_EXTENSIONS_SETTING_WINDOWS_TITLE)); 261 262 source->AddString("extensionSettingsDeveloperMode", 263 l10n_util::GetStringUTF16(IDS_EXTENSIONS_DEVELOPER_MODE_LINK)); 264 source->AddString("extensionSettingsNoExtensions", 265 l10n_util::GetStringUTF16(IDS_EXTENSIONS_NONE_INSTALLED)); 266 source->AddString("extensionSettingsSuggestGallery", 267 l10n_util::GetStringFUTF16(IDS_EXTENSIONS_NONE_INSTALLED_SUGGEST_GALLERY, 268 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( 269 GURL(extension_urls::GetExtensionGalleryURL())).spec()))); 270 source->AddString("extensionSettingsGetMoreExtensions", 271 l10n_util::GetStringUTF16(IDS_GET_MORE_EXTENSIONS)); 272 source->AddString("extensionSettingsGetMoreExtensionsUrl", 273 ASCIIToUTF16(google_util::AppendGoogleLocaleParam( 274 GURL(extension_urls::GetExtensionGalleryURL())).spec())); 275 source->AddString("extensionSettingsExtensionId", 276 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ID)); 277 source->AddString("extensionSettingsExtensionPath", 278 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PATH)); 279 source->AddString("extensionSettingsInspectViews", 280 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSPECT_VIEWS)); 281 source->AddString("extensionSettingsInstallWarnings", 282 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALL_WARNINGS)); 283 source->AddString("viewIncognito", 284 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INCOGNITO)); 285 source->AddString("viewInactive", 286 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VIEW_INACTIVE)); 287 source->AddString("extensionSettingsEnable", 288 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE)); 289 source->AddString("extensionSettingsEnabled", 290 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLED)); 291 source->AddString("extensionSettingsRemove", 292 l10n_util::GetStringUTF16(IDS_EXTENSIONS_REMOVE)); 293 source->AddString("extensionSettingsEnableIncognito", 294 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ENABLE_INCOGNITO)); 295 source->AddString("extensionSettingsAllowFileAccess", 296 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ALLOW_FILE_ACCESS)); 297 source->AddString("extensionSettingsIncognitoWarning", 298 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INCOGNITO_WARNING)); 299 source->AddString("extensionSettingsReloadTerminated", 300 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_TERMINATED)); 301 source->AddString("extensionSettingsLaunch", 302 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LAUNCH)); 303 source->AddString("extensionSettingsRestart", 304 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RESTART)); 305 source->AddString("extensionSettingsReloadUnpacked", 306 l10n_util::GetStringUTF16(IDS_EXTENSIONS_RELOAD_UNPACKED)); 307 source->AddString("extensionSettingsOptions", 308 l10n_util::GetStringUTF16(IDS_EXTENSIONS_OPTIONS_LINK)); 309 source->AddString("extensionSettingsPermissions", 310 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PERMISSIONS_LINK)); 311 source->AddString("extensionSettingsActivity", 312 l10n_util::GetStringUTF16(IDS_EXTENSIONS_ACTIVITY_LINK)); 313 source->AddString("extensionSettingsVisitWebsite", 314 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSITE)); 315 source->AddString("extensionSettingsVisitWebStore", 316 l10n_util::GetStringUTF16(IDS_EXTENSIONS_VISIT_WEBSTORE)); 317 source->AddString("extensionSettingsPolicyControlled", 318 l10n_util::GetStringUTF16(IDS_EXTENSIONS_POLICY_CONTROLLED)); 319 source->AddString("extensionSettingsManagedMode", 320 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOCKED_MANAGED_MODE)); 321 source->AddString("sideloadWipeoutUrl", 322 chrome::kSideloadWipeoutHelpURL); 323 source->AddString("sideloadWipoutLearnMore", 324 l10n_util::GetStringUTF16(IDS_LEARN_MORE)); 325 source->AddString("extensionSettingsShowButton", 326 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_BUTTON)); 327 source->AddString("extensionSettingsLoadUnpackedButton", 328 l10n_util::GetStringUTF16(IDS_EXTENSIONS_LOAD_UNPACKED_BUTTON)); 329 source->AddString("extensionSettingsPackButton", 330 l10n_util::GetStringUTF16(IDS_EXTENSIONS_PACK_BUTTON)); 331 source->AddString("extensionSettingsCommandsLink", 332 l10n_util::GetStringUTF16(IDS_EXTENSIONS_COMMANDS_CONFIGURE)); 333 source->AddString("extensionSettingsUpdateButton", 334 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UPDATE_BUTTON)); 335 source->AddString("extensionSettingsCrashMessage", 336 l10n_util::GetStringUTF16(IDS_EXTENSIONS_CRASHED_EXTENSION)); 337 source->AddString("extensionSettingsInDevelopment", 338 l10n_util::GetStringUTF16(IDS_EXTENSIONS_IN_DEVELOPMENT)); 339 source->AddString("extensionSettingsWarningsTitle", 340 l10n_util::GetStringUTF16(IDS_EXTENSION_WARNINGS_TITLE)); 341 source->AddString("extensionSettingsShowDetails", 342 l10n_util::GetStringUTF16(IDS_EXTENSIONS_SHOW_DETAILS)); 343 source->AddString("extensionSettingsHideDetails", 344 l10n_util::GetStringUTF16(IDS_EXTENSIONS_HIDE_DETAILS)); 345 346 // TODO(estade): comb through the above strings to find ones no longer used in 347 // uber extensions. 348 source->AddString("extensionUninstall", 349 l10n_util::GetStringUTF16(IDS_EXTENSIONS_UNINSTALL)); 350} 351 352void ExtensionSettingsHandler::RenderViewHostCreated( 353 content::RenderViewHost* render_view_host) { 354 Profile* source_profile = Profile::FromBrowserContext( 355 render_view_host->GetSiteInstance()->GetBrowserContext()); 356 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile)) 357 return; 358 MaybeUpdateAfterNotification(); 359} 360 361void ExtensionSettingsHandler::RenderViewDeleted( 362 content::RenderViewHost* render_view_host) { 363 deleting_rvh_ = render_view_host; 364 Profile* source_profile = Profile::FromBrowserContext( 365 render_view_host->GetSiteInstance()->GetBrowserContext()); 366 if (!Profile::FromWebUI(web_ui())->IsSameProfile(source_profile)) 367 return; 368 MaybeUpdateAfterNotification(); 369} 370 371void ExtensionSettingsHandler::NavigateToPendingEntry(const GURL& url, 372 content::NavigationController::ReloadType reload_type) { 373 if (reload_type != content::NavigationController::NO_RELOAD) 374 ReloadUnpackedExtensions(); 375} 376 377void ExtensionSettingsHandler::RegisterMessages() { 378 // Don't override an |extension_service_| or |management_policy_| injected 379 // for testing. 380 if (!extension_service_) { 381 extension_service_ = Profile::FromWebUI(web_ui())->GetOriginalProfile()-> 382 GetExtensionService(); 383 } 384 if (!management_policy_) { 385 management_policy_ = extensions::ExtensionSystem::Get( 386 extension_service_->profile())->management_policy(); 387 } 388 389 web_ui()->RegisterMessageCallback("extensionSettingsRequestExtensionsData", 390 base::Bind(&ExtensionSettingsHandler::HandleRequestExtensionsData, 391 base::Unretained(this))); 392 web_ui()->RegisterMessageCallback("extensionSettingsToggleDeveloperMode", 393 base::Bind(&ExtensionSettingsHandler::HandleToggleDeveloperMode, 394 base::Unretained(this))); 395 web_ui()->RegisterMessageCallback("extensionSettingsInspect", 396 base::Bind(&ExtensionSettingsHandler::HandleInspectMessage, 397 base::Unretained(this))); 398 web_ui()->RegisterMessageCallback("extensionSettingsLaunch", 399 base::Bind(&ExtensionSettingsHandler::HandleLaunchMessage, 400 base::Unretained(this))); 401 web_ui()->RegisterMessageCallback("extensionSettingsRestart", 402 base::Bind(&ExtensionSettingsHandler::HandleRestartMessage, 403 base::Unretained(this))); 404 web_ui()->RegisterMessageCallback("extensionSettingsReload", 405 base::Bind(&ExtensionSettingsHandler::HandleReloadMessage, 406 base::Unretained(this))); 407 web_ui()->RegisterMessageCallback("extensionSettingsEnable", 408 base::Bind(&ExtensionSettingsHandler::HandleEnableMessage, 409 base::Unretained(this))); 410 web_ui()->RegisterMessageCallback("extensionSettingsEnableIncognito", 411 base::Bind(&ExtensionSettingsHandler::HandleEnableIncognitoMessage, 412 base::Unretained(this))); 413 web_ui()->RegisterMessageCallback("extensionSettingsAllowFileAccess", 414 base::Bind(&ExtensionSettingsHandler::HandleAllowFileAccessMessage, 415 base::Unretained(this))); 416 web_ui()->RegisterMessageCallback("extensionSettingsUninstall", 417 base::Bind(&ExtensionSettingsHandler::HandleUninstallMessage, 418 base::Unretained(this))); 419 web_ui()->RegisterMessageCallback("extensionSettingsOptions", 420 base::Bind(&ExtensionSettingsHandler::HandleOptionsMessage, 421 base::Unretained(this))); 422 web_ui()->RegisterMessageCallback("extensionSettingsPermissions", 423 base::Bind(&ExtensionSettingsHandler::HandlePermissionsMessage, 424 base::Unretained(this))); 425 web_ui()->RegisterMessageCallback("extensionSettingsShowButton", 426 base::Bind(&ExtensionSettingsHandler::HandleShowButtonMessage, 427 base::Unretained(this))); 428 web_ui()->RegisterMessageCallback("extensionSettingsAutoupdate", 429 base::Bind(&ExtensionSettingsHandler::HandleAutoUpdateMessage, 430 base::Unretained(this))); 431 web_ui()->RegisterMessageCallback("extensionSettingsLoadUnpackedExtension", 432 base::Bind(&ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage, 433 base::Unretained(this))); 434} 435 436void ExtensionSettingsHandler::FileSelected(const base::FilePath& path, 437 int index, 438 void* params) { 439 last_unpacked_directory_ = base::FilePath(path); 440 extensions::UnpackedInstaller::Create(extension_service_)->Load(path); 441} 442 443void ExtensionSettingsHandler::MultiFilesSelected( 444 const std::vector<base::FilePath>& files, void* params) { 445 NOTREACHED(); 446} 447 448void ExtensionSettingsHandler::Observe( 449 int type, 450 const content::NotificationSource& source, 451 const content::NotificationDetails& details) { 452 Profile* profile = Profile::FromWebUI(web_ui()); 453 Profile* source_profile = NULL; 454 switch (type) { 455 // We listen for notifications that will result in the page being 456 // repopulated with data twice for the same event in certain cases. 457 // For instance, EXTENSION_LOADED & EXTENSION_HOST_CREATED because 458 // we don't know about the views for an extension at EXTENSION_LOADED, but 459 // if we only listen to EXTENSION_HOST_CREATED, we'll miss extensions 460 // that don't have a process at startup. 461 // 462 // Doing it this way gets everything but causes the page to be rendered 463 // more than we need. It doesn't seem to result in any noticeable flicker. 464 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED: 465 deleting_rvh_ = content::Details<BackgroundContents>(details)-> 466 web_contents()->GetRenderViewHost(); 467 // Fall through. 468 case chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED: 469 case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: 470 source_profile = content::Source<Profile>(source).ptr(); 471 if (!profile->IsSameProfile(source_profile)) 472 return; 473 MaybeUpdateAfterNotification(); 474 break; 475 case chrome::NOTIFICATION_EXTENSION_LOADED: 476 case chrome::NOTIFICATION_EXTENSION_UNLOADED: 477 case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: 478 case chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED: 479 MaybeUpdateAfterNotification(); 480 break; 481 default: 482 NOTREACHED(); 483 } 484} 485 486void ExtensionSettingsHandler::ExtensionUninstallAccepted() { 487 DCHECK(!extension_id_prompting_.empty()); 488 489 bool was_terminated = false; 490 491 // The extension can be uninstalled in another window while the UI was 492 // showing. Do nothing in that case. 493 const Extension* extension = 494 extension_service_->GetExtensionById(extension_id_prompting_, true); 495 if (!extension) { 496 extension = extension_service_->GetTerminatedExtension( 497 extension_id_prompting_); 498 was_terminated = true; 499 } 500 if (!extension) 501 return; 502 503 extension_service_->UninstallExtension(extension_id_prompting_, 504 false, // External uninstall. 505 NULL); // Error. 506 extension_id_prompting_ = ""; 507 508 // There will be no EXTENSION_UNLOADED notification for terminated 509 // extensions as they were already unloaded. 510 if (was_terminated) 511 HandleRequestExtensionsData(NULL); 512} 513 514void ExtensionSettingsHandler::ExtensionUninstallCanceled() { 515 extension_id_prompting_ = ""; 516} 517 518void ExtensionSettingsHandler::ExtensionWarningsChanged() { 519 MaybeUpdateAfterNotification(); 520} 521 522void ExtensionSettingsHandler::InstallUIProceed() { 523 // This should never happen. The dialog only has a cancel button. 524 NOTREACHED(); 525} 526 527void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) { 528} 529 530void ExtensionSettingsHandler::ReloadUnpackedExtensions() { 531 const ExtensionSet* extensions = extension_service_->extensions(); 532 std::vector<const Extension*> unpacked_extensions; 533 for (ExtensionSet::const_iterator extension = extensions->begin(); 534 extension != extensions->end(); ++extension) { 535 if (Manifest::IsUnpackedLocation((*extension)->location())) 536 unpacked_extensions.push_back(*extension); 537 } 538 539 for (std::vector<const Extension*>::iterator iter = 540 unpacked_extensions.begin(); iter != unpacked_extensions.end(); ++iter) { 541 extension_service_->ReloadExtension((*iter)->id()); 542 } 543} 544 545void ExtensionSettingsHandler::HandleRequestExtensionsData( 546 const ListValue* args) { 547 DictionaryValue results; 548 549 Profile* profile = Profile::FromWebUI(web_ui()); 550 551 // Add the extensions to the results structure. 552 ListValue* extensions_list = new ListValue(); 553 554 extensions::ExtensionWarningService* warnings = 555 extensions::ExtensionSystem::Get(profile)->warning_service(); 556 557 const ExtensionSet* extensions = extension_service_->extensions(); 558 for (ExtensionSet::const_iterator extension = extensions->begin(); 559 extension != extensions->end(); ++extension) { 560 if ((*extension)->ShouldDisplayInExtensionSettings()) { 561 extensions_list->Append(CreateExtensionDetailValue( 562 *extension, 563 GetInspectablePagesForExtension(*extension, true), 564 warnings)); 565 } 566 } 567 extensions = extension_service_->disabled_extensions(); 568 for (ExtensionSet::const_iterator extension = extensions->begin(); 569 extension != extensions->end(); ++extension) { 570 if ((*extension)->ShouldDisplayInExtensionSettings()) { 571 extensions_list->Append(CreateExtensionDetailValue( 572 *extension, 573 GetInspectablePagesForExtension(*extension, false), 574 warnings)); 575 } 576 } 577 extensions = extension_service_->terminated_extensions(); 578 std::vector<ExtensionPage> empty_pages; 579 for (ExtensionSet::const_iterator extension = extensions->begin(); 580 extension != extensions->end(); ++extension) { 581 if ((*extension)->ShouldDisplayInExtensionSettings()) { 582 extensions_list->Append(CreateExtensionDetailValue( 583 *extension, 584 empty_pages, // Terminated process has no active pages. 585 warnings)); 586 } 587 } 588 results.Set("extensions", extensions_list); 589 590 ManagedUserService* service = 591 ManagedUserServiceFactory::GetForProfile(profile); 592 593 bool is_managed = service->ProfileIsManaged(); 594 bool developer_mode = 595 !is_managed && 596 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); 597 results.SetBoolean("profileIsManaged", is_managed); 598 results.SetBoolean("developerMode", developer_mode); 599 600 bool load_unpacked_disabled = 601 extension_service_->extension_prefs()->ExtensionsBlacklistedByDefault(); 602 results.SetBoolean("loadUnpackedDisabled", load_unpacked_disabled); 603 604 web_ui()->CallJavascriptFunction("ExtensionSettings.returnExtensionsData", 605 results); 606 607 MaybeRegisterForNotifications(); 608} 609 610void ExtensionSettingsHandler::HandleToggleDeveloperMode( 611 const ListValue* args) { 612 Profile* profile = Profile::FromWebUI(web_ui()); 613 if (ManagedUserServiceFactory::GetForProfile(profile)->ProfileIsManaged()) 614 return; 615 616 bool developer_mode = 617 profile->GetPrefs()->GetBoolean(prefs::kExtensionsUIDeveloperMode); 618 profile->GetPrefs()->SetBoolean( 619 prefs::kExtensionsUIDeveloperMode, !developer_mode); 620} 621 622void ExtensionSettingsHandler::HandleInspectMessage(const ListValue* args) { 623 std::string extension_id; 624 std::string render_process_id_str; 625 std::string render_view_id_str; 626 int render_process_id; 627 int render_view_id; 628 bool incognito; 629 CHECK_EQ(4U, args->GetSize()); 630 CHECK(args->GetString(0, &extension_id)); 631 CHECK(args->GetString(1, &render_process_id_str)); 632 CHECK(args->GetString(2, &render_view_id_str)); 633 CHECK(args->GetBoolean(3, &incognito)); 634 CHECK(base::StringToInt(render_process_id_str, &render_process_id)); 635 CHECK(base::StringToInt(render_view_id_str, &render_view_id)); 636 637 if (render_process_id == -1) { 638 // This message is for a lazy background page. Start the page if necessary. 639 const Extension* extension = 640 extension_service_->extensions()->GetByID(extension_id); 641 DCHECK(extension); 642 643 ExtensionService* service = extension_service_; 644 if (incognito) 645 service = extensions::ExtensionSystem::Get(extension_service_-> 646 profile()->GetOffTheRecordProfile())->extension_service(); 647 648 service->InspectBackgroundPage(extension); 649 return; 650 } 651 652 RenderViewHost* host = RenderViewHost::FromID(render_process_id, 653 render_view_id); 654 if (!host) { 655 // This can happen if the host has gone away since the page was displayed. 656 return; 657 } 658 659 DevToolsWindow::OpenDevToolsWindow(host); 660} 661 662void ExtensionSettingsHandler::HandleLaunchMessage(const ListValue* args) { 663 CHECK_EQ(1U, args->GetSize()); 664 std::string extension_id; 665 CHECK(args->GetString(0, &extension_id)); 666 const extensions::Extension* extension = 667 extension_service_->GetExtensionById(extension_id, false); 668 chrome::OpenApplication(chrome::AppLaunchParams(extension_service_->profile(), 669 extension, 670 extension_misc::LAUNCH_WINDOW, 671 NEW_WINDOW)); 672} 673 674void ExtensionSettingsHandler::HandleRestartMessage(const ListValue* args) { 675 CHECK_EQ(1U, args->GetSize()); 676 std::string extension_id; 677 CHECK(args->GetString(0, &extension_id)); 678 extension_service_->RestartExtension(extension_id); 679} 680 681void ExtensionSettingsHandler::HandleReloadMessage(const ListValue* args) { 682 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); 683 CHECK(!extension_id.empty()); 684 extension_service_->ReloadExtension(extension_id); 685} 686 687void ExtensionSettingsHandler::HandleEnableMessage(const ListValue* args) { 688 CHECK_EQ(2U, args->GetSize()); 689 std::string extension_id, enable_str; 690 CHECK(args->GetString(0, &extension_id)); 691 CHECK(args->GetString(1, &enable_str)); 692 693 const Extension* extension = 694 extension_service_->GetInstalledExtension(extension_id); 695 if (!extension || 696 !management_policy_->UserMayModifySettings(extension, NULL)) { 697 LOG(ERROR) << "Attempt to enable an extension that is non-usermanagable was" 698 << "made. Extension id: " << extension->id(); 699 return; 700 } 701 702 if (enable_str == "true") { 703 extensions::ExtensionPrefs* prefs = extension_service_->extension_prefs(); 704 if (prefs->DidExtensionEscalatePermissions(extension_id)) { 705 extensions::ShowExtensionDisabledDialog( 706 extension_service_, web_ui()->GetWebContents(), extension); 707 } else if ((prefs->GetDisableReasons(extension_id) & 708 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) && 709 !requirements_checker_.get()) { 710 // Recheck the requirements. 711 scoped_refptr<const Extension> extension = 712 extension_service_->GetExtensionById(extension_id, 713 true /* include disabled */); 714 requirements_checker_.reset(new extensions::RequirementsChecker()); 715 requirements_checker_->Check( 716 extension, 717 base::Bind(&ExtensionSettingsHandler::OnRequirementsChecked, 718 AsWeakPtr(), extension_id)); 719 } else { 720 extension_service_->EnableExtension(extension_id); 721 722 // Make sure any browser action contained within it is not hidden. 723 extensions::ExtensionActionAPI::SetBrowserActionVisibility( 724 prefs, extension->id(), true); 725 } 726 } else { 727 extension_service_->DisableExtension( 728 extension_id, Extension::DISABLE_USER_ACTION); 729 } 730} 731 732void ExtensionSettingsHandler::HandleEnableIncognitoMessage( 733 const ListValue* args) { 734 CHECK_EQ(2U, args->GetSize()); 735 std::string extension_id, enable_str; 736 CHECK(args->GetString(0, &extension_id)); 737 CHECK(args->GetString(1, &enable_str)); 738 const Extension* extension = 739 extension_service_->GetInstalledExtension(extension_id); 740 if (!extension) 741 return; 742 743 // Flipping the incognito bit will generate unload/load notifications for the 744 // extension, but we don't want to reload the page, because a) we've already 745 // updated the UI to reflect the change, and b) we want the yellow warning 746 // text to stay until the user has left the page. 747 // 748 // TODO(aa): This creates crappiness in some cases. For example, in a main 749 // window, when toggling this, the browser action will flicker because it gets 750 // unloaded, then reloaded. It would be better to have a dedicated 751 // notification for this case. 752 // 753 // Bug: http://crbug.com/41384 754 base::AutoReset<bool> auto_reset_ignore_notifications( 755 &ignore_notifications_, true); 756 extension_service_->SetIsIncognitoEnabled(extension->id(), 757 enable_str == "true"); 758} 759 760void ExtensionSettingsHandler::HandleAllowFileAccessMessage( 761 const ListValue* args) { 762 CHECK_EQ(2U, args->GetSize()); 763 std::string extension_id, allow_str; 764 CHECK(args->GetString(0, &extension_id)); 765 CHECK(args->GetString(1, &allow_str)); 766 const Extension* extension = 767 extension_service_->GetInstalledExtension(extension_id); 768 if (!extension) 769 return; 770 771 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 772 LOG(ERROR) << "Attempt to change allow file access of an extension that is " 773 << "non-usermanagable was made. Extension id : " 774 << extension->id(); 775 return; 776 } 777 778 extension_service_->SetAllowFileAccess(extension, allow_str == "true"); 779} 780 781void ExtensionSettingsHandler::HandleUninstallMessage(const ListValue* args) { 782 CHECK_EQ(1U, args->GetSize()); 783 std::string extension_id; 784 CHECK(args->GetString(0, &extension_id)); 785 const Extension* extension = 786 extension_service_->GetInstalledExtension(extension_id); 787 if (!extension) 788 return; 789 790 if (!management_policy_->UserMayModifySettings(extension, NULL)) { 791 LOG(ERROR) << "Attempt to uninstall an extension that is non-usermanagable " 792 << "was made. Extension id : " << extension->id(); 793 return; 794 } 795 796 if (!extension_id_prompting_.empty()) 797 return; // Only one prompt at a time. 798 799 extension_id_prompting_ = extension_id; 800 801 GetExtensionUninstallDialog()->ConfirmUninstall(extension); 802} 803 804void ExtensionSettingsHandler::HandleOptionsMessage(const ListValue* args) { 805 const Extension* extension = GetActiveExtension(args); 806 if (!extension || 807 extensions::ManifestURL::GetOptionsPage(extension).is_empty()) 808 return; 809 ExtensionTabUtil::OpenOptionsPage(extension, 810 chrome::FindBrowserWithWebContents(web_ui()->GetWebContents())); 811} 812 813void ExtensionSettingsHandler::HandlePermissionsMessage(const ListValue* args) { 814 std::string extension_id(UTF16ToUTF8(ExtractStringValue(args))); 815 CHECK(!extension_id.empty()); 816 const Extension* extension = 817 extension_service_->GetExtensionById(extension_id, true); 818 if (!extension) 819 return; 820 821 prompt_.reset(new ExtensionInstallPrompt(web_contents())); 822 prompt_->ReviewPermissions(this, extension); 823} 824 825void ExtensionSettingsHandler::HandleShowButtonMessage(const ListValue* args) { 826 const Extension* extension = GetActiveExtension(args); 827 if (!extension) 828 return; 829 extensions::ExtensionActionAPI::SetBrowserActionVisibility( 830 extension_service_->extension_prefs(), extension->id(), true); 831} 832 833void ExtensionSettingsHandler::HandleAutoUpdateMessage(const ListValue* args) { 834 ExtensionUpdater* updater = extension_service_->updater(); 835 if (updater) { 836 ExtensionUpdater::CheckParams params; 837 params.install_immediately = true; 838 updater->CheckNow(params); 839 } 840} 841 842void ExtensionSettingsHandler::HandleLoadUnpackedExtensionMessage( 843 const ListValue* args) { 844 DCHECK(args->empty()); 845 846 string16 select_title = 847 l10n_util::GetStringUTF16(IDS_EXTENSION_LOAD_FROM_DIRECTORY); 848 849 const int kFileTypeIndex = 0; // No file type information to index. 850 const ui::SelectFileDialog::Type kSelectType = 851 ui::SelectFileDialog::SELECT_FOLDER; 852 load_extension_dialog_ = ui::SelectFileDialog::Create( 853 this, new ChromeSelectFilePolicy(web_ui()->GetWebContents())); 854 load_extension_dialog_->SelectFile( 855 kSelectType, 856 select_title, 857 last_unpacked_directory_, 858 NULL, 859 kFileTypeIndex, 860 base::FilePath::StringType(), 861 web_ui()->GetWebContents()->GetView()->GetTopLevelNativeWindow(), 862 NULL); 863} 864 865void ExtensionSettingsHandler::ShowAlert(const std::string& message) { 866 ListValue arguments; 867 arguments.Append(Value::CreateStringValue(message)); 868 web_ui()->CallJavascriptFunction("alert", arguments); 869} 870 871const Extension* ExtensionSettingsHandler::GetActiveExtension( 872 const ListValue* args) { 873 std::string extension_id = UTF16ToUTF8(ExtractStringValue(args)); 874 CHECK(!extension_id.empty()); 875 return extension_service_->GetExtensionById(extension_id, false); 876} 877 878void ExtensionSettingsHandler::MaybeUpdateAfterNotification() { 879 WebContents* contents = web_ui()->GetWebContents(); 880 if (!ignore_notifications_ && contents && contents->GetRenderViewHost()) 881 HandleRequestExtensionsData(NULL); 882 deleting_rvh_ = NULL; 883} 884 885void ExtensionSettingsHandler::MaybeRegisterForNotifications() { 886 if (registered_for_notifications_) 887 return; 888 889 registered_for_notifications_ = true; 890 Profile* profile = Profile::FromWebUI(web_ui()); 891 892 // Register for notifications that we need to reload the page. 893 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, 894 content::Source<Profile>(profile)); 895 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, 896 content::Source<Profile>(profile)); 897 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, 898 content::Source<Profile>(profile)); 899 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, 900 content::NotificationService::AllBrowserContextsAndSources()); 901 registrar_.Add(this, 902 chrome::NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED, 903 content::NotificationService::AllBrowserContextsAndSources()); 904 registrar_.Add(this, 905 chrome::NOTIFICATION_BACKGROUND_CONTENTS_DELETED, 906 content::NotificationService::AllBrowserContextsAndSources()); 907 registrar_.Add( 908 this, 909 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED, 910 content::Source<extensions::ExtensionPrefs>( 911 profile->GetExtensionService()->extension_prefs())); 912 913 content::RenderViewHost::AddCreatedCallback(rvh_created_callback_); 914 915 content::WebContentsObserver::Observe(web_ui()->GetWebContents()); 916 917 warning_service_observer_.Add( 918 extensions::ExtensionSystem::Get(profile)->warning_service()); 919 920 base::Closure callback = base::Bind( 921 &ExtensionSettingsHandler::MaybeUpdateAfterNotification, 922 base::Unretained(this)); 923 924 pref_registrar_.Init(profile->GetPrefs()); 925 pref_registrar_.Add(prefs::kExtensionInstallDenyList, callback); 926} 927 928std::vector<ExtensionPage> 929ExtensionSettingsHandler::GetInspectablePagesForExtension( 930 const Extension* extension, bool extension_is_enabled) { 931 std::vector<ExtensionPage> result; 932 933 // Get the extension process's active views. 934 ExtensionProcessManager* process_manager = 935 extensions::ExtensionSystem::Get(extension_service_->profile())-> 936 process_manager(); 937 GetInspectablePagesForExtensionProcess( 938 process_manager->GetRenderViewHostsForExtension(extension->id()), 939 &result); 940 941 // Get shell window views 942 GetShellWindowPagesForExtensionProfile(extension, 943 extension_service_->profile(), &result); 944 945 // Include a link to start the lazy background page, if applicable. 946 if (extensions::BackgroundInfo::HasLazyBackgroundPage(extension) && 947 extension_is_enabled && 948 !process_manager->GetBackgroundHostForExtension(extension->id())) { 949 result.push_back( 950 ExtensionPage(extensions::BackgroundInfo::GetBackgroundURL(extension), 951 -1, -1, false)); 952 } 953 954 // Repeat for the incognito process, if applicable. Don't try to get 955 // shell windows for incognito processes. 956 if (extension_service_->profile()->HasOffTheRecordProfile() && 957 extensions::IncognitoInfo::IsSplitMode(extension)) { 958 ExtensionProcessManager* process_manager = 959 extensions::ExtensionSystem::Get(extension_service_->profile()-> 960 GetOffTheRecordProfile())->process_manager(); 961 GetInspectablePagesForExtensionProcess( 962 process_manager->GetRenderViewHostsForExtension(extension->id()), 963 &result); 964 965 if (extensions::BackgroundInfo::HasLazyBackgroundPage(extension) 966 && extension_is_enabled && 967 !process_manager->GetBackgroundHostForExtension(extension->id())) { 968 result.push_back( 969 ExtensionPage(extensions::BackgroundInfo::GetBackgroundURL(extension), 970 -1, -1, true)); 971 } 972 } 973 974 return result; 975} 976 977void ExtensionSettingsHandler::GetInspectablePagesForExtensionProcess( 978 const std::set<RenderViewHost*>& views, 979 std::vector<ExtensionPage>* result) { 980 for (std::set<RenderViewHost*>::const_iterator iter = views.begin(); 981 iter != views.end(); ++iter) { 982 RenderViewHost* host = *iter; 983 WebContents* web_contents = WebContents::FromRenderViewHost(host); 984 extensions::ViewType host_type = extensions::GetViewType(web_contents); 985 if (host == deleting_rvh_ || 986 extensions::VIEW_TYPE_EXTENSION_POPUP == host_type || 987 extensions::VIEW_TYPE_EXTENSION_DIALOG == host_type) 988 continue; 989 990 GURL url = web_contents->GetURL(); 991 content::RenderProcessHost* process = host->GetProcess(); 992 result->push_back( 993 ExtensionPage(url, process->GetID(), host->GetRoutingID(), 994 process->GetBrowserContext()->IsOffTheRecord())); 995 } 996} 997 998void ExtensionSettingsHandler::GetShellWindowPagesForExtensionProfile( 999 const Extension* extension, 1000 Profile* profile, 1001 std::vector<ExtensionPage>* result) { 1002 extensions::ShellWindowRegistry* registry = 1003 extensions::ShellWindowRegistry::Get(profile); 1004 if (!registry) return; 1005 1006 const extensions::ShellWindowRegistry::ShellWindowList windows = 1007 registry->GetShellWindowsForApp(extension->id()); 1008 1009 for (extensions::ShellWindowRegistry::const_iterator it = windows.begin(); 1010 it != windows.end(); ++it) { 1011 WebContents* web_contents = (*it)->web_contents(); 1012 RenderViewHost* host = web_contents->GetRenderViewHost(); 1013 content::RenderProcessHost* process = host->GetProcess(); 1014 1015 result->push_back( 1016 ExtensionPage(web_contents->GetURL(), process->GetID(), 1017 host->GetRoutingID(), 1018 process->GetBrowserContext()->IsOffTheRecord())); 1019 } 1020} 1021 1022ExtensionUninstallDialog* 1023ExtensionSettingsHandler::GetExtensionUninstallDialog() { 1024#if !defined(OS_ANDROID) 1025 if (!extension_uninstall_dialog_.get()) { 1026 Browser* browser = chrome::FindBrowserWithWebContents( 1027 web_ui()->GetWebContents()); 1028 extension_uninstall_dialog_.reset( 1029 ExtensionUninstallDialog::Create(extension_service_->profile(), 1030 browser, this)); 1031 } 1032 return extension_uninstall_dialog_.get(); 1033#else 1034 return NULL; 1035#endif // !defined(OS_ANDROID) 1036} 1037 1038void ExtensionSettingsHandler::OnRequirementsChecked( 1039 std::string extension_id, 1040 std::vector<std::string> requirement_errors) { 1041 if (requirement_errors.empty()) { 1042 extension_service_->EnableExtension(extension_id); 1043 } else { 1044 ExtensionErrorReporter::GetInstance()->ReportError( 1045 UTF8ToUTF16(JoinString(requirement_errors, ' ')), 1046 true /* be noisy */); 1047 } 1048 requirements_checker_.reset(); 1049} 1050