• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ExtensionPage(const GURL & url,int render_process_id,int render_view_id,bool incognito,bool generated_background_page)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:
BrokerDelegate(const base::WeakPtr<ExtensionSettingsHandler> & delegate)128   explicit BrokerDelegate(
129       const base::WeakPtr<ExtensionSettingsHandler>& delegate)
130       : delegate_(delegate) {}
131 
132   // ExtensionInstallPrompt::Delegate implementation.
InstallUIProceed()133   virtual void InstallUIProceed() OVERRIDE {
134     if (delegate_)
135       delegate_->InstallUIProceed();
136     delete this;
137   };
138 
InstallUIAbort(bool user_initiated)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 
ExtensionSettingsHandler()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 
~ExtensionSettingsHandler()172 ExtensionSettingsHandler::~ExtensionSettingsHandler() {
173 }
174 
ExtensionSettingsHandler(ExtensionService * service,ManagementPolicy * policy)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
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)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 
CreateExtensionDetailValue(const Extension * extension,const std::vector<ExtensionPage> & pages,const ExtensionWarningService * warning_service)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 
GetLocalizedValues(content::WebUIDataSource * source)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 
RenderViewDeleted(RenderViewHost * render_view_host)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 
DidStartNavigationToPendingEntry(const GURL & url,content::NavigationController::ReloadType reload_type)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 
RegisterMessages()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 
OnErrorAdded(const ExtensionError * error)629 void ExtensionSettingsHandler::OnErrorAdded(const ExtensionError* error) {
630   MaybeUpdateAfterNotification();
631 }
632 
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)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 
OnExtensionLoaded(content::BrowserContext * browser_context,const Extension * extension)686 void ExtensionSettingsHandler::OnExtensionLoaded(
687     content::BrowserContext* browser_context,
688     const Extension* extension) {
689   MaybeUpdateAfterNotification();
690 }
691 
OnExtensionUnloaded(content::BrowserContext * browser_context,const Extension * extension,UnloadedExtensionInfo::Reason reason)692 void ExtensionSettingsHandler::OnExtensionUnloaded(
693     content::BrowserContext* browser_context,
694     const Extension* extension,
695     UnloadedExtensionInfo::Reason reason) {
696   MaybeUpdateAfterNotification();
697 }
698 
OnExtensionUninstalled(content::BrowserContext * browser_context,const Extension * extension)699 void ExtensionSettingsHandler::OnExtensionUninstalled(
700     content::BrowserContext* browser_context,
701     const Extension* extension) {
702   MaybeUpdateAfterNotification();
703 }
704 
OnExtensionDisableReasonsChanged(const std::string & extension_id,int disable_reasons)705 void ExtensionSettingsHandler::OnExtensionDisableReasonsChanged(
706     const std::string& extension_id, int disable_reasons) {
707   MaybeUpdateAfterNotification();
708 }
709 
ExtensionUninstallAccepted()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 
ExtensionUninstallCanceled()739 void ExtensionSettingsHandler::ExtensionUninstallCanceled() {
740   extension_id_prompting_ = "";
741 }
742 
ExtensionWarningsChanged()743 void ExtensionSettingsHandler::ExtensionWarningsChanged() {
744   MaybeUpdateAfterNotification();
745 }
746 
747 // This is called when the user clicks "Revoke File Access."
InstallUIProceed()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 
InstallUIAbort(bool user_initiated)760 void ExtensionSettingsHandler::InstallUIAbort(bool user_initiated) {
761   extension_id_prompting_.clear();
762 }
763 
ReloadUnpackedExtensions()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 
HandleRequestExtensionsData(const base::ListValue * args)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 
HandleToggleDeveloperMode(const base::ListValue * args)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 
HandleInspectMessage(const base::ListValue * args)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 
HandleLaunchMessage(const base::ListValue * args)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 
HandleReloadMessage(const base::ListValue * args)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 
HandleEnableMessage(const base::ListValue * args)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 
HandleEnableIncognitoMessage(const base::ListValue * args)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 
HandleEnableErrorCollectionMessage(const base::ListValue * args)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 
HandleAllowFileAccessMessage(const base::ListValue * args)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 
HandleAllowOnAllUrlsMessage(const base::ListValue * args)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 
HandleUninstallMessage(const base::ListValue * args)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 
HandleOptionsMessage(const base::ListValue * args)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 
HandlePermissionsMessage(const base::ListValue * args)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 
HandleShowButtonMessage(const base::ListValue * args)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 
HandleAutoUpdateMessage(const base::ListValue * args)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 
HandleDismissADTPromoMessage(const base::ListValue * args)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 
ShowAlert(const std::string & message)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 
GetActiveExtension(const base::ListValue * args)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 
MaybeUpdateAfterNotification()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 
MaybeRegisterForNotifications()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>
GetInspectablePagesForExtension(const Extension * extension,bool extension_is_enabled)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 
GetInspectablePagesForExtensionProcess(const Extension * extension,const std::set<RenderViewHost * > & views,std::vector<ExtensionPage> * result)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 
GetAppWindowPagesForExtensionProfile(const Extension * extension,Profile * profile,std::vector<ExtensionPage> * result)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*
GetExtensionUninstallDialog()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 
OnRequirementsChecked(std::string extension_id,std::vector<std::string> requirement_errors)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