diff options
author | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-03 10:01:26 +0000 |
---|---|---|
committer | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-03 10:01:26 +0000 |
commit | ab57a59d94280b432f728787fc2563227797d101 (patch) | |
tree | 0bebabb8be797300add05b6673cafc824fc4a9b0 /chrome/common/extensions | |
parent | f979ce4f17143dc97f7bfbdc81759993fd283bc5 (diff) | |
download | chromium_src-ab57a59d94280b432f728787fc2563227797d101.zip chromium_src-ab57a59d94280b432f728787fc2563227797d101.tar.gz chromium_src-ab57a59d94280b432f728787fc2563227797d101.tar.bz2 |
Revert 61323 - Component extensions (and whitelisted extensions) specifying <all_urls> in their Extension match pattern should be allowed to run content scripts everywhere (including chrome://, chrome-extension://, about: and gallery pages.
The intent was to also allow these extensions to specify more granular permissions, such as about:version instead of <all_urls>, but that didn't make the cut this time.
This CL also enables <all_urls> for host permissions for regular extensions, which was disabled before. Note: That still doesn't give them permission to script the gallery and chrome:// pages, etc.
BUG=36275
TEST=New: ExtensionBrowserTest.AllUrlsWhitelistedExtension, ExtensionBrowserTest.AllUrlsRegularExtensions
Review URL: http://codereview.chromium.org/3440027
TBR=finnur@chromium.org
Review URL: http://codereview.chromium.org/3557006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61327 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/extensions')
-rw-r--r-- | chrome/common/extensions/extension.cc | 99 | ||||
-rw-r--r-- | chrome/common/extensions/extension.h | 28 | ||||
-rw-r--r-- | chrome/common/extensions/extension_constants.cc | 3 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern.cc | 49 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern.h | 24 | ||||
-rw-r--r-- | chrome/common/extensions/url_pattern_unittest.cc | 88 |
6 files changed, 34 insertions, 257 deletions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index bddd6ec..b88e7c1 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -33,7 +33,6 @@ #include "chrome/common/extensions/user_script.h" #include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" -#include "googleurl/src/url_util.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" #include "net/base/registry_controlled_domain.h" @@ -131,17 +130,6 @@ const char* kNonPermissionFunctionNames[] = { const size_t kNumNonPermissionFunctionNames = arraysize(kNonPermissionFunctionNames); -// Ids of extensions allowed to execute scripts everywhere. Do not add to this -// list without consulting the Extensions team first. -// Note: Component extensions have this right implicitly and do not need to be -// added to this list. -const char* kCanExecuteScriptsEverywhere[] = { - "", // Extension ids for whitelisted extensions go here. -}; - -// The size of the kCanExecuteScriptsEverywhere list. -static size_t kNumCanExecuteScriptsEverywhere = - arraysize(kCanExecuteScriptsEverywhere); // A map between permission name and its install warning message. class PermissionMap { @@ -174,8 +162,6 @@ static const char kWindowPermission[] = "windows"; } // namespace -char** Extension::scripting_whitelist_ = - const_cast<char**>(&kCanExecuteScriptsEverywhere[0]); const FilePath::CharType Extension::kManifestFilename[] = FILE_PATH_LITERAL("manifest.json"); @@ -488,11 +474,7 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script, return false; } - URLPattern pattern; - if (CanExecuteScriptEverywhere()) - pattern = URLPattern(URLPattern::SCHEME_ALL); - else - pattern = URLPattern(UserScript::kValidUserScriptSchemes); + URLPattern pattern(UserScript::kValidUserScriptSchemes); if (!pattern.Parse(match_str)) { *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidMatch, base::IntToString(definition_index), base::IntToString(j)); @@ -1532,11 +1514,11 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key, UserScript script; if (!LoadUserScriptHelper(content_script, i, error, &script)) - return false; // Failed to parse script context definition. + return false; // Failed to parse script context definition script.set_extension_id(id()); if (converted_from_user_script_) { script.set_emulate_greasemonkey(true); - script.set_match_all_frames(true); // Greasemonkey matches all frames. + script.set_match_all_frames(true); // greasemonkey matches all frames } content_scripts_.push_back(script); } @@ -1689,18 +1671,16 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key, } // Otherwise, it's a host pattern permission. - URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ? - URLPattern::SCHEME_ALL : - (UserScript::kValidUserScriptSchemes | - URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE); - + URLPattern pattern(URLPattern::SCHEME_HTTP | + URLPattern::SCHEME_HTTPS | + URLPattern::SCHEME_CHROMEUI); if (!pattern.Parse(permission_str)) { *error = ExtensionErrorUtils::FormatErrorMessage( errors::kInvalidPermission, base::IntToString(i)); return false; } - if (!CanSpecifyHostPermission(pattern)) { + if (!CanAccessURL(pattern)) { *error = ExtensionErrorUtils::FormatErrorMessage( errors::kInvalidPermissionScheme, base::IntToString(i)); return false; @@ -1906,13 +1886,6 @@ static std::string SizeToString(const gfx::Size& max_size) { base::IntToString(max_size.height()); } -// static -void Extension::SetScriptingWhitelist(const char** whitelist, size_t size) { - DCHECK(whitelist); - scripting_whitelist_ = const_cast<char**>(whitelist); - kNumCanExecuteScriptsEverywhere = size; -} - void Extension::SetCachedImage(const ExtensionResource& source, const SkBitmap& image, const gfx::Size& original_size) { @@ -1981,13 +1954,12 @@ GURL Extension::GetIconURL(int size, ExtensionIconSet::MatchType match_type) { return GetResourceURL(path); } -bool Extension::CanSpecifyHostPermission(const URLPattern pattern) const { - if (!pattern.match_all_urls() && - pattern.MatchesScheme(chrome::kChromeUIScheme)) { +bool Extension::CanAccessURL(const URLPattern pattern) const { + if (pattern.MatchesScheme(chrome::kChromeUIScheme)) { // Only allow access to chrome://favicon to regular extensions. Component // extensions can have access to all of chrome://*. return (pattern.host() == chrome::kChromeUIFavIconHost || - CanExecuteScriptEverywhere()); + location() == Extension::COMPONENT); } // Otherwise, the valid schemes were handled by URLPattern. @@ -2051,45 +2023,6 @@ void Extension::InitEffectiveHostPermissions() { } } -// static -bool Extension::CanExecuteScriptOnPage( - const GURL& page_url, bool can_execute_script_everywhere, - const std::vector<URLPattern>* host_permissions, - UserScript* script, - std::string* error) { - DCHECK(!(host_permissions && script)) << "Shouldn't specify both"; - - // 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). - if ((page_url.host() == GURL(Extension::ChromeStoreURL()).host()) && - !can_execute_script_everywhere && - !CommandLine::ForCurrentProcess()->HasSwitch( - switches::kAllowScriptingGallery)) { - if (error) - *error = errors::kCannotScriptGallery; - return false; - } - - if (host_permissions) { - for (size_t i = 0; i < host_permissions->size(); ++i) { - if ((*host_permissions)[i].MatchesUrl(page_url)) - return true; - } - } - if (script) { - if (script->MatchesUrl(page_url)) - return true; - } - - if (error) { - *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, - page_url.spec()); - } - - return false; -} - bool Extension::HasEffectiveAccessToAllHosts() const { // Some APIs effectively grant access to every site. New ones should be // added here. (I'm looking at you, network API) @@ -2137,18 +2070,6 @@ bool Extension::IsAPIPermission(const std::string& str) { return false; } -bool Extension::CanExecuteScriptEverywhere() const { - if (location() == Extension::COMPONENT) - return true; - - for (size_t i = 0; i < kNumCanExecuteScriptsEverywhere; ++i) { - if (id() == scripting_whitelist_[i]) - return true; - } - - return false; -} - ExtensionInfo::ExtensionInfo(const DictionaryValue* manifest, const std::string& id, const FilePath& path, diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index b1b00d3..f55ffe0 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -308,23 +308,6 @@ class Extension { // slash. static std::string ChromeStoreURL(); - // Helper function that consolidates the check for whether the script can - // execute into one location. |page_url| is the page that is the candidate - // for running the script, |can_execute_script_everywhere| specifies whether - // the extension is on the whitelist, |allowed_pages| is a vector of - // URLPatterns, listing what access the extension has, |script| is the script - // pointer (if content script) and |error| is an optional parameter, which - // will receive the error string listing why access was denied. - static bool CanExecuteScriptOnPage( - const GURL& page_url, - bool can_execute_script_everywhere, - const std::vector<URLPattern>* allowed_pages, - UserScript* script, - std::string* error); - - // Adds an extension to the scripting whitelist. Used for testing only. - static void SetScriptingWhitelist(const char** whitelist, size_t size); - // Initialize the extension from a parsed manifest. // Usually, the id of an extension is generated by the "key" property of // its manifest, but if |require_key| is |false|, a temporary ID will be @@ -379,7 +362,7 @@ class Extension { // the manifest. http, https, and chrome://favicon/ is allowed for all // extensions, while component extensions are allowed access to // chrome://resources. - bool CanSpecifyHostPermission(const URLPattern pattern) const; + bool CanAccessURL(const URLPattern pattern) const; // Whether the extension has access to the given URL. bool HasHostPermission(const GURL& url) const; @@ -479,10 +462,6 @@ class Extension { bool is_hosted_app() const { return is_app() && !web_extent().is_empty(); } bool is_packaged_app() const { return is_app() && web_extent().is_empty(); } - // Returns true if this extension is a COMPONENT extension, or if it is - // on the whitelist of extensions that can script all pages. - bool CanExecuteScriptEverywhere() const; - private: // We keep a cache of images loaded from extension resources based on their // path and a string representation of a size that may have been used to @@ -645,9 +624,6 @@ class Extension { // The type of container to launch into. extension_misc::LaunchContainer launch_container_; - // A whitelist of extensions that can script anywhere. - static char** scripting_whitelist_; - // The default size of the container when launching. Only respected for // containers like panels and windows. int launch_width_; @@ -656,7 +632,7 @@ class Extension { // Cached images for this extension. ImageCache image_cache_; - // The Omnibox keyword for this extension, or empty if there is none. + // The omnibox keyword for this extension, or empty if there is none. std::string omnibox_keyword_; // Runtime data: diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc index 17444ee..f725181 100644 --- a/chrome/common/extensions/extension_constants.cc +++ b/chrome/common/extensions/extension_constants.cc @@ -202,7 +202,8 @@ const char* kInvalidPermission = const char* kInvalidPermissions = "Required value 'permissions' is missing or invalid."; const char* kInvalidPermissionScheme = - "Invalid scheme for 'permissions[*]'."; + "Invalid scheme for 'permissions[*]'. Only 'http' and 'https' are " + "allowed."; const char* kInvalidPlugins = "Invalid value for 'plugins'."; const char* kInvalidPluginsPath = diff --git a/chrome/common/extensions/url_pattern.cc b/chrome/common/extensions/url_pattern.cc index 62459a3..80fc5fb 100644 --- a/chrome/common/extensions/url_pattern.cc +++ b/chrome/common/extensions/url_pattern.cc @@ -9,7 +9,6 @@ #include "base/string_util.h" #include "chrome/common/url_constants.h" #include "googleurl/src/gurl.h" -#include "googleurl/src/url_util.h" // TODO(aa): Consider adding chrome-extension? What about more obscure ones // like data: and javascript: ? @@ -35,21 +34,10 @@ COMPILE_ASSERT(arraysize(kValidSchemes) == arraysize(kValidSchemeMasks), static const char kPathSeparator[] = "/"; -const char URLPattern::kAllUrlsPattern[] = "<all_urls>"; - -static bool IsStandardScheme(const std::string& scheme) { - // "*" gets the same treatment as a standard scheme. - if (scheme == "*") - return true; - - return url_util::IsStandard(scheme.c_str(), - url_parse::Component(0, static_cast<int>(scheme.length()))); -} +static const char kAllUrlsPattern[] = "<all_urls>"; URLPattern::URLPattern() - : valid_schemes_(SCHEME_NONE), - match_all_urls_(false), - match_subdomains_(false) {} + : valid_schemes_(0), match_all_urls_(false), match_subdomains_(false) {} URLPattern::URLPattern(int valid_schemes) : valid_schemes_(valid_schemes), match_all_urls_(false), @@ -76,32 +64,24 @@ bool URLPattern::Parse(const std::string& pattern) { return true; } - size_t scheme_end_pos = pattern.find(":"); + size_t scheme_end_pos = pattern.find(chrome::kStandardSchemeSeparator); if (scheme_end_pos == std::string::npos) return false; if (!SetScheme(pattern.substr(0, scheme_end_pos))) return false; - std::string separator = - pattern.substr(scheme_end_pos, strlen(chrome::kStandardSchemeSeparator)); - if (separator == chrome::kStandardSchemeSeparator) - scheme_end_pos += strlen(chrome::kStandardSchemeSeparator); - else - scheme_end_pos += 1; - - // Advance past the scheme separator. - size_t host_start_pos = scheme_end_pos; + size_t host_start_pos = scheme_end_pos + + strlen(chrome::kStandardSchemeSeparator); if (host_start_pos >= pattern.length()) return false; // Parse out the host and path. size_t path_start_pos = 0; - bool standard_scheme = IsStandardScheme(scheme_); - - // File URLs are special because they have no host. - if (scheme_ == chrome::kFileScheme || !standard_scheme) { + // File URLs are special because they have no host. There are other schemes + // with the same structure, but we don't support them (yet). + if (scheme_ == chrome::kFileScheme) { path_start_pos = host_start_pos; } else { size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos); @@ -145,9 +125,6 @@ bool URLPattern::SetScheme(const std::string& scheme) { } bool URLPattern::IsValidScheme(const std::string& scheme) const { - if (valid_schemes_ == SCHEME_ALL) - return true; - for (size_t i = 0; i < arraysize(kValidSchemes); ++i) { if (scheme == kValidSchemes[i] && (valid_schemes_ & kValidSchemeMasks[i])) return true; @@ -160,9 +137,6 @@ bool URLPattern::MatchesUrl(const GURL &test) const { if (!MatchesScheme(test.scheme())) return false; - if (match_all_urls_) - return true; - if (!MatchesHost(test)) return false; @@ -235,12 +209,9 @@ std::string URLPattern::GetAsString() const { if (match_all_urls_) return kAllUrlsPattern; - bool standard_scheme = IsStandardScheme(scheme_); - - std::string spec = scheme_ + - (standard_scheme ? chrome::kStandardSchemeSeparator : ":"); + std::string spec = scheme_ + chrome::kStandardSchemeSeparator; - if (scheme_ != chrome::kFileScheme && standard_scheme) { + if (scheme_ != chrome::kFileScheme) { if (match_subdomains_) { spec += "*"; if (!host_.empty()) diff --git a/chrome/common/extensions/url_pattern.h b/chrome/common/extensions/url_pattern.h index 0067678..3fe6eb6 100644 --- a/chrome/common/extensions/url_pattern.h +++ b/chrome/common/extensions/url_pattern.h @@ -77,23 +77,13 @@ class URLPattern { public: // A collection of scheme bitmasks for use with valid_schemes. enum SchemeMasks { - SCHEME_NONE = 0, - SCHEME_HTTP = 1 << 0, - SCHEME_HTTPS = 1 << 1, - SCHEME_FILE = 1 << 2, - SCHEME_FTP = 1 << 3, - SCHEME_CHROMEUI = 1 << 4, - // SCHEME_ALL will match every scheme, including chrome://, chrome- - // extension://, about:, etc. Because this has lots of security - // implications, third-party extensions should never be able to get access - // to URL patterns initialized this way. It should only be used for internal - // Chrome code. - SCHEME_ALL = -1, + SCHEME_HTTP = 1<<0, + SCHEME_HTTPS = 1<<1, + SCHEME_FILE = 1<<2, + SCHEME_FTP = 1<<3, + SCHEME_CHROMEUI = 1<<4, }; - // The <all_urls> string pattern. - static const char kAllUrlsPattern[]; - // Note: don't use this directly. This exists so URLPattern can be used // with STL containers. URLPattern(); @@ -171,8 +161,8 @@ class URLPattern { // would result in the same answer. bool OverlapsWith(const URLPattern& other) const; - // Convert this URLPattern into an equivalent set of URLPatterns that don't - // use a wildcard in the scheme component. If this URLPattern doesn't use a + // Conver this URLPattern into an equivalent set of URLPatterns that don't use + // a wildcard in the scheme component. If this URLPattern doesn't use a // wildcard scheme, then the returned set will contain one element that is // equivalent to this instance. std::vector<URLPattern> ConvertToExplicitSchemes() const; diff --git a/chrome/common/extensions/url_pattern_unittest.cc b/chrome/common/extensions/url_pattern_unittest.cc index a9ef21e..47cbdc8 100644 --- a/chrome/common/extensions/url_pattern_unittest.cc +++ b/chrome/common/extensions/url_pattern_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -19,20 +19,18 @@ static const int kAllSchemes = TEST(URLPatternTest, ParseInvalid) { const char* kInvalidPatterns[] = { "http", // no scheme - "http:", - "http:/", "http://", // no path separator "http://foo", // no path separator "http://*foo/bar", // not allowed as substring of host component "http://foo.*.bar/baz", // must be first component "http:/bar", // scheme separator not found "foo://*", // invalid scheme - "chrome-extension://*/*", // we don't support chrome extension URLs + "chrome-extenstions://*/*", // we don't support chrome extension URLs }; for (size_t i = 0; i < arraysize(kInvalidPatterns); ++i) { URLPattern pattern; - EXPECT_FALSE(pattern.Parse(kInvalidPatterns[i])) << kInvalidPatterns[i]; + EXPECT_FALSE(pattern.Parse(kInvalidPatterns[i])); } }; @@ -185,86 +183,6 @@ TEST(URLPatternTest, Match11) { EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo/bar"))); }; -// SCHEME_ALL matches all schemes. -TEST(URLPatternTest, Match12) { - URLPattern pattern(URLPattern::SCHEME_ALL); - EXPECT_TRUE(pattern.Parse("<all_urls>")); - EXPECT_TRUE(pattern.MatchesScheme("chrome")); - EXPECT_TRUE(pattern.MatchesScheme("http")); - EXPECT_TRUE(pattern.MatchesScheme("https")); - EXPECT_TRUE(pattern.MatchesScheme("file")); - EXPECT_TRUE(pattern.MatchesScheme("javascript")); - EXPECT_TRUE(pattern.MatchesScheme("data")); - EXPECT_TRUE(pattern.MatchesScheme("about")); - EXPECT_TRUE(pattern.MatchesScheme("chrome-extension")); - EXPECT_TRUE(pattern.match_subdomains()); - EXPECT_TRUE(pattern.match_all_urls()); - EXPECT_EQ("/*", pattern.path()); - EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://favicon/http://google.com"))); - EXPECT_TRUE(pattern.MatchesUrl(GURL("http://127.0.0.1"))); - EXPECT_TRUE(pattern.MatchesUrl(GURL("file:///foo/bar"))); - EXPECT_TRUE(pattern.MatchesUrl(GURL("chrome://newtab"))); - EXPECT_TRUE(pattern.MatchesUrl(GURL("about:blank"))); - EXPECT_TRUE(pattern.MatchesUrl(GURL("about:version"))); - EXPECT_TRUE(pattern.MatchesUrl( - GURL("data:text/html;charset=utf-8,<html>asdf</html>"))); -}; - -static const struct MatchPatterns { - const char* pattern; - const char* matches; -} kMatch13UrlPatternTestCases[] = { - {"about:*", "about:blank"}, - {"about:blank", "about:blank"}, - {"about:*", "about:version"}, - {"chrome-extension://*/*", "chrome-extension://FTW"}, - {"data:*", "data:monkey"}, - {"javascript:*", "javascript:atemyhomework"}, -}; - -// SCHEME_ALL and specific schemes. -TEST(URLPatternTest, Match13) { - for (size_t i = 0; i < arraysize(kMatch13UrlPatternTestCases); ++i) { - URLPattern pattern(URLPattern::SCHEME_ALL); - EXPECT_TRUE(pattern.Parse(kMatch13UrlPatternTestCases[i].pattern)) - << " while parsing " << kMatch13UrlPatternTestCases[i].pattern; - EXPECT_TRUE(pattern.MatchesUrl( - GURL(kMatch13UrlPatternTestCases[i].matches))) - << " while matching " << kMatch13UrlPatternTestCases[i].matches; - } - - // Negative test. - URLPattern pattern(URLPattern::SCHEME_ALL); - EXPECT_TRUE(pattern.Parse("data:*")); - EXPECT_FALSE(pattern.MatchesUrl(GURL("about:blank"))); -}; - -static const struct GetAsStringPatterns { - const char* pattern; -} kGetAsStringTestCases[] = { - { "http://www/" }, - { "http://*/*" }, - { "chrome://*/*" }, - { "chrome://newtab/" }, - { "about:*" }, - { "about:blank" }, - { "chrome-extension://*/*" }, - { "chrome-extension://FTW/" }, - { "data:*" }, - { "data:monkey" }, - { "javascript:*" }, - { "javascript:atemyhomework" }, -}; - -TEST(URLPatternTest, GetAsString) { - for (size_t i = 0; i < arraysize(kGetAsStringTestCases); ++i) { - URLPattern pattern(URLPattern::SCHEME_ALL); - EXPECT_TRUE(pattern.Parse(kGetAsStringTestCases[i].pattern)); - EXPECT_STREQ(kGetAsStringTestCases[i].pattern, - pattern.GetAsString().c_str()); - } -} - void TestPatternOverlap(const URLPattern& pattern1, const URLPattern& pattern2, bool expect_overlap) { EXPECT_EQ(expect_overlap, pattern1.OverlapsWith(pattern2)) |