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.
130 DCHECK(feature) << "Could not find feature for " << iter->name();
131 // http://crbug.com/176381
133 to_remove.push_back(iter->id());
137 Feature::Availability availability =
138 feature->IsAvailableToExtension(extension);
140 if (!availability.is_available()) {
141 // Don't fail, but warn the developer that the manifest contains
142 // unrecognized permissions. This may happen legitimately if the
143 // extensions requests platform- or channel-specific permissions.
144 extension->AddInstallWarning(InstallWarning(availability.message(),
146 to_remove.push_back(iter->id());
150 if (iter->id() == APIPermission::kExperimental) {
151 if (!CanSpecifyExperimentalPermission(extension)) {
152 *error = base::ASCIIToUTF16(errors::kExperimentalFlagRequired);
158 api_permissions->AddImpliedPermissions();
160 // Remove permissions that are not available to this extension.
161 for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
162 iter != to_remove.end(); ++iter) {
163 api_permissions->erase(*iter);
166 // Parse host pattern permissions.
167 const int kAllowedSchemes =
168 PermissionsData::CanExecuteScriptEverywhere(extension) ?
169 URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes;
171 for (std::vector<std::string>::const_iterator iter = host_data.begin();
172 iter != host_data.end(); ++iter) {
173 const std::string& permission_str = *iter;
175 // Check if it's a host pattern permission.
176 URLPattern pattern = URLPattern(kAllowedSchemes);
177 URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
178 if (parse_result == URLPattern::PARSE_SUCCESS) {
179 // The path component is not used for host permissions, so we force it
180 // to match all paths.
181 pattern.SetPath("/*");
182 int valid_schemes = pattern.valid_schemes();
183 if (pattern.MatchesScheme(content::kFileScheme) &&
184 !PermissionsData::CanExecuteScriptEverywhere(extension)) {
185 extension->set_wants_file_access(true);
186 if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
187 valid_schemes &= ~URLPattern::SCHEME_FILE;
190 if (pattern.scheme() != content::kChromeUIScheme &&
191 !PermissionsData::CanExecuteScriptEverywhere(extension)) {
192 // Keep chrome:// in allowed schemes only if it's explicitly requested
193 // or CanExecuteScriptEverywhere is true. If the
194 // extensions_on_chrome_urls flag is not set, CanSpecifyHostPermission
195 // will fail, so don't check the flag here.
196 valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
198 pattern.SetValidSchemes(valid_schemes);
200 if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
201 // TODO(aboxhall): make a warning (see pattern.match_all_urls() block
203 extension->AddInstallWarning(InstallWarning(
204 ErrorUtils::FormatErrorMessage(
205 errors::kInvalidPermissionScheme, permission_str),
211 host_permissions->AddPattern(pattern);
212 // We need to make sure all_urls matches chrome://favicon and (maybe)
213 // chrome://thumbnail, so add them back in to host_permissions separately.
214 if (pattern.match_all_urls()) {
215 host_permissions->AddPatterns(
216 ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
217 extension, *api_permissions));
222 // It's probably an unknown API permission. Do not throw an error so
223 // extensions can retain backwards compatability (http://crbug.com/42742).
224 extension->AddInstallWarning(InstallWarning(
225 ErrorUtils::FormatErrorMessage(
226 manifest_errors::kPermissionUnknownOrMalformed,
235 // Returns true if this extension id is from a trusted provider.
236 bool IsTrustedId(const std::string& extension_id) {
237 // See http://b/4946060 for more details.
238 return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
243 struct PermissionsData::InitialPermissions {
244 APIPermissionSet api_permissions;
245 ManifestPermissionSet manifest_permissions;
246 URLPatternSet host_permissions;
247 URLPatternSet scriptable_hosts;
250 PermissionsData::PermissionsData() {
253 PermissionsData::~PermissionsData() {
257 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
258 g_policy_delegate = delegate;
262 const PermissionSet* PermissionsData::GetOptionalPermissions(
263 const Extension* extension) {
264 return extension->permissions_data()->optional_permission_set_.get();
268 const PermissionSet* PermissionsData::GetRequiredPermissions(
269 const Extension* extension) {
270 return extension->permissions_data()->required_permission_set_.get();
274 const APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
275 const Extension* extension) {
276 return &extension->permissions_data()->
277 initial_required_permissions_->api_permissions;
281 APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
282 Extension* extension) {
283 return &extension->permissions_data()->
284 initial_required_permissions_->api_permissions;
288 void PermissionsData::SetInitialScriptableHosts(
289 Extension* extension, const URLPatternSet& scriptable_hosts) {
290 extension->permissions_data()->
291 initial_required_permissions_->scriptable_hosts = scriptable_hosts;
295 void PermissionsData::SetActivePermissions(const Extension* extension,
296 const PermissionSet* permissions) {
297 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
298 extension->permissions_data()->active_permissions_ = permissions;
302 scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions(
303 const Extension* extension) {
304 return extension->permissions_data()->active_permissions_;
308 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
309 const Extension* extension,
312 TabPermissionsMap::const_iterator iter =
313 extension->permissions_data()->tab_specific_permissions_.find(tab_id);
315 (iter != extension->permissions_data()->tab_specific_permissions_.end())
321 void PermissionsData::UpdateTabSpecificPermissions(
322 const Extension* extension,
324 scoped_refptr<const PermissionSet> permissions) {
326 TabPermissionsMap* tab_permissions =
327 &extension->permissions_data()->tab_specific_permissions_;
328 if (tab_permissions->count(tab_id)) {
329 (*tab_permissions)[tab_id] = PermissionSet::CreateUnion(
330 (*tab_permissions)[tab_id].get(), permissions.get());
332 (*tab_permissions)[tab_id] = permissions;
337 void PermissionsData::ClearTabSpecificPermissions(
338 const Extension* extension,
341 extension->permissions_data()->tab_specific_permissions_.erase(tab_id);
345 bool PermissionsData::HasAPIPermission(const Extension* extension,
346 APIPermission::ID permission) {
347 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
348 return GetActivePermissions(extension)->HasAPIPermission(permission);
352 bool PermissionsData::HasAPIPermission(
353 const Extension* extension,
354 const std::string& permission_name) {
355 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
356 return GetActivePermissions(extension)->HasAPIPermission(permission_name);
360 bool PermissionsData::HasAPIPermissionForTab(
361 const Extension* extension,
363 APIPermission::ID permission) {
364 if (HasAPIPermission(extension, permission))
367 // Place autolock below the HasAPIPermission() check, since HasAPIPermission
368 // also acquires the lock.
369 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
370 scoped_refptr<const PermissionSet> tab_permissions =
371 GetTabSpecificPermissions(extension, tab_id);
372 return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
376 bool PermissionsData::CheckAPIPermissionWithParam(
377 const Extension* extension,
378 APIPermission::ID permission,
379 const APIPermission::CheckParam* param) {
380 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
381 return GetActivePermissions(extension)->CheckAPIPermissionWithParam(
386 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions(
387 const Extension* extension) {
388 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
389 return GetActivePermissions(extension)->effective_hosts();
393 bool PermissionsData::CanSilentlyIncreasePermissions(
394 const Extension* extension) {
395 return extension->location() != Manifest::INTERNAL;
399 bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) {
400 return IsTrustedId(extension->id());
404 bool PermissionsData::HasHostPermission(const Extension* extension,
406 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
407 return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url);
411 bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) {
412 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
413 return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts();
417 PermissionMessages PermissionsData::GetPermissionMessages(
418 const Extension* extension) {
419 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
420 if (ShouldSkipPermissionWarnings(extension)) {
421 return PermissionMessages();
423 return PermissionMessageProvider::Get()->GetPermissionMessages(
424 GetActivePermissions(extension), extension->GetType());
429 std::vector<base::string16> PermissionsData::GetPermissionMessageStrings(
430 const Extension* extension) {
431 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
432 if (ShouldSkipPermissionWarnings(extension)) {
433 return std::vector<base::string16>();
435 return PermissionMessageProvider::Get()->GetWarningMessages(
436 GetActivePermissions(extension), extension->GetType());
441 std::vector<base::string16> PermissionsData::GetPermissionMessageDetailsStrings(
442 const Extension* extension) {
443 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
444 if (ShouldSkipPermissionWarnings(extension)) {
445 return std::vector<base::string16>();
447 return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
448 GetActivePermissions(extension), extension->GetType());
453 bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension,
454 const GURL& document_url,
455 const GURL& top_frame_url,
457 const UserScript* script,
459 std::string* error) {
460 base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
461 const CommandLine* command_line = CommandLine::ForCurrentProcess();
462 bool can_execute_everywhere = CanExecuteScriptEverywhere(extension);
464 if (g_policy_delegate &&
465 !g_policy_delegate->CanExecuteScriptOnPage(
466 extension, document_url, top_frame_url, tab_id,
467 script, process_id, error))
470 if (!can_execute_everywhere &&
471 !ExtensionsClient::Get()->IsScriptableURL(document_url, error)) {
475 if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) {
476 if (document_url.SchemeIs(content::kChromeUIScheme) &&
477 !can_execute_everywhere) {
479 *error = errors::kCannotAccessChromeUrl;
484 if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
485 top_frame_url.GetOrigin() !=
486 Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() &&
487 !can_execute_everywhere) {
489 *error = errors::kCannotAccessExtensionUrl;
493 // If a tab ID is specified, try the tab-specific permissions.
495 scoped_refptr<const PermissionSet> tab_permissions =
496 GetTabSpecificPermissions(extension, tab_id);
497 if (tab_permissions.get() &&
498 tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
503 bool can_access = false;
506 // If a script is specified, use its matches.
507 can_access = script->MatchesURL(document_url);
509 // Otherwise, see if this extension has permission to execute script
510 // programmatically on pages.
511 can_access = GetActivePermissions(extension)->
512 HasExplicitAccessToOrigin(document_url);
515 if (!can_access && error) {
516 *error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
517 document_url.spec());
524 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
525 if (extension->location() == Manifest::COMPONENT)
528 const ExtensionsClient::ScriptingWhitelist& whitelist =
529 ExtensionsClient::Get()->GetScriptingWhitelist();
531 return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
536 bool PermissionsData::CanCaptureVisiblePage(const Extension* extension,
538 std::string* error) {
539 scoped_refptr<const PermissionSet> active_permissions =
540 GetActivePermissions(extension);
541 const URLPattern all_urls(URLPattern::SCHEME_ALL,
542 URLPattern::kAllUrlsPattern);
543 if (active_permissions->explicit_hosts().ContainsPattern(all_urls))
547 scoped_refptr<const PermissionSet> tab_permissions =
548 GetTabSpecificPermissions(extension, tab_id);
549 if (tab_permissions &&
550 tab_permissions->HasAPIPermission(APIPermission::kTab)) {
554 *error = errors::kActiveTabPermissionNotGranted;
559 *error = errors::kAllURLOrActiveTabNeeded;
563 bool PermissionsData::ParsePermissions(Extension* extension,
564 base::string16* error) {
565 initial_required_permissions_.reset(new InitialPermissions);
566 if (!ParseHelper(extension,
568 &initial_required_permissions_->api_permissions,
569 &initial_required_permissions_->host_permissions,
574 initial_optional_permissions_.reset(new InitialPermissions);
575 if (!ParseHelper(extension,
576 keys::kOptionalPermissions,
577 &initial_optional_permissions_->api_permissions,
578 &initial_optional_permissions_->host_permissions,
586 void PermissionsData::InitializeManifestPermissions(Extension* extension) {
587 ManifestHandler::AddExtensionInitialRequiredPermissions(
588 extension, &initial_required_permissions_->manifest_permissions);
591 void PermissionsData::FinalizePermissions(Extension* extension) {
592 active_permissions_ = new PermissionSet(
593 initial_required_permissions_->api_permissions,
594 initial_required_permissions_->manifest_permissions,
595 initial_required_permissions_->host_permissions,
596 initial_required_permissions_->scriptable_hosts);
598 required_permission_set_ = new PermissionSet(
599 initial_required_permissions_->api_permissions,
600 initial_required_permissions_->manifest_permissions,
601 initial_required_permissions_->host_permissions,
602 initial_required_permissions_->scriptable_hosts);
604 optional_permission_set_ = new PermissionSet(
605 initial_optional_permissions_->api_permissions,
606 initial_optional_permissions_->manifest_permissions,
607 initial_optional_permissions_->host_permissions,
610 initial_required_permissions_.reset();
611 initial_optional_permissions_.reset();
614 } // namespace extensions