| Index: chrome/common/extensions/extension.cc
|
| diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
|
| index 111ed76927009f130d94fe1b5e2f1befdaa1e07d..54883497fa37a3db96979a89b969fd53959afd3b 100644
|
| --- a/chrome/common/extensions/extension.cc
|
| +++ b/chrome/common/extensions/extension.cc
|
| @@ -286,20 +286,6 @@ Extension::Location Extension::GetHigherPriorityLocation(
|
| return (loc1_rank > loc2_rank ? loc1 : loc2 );
|
| }
|
|
|
| -ExtensionPermissionMessages Extension::GetPermissionMessages() const {
|
| - if (IsTrustedId(id_))
|
| - return ExtensionPermissionMessages();
|
| - else
|
| - return permission_set_->GetPermissionMessages();
|
| -}
|
| -
|
| -std::vector<string16> Extension::GetPermissionMessageStrings() const {
|
| - if (IsTrustedId(id_))
|
| - return std::vector<string16>();
|
| - else
|
| - return permission_set_->GetWarningMessages();
|
| -}
|
| -
|
| void Extension::OverrideLaunchUrl(const GURL& override_url) {
|
| GURL new_url(override_url);
|
| if (!new_url.is_valid()) {
|
| @@ -1202,6 +1188,7 @@ bool Extension::EnsureNotHybridApp(const DictionaryValue* manifest,
|
| if (!IsBaseCrxKey(*key) &&
|
| *key != keys::kApp &&
|
| *key != keys::kPermissions &&
|
| + *key != keys::kOptionalPermissions &&
|
| *key != keys::kOptionsPage &&
|
| *key != keys::kBackground) {
|
| *error = ExtensionErrorUtils::FormatErrorMessage(
|
| @@ -1385,13 +1372,16 @@ GURL Extension::GetBaseURLFromExtensionId(const std::string& extension_id) {
|
|
|
| bool Extension::InitFromValue(const DictionaryValue& source, int flags,
|
| std::string* error) {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| // When strict error checks are enabled, make URL pattern parsing strict.
|
| URLPattern::ParseOption parse_strictness =
|
| (flags & STRICT_ERROR_CHECKS ? URLPattern::ERROR_ON_PORTS
|
| : URLPattern::IGNORE_PORTS);
|
|
|
| // Initialize permissions with an empty, default permission set.
|
| - permission_set_.reset(new ExtensionPermissionSet());
|
| + runtime_data_.SetActivePermissions(new ExtensionPermissionSet());
|
| + optional_permission_set_ = new ExtensionPermissionSet();
|
| + required_permission_set_ = new ExtensionPermissionSet();
|
|
|
| if (source.HasKey(keys::kPublicKey)) {
|
| std::string public_key_bytes;
|
| @@ -1911,104 +1901,30 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
|
| }
|
| }
|
|
|
| + // Initialize the permissions (optional).
|
| ExtensionAPIPermissionSet api_permissions;
|
| URLPatternSet host_permissions;
|
| + if (!ParsePermissions(&source,
|
| + keys::kPermissions,
|
| + flags,
|
| + error,
|
| + &api_permissions,
|
| + &host_permissions)) {
|
| + return false;
|
| + }
|
|
|
| - // Initialize the permissions (optional).
|
| - if (source.HasKey(keys::kPermissions)) {
|
| - ListValue* permissions = NULL;
|
| - if (!source.GetList(keys::kPermissions, &permissions)) {
|
| - *error = ExtensionErrorUtils::FormatErrorMessage(
|
| - errors::kInvalidPermissions, "");
|
| - return false;
|
| - }
|
| -
|
| - for (size_t i = 0; i < permissions->GetSize(); ++i) {
|
| - std::string permission_str;
|
| - if (!permissions->GetString(i, &permission_str)) {
|
| - *error = ExtensionErrorUtils::FormatErrorMessage(
|
| - errors::kInvalidPermission, base::IntToString(i));
|
| - return false;
|
| - }
|
| -
|
| - ExtensionAPIPermission* permission =
|
| - ExtensionPermissionsInfo::GetInstance()->GetByName(permission_str);
|
| -
|
| - // Only COMPONENT extensions can use private APIs.
|
| - // TODO(asargent) - We want a more general purpose mechanism for this,
|
| - // and better error messages. (http://crbug.com/54013)
|
| - if (!IsComponentOnlyPermission(permission)
|
| -#ifndef NDEBUG
|
| - && !CommandLine::ForCurrentProcess()->HasSwitch(
|
| - switches::kExposePrivateExtensionApi)
|
| -#endif
|
| - ) {
|
| - continue;
|
| - }
|
| -
|
| - if (web_extent().is_empty() || location() == Extension::COMPONENT) {
|
| - // Check if it's a module permission. If so, enable that permission.
|
| - if (permission != NULL) {
|
| - // Only allow the experimental API permission if the command line
|
| - // flag is present, or if the extension is a component of Chrome.
|
| - if (IsDisallowedExperimentalPermission(permission->id()) &&
|
| - location() != Extension::COMPONENT) {
|
| - *error = errors::kExperimentalFlagRequired;
|
| - return false;
|
| - }
|
| - api_permissions.insert(permission->id());
|
| - continue;
|
| - }
|
| - } else {
|
| - // Hosted apps only get access to a subset of the valid permissions.
|
| - if (permission != NULL && permission->is_hosted_app()) {
|
| - if (IsDisallowedExperimentalPermission(permission->id())) {
|
| - *error = errors::kExperimentalFlagRequired;
|
| - return false;
|
| - }
|
| - api_permissions.insert(permission->id());
|
| - continue;
|
| - }
|
| - }
|
| -
|
| - // Check if it's a host pattern permission.
|
| - URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ?
|
| - URLPattern::SCHEME_ALL : kValidHostPermissionSchemes);
|
| -
|
| - URLPattern::ParseResult parse_result = pattern.Parse(permission_str,
|
| - parse_strictness);
|
| - if (parse_result == URLPattern::PARSE_SUCCESS) {
|
| - if (!CanSpecifyHostPermission(pattern)) {
|
| - *error = ExtensionErrorUtils::FormatErrorMessage(
|
| - errors::kInvalidPermissionScheme, base::IntToString(i));
|
| - return false;
|
| - }
|
| -
|
| - // The path component is not used for host permissions, so we force it
|
| - // to match all paths.
|
| - pattern.SetPath("/*");
|
| -
|
| - if (pattern.MatchesScheme(chrome::kFileScheme) &&
|
| - !CanExecuteScriptEverywhere()) {
|
| - wants_file_access_ = true;
|
| - if (!(flags & ALLOW_FILE_ACCESS))
|
| - pattern.SetValidSchemes(
|
| - pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
|
| - }
|
| -
|
| - host_permissions.AddPattern(pattern);
|
| - }
|
| -
|
| - // If it's not a host permission, then it's probably an unknown API
|
| - // permission. Do not throw an error so extensions can retain
|
| - // backwards compatability (http://crbug.com/42742).
|
| - // TODO(jstritar): We can improve error messages by adding better
|
| - // validation of API permissions here.
|
| - // TODO(skerner): Consider showing the reason |permission_str| is not
|
| - // a valid URL pattern if it is almost valid. For example, if it has
|
| - // a valid scheme, and failed to parse because it has a port, show an
|
| - // error.
|
| - }
|
| + // Initialize the optional permissions (optional).
|
| + ExtensionAPIPermissionSet optional_api_permissions;
|
| + URLPatternSet optional_host_permissions;
|
| + if (CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kEnableExperimentalExtensionApis) &&
|
| + !ParsePermissions(&source,
|
| + keys::kOptionalPermissions,
|
| + flags,
|
| + error,
|
| + &optional_api_permissions,
|
| + &optional_host_permissions)) {
|
| + return false;
|
| }
|
|
|
| // Initialize background url (optional).
|
| @@ -2394,8 +2310,12 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
|
| return false;
|
| }
|
|
|
| - permission_set_.reset(
|
| - new ExtensionPermissionSet(this, api_permissions, host_permissions));
|
| + runtime_data_.SetActivePermissions(new ExtensionPermissionSet(
|
| + this, api_permissions, host_permissions));
|
| + required_permission_set_ = new ExtensionPermissionSet(
|
| + this, api_permissions, host_permissions);
|
| + optional_permission_set_ = new ExtensionPermissionSet(
|
| + optional_api_permissions, optional_host_permissions, URLPatternSet());
|
|
|
| // Although |source| is passed in as a const, it's still possible to modify
|
| // it. This is dangerous since the utility process re-uses |source| after
|
| @@ -2573,6 +2493,118 @@ GURL Extension::GetIconURL(int size,
|
| return GetResourceURL(path);
|
| }
|
|
|
| +bool Extension::ParsePermissions(const DictionaryValue* source,
|
| + const char* key,
|
| + int flags,
|
| + std::string* error,
|
| + ExtensionAPIPermissionSet* api_permissions,
|
| + URLPatternSet* host_permissions) {
|
| + if (source->HasKey(key)) {
|
| + // When strict error checks are enabled, make URL pattern parsing strict.
|
| + URLPattern::ParseOption parse_strictness =
|
| + (flags & STRICT_ERROR_CHECKS ? URLPattern::ERROR_ON_PORTS
|
| + : URLPattern::IGNORE_PORTS);
|
| + ListValue* permissions = NULL;
|
| + if (!source->GetList(key, &permissions)) {
|
| + *error = ExtensionErrorUtils::FormatErrorMessage(
|
| + errors::kInvalidPermissions, "");
|
| + return false;
|
| + }
|
| +
|
| + for (size_t i = 0; i < permissions->GetSize(); ++i) {
|
| + std::string permission_str;
|
| + if (!permissions->GetString(i, &permission_str)) {
|
| + *error = ExtensionErrorUtils::FormatErrorMessage(
|
| + errors::kInvalidPermission, base::IntToString(i));
|
| + return false;
|
| + }
|
| +
|
| + ExtensionAPIPermission* permission =
|
| + ExtensionPermissionsInfo::GetInstance()->GetByName(permission_str);
|
| +
|
| + // Only COMPONENT extensions can use private APIs.
|
| + // TODO(asargent) - We want a more general purpose mechanism for this,
|
| + // and better error messages. (http://crbug.com/54013)
|
| + if (!IsComponentOnlyPermission(permission)
|
| +#ifndef NDEBUG
|
| + && !CommandLine::ForCurrentProcess()->HasSwitch(
|
| + switches::kExposePrivateExtensionApi)
|
| +#endif
|
| + ) {
|
| + continue;
|
| + }
|
| +
|
| + if (web_extent().is_empty() || location() == Extension::COMPONENT) {
|
| + // Check if it's a module permission. If so, enable that permission.
|
| + if (permission != NULL) {
|
| + // Only allow the experimental API permission if the command line
|
| + // flag is present, or if the extension is a component of Chrome.
|
| + if (IsDisallowedExperimentalPermission(permission->id()) &&
|
| + location() != Extension::COMPONENT) {
|
| + *error = errors::kExperimentalFlagRequired;
|
| + return false;
|
| + }
|
| + api_permissions->insert(permission->id());
|
| + continue;
|
| + }
|
| + } else {
|
| + // Hosted apps only get access to a subset of the valid permissions.
|
| + if (permission != NULL && permission->is_hosted_app()) {
|
| + if (IsDisallowedExperimentalPermission(permission->id())) {
|
| + *error = errors::kExperimentalFlagRequired;
|
| + return false;
|
| + }
|
| + api_permissions->insert(permission->id());
|
| + continue;
|
| + }
|
| + }
|
| +
|
| + // Check if it's a host pattern permission.
|
| + URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ?
|
| + URLPattern::SCHEME_ALL : kValidHostPermissionSchemes);
|
| +
|
| + URLPattern::ParseResult parse_result = pattern.Parse(permission_str,
|
| + parse_strictness);
|
| + if (parse_result == URLPattern::PARSE_SUCCESS) {
|
| + if (!CanSpecifyHostPermission(pattern)) {
|
| + *error = ExtensionErrorUtils::FormatErrorMessage(
|
| + errors::kInvalidPermissionScheme, base::IntToString(i));
|
| + return false;
|
| + }
|
| +
|
| + // The path component is not used for host permissions, so we force it
|
| + // to match all paths.
|
| + pattern.SetPath("/*");
|
| +
|
| + if (pattern.MatchesScheme(chrome::kFileScheme) &&
|
| + !CanExecuteScriptEverywhere()) {
|
| + wants_file_access_ = true;
|
| + if (!(flags & ALLOW_FILE_ACCESS))
|
| + pattern.SetValidSchemes(
|
| + pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
|
| + }
|
| +
|
| + host_permissions->AddPattern(pattern);
|
| + }
|
| +
|
| + // If it's not a host permission, then it's probably an unknown API
|
| + // permission. Do not throw an error so extensions can retain
|
| + // backwards compatability (http://crbug.com/42742).
|
| + // TODO(jstritar): We can improve error messages by adding better
|
| + // validation of API permissions here.
|
| + // TODO(skerner): Consider showing the reason |permission_str| is not
|
| + // a valid URL pattern if it is almost valid. For example, if it has
|
| + // a valid scheme, and failed to parse because it has a port, show an
|
| + // error.
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +bool Extension::CanSilentlyIncreasePermissions() const {
|
| + return location() != INTERNAL;
|
| +}
|
| +
|
| bool Extension::CanSpecifyHostPermission(const URLPattern& pattern) const {
|
| if (!pattern.match_all_urls() &&
|
| pattern.MatchesScheme(chrome::kChromeUIScheme)) {
|
| @@ -2588,24 +2620,68 @@ bool Extension::CanSpecifyHostPermission(const URLPattern& pattern) const {
|
|
|
| bool Extension::HasAPIPermission(
|
| ExtensionAPIPermission::ID permission) const {
|
| - return permission_set()->HasAPIPermission(permission);
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + return runtime_data_.GetActivePermissions()->HasAPIPermission(permission);
|
| }
|
|
|
| bool Extension::HasAPIPermission(
|
| const std::string& function_name) const {
|
| - return permission_set()->HasAccessToFunction(function_name);
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + return runtime_data_.GetActivePermissions()->
|
| + HasAccessToFunction(function_name);
|
| }
|
|
|
| const URLPatternSet& Extension::GetEffectiveHostPermissions() const {
|
| - return permission_set()->effective_hosts();
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + return runtime_data_.GetActivePermissions()->effective_hosts();
|
| }
|
|
|
| bool Extension::HasHostPermission(const GURL& url) const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| if (url.SchemeIs(chrome::kChromeUIScheme) &&
|
| url.host() != chrome::kChromeUIFaviconHost &&
|
| location() != Extension::COMPONENT)
|
| return false;
|
| - return permission_set()->HasExplicitAccessToOrigin(url);
|
| + return runtime_data_.GetActivePermissions()->
|
| + HasExplicitAccessToOrigin(url);
|
| +}
|
| +
|
| +bool Extension::HasEffectiveAccessToAllHosts() const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + return runtime_data_.GetActivePermissions()->HasEffectiveAccessToAllHosts();
|
| +}
|
| +
|
| +bool Extension::HasFullPermissions() const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + return runtime_data_.GetActivePermissions()->HasEffectiveFullAccess();
|
| +}
|
| +
|
| +ExtensionPermissionMessages Extension::GetPermissionMessages() const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + if (IsTrustedId(id_))
|
| + return ExtensionPermissionMessages();
|
| + else
|
| + return runtime_data_.GetActivePermissions()->GetPermissionMessages();
|
| +}
|
| +
|
| +std::vector<string16> Extension::GetPermissionMessageStrings() const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + if (IsTrustedId(id_))
|
| + return std::vector<string16>();
|
| + else
|
| + return runtime_data_.GetActivePermissions()->GetWarningMessages();
|
| +}
|
| +
|
| +void Extension::SetActivePermissions(
|
| + const ExtensionPermissionSet* permissions) const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + runtime_data_.SetActivePermissions(permissions);
|
| +}
|
| +
|
| +scoped_refptr<const ExtensionPermissionSet>
|
| + Extension::GetActivePermissions() const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| + return runtime_data_.GetActivePermissions();
|
| }
|
|
|
| bool Extension::IsComponentOnlyPermission(
|
| @@ -2637,6 +2713,7 @@ bool Extension::HasMultipleUISurfaces() const {
|
| bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
|
| const UserScript* script,
|
| std::string* error) const {
|
| + base::AutoLock auto_lock(runtime_data_lock_);
|
| // The gallery is special-cased as a restricted URL for scripting to prevent
|
| // access to special JS bindings we expose to the gallery (and avoid things
|
| // like extensions removing the "report abuse" link).
|
| @@ -2661,7 +2738,8 @@ bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
|
|
|
| // Otherwise, see if this extension has permission to execute script
|
| // programmatically on pages.
|
| - if (permission_set()->HasExplicitAccessToOrigin(page_url))
|
| + if (runtime_data_.GetActivePermissions()->HasExplicitAccessToOrigin(
|
| + page_url))
|
| return true;
|
|
|
| if (error) {
|
| @@ -2672,14 +2750,6 @@ bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
|
| return false;
|
| }
|
|
|
| -bool Extension::HasEffectiveAccessToAllHosts() const {
|
| - return permission_set_->HasEffectiveAccessToAllHosts();
|
| -}
|
| -
|
| -bool Extension::HasFullPermissions() const {
|
| - return permission_set_->HasEffectiveFullAccess();
|
| -}
|
| -
|
| bool Extension::ShowConfigureContextMenus() const {
|
| // Don't show context menu for component extensions. We might want to show
|
| // options for component extension button but now there is no component
|
| @@ -2767,11 +2837,26 @@ ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest,
|
|
|
| ExtensionInfo::~ExtensionInfo() {}
|
|
|
| +Extension::RuntimeData::RuntimeData() {}
|
| +Extension::RuntimeData::RuntimeData(const ExtensionPermissionSet* active)
|
| + : active_permissions_(active) {}
|
| +Extension::RuntimeData::~RuntimeData() {}
|
| +
|
| +scoped_refptr<const ExtensionPermissionSet>
|
| + Extension::RuntimeData::GetActivePermissions() const {
|
| + return active_permissions_;
|
| +}
|
| +
|
| +void Extension::RuntimeData::SetActivePermissions(
|
| + const ExtensionPermissionSet* active) {
|
| + active_permissions_ = active;
|
| +}
|
| +
|
| UninstalledExtensionInfo::UninstalledExtensionInfo(
|
| const Extension& extension)
|
| : extension_id(extension.id()),
|
| extension_api_permissions(
|
| - extension.permission_set()->GetAPIsAsStrings()),
|
| + extension.GetActivePermissions()->GetAPIsAsStrings()),
|
| extension_type(extension.GetType()),
|
| update_url(extension.update_url()) {}
|
|
|
| @@ -2784,3 +2869,11 @@ UnloadedExtensionInfo::UnloadedExtensionInfo(
|
| : reason(reason),
|
| already_disabled(false),
|
| extension(extension) {}
|
| +
|
| +UpdatedExtensionPermissionsInfo::UpdatedExtensionPermissionsInfo(
|
| + const Extension* extension,
|
| + const ExtensionPermissionSet* permissions,
|
| + Reason reason)
|
| + : reason(reason),
|
| + extension(extension),
|
| + permissions(permissions) {}
|
|
|