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