1 // Copyright (c) 2013 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 "extensions/common/permissions/permissions_data.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string16.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "content/public/common/url_constants.h"
15 #include "extensions/common/constants.h"
16 #include "extensions/common/error_utils.h"
17 #include "extensions/common/extension.h"
18 #include "extensions/common/extensions_client.h"
19 #include "extensions/common/features/feature.h"
20 #include "extensions/common/features/feature_provider.h"
21 #include "extensions/common/manifest.h"
22 #include "extensions/common/manifest_constants.h"
23 #include "extensions/common/manifest_handler.h"
24 #include "extensions/common/permissions/api_permission_set.h"
25 #include "extensions/common/permissions/permission_message_provider.h"
26 #include "extensions/common/permissions/permission_set.h"
27 #include "extensions/common/permissions/permissions_info.h"
28 #include "extensions/common/switches.h"
29 #include "extensions/common/url_pattern_set.h"
30 #include "extensions/common/user_script.h"
33 namespace extensions
{
35 namespace keys
= manifest_keys
;
36 namespace errors
= manifest_errors
;
40 PermissionsData::PolicyDelegate
* g_policy_delegate
= NULL
;
42 // Custom checks for the experimental permission that can't be expressed in
43 // _permission_features.json.
44 bool CanSpecifyExperimentalPermission(const Extension
* extension
) {
45 if (extension
->location() == Manifest::COMPONENT
)
48 if (CommandLine::ForCurrentProcess()->HasSwitch(
49 switches::kEnableExperimentalExtensionApis
)) {
53 // We rely on the webstore to check access to experimental. This way we can
54 // whitelist extensions to have access to experimental in just the store, and
55 // not have to push a new version of the client.
56 if (extension
->from_webstore())
62 // Checks whether the host |pattern| is allowed for the given |extension|,
63 // given API permissions |permissions|.
64 bool CanSpecifyHostPermission(const Extension
* extension
,
65 const URLPattern
& pattern
,
66 const APIPermissionSet
& permissions
) {
67 if (!pattern
.match_all_urls() &&
68 pattern
.MatchesScheme(content::kChromeUIScheme
)) {
69 URLPatternSet chrome_scheme_hosts
= ExtensionsClient::Get()->
70 GetPermittedChromeSchemeHosts(extension
, permissions
);
71 if (chrome_scheme_hosts
.ContainsPattern(pattern
))
74 // Component extensions can have access to all of chrome://*.
75 if (PermissionsData::CanExecuteScriptEverywhere(extension
))
78 if (CommandLine::ForCurrentProcess()->HasSwitch(
79 switches::kExtensionsOnChromeURLs
)) {
83 // TODO(aboxhall): return from_webstore() when webstore handles blocking
84 // extensions which request chrome:// urls
88 // Otherwise, the valid schemes were handled by URLPattern.
92 // Parses the host and api permissions from the specified permission |key|
93 // from |extension|'s manifest.
94 bool ParseHelper(Extension
* extension
,
96 APIPermissionSet
* api_permissions
,
97 URLPatternSet
* host_permissions
,
98 base::string16
* error
) {
99 if (!extension
->manifest()->HasKey(key
))
102 const base::ListValue
* permissions
= NULL
;
103 if (!extension
->manifest()->GetList(key
, &permissions
)) {
104 *error
= ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions
,
109 // NOTE: We need to get the APIPermission before we check if features
110 // associated with them are available because the feature system does not
111 // know about aliases.
113 std::vector
<std::string
> host_data
;
114 if (!APIPermissionSet::ParseFromJSON(
115 permissions
, APIPermissionSet::kDisallowInternalPermissions
,
116 api_permissions
, error
, &host_data
)) {
120 // Verify feature availability of permissions.
121 std::vector
<APIPermission::ID
> to_remove
;
122 FeatureProvider
* permission_features
=
123 FeatureProvider::GetPermissionFeatures();
124 for (APIPermissionSet::const_iterator iter
= api_permissions
->begin();
125 iter
!= api_permissions
->end(); ++iter
) {
126 Feature
* feature
= permission_features
->GetFeature(iter
->name());
128 // The feature should exist since we just got an APIPermission for it. The
129 // two systems should be updated together whenever a permission is added.
131 // http://crbug.com/176381
133 to_remove
.push_back(iter
->id());
137 Feature::Availability availability
= feature
->IsAvailableToManifest(
139 extension
->GetType(),
140 Feature::ConvertLocation(extension
->location()),
141 extension
->manifest_version());
143 if (!availability
.is_available()) {
144 // Don't fail, but warn the developer that the manifest contains
145 // unrecognized permissions. This may happen legitimately if the
146 // extensions requests platform- or channel-specific permissions.
147 extension
->AddInstallWarning(InstallWarning(availability
.message(),
149 to_remove
.push_back(iter
->id());
153 if (iter
->id() == APIPermission::kExperimental
) {
154 if (!CanSpecifyExperimentalPermission(extension
)) {
155 *error
= base::ASCIIToUTF16(errors::kExperimentalFlagRequired
);
161 api_permissions
->AddImpliedPermissions();
163 // Remove permissions that are not available to this extension.
164 for (std::vector
<APIPermission::ID
>::const_iterator iter
= to_remove
.begin();
165 iter
!= to_remove
.end(); ++iter
) {
166 api_permissions
->erase(*iter
);
169 // Parse host pattern permissions.
170 const int kAllowedSchemes
=
171 PermissionsData::CanExecuteScriptEverywhere(extension
) ?
172 URLPattern::SCHEME_ALL
: Extension::kValidHostPermissionSchemes
;
174 for (std::vector
<std::string
>::const_iterator iter
= host_data
.begin();
175 iter
!= host_data
.end(); ++iter
) {
176 const std::string
& permission_str
= *iter
;
178 // Check if it's a host pattern permission.
179 URLPattern pattern
= URLPattern(kAllowedSchemes
);
180 URLPattern::ParseResult parse_result
= pattern
.Parse(permission_str
);
181 if (parse_result
== URLPattern::PARSE_SUCCESS
) {
182 // The path component is not used for host permissions, so we force it
183 // to match all paths.
184 pattern
.SetPath("/*");
185 int valid_schemes
= pattern
.valid_schemes();
186 if (pattern
.MatchesScheme(content::kFileScheme
) &&
187 !PermissionsData::CanExecuteScriptEverywhere(extension
)) {
188 extension
->set_wants_file_access(true);
189 if (!(extension
->creation_flags() & Extension::ALLOW_FILE_ACCESS
))
190 valid_schemes
&= ~URLPattern::SCHEME_FILE
;
193 if (pattern
.scheme() != content::kChromeUIScheme
&&
194 !PermissionsData::CanExecuteScriptEverywhere(extension
)) {
195 // Keep chrome:// in allowed schemes only if it's explicitly requested
196 // or CanExecuteScriptEverywhere is true. If the
197 // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
198 // will fail, so don't check the flag here.
199 valid_schemes
&= ~URLPattern::SCHEME_CHROMEUI
;
201 pattern
.SetValidSchemes(valid_schemes
);
203 if (!CanSpecifyHostPermission(extension
, pattern
, *api_permissions
)) {
204 // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
206 extension
->AddInstallWarning(InstallWarning(
207 ErrorUtils::FormatErrorMessage(
208 errors::kInvalidPermissionScheme
, permission_str
),
214 host_permissions
->AddPattern(pattern
);
215 // We need to make sure all_urls matches chrome://favicon and (maybe)
216 // chrome://thumbnail, so add them back in to host_permissions separately.
217 if (pattern
.match_all_urls()) {
218 host_permissions
->AddPatterns(
219 ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
220 extension
, *api_permissions
));
225 // It's probably an unknown API permission. Do not throw an error so
226 // extensions can retain backwards compatability (http://crbug.com/42742).
227 extension
->AddInstallWarning(InstallWarning(
228 ErrorUtils::FormatErrorMessage(
229 manifest_errors::kPermissionUnknownOrMalformed
,
238 // Returns true if this extension id is from a trusted provider.
239 bool IsTrustedId(const std::string
& extension_id
) {
240 // See http://b/4946060 for more details.
241 return extension_id
== std::string("nckgahadagoaajjgafhacjanaoiihapd");
246 struct PermissionsData::InitialPermissions
{
247 APIPermissionSet api_permissions
;
248 ManifestPermissionSet manifest_permissions
;
249 URLPatternSet host_permissions
;
250 URLPatternSet scriptable_hosts
;
253 PermissionsData::PermissionsData() {
256 PermissionsData::~PermissionsData() {
260 void PermissionsData::SetPolicyDelegate(PolicyDelegate
* delegate
) {
261 g_policy_delegate
= delegate
;
265 const PermissionSet
* PermissionsData::GetOptionalPermissions(
266 const Extension
* extension
) {
267 return extension
->permissions_data()->optional_permission_set_
.get();
271 const PermissionSet
* PermissionsData::GetRequiredPermissions(
272 const Extension
* extension
) {
273 return extension
->permissions_data()->required_permission_set_
.get();
277 const APIPermissionSet
* PermissionsData::GetInitialAPIPermissions(
278 const Extension
* extension
) {
279 return &extension
->permissions_data()->
280 initial_required_permissions_
->api_permissions
;
284 APIPermissionSet
* PermissionsData::GetInitialAPIPermissions(
285 Extension
* extension
) {
286 return &extension
->permissions_data()->
287 initial_required_permissions_
->api_permissions
;
291 void PermissionsData::SetInitialScriptableHosts(
292 Extension
* extension
, const URLPatternSet
& scriptable_hosts
) {
293 extension
->permissions_data()->
294 initial_required_permissions_
->scriptable_hosts
= scriptable_hosts
;
298 void PermissionsData::SetActivePermissions(const Extension
* extension
,
299 const PermissionSet
* permissions
) {
300 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
301 extension
->permissions_data()->active_permissions_
= permissions
;
305 scoped_refptr
<const PermissionSet
> PermissionsData::GetActivePermissions(
306 const Extension
* extension
) {
307 return extension
->permissions_data()->active_permissions_
;
311 scoped_refptr
<const PermissionSet
> PermissionsData::GetTabSpecificPermissions(
312 const Extension
* extension
,
315 TabPermissionsMap::const_iterator iter
=
316 extension
->permissions_data()->tab_specific_permissions_
.find(tab_id
);
318 (iter
!= extension
->permissions_data()->tab_specific_permissions_
.end())
324 void PermissionsData::UpdateTabSpecificPermissions(
325 const Extension
* extension
,
327 scoped_refptr
<const PermissionSet
> permissions
) {
329 TabPermissionsMap
* tab_permissions
=
330 &extension
->permissions_data()->tab_specific_permissions_
;
331 if (tab_permissions
->count(tab_id
)) {
332 (*tab_permissions
)[tab_id
] = PermissionSet::CreateUnion(
333 (*tab_permissions
)[tab_id
].get(), permissions
.get());
335 (*tab_permissions
)[tab_id
] = permissions
;
340 void PermissionsData::ClearTabSpecificPermissions(
341 const Extension
* extension
,
344 extension
->permissions_data()->tab_specific_permissions_
.erase(tab_id
);
348 bool PermissionsData::HasAPIPermission(const Extension
* extension
,
349 APIPermission::ID permission
) {
350 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
351 return GetActivePermissions(extension
)->HasAPIPermission(permission
);
355 bool PermissionsData::HasAPIPermission(
356 const Extension
* extension
,
357 const std::string
& permission_name
) {
358 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
359 return GetActivePermissions(extension
)->HasAPIPermission(permission_name
);
363 bool PermissionsData::HasAPIPermissionForTab(
364 const Extension
* extension
,
366 APIPermission::ID permission
) {
367 if (HasAPIPermission(extension
, permission
))
370 // Place autolock below the HasAPIPermission() check, since HasAPIPermission
371 // also acquires the lock.
372 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
373 scoped_refptr
<const PermissionSet
> tab_permissions
=
374 GetTabSpecificPermissions(extension
, tab_id
);
375 return tab_permissions
.get() && tab_permissions
->HasAPIPermission(permission
);
379 bool PermissionsData::CheckAPIPermissionWithParam(
380 const Extension
* extension
,
381 APIPermission::ID permission
,
382 const APIPermission::CheckParam
* param
) {
383 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
384 return GetActivePermissions(extension
)->CheckAPIPermissionWithParam(
389 const URLPatternSet
& PermissionsData::GetEffectiveHostPermissions(
390 const Extension
* extension
) {
391 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
392 return GetActivePermissions(extension
)->effective_hosts();
396 bool PermissionsData::CanSilentlyIncreasePermissions(
397 const Extension
* extension
) {
398 return extension
->location() != Manifest::INTERNAL
;
402 bool PermissionsData::ShouldSkipPermissionWarnings(const Extension
* extension
) {
403 return IsTrustedId(extension
->id());
407 bool PermissionsData::HasHostPermission(const Extension
* extension
,
409 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
410 return GetActivePermissions(extension
)->HasExplicitAccessToOrigin(url
);
414 bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension
* extension
) {
415 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
416 return GetActivePermissions(extension
)->HasEffectiveAccessToAllHosts();
420 PermissionMessages
PermissionsData::GetPermissionMessages(
421 const Extension
* extension
) {
422 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
423 if (ShouldSkipPermissionWarnings(extension
)) {
424 return PermissionMessages();
426 return PermissionMessageProvider::Get()->GetPermissionMessages(
427 GetActivePermissions(extension
), extension
->GetType());
432 std::vector
<base::string16
> PermissionsData::GetPermissionMessageStrings(
433 const Extension
* extension
) {
434 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
435 if (ShouldSkipPermissionWarnings(extension
)) {
436 return std::vector
<base::string16
>();
438 return PermissionMessageProvider::Get()->GetWarningMessages(
439 GetActivePermissions(extension
), extension
->GetType());
444 std::vector
<base::string16
> PermissionsData::GetPermissionMessageDetailsStrings(
445 const Extension
* extension
) {
446 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
447 if (ShouldSkipPermissionWarnings(extension
)) {
448 return std::vector
<base::string16
>();
450 return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
451 GetActivePermissions(extension
), extension
->GetType());
456 bool PermissionsData::CanExecuteScriptOnPage(const Extension
* extension
,
457 const GURL
& document_url
,
458 const GURL
& top_frame_url
,
460 const UserScript
* script
,
462 std::string
* error
) {
463 base::AutoLock
auto_lock(extension
->permissions_data()->runtime_lock_
);
464 const CommandLine
* command_line
= CommandLine::ForCurrentProcess();
465 bool can_execute_everywhere
= CanExecuteScriptEverywhere(extension
);
467 if (g_policy_delegate
&&
468 !g_policy_delegate
->CanExecuteScriptOnPage(
469 extension
, document_url
, top_frame_url
, tab_id
,
470 script
, process_id
, error
))
473 if (!can_execute_everywhere
&&
474 !ExtensionsClient::Get()->IsScriptableURL(document_url
, error
)) {
478 if (!command_line
->HasSwitch(switches::kExtensionsOnChromeURLs
)) {
479 if (document_url
.SchemeIs(content::kChromeUIScheme
) &&
480 !can_execute_everywhere
) {
482 *error
= errors::kCannotAccessChromeUrl
;
487 if (top_frame_url
.SchemeIs(extensions::kExtensionScheme
) &&
488 top_frame_url
.GetOrigin() !=
489 Extension::GetBaseURLFromExtensionId(extension
->id()).GetOrigin() &&
490 !can_execute_everywhere
) {
492 *error
= errors::kCannotAccessExtensionUrl
;
496 // If a tab ID is specified, try the tab-specific permissions.
498 scoped_refptr
<const PermissionSet
> tab_permissions
=
499 GetTabSpecificPermissions(extension
, tab_id
);
500 if (tab_permissions
.get() &&
501 tab_permissions
->explicit_hosts().MatchesSecurityOrigin(document_url
)) {
506 bool can_access
= false;
509 // If a script is specified, use its matches.
510 can_access
= script
->MatchesURL(document_url
);
512 // Otherwise, see if this extension has permission to execute script
513 // programmatically on pages.
514 can_access
= GetActivePermissions(extension
)->
515 HasExplicitAccessToOrigin(document_url
);
518 if (!can_access
&& error
) {
519 *error
= ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage
,
520 document_url
.spec());
527 bool PermissionsData::CanExecuteScriptEverywhere(const Extension
* extension
) {
528 if (extension
->location() == Manifest::COMPONENT
)
531 const ExtensionsClient::ScriptingWhitelist
& whitelist
=
532 ExtensionsClient::Get()->GetScriptingWhitelist();
534 return std::find(whitelist
.begin(), whitelist
.end(), extension
->id()) !=
539 bool PermissionsData::CanCaptureVisiblePage(const Extension
* extension
,
541 std::string
* error
) {
542 scoped_refptr
<const PermissionSet
> active_permissions
=
543 GetActivePermissions(extension
);
544 const URLPattern
all_urls(URLPattern::SCHEME_ALL
,
545 URLPattern::kAllUrlsPattern
);
546 if (active_permissions
->explicit_hosts().ContainsPattern(all_urls
))
550 scoped_refptr
<const PermissionSet
> tab_permissions
=
551 GetTabSpecificPermissions(extension
, tab_id
);
552 if (tab_permissions
&&
553 tab_permissions
->HasAPIPermission(APIPermission::kTab
)) {
557 *error
= errors::kActiveTabPermissionNotGranted
;
562 *error
= errors::kAllURLOrActiveTabNeeded
;
566 bool PermissionsData::ParsePermissions(Extension
* extension
,
567 base::string16
* error
) {
568 initial_required_permissions_
.reset(new InitialPermissions
);
569 if (!ParseHelper(extension
,
571 &initial_required_permissions_
->api_permissions
,
572 &initial_required_permissions_
->host_permissions
,
577 initial_optional_permissions_
.reset(new InitialPermissions
);
578 if (!ParseHelper(extension
,
579 keys::kOptionalPermissions
,
580 &initial_optional_permissions_
->api_permissions
,
581 &initial_optional_permissions_
->host_permissions
,
589 void PermissionsData::InitializeManifestPermissions(Extension
* extension
) {
590 ManifestHandler::AddExtensionInitialRequiredPermissions(
591 extension
, &initial_required_permissions_
->manifest_permissions
);
594 void PermissionsData::FinalizePermissions(Extension
* extension
) {
595 active_permissions_
= new PermissionSet(
596 initial_required_permissions_
->api_permissions
,
597 initial_required_permissions_
->manifest_permissions
,
598 initial_required_permissions_
->host_permissions
,
599 initial_required_permissions_
->scriptable_hosts
);
601 required_permission_set_
= new PermissionSet(
602 initial_required_permissions_
->api_permissions
,
603 initial_required_permissions_
->manifest_permissions
,
604 initial_required_permissions_
->host_permissions
,
605 initial_required_permissions_
->scriptable_hosts
);
607 optional_permission_set_
= new PermissionSet(
608 initial_optional_permissions_
->api_permissions
,
609 initial_optional_permissions_
->manifest_permissions
,
610 initial_optional_permissions_
->host_permissions
,
613 initial_required_permissions_
.reset();
614 initial_optional_permissions_
.reset();
617 } // namespace extensions