This source file includes following definitions.
- CanSpecifyExperimentalPermission
- CanSpecifyHostPermission
- ParseHelper
- IsTrustedId
- SetPolicyDelegate
- GetOptionalPermissions
- GetRequiredPermissions
- GetInitialAPIPermissions
- GetInitialAPIPermissions
- SetInitialScriptableHosts
- SetActivePermissions
- GetActivePermissions
- GetTabSpecificPermissions
- UpdateTabSpecificPermissions
- ClearTabSpecificPermissions
- HasAPIPermission
- HasAPIPermission
- HasAPIPermissionForTab
- CheckAPIPermissionWithParam
- GetEffectiveHostPermissions
- CanSilentlyIncreasePermissions
- ShouldSkipPermissionWarnings
- HasHostPermission
- HasEffectiveAccessToAllHosts
- GetPermissionMessages
- GetPermissionMessageStrings
- GetPermissionMessageDetailsStrings
- CanExecuteScriptOnPage
- CanExecuteScriptEverywhere
- CanCaptureVisiblePage
- ParsePermissions
- InitializeManifestPermissions
- FinalizePermissions
#include "extensions/common/permissions/permissions_data.h"
#include "base/command_line.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/common/url_constants.h"
#include "extensions/common/constants.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/extensions_client.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/features/feature_provider.h"
#include "extensions/common/manifest.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/manifest_handler.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/permissions/permission_message_provider.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_info.h"
#include "extensions/common/switches.h"
#include "extensions/common/url_pattern_set.h"
#include "extensions/common/user_script.h"
#include "url/gurl.h"
namespace extensions {
namespace keys = manifest_keys;
namespace errors = manifest_errors;
namespace {
PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
bool CanSpecifyExperimentalPermission(const Extension* extension) {
if (extension->location() == Manifest::COMPONENT)
return true;
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalExtensionApis)) {
return true;
}
if (extension->from_webstore())
return true;
return false;
}
bool CanSpecifyHostPermission(const Extension* extension,
const URLPattern& pattern,
const APIPermissionSet& permissions) {
if (!pattern.match_all_urls() &&
pattern.MatchesScheme(content::kChromeUIScheme)) {
URLPatternSet chrome_scheme_hosts = ExtensionsClient::Get()->
GetPermittedChromeSchemeHosts(extension, permissions);
if (chrome_scheme_hosts.ContainsPattern(pattern))
return true;
if (PermissionsData::CanExecuteScriptEverywhere(extension))
return true;
if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kExtensionsOnChromeURLs)) {
return true;
}
return false;
}
return true;
}
bool ParseHelper(Extension* extension,
const char* key,
APIPermissionSet* api_permissions,
URLPatternSet* host_permissions,
base::string16* error) {
if (!extension->manifest()->HasKey(key))
return true;
const base::ListValue* permissions = NULL;
if (!extension->manifest()->GetList(key, &permissions)) {
*error = ErrorUtils::FormatErrorMessageUTF16(errors::kInvalidPermissions,
std::string());
return false;
}
std::vector<std::string> host_data;
if (!APIPermissionSet::ParseFromJSON(
permissions, APIPermissionSet::kDisallowInternalPermissions,
api_permissions, error, &host_data)) {
return false;
}
std::vector<APIPermission::ID> to_remove;
FeatureProvider* permission_features =
FeatureProvider::GetPermissionFeatures();
for (APIPermissionSet::const_iterator iter = api_permissions->begin();
iter != api_permissions->end(); ++iter) {
Feature* feature = permission_features->GetFeature(iter->name());
DCHECK(feature) << "Could not find feature for " << iter->name();
if (!feature) {
to_remove.push_back(iter->id());
continue;
}
Feature::Availability availability = feature->IsAvailableToManifest(
extension->id(),
extension->GetType(),
Feature::ConvertLocation(extension->location()),
extension->manifest_version());
if (!availability.is_available()) {
extension->AddInstallWarning(InstallWarning(availability.message(),
feature->name()));
to_remove.push_back(iter->id());
continue;
}
if (iter->id() == APIPermission::kExperimental) {
if (!CanSpecifyExperimentalPermission(extension)) {
*error = base::ASCIIToUTF16(errors::kExperimentalFlagRequired);
return false;
}
}
}
api_permissions->AddImpliedPermissions();
for (std::vector<APIPermission::ID>::const_iterator iter = to_remove.begin();
iter != to_remove.end(); ++iter) {
api_permissions->erase(*iter);
}
const int kAllowedSchemes =
PermissionsData::CanExecuteScriptEverywhere(extension) ?
URLPattern::SCHEME_ALL : Extension::kValidHostPermissionSchemes;
for (std::vector<std::string>::const_iterator iter = host_data.begin();
iter != host_data.end(); ++iter) {
const std::string& permission_str = *iter;
URLPattern pattern = URLPattern(kAllowedSchemes);
URLPattern::ParseResult parse_result = pattern.Parse(permission_str);
if (parse_result == URLPattern::PARSE_SUCCESS) {
pattern.SetPath("/*");
int valid_schemes = pattern.valid_schemes();
if (pattern.MatchesScheme(content::kFileScheme) &&
!PermissionsData::CanExecuteScriptEverywhere(extension)) {
extension->set_wants_file_access(true);
if (!(extension->creation_flags() & Extension::ALLOW_FILE_ACCESS))
valid_schemes &= ~URLPattern::SCHEME_FILE;
}
if (pattern.scheme() != content::kChromeUIScheme &&
!PermissionsData::CanExecuteScriptEverywhere(extension)) {
valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
}
pattern.SetValidSchemes(valid_schemes);
if (!CanSpecifyHostPermission(extension, pattern, *api_permissions)) {
extension->AddInstallWarning(InstallWarning(
ErrorUtils::FormatErrorMessage(
errors::kInvalidPermissionScheme, permission_str),
key,
permission_str));
continue;
}
host_permissions->AddPattern(pattern);
if (pattern.match_all_urls()) {
host_permissions->AddPatterns(
ExtensionsClient::Get()->GetPermittedChromeSchemeHosts(
extension, *api_permissions));
}
continue;
}
extension->AddInstallWarning(InstallWarning(
ErrorUtils::FormatErrorMessage(
manifest_errors::kPermissionUnknownOrMalformed,
permission_str),
key,
permission_str));
}
return true;
}
bool IsTrustedId(const std::string& extension_id) {
return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
}
}
struct PermissionsData::InitialPermissions {
APIPermissionSet api_permissions;
ManifestPermissionSet manifest_permissions;
URLPatternSet host_permissions;
URLPatternSet scriptable_hosts;
};
PermissionsData::PermissionsData() {
}
PermissionsData::~PermissionsData() {
}
void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
g_policy_delegate = delegate;
}
const PermissionSet* PermissionsData::GetOptionalPermissions(
const Extension* extension) {
return extension->permissions_data()->optional_permission_set_.get();
}
const PermissionSet* PermissionsData::GetRequiredPermissions(
const Extension* extension) {
return extension->permissions_data()->required_permission_set_.get();
}
const APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
const Extension* extension) {
return &extension->permissions_data()->
initial_required_permissions_->api_permissions;
}
APIPermissionSet* PermissionsData::GetInitialAPIPermissions(
Extension* extension) {
return &extension->permissions_data()->
initial_required_permissions_->api_permissions;
}
void PermissionsData::SetInitialScriptableHosts(
Extension* extension, const URLPatternSet& scriptable_hosts) {
extension->permissions_data()->
initial_required_permissions_->scriptable_hosts = scriptable_hosts;
}
void PermissionsData::SetActivePermissions(const Extension* extension,
const PermissionSet* permissions) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
extension->permissions_data()->active_permissions_ = permissions;
}
scoped_refptr<const PermissionSet> PermissionsData::GetActivePermissions(
const Extension* extension) {
return extension->permissions_data()->active_permissions_;
}
scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
const Extension* extension,
int tab_id) {
CHECK_GE(tab_id, 0);
TabPermissionsMap::const_iterator iter =
extension->permissions_data()->tab_specific_permissions_.find(tab_id);
return
(iter != extension->permissions_data()->tab_specific_permissions_.end())
? iter->second
: NULL;
}
void PermissionsData::UpdateTabSpecificPermissions(
const Extension* extension,
int tab_id,
scoped_refptr<const PermissionSet> permissions) {
CHECK_GE(tab_id, 0);
TabPermissionsMap* tab_permissions =
&extension->permissions_data()->tab_specific_permissions_;
if (tab_permissions->count(tab_id)) {
(*tab_permissions)[tab_id] = PermissionSet::CreateUnion(
(*tab_permissions)[tab_id].get(), permissions.get());
} else {
(*tab_permissions)[tab_id] = permissions;
}
}
void PermissionsData::ClearTabSpecificPermissions(
const Extension* extension,
int tab_id) {
CHECK_GE(tab_id, 0);
extension->permissions_data()->tab_specific_permissions_.erase(tab_id);
}
bool PermissionsData::HasAPIPermission(const Extension* extension,
APIPermission::ID permission) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
return GetActivePermissions(extension)->HasAPIPermission(permission);
}
bool PermissionsData::HasAPIPermission(
const Extension* extension,
const std::string& permission_name) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
return GetActivePermissions(extension)->HasAPIPermission(permission_name);
}
bool PermissionsData::HasAPIPermissionForTab(
const Extension* extension,
int tab_id,
APIPermission::ID permission) {
if (HasAPIPermission(extension, permission))
return true;
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
scoped_refptr<const PermissionSet> tab_permissions =
GetTabSpecificPermissions(extension, tab_id);
return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
}
bool PermissionsData::CheckAPIPermissionWithParam(
const Extension* extension,
APIPermission::ID permission,
const APIPermission::CheckParam* param) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
return GetActivePermissions(extension)->CheckAPIPermissionWithParam(
permission, param);
}
const URLPatternSet& PermissionsData::GetEffectiveHostPermissions(
const Extension* extension) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
return GetActivePermissions(extension)->effective_hosts();
}
bool PermissionsData::CanSilentlyIncreasePermissions(
const Extension* extension) {
return extension->location() != Manifest::INTERNAL;
}
bool PermissionsData::ShouldSkipPermissionWarnings(const Extension* extension) {
return IsTrustedId(extension->id());
}
bool PermissionsData::HasHostPermission(const Extension* extension,
const GURL& url) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
return GetActivePermissions(extension)->HasExplicitAccessToOrigin(url);
}
bool PermissionsData::HasEffectiveAccessToAllHosts(const Extension* extension) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
return GetActivePermissions(extension)->HasEffectiveAccessToAllHosts();
}
PermissionMessages PermissionsData::GetPermissionMessages(
const Extension* extension) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
if (ShouldSkipPermissionWarnings(extension)) {
return PermissionMessages();
} else {
return PermissionMessageProvider::Get()->GetPermissionMessages(
GetActivePermissions(extension), extension->GetType());
}
}
std::vector<base::string16> PermissionsData::GetPermissionMessageStrings(
const Extension* extension) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
if (ShouldSkipPermissionWarnings(extension)) {
return std::vector<base::string16>();
} else {
return PermissionMessageProvider::Get()->GetWarningMessages(
GetActivePermissions(extension), extension->GetType());
}
}
std::vector<base::string16> PermissionsData::GetPermissionMessageDetailsStrings(
const Extension* extension) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
if (ShouldSkipPermissionWarnings(extension)) {
return std::vector<base::string16>();
} else {
return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
GetActivePermissions(extension), extension->GetType());
}
}
bool PermissionsData::CanExecuteScriptOnPage(const Extension* extension,
const GURL& document_url,
const GURL& top_frame_url,
int tab_id,
const UserScript* script,
int process_id,
std::string* error) {
base::AutoLock auto_lock(extension->permissions_data()->runtime_lock_);
const CommandLine* command_line = CommandLine::ForCurrentProcess();
bool can_execute_everywhere = CanExecuteScriptEverywhere(extension);
if (g_policy_delegate &&
!g_policy_delegate->CanExecuteScriptOnPage(
extension, document_url, top_frame_url, tab_id,
script, process_id, error))
return false;
if (!can_execute_everywhere &&
!ExtensionsClient::Get()->IsScriptableURL(document_url, error)) {
return false;
}
if (!command_line->HasSwitch(switches::kExtensionsOnChromeURLs)) {
if (document_url.SchemeIs(content::kChromeUIScheme) &&
!can_execute_everywhere) {
if (error)
*error = errors::kCannotAccessChromeUrl;
return false;
}
}
if (top_frame_url.SchemeIs(extensions::kExtensionScheme) &&
top_frame_url.GetOrigin() !=
Extension::GetBaseURLFromExtensionId(extension->id()).GetOrigin() &&
!can_execute_everywhere) {
if (error)
*error = errors::kCannotAccessExtensionUrl;
return false;
}
if (tab_id >= 0) {
scoped_refptr<const PermissionSet> tab_permissions =
GetTabSpecificPermissions(extension, tab_id);
if (tab_permissions.get() &&
tab_permissions->explicit_hosts().MatchesSecurityOrigin(document_url)) {
return true;
}
}
bool can_access = false;
if (script) {
can_access = script->MatchesURL(document_url);
} else {
can_access = GetActivePermissions(extension)->
HasExplicitAccessToOrigin(document_url);
}
if (!can_access && error) {
*error = ErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
document_url.spec());
}
return can_access;
}
bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
if (extension->location() == Manifest::COMPONENT)
return true;
const ExtensionsClient::ScriptingWhitelist& whitelist =
ExtensionsClient::Get()->GetScriptingWhitelist();
return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
whitelist.end();
}
bool PermissionsData::CanCaptureVisiblePage(const Extension* extension,
int tab_id,
std::string* error) {
scoped_refptr<const PermissionSet> active_permissions =
GetActivePermissions(extension);
const URLPattern all_urls(URLPattern::SCHEME_ALL,
URLPattern::kAllUrlsPattern);
if (active_permissions->explicit_hosts().ContainsPattern(all_urls))
return true;
if (tab_id >= 0) {
scoped_refptr<const PermissionSet> tab_permissions =
GetTabSpecificPermissions(extension, tab_id);
if (tab_permissions &&
tab_permissions->HasAPIPermission(APIPermission::kTab)) {
return true;
}
if (error)
*error = errors::kActiveTabPermissionNotGranted;
return false;
}
if (error)
*error = errors::kAllURLOrActiveTabNeeded;
return false;
}
bool PermissionsData::ParsePermissions(Extension* extension,
base::string16* error) {
initial_required_permissions_.reset(new InitialPermissions);
if (!ParseHelper(extension,
keys::kPermissions,
&initial_required_permissions_->api_permissions,
&initial_required_permissions_->host_permissions,
error)) {
return false;
}
initial_optional_permissions_.reset(new InitialPermissions);
if (!ParseHelper(extension,
keys::kOptionalPermissions,
&initial_optional_permissions_->api_permissions,
&initial_optional_permissions_->host_permissions,
error)) {
return false;
}
return true;
}
void PermissionsData::InitializeManifestPermissions(Extension* extension) {
ManifestHandler::AddExtensionInitialRequiredPermissions(
extension, &initial_required_permissions_->manifest_permissions);
}
void PermissionsData::FinalizePermissions(Extension* extension) {
active_permissions_ = new PermissionSet(
initial_required_permissions_->api_permissions,
initial_required_permissions_->manifest_permissions,
initial_required_permissions_->host_permissions,
initial_required_permissions_->scriptable_hosts);
required_permission_set_ = new PermissionSet(
initial_required_permissions_->api_permissions,
initial_required_permissions_->manifest_permissions,
initial_required_permissions_->host_permissions,
initial_required_permissions_->scriptable_hosts);
optional_permission_set_ = new PermissionSet(
initial_optional_permissions_->api_permissions,
initial_optional_permissions_->manifest_permissions,
initial_optional_permissions_->host_permissions,
URLPatternSet());
initial_required_permissions_.reset();
initial_optional_permissions_.reset();
}
}