Chromium Code Reviews| Index: extensions/common/permissions/permissions_data.cc |
| diff --git a/extensions/common/permissions/permissions_data.cc b/extensions/common/permissions/permissions_data.cc |
| index 1b160cab003c68e23a2895efa2b72a5bd5e01b12..724e1c276a6b91aca7438a26198fc5eb6650d064 100644 |
| --- a/extensions/common/permissions/permissions_data.cc |
| +++ b/extensions/common/permissions/permissions_data.cc |
| @@ -9,6 +9,7 @@ |
| #include "extensions/common/constants.h" |
| #include "extensions/common/error_utils.h" |
| #include "extensions/common/extensions_client.h" |
| +#include "extensions/common/feature_switch.h" |
| #include "extensions/common/manifest.h" |
| #include "extensions/common/manifest_constants.h" |
| #include "extensions/common/manifest_handlers/permissions_parser.h" |
| @@ -31,18 +32,29 @@ bool ShouldSkipPermissionWarnings(const std::string& extension_id) { |
| return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd"); |
| } |
| +// Divvy up the |url patterns| between those we grant and those we do not. If |
| +// |withhold_permissions| is false (because the requisite feature is not |
| +// enabled), no permissions are withheld. |
| +void SegregateUrlPermissions(const URLPatternSet& url_patterns, |
| + bool withhold_permissions, |
| + URLPatternSet* granted, |
| + URLPatternSet* withheld) { |
| + for (URLPatternSet::const_iterator iter = url_patterns.begin(); |
| + iter != url_patterns.end(); |
| + ++iter) { |
| + if (withhold_permissions && iter->ImpliesAllHosts()) |
| + withheld->AddPattern(*iter); |
| + else |
| + granted->AddPattern(*iter); |
| + } |
| +} |
| + |
| } // namespace |
| PermissionsData::PermissionsData(const Extension* extension) |
| : extension_id_(extension->id()), manifest_type_(extension->GetType()) { |
| - base::AutoLock auto_lock(runtime_lock_); |
| - scoped_refptr<const PermissionSet> required_permissions = |
| - PermissionsParser::GetRequiredPermissions(extension); |
| - active_permissions_unsafe_ = |
| - new PermissionSet(required_permissions->apis(), |
| - required_permissions->manifest_permissions(), |
| - required_permissions->explicit_hosts(), |
| - required_permissions->scriptable_hosts()); |
| + InitializePermissions(PermissionsParser::GetRequiredPermissions(extension), |
| + extension); |
| } |
| PermissionsData::~PermissionsData() { |
| @@ -113,10 +125,54 @@ bool PermissionsData::IsRestrictedUrl(const GURL& document_url, |
| return false; |
| } |
| -void PermissionsData::SetActivePermissions( |
| - const PermissionSet* permissions) const { |
| +void PermissionsData::InitializePermissions(const PermissionSet* permissions, |
|
not at google - send to devlin
2014/06/27 23:24:34
you don't actually use |permissions| anywhere.
Devlin
2014/06/30 17:06:10
Whoops! Done.
|
| + const Extension* extension) const { |
| base::AutoLock auto_lock(runtime_lock_); |
| - active_permissions_unsafe_ = permissions; |
| + scoped_refptr<const PermissionSet> required_permissions = |
| + PermissionsParser::GetRequiredPermissions(extension); |
| + |
| + // We withhold permissions iff the switch to do so is enabled, the extension |
| + // shows up in chrome:extensions (so the user can grant withheld permissions), |
| + // the extension is not part of chrome or corporate policy, and also not on |
| + // the scripting whitelist. |
| + bool withhold_permissions = |
| + FeatureSwitch::scripts_require_action()->IsEnabled() && |
| + extension->ShouldDisplayInExtensionSettings() && |
| + !Manifest::IsPolicyLocation(extension->location()) && |
| + !Manifest::IsComponentLocation(extension->location()) && |
| + !CanExecuteScriptEverywhere(extension); |
| + |
| + URLPatternSet granted_explicit_hosts; |
| + URLPatternSet withheld_explicit_hosts; |
| + SegregateUrlPermissions(required_permissions->explicit_hosts(), |
| + withhold_permissions, |
| + &granted_explicit_hosts, |
| + &withheld_explicit_hosts); |
| + |
| + URLPatternSet granted_scriptable_hosts; |
| + URLPatternSet withheld_scriptable_hosts; |
| + SegregateUrlPermissions(required_permissions->scriptable_hosts(), |
| + withhold_permissions, |
| + &granted_scriptable_hosts, |
| + &withheld_scriptable_hosts); |
| + |
| + active_permissions_unsafe_ = |
| + new PermissionSet(required_permissions->apis(), |
| + required_permissions->manifest_permissions(), |
| + granted_explicit_hosts, |
| + granted_scriptable_hosts); |
| + |
| + withheld_permissions_unsafe_ = new PermissionSet(APIPermissionSet(), |
| + ManifestPermissionSet(), |
| + withheld_explicit_hosts, |
| + withheld_scriptable_hosts); |
| +} |
| + |
| +void PermissionsData::SetPermissions(const PermissionSet* active, |
| + const PermissionSet* withheld) const { |
| + base::AutoLock auto_lock(runtime_lock_); |
| + active_permissions_unsafe_ = active; |
| + withheld_permissions_unsafe_ = withheld; |
| } |
| void PermissionsData::UpdateTabSpecificPermissions( |
| @@ -204,18 +260,103 @@ PermissionsData::GetPermissionMessageDetailsStrings() const { |
| active_permissions(), manifest_type_); |
| } |
| +bool PermissionsData::HasWithheldAllHosts() const { |
| + // Since we currently only withhold all_hosts, it's sufficient to check |
| + // that either set is not empty. |
| + return !withheld_permissions()->explicit_hosts().is_empty() || |
| + !withheld_permissions()->scriptable_hosts().is_empty(); |
| +} |
| + |
| +void PermissionsData::WithholdAllHosts() const { |
| + base::AutoLock auto_lock(runtime_lock_); |
| + |
| + URLPatternSet withheld_scriptable = |
| + withheld_permissions_unsafe_->scriptable_hosts(); |
| + URLPatternSet active_scriptable; |
| + SegregateUrlPermissions(active_permissions_unsafe_->scriptable_hosts(), |
| + true, // withhold permissions |
| + &active_scriptable, |
| + &withheld_scriptable); |
| + |
| + URLPatternSet withheld_explicit = |
| + withheld_permissions_unsafe_->explicit_hosts(); |
| + URLPatternSet active_explicit; |
| + SegregateUrlPermissions(active_permissions_unsafe_->explicit_hosts(), |
| + true, // withhold permissions |
| + &active_explicit, |
| + &withheld_explicit); |
| + |
| + active_permissions_unsafe_ = |
| + new PermissionSet(active_permissions_unsafe_->apis(), |
| + active_permissions_unsafe_->manifest_permissions(), |
| + active_explicit, |
| + active_scriptable); |
| + withheld_permissions_unsafe_ = |
| + new PermissionSet(withheld_permissions_unsafe_->apis(), |
| + withheld_permissions_unsafe_->manifest_permissions(), |
| + withheld_explicit, |
| + withheld_scriptable); |
| +} |
| + |
| +void PermissionsData::GrantWithheldAllHosts() const { |
| + base::AutoLock auto_lock(runtime_lock_); |
| + |
| + // Move the all-hosts permission from withheld to active. |
| + // We can cheat a bit here since we know that the only host permission we |
| + // withhold is allhosts (or something similar enough to it), so we can just |
| + // grant all withheld host permissions. |
| + URLPatternSet explicit_hosts; |
| + URLPatternSet::CreateUnion(active_permissions_unsafe_->explicit_hosts(), |
| + withheld_permissions_unsafe_->explicit_hosts(), |
| + &explicit_hosts); |
| + URLPatternSet scriptable_hosts; |
| + URLPatternSet::CreateUnion(active_permissions_unsafe_->scriptable_hosts(), |
| + withheld_permissions_unsafe_->scriptable_hosts(), |
| + &scriptable_hosts); |
| + scoped_refptr<const PermissionSet> new_active_permissions = |
| + new PermissionSet(active_permissions_unsafe_->apis(), |
| + active_permissions_unsafe_->manifest_permissions(), |
| + explicit_hosts, |
| + scriptable_hosts); |
| + |
| + active_permissions_unsafe_ = new_active_permissions; |
| + // Since we only withhold host permissions (so far), we know that withheld |
| + // permissions will be empty. |
| + withheld_permissions_unsafe_ = new PermissionSet(); |
| +} |
| + |
| bool PermissionsData::CanAccessPage(const Extension* extension, |
| const GURL& document_url, |
| const GURL& top_frame_url, |
| int tab_id, |
| int process_id, |
| std::string* error) const { |
| + AccessType result = CanRunOnPage(extension, |
| + document_url, |
| + top_frame_url, |
| + tab_id, |
| + process_id, |
| + active_permissions()->explicit_hosts(), |
| + withheld_permissions()->explicit_hosts(), |
| + error); |
| + // TODO(rdevlin.cronin) Update callers so that they only need ALLOW_ACCESS. |
| + return result == ALLOW_ACCESS || result == REQUEST_ACCESS; |
| +} |
| + |
| +PermissionsData::AccessType PermissionsData::CanAccessPageWithUserConsent( |
| + const Extension* extension, |
| + const GURL& document_url, |
| + const GURL& top_frame_url, |
| + int tab_id, |
| + int process_id, |
| + std::string* error) const { |
| return CanRunOnPage(extension, |
| document_url, |
| top_frame_url, |
| tab_id, |
| process_id, |
| active_permissions()->explicit_hosts(), |
| + withheld_permissions()->explicit_hosts(), |
| error); |
| } |
| @@ -225,12 +366,33 @@ bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension, |
| int tab_id, |
| int process_id, |
| std::string* error) const { |
| + AccessType result = CanRunOnPage(extension, |
| + document_url, |
| + top_frame_url, |
| + tab_id, |
| + process_id, |
| + active_permissions()->scriptable_hosts(), |
| + withheld_permissions()->scriptable_hosts(), |
| + error); |
| + // TODO(rdevlin.cronin) Update callers so that they only need ALLOW_ACCESS. |
| + return result == ALLOW_ACCESS || result == REQUEST_ACCESS; |
| +} |
| + |
| +PermissionsData::AccessType |
| +PermissionsData::CanRunContentScriptOnPageWithUserConsent( |
| + const Extension* extension, |
| + const GURL& document_url, |
| + const GURL& top_frame_url, |
| + int tab_id, |
| + int process_id, |
| + std::string* error) const { |
| return CanRunOnPage(extension, |
| document_url, |
| top_frame_url, |
| tab_id, |
| process_id, |
| active_permissions()->scriptable_hosts(), |
| + withheld_permissions()->scriptable_hosts(), |
| error); |
| } |
| @@ -259,37 +421,6 @@ bool PermissionsData::CanCaptureVisiblePage(int tab_id, |
| return false; |
| } |
| -// static |
| -bool PermissionsData::RequiresActionForScriptExecution( |
| - const Extension* extension) const { |
| - return RequiresActionForScriptExecution(extension, -1, GURL()); |
| -} |
| - |
| -// static |
| -bool PermissionsData::RequiresActionForScriptExecution( |
| - const Extension* extension, |
| - int tab_id, |
| - const GURL& url) const { |
| - // For now, the user should be notified when an extension with all hosts |
| - // permission tries to execute a script on a page. Exceptions for policy- |
| - // enabled and component extensions, and extensions which are whitelisted to |
| - // execute scripts everywhere. |
| - if (!extension->ShouldDisplayInExtensionSettings() || |
| - Manifest::IsPolicyLocation(extension->location()) || |
| - Manifest::IsComponentLocation(extension->location()) || |
| - CanExecuteScriptEverywhere(extension) || |
| - !active_permissions()->ShouldWarnAllHosts()) { |
| - return false; |
| - } |
| - |
| - // If the extension has explicit permission to run on the given tab, then |
| - // we don't need to alert the user. |
| - if (HasTabSpecificPermissionToExecuteScript(tab_id, url)) |
| - return false; |
| - |
| - return true; |
| -} |
| - |
| scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions( |
| int tab_id) const { |
| base::AutoLock auto_lock(runtime_lock_); |
| @@ -313,33 +444,38 @@ bool PermissionsData::HasTabSpecificPermissionToExecuteScript( |
| return false; |
| } |
| -bool PermissionsData::CanRunOnPage(const Extension* extension, |
| - const GURL& document_url, |
| - const GURL& top_frame_url, |
| - int tab_id, |
| - int process_id, |
| - const URLPatternSet& permitted_url_patterns, |
| - std::string* error) const { |
| +PermissionsData::AccessType PermissionsData::CanRunOnPage( |
| + const Extension* extension, |
| + const GURL& document_url, |
| + const GURL& top_frame_url, |
| + int tab_id, |
| + int process_id, |
| + const URLPatternSet& permitted_url_patterns, |
| + const URLPatternSet& withheld_url_patterns, |
| + std::string* error) const { |
| if (g_policy_delegate && |
| !g_policy_delegate->CanExecuteScriptOnPage( |
| extension, document_url, top_frame_url, tab_id, process_id, error)) { |
| - return false; |
| + return DENY_ACCESS; |
| } |
| if (IsRestrictedUrl(document_url, top_frame_url, extension, error)) |
| - return false; |
| + return DENY_ACCESS; |
| if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url)) |
| - return true; |
| + return ALLOW_ACCESS; |
| + |
| + if (permitted_url_patterns.MatchesURL(document_url)) |
| + return ALLOW_ACCESS; |
| - bool can_access = permitted_url_patterns.MatchesURL(document_url); |
| + if (withheld_url_patterns.MatchesURL(document_url)) |
| + return REQUEST_ACCESS; |
| - if (!can_access && error) { |
| + if (error) { |
| *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage, |
| document_url.spec()); |
| } |
| - |
| - return can_access; |
| + return DENY_ACCESS; |
| } |
| } // namespace extensions |