1 // Copyright 2015 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.
5 #include "chrome/browser/extensions/api/developer_private/extension_info_generator.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/browser/extensions/api/developer_private/inspectable_views_finder.h"
9 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
10 #include "chrome/browser/extensions/error_console/error_console.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/extension_ui_util.h"
13 #include "chrome/browser/extensions/extension_util.h"
14 #include "chrome/browser/extensions/path_util.h"
15 #include "chrome/browser/extensions/shared_module_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
18 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
19 #include "chrome/grit/generated_resources.h"
20 #include "content/public/browser/render_view_host.h"
21 #include "extensions/browser/extension_error.h"
22 #include "extensions/browser/extension_prefs.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/extension_system.h"
25 #include "extensions/browser/warning_service.h"
26 #include "extensions/common/extension_set.h"
27 #include "extensions/common/feature_switch.h"
28 #include "extensions/common/install_warning.h"
29 #include "extensions/common/manifest.h"
30 #include "extensions/common/manifest_handlers/background_info.h"
31 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
32 #include "extensions/common/manifest_handlers/options_page_info.h"
33 #include "extensions/common/manifest_url_handlers.h"
34 #include "extensions/common/permissions/permissions_data.h"
35 #include "ui/base/l10n/l10n_util.h"
37 namespace extensions
{
39 namespace developer
= api::developer_private
;
43 // Given a Manifest::Type, converts it into its developer_private
45 developer::ExtensionType
GetExtensionType(Manifest::Type manifest_type
) {
46 developer::ExtensionType type
= developer::EXTENSION_TYPE_EXTENSION
;
47 switch (manifest_type
) {
48 case Manifest::TYPE_EXTENSION
:
49 type
= developer::EXTENSION_TYPE_EXTENSION
;
51 case Manifest::TYPE_THEME
:
52 type
= developer::EXTENSION_TYPE_THEME
;
54 case Manifest::TYPE_HOSTED_APP
:
55 type
= developer::EXTENSION_TYPE_HOSTED_APP
;
57 case Manifest::TYPE_LEGACY_PACKAGED_APP
:
58 type
= developer::EXTENSION_TYPE_LEGACY_PACKAGED_APP
;
60 case Manifest::TYPE_PLATFORM_APP
:
61 type
= developer::EXTENSION_TYPE_PLATFORM_APP
;
63 case Manifest::TYPE_SHARED_MODULE
:
64 type
= developer::EXTENSION_TYPE_SHARED_MODULE
;
72 // Populates the common fields of an extension error.
73 template <typename ErrorType
>
74 void PopulateErrorBase(const ExtensionError
& error
, ErrorType
* out
) {
76 out
->type
= error
.type() == ExtensionError::MANIFEST_ERROR
?
77 developer::ERROR_TYPE_MANIFEST
: developer::ERROR_TYPE_RUNTIME
;
78 out
->extension_id
= error
.extension_id();
79 out
->from_incognito
= error
.from_incognito();
80 out
->source
= base::UTF16ToUTF8(error
.source());
81 out
->message
= base::UTF16ToUTF8(error
.message());
84 // Given a ManifestError object, converts it into its developer_private
86 linked_ptr
<developer::ManifestError
> ConstructManifestError(
87 const ManifestError
& error
) {
88 linked_ptr
<developer::ManifestError
> result(new developer::ManifestError());
89 PopulateErrorBase(error
, result
.get());
90 result
->manifest_key
= base::UTF16ToUTF8(error
.manifest_key());
91 if (!error
.manifest_specific().empty()) {
92 result
->manifest_specific
.reset(
93 new std::string(base::UTF16ToUTF8(error
.manifest_specific())));
98 // Given a RuntimeError object, converts it into its developer_private
100 linked_ptr
<developer::RuntimeError
> ConstructRuntimeError(
101 const RuntimeError
& error
) {
102 linked_ptr
<developer::RuntimeError
> result(new developer::RuntimeError());
103 PopulateErrorBase(error
, result
.get());
104 switch (error
.level()) {
105 case logging::LOG_VERBOSE
:
106 case logging::LOG_INFO
:
107 result
->severity
= developer::ERROR_LEVEL_LOG
;
109 case logging::LOG_WARNING
:
110 result
->severity
= developer::ERROR_LEVEL_WARN
;
112 case logging::LOG_FATAL
:
113 case logging::LOG_ERROR
:
114 result
->severity
= developer::ERROR_LEVEL_ERROR
;
119 result
->occurrences
= error
.occurrences();
120 result
->render_view_id
= error
.render_view_id();
121 result
->render_process_id
= error
.render_process_id();
122 result
->can_inspect
=
123 content::RenderViewHost::FromID(error
.render_process_id(),
124 error
.render_view_id()) != nullptr;
125 for (const StackFrame
& f
: error
.stack_trace()) {
126 linked_ptr
<developer::StackFrame
> frame(new developer::StackFrame());
127 frame
->line_number
= f
.line_number
;
128 frame
->column_number
= f
.column_number
;
129 frame
->url
= base::UTF16ToUTF8(f
.source
);
130 frame
->function_name
= base::UTF16ToUTF8(f
.function
);
131 result
->stack_trace
.push_back(frame
);
138 ExtensionInfoGenerator::ExtensionInfoGenerator(
139 content::BrowserContext
* browser_context
)
140 : browser_context_(browser_context
),
141 extension_system_(ExtensionSystem::Get(browser_context
)),
142 extension_prefs_(ExtensionPrefs::Get(browser_context
)),
143 warning_service_(WarningService::Get(browser_context
)),
144 error_console_(ErrorConsole::Get(browser_context
)) {
147 ExtensionInfoGenerator::~ExtensionInfoGenerator() {
150 scoped_ptr
<developer::ExtensionInfo
>
151 ExtensionInfoGenerator::CreateExtensionInfo(const Extension
& extension
,
152 developer::ExtensionState state
) {
153 scoped_ptr
<developer::ExtensionInfo
> info(new developer::ExtensionInfo());
155 // Don't consider the button hidden with the redesign, because "hidden"
156 // buttons are now just hidden in the wrench menu.
157 info
->action_button_hidden
=
158 !ExtensionActionAPI::GetBrowserActionVisibility(
159 extension_prefs_
, extension
.id()) &&
160 !FeatureSwitch::extension_action_redesign()->IsEnabled();
163 int blacklist_text
= -1;
164 switch (extension_prefs_
->GetExtensionBlacklistState(extension
.id())) {
165 case BLACKLISTED_SECURITY_VULNERABILITY
:
166 blacklist_text
= IDS_OPTIONS_BLACKLISTED_SECURITY_VULNERABILITY
;
168 case BLACKLISTED_CWS_POLICY_VIOLATION
:
169 blacklist_text
= IDS_OPTIONS_BLACKLISTED_CWS_POLICY_VIOLATION
;
171 case BLACKLISTED_POTENTIALLY_UNWANTED
:
172 blacklist_text
= IDS_OPTIONS_BLACKLISTED_POTENTIALLY_UNWANTED
;
177 if (blacklist_text
!= -1) {
178 info
->blacklist_text
.reset(
179 new std::string(l10n_util::GetStringUTF8(blacklist_text
)));
182 // Dependent extensions.
183 if (extension
.is_shared_module()) {
184 scoped_ptr
<ExtensionSet
> dependent_extensions
=
185 extension_system_
->extension_service()->
186 shared_module_service()->GetDependentExtensions(&extension
);
187 for (const scoped_refptr
<const Extension
>& dependent
:
188 *dependent_extensions
)
189 info
->dependent_extensions
.push_back(dependent
->id());
192 info
->description
= extension
.description();
195 int disable_reasons
= extension_prefs_
->GetDisableReasons(extension
.id());
196 info
->disable_reasons
.suspicious_install
=
197 (disable_reasons
& Extension::DISABLE_NOT_VERIFIED
) != 0;
198 info
->disable_reasons
.corrupt_install
=
199 (disable_reasons
& Extension::DISABLE_CORRUPTED
) != 0;
200 info
->disable_reasons
.update_required
=
201 (disable_reasons
& Extension::DISABLE_UPDATE_REQUIRED_BY_POLICY
) != 0;
204 bool error_console_enabled
=
205 error_console_
->IsEnabledForChromeExtensionsPage();
206 info
->error_collection
.is_enabled
= error_console_enabled
;
207 info
->error_collection
.is_active
=
208 error_console_enabled
&&
209 error_console_
->IsReportingEnabledForExtension(extension
.id());
212 info
->file_access
.is_enabled
= extension
.wants_file_access();
213 info
->file_access
.is_active
=
214 util::AllowFileAccess(extension
.id(), browser_context_
);
217 info
->home_page
.url
= ManifestURL::GetHomepageURL(&extension
).spec();
218 info
->home_page
.specified
= ManifestURL::SpecifiedHomepageURL(&extension
);
220 bool is_enabled
= state
== developer::EXTENSION_STATE_ENABLED
;
222 // TODO(devlin): This won't work with apps (CORS). We should convert to data
225 ExtensionIconSource::GetIconURL(&extension
,
226 extension_misc::EXTENSION_ICON_MEDIUM
,
227 ExtensionIconSet::MATCH_BIGGER
,
231 info
->id
= extension
.id();
234 info
->incognito_access
.is_enabled
= extension
.can_be_incognito_enabled();
235 info
->incognito_access
.is_active
=
236 util::IsIncognitoEnabled(extension
.id(), browser_context_
);
238 Profile
* profile
= Profile::FromBrowserContext(browser_context_
);
239 info
->installed_by_custodian
=
240 util::IsExtensionSupervised(&extension
, profile
);
242 // Install warnings (only if unpacked and no error console).
243 if (!error_console_enabled
&&
244 Manifest::IsUnpackedLocation(extension
.location())) {
245 const std::vector
<InstallWarning
>& install_warnings
=
246 extension
.install_warnings();
247 for (const InstallWarning
& warning
: install_warnings
)
248 info
->install_warnings
.push_back(warning
.message
);
252 if (extension
.is_app()) {
253 info
->launch_url
.reset(
254 new std::string(AppLaunchInfo::GetFullLaunchURL(&extension
).spec()));
258 if (extension
.location() == Manifest::INTERNAL
&&
259 ManifestURL::UpdatesFromGallery(&extension
)) {
260 info
->location
= developer::LOCATION_FROM_STORE
;
261 } else if (Manifest::IsUnpackedLocation(extension
.location())) {
262 info
->location
= developer::LOCATION_UNPACKED
;
263 } else if (Manifest::IsExternalLocation(extension
.location()) &&
264 ManifestURL::UpdatesFromGallery(&extension
)) {
265 info
->location
= developer::LOCATION_THIRD_PARTY
;
267 info
->location
= developer::LOCATION_UNKNOWN
;
271 int location_text
= -1;
272 if (info
->location
== developer::LOCATION_UNKNOWN
)
273 location_text
= IDS_OPTIONS_INSTALL_LOCATION_UNKNOWN
;
274 else if (extension
.location() == Manifest::EXTERNAL_REGISTRY
)
275 location_text
= IDS_OPTIONS_INSTALL_LOCATION_3RD_PARTY
;
276 else if (extension
.is_shared_module())
277 location_text
= IDS_OPTIONS_INSTALL_LOCATION_SHARED_MODULE
;
278 if (location_text
!= -1) {
279 info
->location_text
.reset(
280 new std::string(l10n_util::GetStringUTF8(location_text
)));
283 // Runtime/Manifest errors.
284 if (error_console_enabled
) {
285 const ErrorList
& errors
=
286 error_console_
->GetErrorsForExtension(extension
.id());
287 for (const ExtensionError
* error
: errors
) {
288 switch (error
->type()) {
289 case ExtensionError::MANIFEST_ERROR
:
290 info
->manifest_errors
.push_back(ConstructManifestError(
291 static_cast<const ManifestError
&>(*error
)));
293 case ExtensionError::RUNTIME_ERROR
:
294 info
->runtime_errors
.push_back(ConstructRuntimeError(
295 static_cast<const RuntimeError
&>(*error
)));
297 case ExtensionError::NUM_ERROR_TYPES
:
304 ManagementPolicy
* management_policy
= extension_system_
->management_policy();
305 info
->must_remain_installed
=
306 management_policy
->MustRemainInstalled(&extension
, nullptr);
308 info
->name
= extension
.name();
309 info
->offline_enabled
= OfflineEnabledInfo::IsOfflineEnabled(&extension
);
312 if (OptionsPageInfo::HasOptionsPage(&extension
)) {
313 info
->options_page
.reset(new developer::OptionsPage());
314 info
->options_page
->open_in_tab
=
315 OptionsPageInfo::ShouldOpenInTab(&extension
);
316 info
->options_page
->url
=
317 OptionsPageInfo::GetOptionsPage(&extension
).spec();
321 if (Manifest::IsUnpackedLocation(extension
.location())) {
322 info
->path
.reset(new std::string(extension
.path().AsUTF8Unsafe()));
323 info
->prettified_path
.reset(new std::string(
324 extensions::path_util::PrettifyPath(extension
.path()).AsUTF8Unsafe()));
327 if (Manifest::IsPolicyLocation(extension
.location())) {
328 info
->policy_text
.reset(new std::string(
329 l10n_util::GetStringUTF8(IDS_OPTIONS_INSTALL_LOCATION_ENTERPRISE
)));
333 info
->run_on_all_urls
.is_enabled
=
334 (FeatureSwitch::scripts_require_action()->IsEnabled() &&
335 PermissionsData::ScriptsMayRequireActionForExtension(
337 extension
.permissions_data()->active_permissions().get())) ||
338 extension
.permissions_data()->HasWithheldImpliedAllHosts() ||
339 util::HasSetAllowedScriptingOnAllUrls(extension
.id(), browser_context_
);
340 info
->run_on_all_urls
.is_active
=
341 util::AllowedScriptingOnAllUrls(extension
.id(), browser_context_
);
344 std::vector
<std::string
> warnings
=
345 warning_service_
->GetWarningMessagesForExtension(extension
.id());
346 for (const std::string
& warning
: warnings
)
347 info
->runtime_warnings
.push_back(warning
);
351 info
->type
= GetExtensionType(extension
.manifest()->type());
353 info
->update_url
= ManifestURL::GetUpdateURL(&extension
).spec();
355 info
->user_may_modify
=
356 management_policy
->UserMayModifySettings(&extension
, nullptr);
358 info
->version
= extension
.GetVersionForDisplay();
360 if (state
!= developer::EXTENSION_STATE_TERMINATED
) {
361 info
->views
= InspectableViewsFinder(profile
, nullptr).
362 GetViewsForExtension(extension
, is_enabled
);
367 scoped_ptr
<api::developer_private::ExtensionInfo
>
368 ExtensionInfoGenerator::CreateExtensionInfo(const std::string
& id
) {
369 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context_
);
371 const Extension
* enabled
= registry
->enabled_extensions().GetByID(id
);
373 ui_util::ShouldDisplayInExtensionSettings(enabled
, browser_context_
)) {
374 return CreateExtensionInfo(*enabled
, developer::EXTENSION_STATE_ENABLED
);
377 const Extension
* disabled
= registry
->disabled_extensions().GetByID(id
);
379 ui_util::ShouldDisplayInExtensionSettings(disabled
, browser_context_
)) {
380 return CreateExtensionInfo(*disabled
, developer::EXTENSION_STATE_DISABLED
);
383 const Extension
* terminated
= registry
->terminated_extensions().GetByID(id
);
385 ui_util::ShouldDisplayInExtensionSettings(terminated
, browser_context_
)) {
386 return CreateExtensionInfo(*terminated
,
387 developer::EXTENSION_STATE_TERMINATED
);
390 return scoped_ptr
<api::developer_private::ExtensionInfo
>();
393 ExtensionInfoGenerator::ExtensionInfoList
394 ExtensionInfoGenerator::CreateExtensionsInfo(bool include_disabled
,
395 bool include_terminated
) {
396 std::vector
<linked_ptr
<developer::ExtensionInfo
>> list
;
397 auto add_to_list
= [this, &list
](const ExtensionSet
& extensions
,
398 developer::ExtensionState state
) {
399 for (const scoped_refptr
<const Extension
>& extension
: extensions
) {
400 if (ui_util::ShouldDisplayInExtensionSettings(extension
.get(),
402 scoped_ptr
<developer::ExtensionInfo
> info
=
403 CreateExtensionInfo(*extension
, state
);
404 list
.push_back(make_linked_ptr(info
.release()));
409 ExtensionRegistry
* registry
= ExtensionRegistry::Get(browser_context_
);
410 add_to_list(registry
->enabled_extensions(),
411 developer::EXTENSION_STATE_ENABLED
);
412 if (include_disabled
) {
413 add_to_list(registry
->disabled_extensions(),
414 developer::EXTENSION_STATE_DISABLED
);
416 if (include_terminated
) {
417 add_to_list(registry
->terminated_extensions(),
418 developer::EXTENSION_STATE_TERMINATED
);
424 } // namespace extensions