summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/extensions/all_urls_apitest.cc112
-rw-r--r--chrome/browser/extensions/execute_code_in_tab_function.cc17
-rw-r--r--chrome/browser/extensions/extension_browsertests_misc.cc1
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc12
-rw-r--r--chrome/browser/extensions/extensions_service.cc24
-rw-r--r--chrome/browser/extensions/extensions_service.h7
-rw-r--r--chrome/browser/renderer_host/browser_render_process_host.cc3
-rw-r--r--chrome/browser/tab_contents/tab_contents.cc4
-rw-r--r--chrome/browser/tab_contents/tab_contents.h1
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/extension.cc99
-rw-r--r--chrome/common/extensions/extension.h28
-rw-r--r--chrome/common/extensions/extension_constants.cc3
-rw-r--r--chrome/common/extensions/url_pattern.cc49
-rw-r--r--chrome/common/extensions/url_pattern.h24
-rw-r--r--chrome/common/extensions/url_pattern_unittest.cc88
-rw-r--r--chrome/common/render_messages_params.cc14
-rw-r--r--chrome/common/render_messages_params.h7
-rw-r--r--chrome/renderer/extensions/extension_renderer_info.cc9
-rw-r--r--chrome/renderer/extensions/extension_renderer_info.h14
-rw-r--r--chrome/renderer/render_view.cc32
-rw-r--r--chrome/renderer/user_script_slave.cc30
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/content_script/background.html17
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/content_script/content_script.js10
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/content_script/manifest.json10
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/execute_script/background.html21
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/execute_script/execute_script.js10
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/execute_script/manifest.json7
-rw-r--r--chrome/test/data/extensions/api_test/all_urls/index.html1
29 files changed, 531 insertions, 124 deletions
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc
new file mode 100644
index 0000000..067eef0
--- /dev/null
+++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -0,0 +1,112 @@
+// Copyright (c) 2010 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.
+
+
+#include "chrome/browser/browser.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_test_message_listener.h"
+#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/profile.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/test/ui_test_utils.h"
+
+const std::string kAllUrlsTarget =
+ "files/extensions/uitests/component_all_urls/index.html";
+
+typedef ExtensionApiTest AllUrlsApiTest;
+
+#if !defined(OS_WIN)
+// Disabled, see http://crbug.com/57694.
+#define WhitelistedExtension DISABLED_WhitelistedExtension
+#endif
+
+IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, WhitelistedExtension) {
+ // First add the two extensions we are going to load to the whitelist.
+ const char* kCanExecuteScriptsEverywhere[] = {
+ "fekpfaahmgnelcjpkefdnpiofglcgmgo",
+ "bpkfbiacjfimfmglhncgmibnddpnhmoj",
+ };
+ Extension::SetScriptingWhitelist(kCanExecuteScriptsEverywhere,
+ arraysize(kCanExecuteScriptsEverywhere));
+
+ // Then load the two extension.
+ FilePath extension_dir1 = test_data_dir_.AppendASCII("all_urls")
+ .AppendASCII("content_script");
+ FilePath extension_dir2 = test_data_dir_.AppendASCII("all_urls")
+ .AppendASCII("execute_script");
+
+ ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ const size_t size_before = service->extensions()->size();
+ ASSERT_TRUE(LoadExtension(extension_dir1));
+ ASSERT_TRUE(LoadExtension(extension_dir2));
+ EXPECT_EQ(size_before + 2, service->extensions()->size());
+
+ std::string url;
+
+ // Now verify we run content scripts on chrome://newtab/.
+ url = "chrome://newtab/";
+ ExtensionTestMessageListener listener1a("content script: " + url);
+ ExtensionTestMessageListener listener1b("execute: " + url);
+ ui_test_utils::NavigateToURL(browser(), GURL(url));
+ ASSERT_TRUE(listener1a.WaitUntilSatisfied());
+ ASSERT_TRUE(listener1b.WaitUntilSatisfied());
+
+ // Now verify data: urls.
+ url = "data:text/html;charset=utf-8,<html>asdf</html>";
+ ExtensionTestMessageListener listener2a("content script: " + url);
+ ExtensionTestMessageListener listener2b("execute: " + url);
+ ui_test_utils::NavigateToURL(browser(), GURL(url));
+ ASSERT_TRUE(listener2a.WaitUntilSatisfied());
+ ASSERT_TRUE(listener2b.WaitUntilSatisfied());
+
+ // Now verify about:version.
+ url = "about:version";
+ ExtensionTestMessageListener listener3a("content script: " + url);
+ ExtensionTestMessageListener listener3b("execute: " + url);
+ ui_test_utils::NavigateToURL(browser(), GURL(url));
+ ASSERT_TRUE(listener3a.WaitUntilSatisfied());
+ ASSERT_TRUE(listener3b.WaitUntilSatisfied());
+
+ // Now verify about:blank.
+ url = "about:blank";
+ ExtensionTestMessageListener listener4a("content script: " + url);
+ ExtensionTestMessageListener listener4b("execute: " + url);
+ ui_test_utils::NavigateToURL(browser(), GURL(url));
+ ASSERT_TRUE(listener4a.WaitUntilSatisfied());
+ ASSERT_TRUE(listener4b.WaitUntilSatisfied());
+
+ // Now verify we can script a regular http page.
+ ASSERT_TRUE(test_server()->Start());
+ GURL page_url = test_server()->GetURL(kAllUrlsTarget);
+ ExtensionTestMessageListener listener5a("content script: " + page_url.spec());
+ ExtensionTestMessageListener listener5b("execute: " + page_url.spec());
+ ui_test_utils::NavigateToURL(browser(), page_url);
+ ASSERT_TRUE(listener5a.WaitUntilSatisfied());
+ ASSERT_TRUE(listener5b.WaitUntilSatisfied());
+}
+
+// Test that an extension NOT whitelisted for scripting can ask for <all_urls>
+// and run scripts on non-restricted all pages.
+IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, RegularExtensions) {
+ // First load the two extension.
+ FilePath extension_dir1 = test_data_dir_.AppendASCII("all_urls")
+ .AppendASCII("content_script");
+ FilePath extension_dir2 = test_data_dir_.AppendASCII("all_urls")
+ .AppendASCII("execute_script");
+
+ ExtensionsService* service = browser()->profile()->GetExtensionsService();
+ const size_t size_before = service->extensions()->size();
+ ASSERT_TRUE(LoadExtension(extension_dir1));
+ ASSERT_TRUE(LoadExtension(extension_dir2));
+ EXPECT_EQ(size_before + 2, service->extensions()->size());
+
+ // Now verify we can script a regular http page.
+ ASSERT_TRUE(test_server()->Start());
+ GURL page_url = test_server()->GetURL(kAllUrlsTarget);
+ ExtensionTestMessageListener listener1a("content script: " + page_url.spec());
+ ExtensionTestMessageListener listener1b("execute: " + page_url.spec());
+ ui_test_utils::NavigateToURL(browser(), page_url);
+ ASSERT_TRUE(listener1a.WaitUntilSatisfied());
+ ASSERT_TRUE(listener1b.WaitUntilSatisfied());
+}
diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc
index 52f519d..b7bf999 100644
--- a/chrome/browser/extensions/execute_code_in_tab_function.cc
+++ b/chrome/browser/extensions/execute_code_in_tab_function.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -78,9 +78,17 @@ bool ExecuteCodeInTabFunction::RunImpl() {
// NOTE: This can give the wrong answer due to race conditions, but it is OK,
// we check again in the renderer.
- if (!profile()->GetExtensionsService()->CanExecuteScriptOnHost(
- GetExtension(), contents->GetURL(), &error_))
+ Extension* extension = GetExtension();
+ const std::vector<URLPattern> host_permissions =
+ extension->host_permissions();
+ if (!Extension::CanExecuteScriptOnPage(
+ contents->GetURL(),
+ extension->CanExecuteScriptEverywhere(),
+ &host_permissions,
+ NULL,
+ &error_)) {
return false;
+ }
if (script_info->HasKey(keys::kAllFramesKey)) {
if (!script_info->GetBoolean(keys::kAllFramesKey, &all_frames_))
@@ -164,8 +172,7 @@ bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) {
DCHECK(false);
}
if (!contents->ExecuteCode(request_id(), extension->id(),
- extension->host_permissions(), is_js_code,
- code_string, all_frames_)) {
+ is_js_code, code_string, all_frames_)) {
SendResponse(false);
return false;
}
diff --git a/chrome/browser/extensions/extension_browsertests_misc.cc b/chrome/browser/extensions/extension_browsertests_misc.cc
index 012420a..8338a52 100644
--- a/chrome/browser/extensions/extension_browsertests_misc.cc
+++ b/chrome/browser/extensions/extension_browsertests_misc.cc
@@ -799,7 +799,6 @@ IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, DISABLED_OptionsPage) {
// Test window.chrome.app.isInstalled .
IN_PROC_BROWSER_TEST_F(ExtensionBrowserTest, PropertyAppIsInstalled) {
-
std::string app_host("app.com");
std::string nonapp_host("nonapp.com");
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index 016c3ec..60160c2 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -661,9 +661,17 @@ bool UpdateTabFunction::RunImpl() {
// JavaScript URLs can do the same kinds of things as cross-origin XHR, so
// we need to check host permissions before allowing them.
if (url.SchemeIs(chrome::kJavaScriptScheme)) {
- if (!profile()->GetExtensionsService()->CanExecuteScriptOnHost(
- GetExtension(), contents->GetURL(), &error_))
+ Extension* extension = GetExtension();
+ const std::vector<URLPattern> host_permissions =
+ extension->host_permissions();
+ if (!Extension::CanExecuteScriptOnPage(
+ contents->GetURL(),
+ extension->CanExecuteScriptEverywhere(),
+ &host_permissions,
+ NULL,
+ &error_)) {
return false;
+ }
// TODO(aa): How does controller queue URLs? Is there any chance that this
// JavaScript URL will end up applying to something other than
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index bffb732..ea47716 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -1259,30 +1259,6 @@ void ExtensionsService::SetAllowFileAccess(Extension* extension, bool allow) {
Details<Extension>(extension));
}
-bool ExtensionsService::CanExecuteScriptOnHost(Extension* extension,
- const GURL& url,
- std::string* error) const {
- // No extensions are allowed to execute script on the gallery because that
- // would allow extensions to manipulate their own install pages.
- if (url.host() == GURL(Extension::ChromeStoreURL()).host()
- && !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowScriptingGallery)) {
- if (error)
- *error = errors::kCannotScriptGallery;
- return false;
- }
-
- if (extension->HasHostPermission(url))
- return true;
-
- if (error) {
- *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
- url.spec());
- }
-
- return false;
-}
-
void ExtensionsService::CheckForExternalUpdates() {
// This installs or updates externally provided extensions.
// TODO(aa): Why pass this list into the provider, why not just filter it
diff --git a/chrome/browser/extensions/extensions_service.h b/chrome/browser/extensions/extensions_service.h
index 18ef1f3..1cf9fd4 100644
--- a/chrome/browser/extensions/extensions_service.h
+++ b/chrome/browser/extensions/extensions_service.h
@@ -178,13 +178,6 @@ class ExtensionsService
bool AllowFileAccess(const Extension* extension);
void SetAllowFileAccess(Extension* extension, bool allow);
- // Returns true if the extension has permission to execute script on a
- // particular host.
- // TODO(aa): Also use this in the renderer, for normal content script
- // injection. Currently, that has its own copy of this code.
- bool CanExecuteScriptOnHost(Extension* extension,
- const GURL& url, std::string* error) const;
-
const FilePath& install_directory() const { return install_directory_; }
// Initialize and start all installed extensions.
diff --git a/chrome/browser/renderer_host/browser_render_process_host.cc b/chrome/browser/renderer_host/browser_render_process_host.cc
index b2bd5d9..9e8b99e 100644
--- a/chrome/browser/renderer_host/browser_render_process_host.cc
+++ b/chrome/browser/renderer_host/browser_render_process_host.cc
@@ -701,6 +701,9 @@ void BrowserRenderProcessHost::SendExtensionInfo() {
info.web_extent = extension->web_extent();
info.name = extension->name();
info.location = extension->location();
+ info.allowed_to_execute_script_everywhere =
+ extension->CanExecuteScriptEverywhere();
+ info.host_permissions = extension->host_permissions();
// The icon in the page is 96px. We'd rather not scale up, so use 128.
info.icon_url = extension->GetIconURL(Extension::EXTENSION_ICON_LARGE,
diff --git a/chrome/browser/tab_contents/tab_contents.cc b/chrome/browser/tab_contents/tab_contents.cc
index d37fdcc..a9d94f4 100644
--- a/chrome/browser/tab_contents/tab_contents.cc
+++ b/chrome/browser/tab_contents/tab_contents.cc
@@ -1021,7 +1021,6 @@ void TabContents::AddNewContents(TabContents* new_contents,
}
bool TabContents::ExecuteCode(int request_id, const std::string& extension_id,
- const std::vector<URLPattern>& host_permissions,
bool is_js_code, const std::string& code_string,
bool all_frames) {
RenderViewHost* host = render_view_host();
@@ -1029,7 +1028,7 @@ bool TabContents::ExecuteCode(int request_id, const std::string& extension_id,
return false;
return host->Send(new ViewMsg_ExecuteCode(host->routing_id(),
- ViewMsg_ExecuteCode_Params(request_id, extension_id, host_permissions,
+ ViewMsg_ExecuteCode_Params(request_id, extension_id,
is_js_code, code_string, all_frames)));
}
@@ -2475,7 +2474,6 @@ void TabContents::DidNavigate(RenderViewHost* rvh,
NotificationType::FRAME_PROVISIONAL_LOAD_COMMITTED,
Source<NavigationController>(&controller_),
Details<ProvisionalLoadDetails>(&load_details));
-
}
// Update history. Note that this needs to happen after the entry is complete,
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index b556c62..b8264fc 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -397,7 +397,6 @@ class TabContents : public PageNavigator,
// Execute code in this tab. Returns true if the message was successfully
// sent.
bool ExecuteCode(int request_id, const std::string& extension_id,
- const std::vector<URLPattern>& host_permissions,
bool is_js_code, const std::string& code_string,
bool all_frames);
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 1ebb39d..4632e95 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1881,6 +1881,7 @@
'browser/dom_ui/mediaplayer_browsertest.cc',
'browser/download/save_page_browsertest.cc',
'browser/extensions/alert_apitest.cc',
+ 'browser/extensions/all_urls_apitest.cc',
'browser/extensions/app_background_page_apitest.cc',
'browser/extensions/app_process_apitest.cc',
'browser/extensions/autoupdate_interceptor.cc',
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index b88e7c1..bddd6ec 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -33,6 +33,7 @@
#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"
@@ -130,6 +131,17 @@ 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 {
@@ -162,6 +174,8 @@ 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");
@@ -474,7 +488,11 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
return false;
}
- URLPattern pattern(UserScript::kValidUserScriptSchemes);
+ URLPattern pattern;
+ if (CanExecuteScriptEverywhere())
+ pattern = URLPattern(URLPattern::SCHEME_ALL);
+ else
+ pattern = URLPattern(UserScript::kValidUserScriptSchemes);
if (!pattern.Parse(match_str)) {
*error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidMatch,
base::IntToString(definition_index), base::IntToString(j));
@@ -1514,11 +1532,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);
}
@@ -1671,16 +1689,18 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_key,
}
// Otherwise, it's a host pattern permission.
- URLPattern pattern(URLPattern::SCHEME_HTTP |
- URLPattern::SCHEME_HTTPS |
- URLPattern::SCHEME_CHROMEUI);
+ URLPattern pattern = URLPattern(CanExecuteScriptEverywhere() ?
+ URLPattern::SCHEME_ALL :
+ (UserScript::kValidUserScriptSchemes |
+ URLPattern::SCHEME_CHROMEUI) & ~URLPattern::SCHEME_FILE);
+
if (!pattern.Parse(permission_str)) {
*error = ExtensionErrorUtils::FormatErrorMessage(
errors::kInvalidPermission, base::IntToString(i));
return false;
}
- if (!CanAccessURL(pattern)) {
+ if (!CanSpecifyHostPermission(pattern)) {
*error = ExtensionErrorUtils::FormatErrorMessage(
errors::kInvalidPermissionScheme, base::IntToString(i));
return false;
@@ -1886,6 +1906,13 @@ 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) {
@@ -1954,12 +1981,13 @@ GURL Extension::GetIconURL(int size, ExtensionIconSet::MatchType match_type) {
return GetResourceURL(path);
}
-bool Extension::CanAccessURL(const URLPattern pattern) const {
- if (pattern.MatchesScheme(chrome::kChromeUIScheme)) {
+bool Extension::CanSpecifyHostPermission(const URLPattern pattern) const {
+ if (!pattern.match_all_urls() &&
+ 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 ||
- location() == Extension::COMPONENT);
+ CanExecuteScriptEverywhere());
}
// Otherwise, the valid schemes were handled by URLPattern.
@@ -2023,6 +2051,45 @@ 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)
@@ -2070,6 +2137,18 @@ 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 f55ffe0..b1b00d3 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -308,6 +308,23 @@ 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
@@ -362,7 +379,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 CanAccessURL(const URLPattern pattern) const;
+ bool CanSpecifyHostPermission(const URLPattern pattern) const;
// Whether the extension has access to the given URL.
bool HasHostPermission(const GURL& url) const;
@@ -462,6 +479,10 @@ 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
@@ -624,6 +645,9 @@ 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_;
@@ -632,7 +656,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 f725181..17444ee 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -202,8 +202,7 @@ const char* kInvalidPermission =
const char* kInvalidPermissions =
"Required value 'permissions' is missing or invalid.";
const char* kInvalidPermissionScheme =
- "Invalid scheme for 'permissions[*]'. Only 'http' and 'https' are "
- "allowed.";
+ "Invalid scheme for 'permissions[*]'.";
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 80fc5fb..62459a3 100644
--- a/chrome/common/extensions/url_pattern.cc
+++ b/chrome/common/extensions/url_pattern.cc
@@ -9,6 +9,7 @@
#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: ?
@@ -34,10 +35,21 @@ COMPILE_ASSERT(arraysize(kValidSchemes) == arraysize(kValidSchemeMasks),
static const char kPathSeparator[] = "/";
-static const char kAllUrlsPattern[] = "<all_urls>";
+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())));
+}
URLPattern::URLPattern()
- : valid_schemes_(0), match_all_urls_(false), match_subdomains_(false) {}
+ : valid_schemes_(SCHEME_NONE),
+ match_all_urls_(false),
+ match_subdomains_(false) {}
URLPattern::URLPattern(int valid_schemes)
: valid_schemes_(valid_schemes), match_all_urls_(false),
@@ -64,24 +76,32 @@ bool URLPattern::Parse(const std::string& pattern) {
return true;
}
- size_t scheme_end_pos = pattern.find(chrome::kStandardSchemeSeparator);
+ size_t scheme_end_pos = pattern.find(":");
if (scheme_end_pos == std::string::npos)
return false;
if (!SetScheme(pattern.substr(0, scheme_end_pos)))
return false;
- size_t host_start_pos = scheme_end_pos +
- strlen(chrome::kStandardSchemeSeparator);
+ 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;
if (host_start_pos >= pattern.length())
return false;
// Parse out the host and path.
size_t path_start_pos = 0;
- // 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) {
+ bool standard_scheme = IsStandardScheme(scheme_);
+
+ // File URLs are special because they have no host.
+ if (scheme_ == chrome::kFileScheme || !standard_scheme) {
path_start_pos = host_start_pos;
} else {
size_t host_end_pos = pattern.find(kPathSeparator, host_start_pos);
@@ -125,6 +145,9 @@ 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;
@@ -137,6 +160,9 @@ bool URLPattern::MatchesUrl(const GURL &test) const {
if (!MatchesScheme(test.scheme()))
return false;
+ if (match_all_urls_)
+ return true;
+
if (!MatchesHost(test))
return false;
@@ -209,9 +235,12 @@ std::string URLPattern::GetAsString() const {
if (match_all_urls_)
return kAllUrlsPattern;
- std::string spec = scheme_ + chrome::kStandardSchemeSeparator;
+ bool standard_scheme = IsStandardScheme(scheme_);
+
+ std::string spec = scheme_ +
+ (standard_scheme ? chrome::kStandardSchemeSeparator : ":");
- if (scheme_ != chrome::kFileScheme) {
+ if (scheme_ != chrome::kFileScheme && standard_scheme) {
if (match_subdomains_) {
spec += "*";
if (!host_.empty())
diff --git a/chrome/common/extensions/url_pattern.h b/chrome/common/extensions/url_pattern.h
index 3fe6eb6..0067678 100644
--- a/chrome/common/extensions/url_pattern.h
+++ b/chrome/common/extensions/url_pattern.h
@@ -77,13 +77,23 @@ class URLPattern {
public:
// A collection of scheme bitmasks for use with valid_schemes.
enum SchemeMasks {
- SCHEME_HTTP = 1<<0,
- SCHEME_HTTPS = 1<<1,
- SCHEME_FILE = 1<<2,
- SCHEME_FTP = 1<<3,
- SCHEME_CHROMEUI = 1<<4,
+ 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,
};
+ // 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();
@@ -161,8 +171,8 @@ class URLPattern {
// would result in the same answer.
bool OverlapsWith(const URLPattern& other) const;
- // 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
+ // 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
// 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 47cbdc8..a9ef21e 100644
--- a/chrome/common/extensions/url_pattern_unittest.cc
+++ b/chrome/common/extensions/url_pattern_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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,18 +19,20 @@ 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-extenstions://*/*", // we don't support chrome extension URLs
+ "chrome-extension://*/*", // we don't support chrome extension URLs
};
for (size_t i = 0; i < arraysize(kInvalidPatterns); ++i) {
URLPattern pattern;
- EXPECT_FALSE(pattern.Parse(kInvalidPatterns[i]));
+ EXPECT_FALSE(pattern.Parse(kInvalidPatterns[i])) << kInvalidPatterns[i];
}
};
@@ -183,6 +185,86 @@ 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))
diff --git a/chrome/common/render_messages_params.cc b/chrome/common/render_messages_params.cc
index 8bd3eb8..ac81931 100644
--- a/chrome/common/render_messages_params.cc
+++ b/chrome/common/render_messages_params.cc
@@ -207,12 +207,11 @@ ViewMsg_ExecuteCode_Params::ViewMsg_ExecuteCode_Params() {
ViewMsg_ExecuteCode_Params::ViewMsg_ExecuteCode_Params(
int request_id,
const std::string& extension_id,
- const std::vector<URLPattern>& host_permissions,
bool is_javascript,
const std::string& code,
bool all_frames)
: request_id(request_id), extension_id(extension_id),
- host_permissions(host_permissions), is_javascript(is_javascript),
+ is_javascript(is_javascript),
code(code), all_frames(all_frames) {
}
@@ -267,7 +266,8 @@ ViewHostMsg_RunFileChooser_Params::~ViewHostMsg_RunFileChooser_Params() {
}
ViewMsg_ExtensionRendererInfo::ViewMsg_ExtensionRendererInfo()
- : location(Extension::INVALID) {
+ : location(Extension::INVALID),
+ allowed_to_execute_script_everywhere(false) {
}
ViewMsg_ExtensionRendererInfo::~ViewMsg_ExtensionRendererInfo() {
@@ -1414,7 +1414,6 @@ void ParamTraits<ViewMsg_ExecuteCode_Params>::Write(Message* m,
const param_type& p) {
WriteParam(m, p.request_id);
WriteParam(m, p.extension_id);
- WriteParam(m, p.host_permissions);
WriteParam(m, p.is_javascript);
WriteParam(m, p.code);
WriteParam(m, p.all_frames);
@@ -1426,7 +1425,6 @@ bool ParamTraits<ViewMsg_ExecuteCode_Params>::Read(const Message* m,
return
ReadParam(m, iter, &p->request_id) &&
ReadParam(m, iter, &p->extension_id) &&
- ReadParam(m, iter, &p->host_permissions) &&
ReadParam(m, iter, &p->is_javascript) &&
ReadParam(m, iter, &p->code) &&
ReadParam(m, iter, &p->all_frames);
@@ -1671,6 +1669,8 @@ void ParamTraits<ViewMsg_ExtensionRendererInfo>::Write(Message* m,
WriteParam(m, p.name);
WriteParam(m, p.icon_url);
WriteParam(m, p.location);
+ WriteParam(m, p.allowed_to_execute_script_everywhere);
+ WriteParam(m, p.host_permissions);
}
bool ParamTraits<ViewMsg_ExtensionRendererInfo>::Read(const Message* m,
@@ -1680,7 +1680,9 @@ bool ParamTraits<ViewMsg_ExtensionRendererInfo>::Read(const Message* m,
ReadParam(m, iter, &p->web_extent) &&
ReadParam(m, iter, &p->name) &&
ReadParam(m, iter, &p->icon_url) &&
- ReadParam(m, iter, &p->location);
+ ReadParam(m, iter, &p->location) &&
+ ReadParam(m, iter, &p->allowed_to_execute_script_everywhere) &&
+ ReadParam(m, iter, &p->host_permissions);
}
void ParamTraits<ViewMsg_ExtensionRendererInfo>::Log(const param_type& p,
diff --git a/chrome/common/render_messages_params.h b/chrome/common/render_messages_params.h
index dfb78b8..0359b1e 100644
--- a/chrome/common/render_messages_params.h
+++ b/chrome/common/render_messages_params.h
@@ -746,7 +746,6 @@ struct ViewHostMsg_IDBObjectStoreOpenCursor_Params {
struct ViewMsg_ExecuteCode_Params {
ViewMsg_ExecuteCode_Params();
ViewMsg_ExecuteCode_Params(int request_id, const std::string& extension_id,
- const std::vector<URLPattern>& host_permissions,
bool is_javascript, const std::string& code,
bool all_frames);
~ViewMsg_ExecuteCode_Params();
@@ -758,10 +757,6 @@ struct ViewMsg_ExecuteCode_Params {
// execute the code inside of.
std::string extension_id;
- // The host permissions of the requesting extension. So that we can check them
- // right before injecting, to avoid any race conditions.
- std::vector<URLPattern> host_permissions;
-
// Whether the code is JavaScript or CSS.
bool is_javascript;
@@ -921,6 +916,8 @@ struct ViewMsg_ExtensionRendererInfo {
std::string name;
GURL icon_url;
Extension::Location location;
+ bool allowed_to_execute_script_everywhere;
+ std::vector<URLPattern> host_permissions;
};
struct ViewMsg_ExtensionsUpdated_Params {
diff --git a/chrome/renderer/extensions/extension_renderer_info.cc b/chrome/renderer/extensions/extension_renderer_info.cc
index f4b61a1..24d0064 100644
--- a/chrome/renderer/extensions/extension_renderer_info.cc
+++ b/chrome/renderer/extensions/extension_renderer_info.cc
@@ -11,7 +11,8 @@
// static
std::vector<ExtensionRendererInfo>* ExtensionRendererInfo::extensions_ = NULL;
-ExtensionRendererInfo::ExtensionRendererInfo() {
+ExtensionRendererInfo::ExtensionRendererInfo()
+ : allowed_to_execute_script_everywhere_(false) {
}
ExtensionRendererInfo::ExtensionRendererInfo(
@@ -20,6 +21,9 @@ ExtensionRendererInfo::ExtensionRendererInfo(
web_extent_ = that.web_extent_;
name_ = that.name_;
icon_url_ = that.icon_url_;
+ allowed_to_execute_script_everywhere_ =
+ that.allowed_to_execute_script_everywhere_;
+ host_permissions_ = that.host_permissions_;
}
ExtensionRendererInfo::~ExtensionRendererInfo() {
@@ -31,6 +35,9 @@ void ExtensionRendererInfo::Update(const ViewMsg_ExtensionRendererInfo& info) {
name_ = info.name;
location_ = info.location;
icon_url_ = info.icon_url;
+ allowed_to_execute_script_everywhere_ =
+ info.allowed_to_execute_script_everywhere;
+ host_permissions_ = info.host_permissions;
}
// static
diff --git a/chrome/renderer/extensions/extension_renderer_info.h b/chrome/renderer/extensions/extension_renderer_info.h
index 926f275..b9b74e5 100644
--- a/chrome/renderer/extensions/extension_renderer_info.h
+++ b/chrome/renderer/extensions/extension_renderer_info.h
@@ -29,6 +29,12 @@ class ExtensionRendererInfo {
const ExtensionExtent& web_extent() const { return web_extent_; }
const std::string& name() const { return name_; }
const GURL& icon_url() const { return icon_url_; }
+ const bool allowed_to_execute_script_everywhere() const {
+ return allowed_to_execute_script_everywhere_;
+ }
+ const std::vector<URLPattern> host_permissions() const {
+ return host_permissions_;
+ }
// Replace the list of extensions with those provided in |params|.
static void UpdateExtensions(const ViewMsg_ExtensionsUpdated_Params& params);
@@ -67,6 +73,14 @@ class ExtensionRendererInfo {
Extension::Location location_;
GURL icon_url_;
+ // Some internal extensions, such as accessibility extensions, should be able
+ // to execute scripts everywhere.
+ bool allowed_to_execute_script_everywhere_;
+
+ // The list of host permissions, that the extension is allowed to run scripts
+ // on.
+ std::vector<URLPattern> host_permissions_;
+
// static
static std::vector<ExtensionRendererInfo>* extensions_;
};
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 9d07d18..d80b160 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -308,16 +308,6 @@ static void GetRedirectChain(WebDataSource* ds, std::vector<GURL>* result) {
result->push_back(urls[i]);
}
-static bool UrlMatchesPermissions(
- const GURL& url, const std::vector<URLPattern>& host_permissions) {
- for (size_t i = 0; i < host_permissions.size(); ++i) {
- if (host_permissions[i].MatchesUrl(url))
- return true;
- }
-
- return false;
-}
-
static bool PaintViewIntoCanvas(WebView* view,
skia::PlatformCanvas& canvas) {
view->layout();
@@ -5633,15 +5623,6 @@ void RenderView::OnExecuteCode(const ViewMsg_ExecuteCode_Params& params) {
void RenderView::ExecuteCodeImpl(WebFrame* frame,
const ViewMsg_ExecuteCode_Params& params) {
- // Don't execute scripts in gallery pages.
- GURL frame_url = GURL(frame->url());
- if (frame_url.host() == GURL(Extension::ChromeStoreURL()).host()
- && !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowScriptingGallery)) {
- Send(new ViewMsg_ExecuteCodeFinished(routing_id_, params.request_id, true));
- return;
- }
-
std::vector<WebFrame*> frame_vector;
frame_vector.push_back(frame);
if (params.all_frames)
@@ -5651,8 +5632,19 @@ void RenderView::ExecuteCodeImpl(WebFrame* frame,
frame_it != frame_vector.end(); ++frame_it) {
WebFrame* frame = *frame_it;
if (params.is_javascript) {
- if (!UrlMatchesPermissions(frame->url(), params.host_permissions))
+ ExtensionRendererInfo* extension =
+ ExtensionRendererInfo::GetByID(params.extension_id);
+
+ const std::vector<URLPattern> host_permissions =
+ extension->host_permissions();
+ if (!Extension::CanExecuteScriptOnPage(
+ frame->url(),
+ extension->allowed_to_execute_script_everywhere(),
+ &host_permissions,
+ NULL,
+ NULL)) {
continue;
+ }
std::vector<WebScriptSource> sources;
sources.push_back(
diff --git a/chrome/renderer/user_script_slave.cc b/chrome/renderer/user_script_slave.cc
index 64849aa..032406f 100644
--- a/chrome/renderer/user_script_slave.cc
+++ b/chrome/renderer/user_script_slave.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2010 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.
@@ -16,6 +16,7 @@
#include "chrome/common/extensions/extension.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/extension_groups.h"
+#include "chrome/renderer/extensions/extension_renderer_info.h"
#include "chrome/renderer/render_thread.h"
#include "googleurl/src/gurl.h"
#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
@@ -66,7 +67,8 @@ UserScriptSlave::UserScriptSlave()
IDR_GREASEMONKEY_API_JS);
}
-void UserScriptSlave::GetActiveExtensions(std::set<std::string>* extension_ids) {
+void UserScriptSlave::GetActiveExtensions(
+ std::set<std::string>* extension_ids) {
for (size_t i = 0; i < scripts_.size(); ++i) {
DCHECK(!scripts_[i]->extension_id().empty());
extension_ids->insert(scripts_[i]->extension_id());
@@ -185,19 +187,9 @@ void UserScriptSlave::InsertInitExtensionCode(
void UserScriptSlave::InjectScripts(WebFrame* frame,
UserScript::RunLocation location) {
GURL frame_url = GURL(frame->url());
- // Don't bother if this is not a URL we inject script into.
- if (!URLPattern(UserScript::kValidUserScriptSchemes).IsValidScheme(
- frame_url.scheme()))
+ if (frame_url.is_empty())
return;
- // Don't inject user scripts into the gallery itself. This prevents
- // a user script from removing the "report abuse" link, for example.
- if (frame_url.host() == GURL(Extension::ChromeStoreURL()).host()
- && !CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kAllowScriptingGallery)) {
- return;
- }
-
PerfTimer timer;
int num_css = 0;
int num_scripts = 0;
@@ -209,8 +201,16 @@ void UserScriptSlave::InjectScripts(WebFrame* frame,
if (frame->parent() && !script->match_all_frames())
continue; // Only match subframes if the script declared it wanted to.
- if (!script->MatchesUrl(frame->url()))
- continue; // This frame doesn't match the script url pattern, skip it.
+ ExtensionRendererInfo* extension =
+ ExtensionRendererInfo::GetByID(script->extension_id());
+ if (!Extension::CanExecuteScriptOnPage(
+ frame_url,
+ extension->allowed_to_execute_script_everywhere(),
+ NULL,
+ script,
+ NULL)) {
+ continue;
+ }
if (frame_url.SchemeIsFile() && !script->allow_file_access())
continue; // This script isn't allowed to run on file URLs.
diff --git a/chrome/test/data/extensions/api_test/all_urls/content_script/background.html b/chrome/test/data/extensions/api_test/all_urls/content_script/background.html
new file mode 100644
index 0000000..91c527d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/content_script/background.html
@@ -0,0 +1,17 @@
+<!--
+ * Copyright (c) 2010 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.
+-->
+<html>
+<head>
+<script>
+chrome.extension.onRequest.addListener(
+ function(request, sender, sendResponse) {
+ // Let the extension know where the script ran.
+ var url = sender.tab ? sender.tab.url : 'about:blank';
+ chrome.test.sendMessage('content script: ' + url);
+ });
+</script>
+</head>
+</html>
diff --git a/chrome/test/data/extensions/api_test/all_urls/content_script/content_script.js b/chrome/test/data/extensions/api_test/all_urls/content_script/content_script.js
new file mode 100644
index 0000000..2f7a3f5
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/content_script/content_script.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+// Let the background page know this content script executed.
+chrome.extension.sendRequest({greeting: "hello"}, function(response) {
+ console.log(response.farewell);
+});
diff --git a/chrome/test/data/extensions/api_test/all_urls/content_script/manifest.json b/chrome/test/data/extensions/api_test/all_urls/content_script/manifest.json
new file mode 100644
index 0000000..922c40d
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/content_script/manifest.json
@@ -0,0 +1,10 @@
+{
+ "background_page": "background.html",
+ "content_scripts": [ {
+ "js": [ "content_script.js" ],
+ "matches": [ "<all_urls>" ]
+ } ],
+ "description": "Test whether whitelisted extensions can run scripts everywhere using content script",
+ "name": "AllUrls content script permissions",
+ "version": "1.0"
+}
diff --git a/chrome/test/data/extensions/api_test/all_urls/execute_script/background.html b/chrome/test/data/extensions/api_test/all_urls/execute_script/background.html
new file mode 100644
index 0000000..fe10b9c
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/execute_script/background.html
@@ -0,0 +1,21 @@
+<!--
+ * Copyright (c) 2010 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.
+-->
+<html>
+<head>
+<script>
+chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
+ chrome.tabs.executeScript(tabId, {file: "execute_script.js"})
+});
+
+chrome.extension.onRequest.addListener(
+ function(request, sender, sendResponse) {
+ // Let the extension know where the script ran.
+ var url = sender.tab ? sender.tab.url : 'about:blank';
+ chrome.test.sendMessage('execute: ' + url);
+ });
+</script>
+</head>
+</html>
diff --git a/chrome/test/data/extensions/api_test/all_urls/execute_script/execute_script.js b/chrome/test/data/extensions/api_test/all_urls/execute_script/execute_script.js
new file mode 100644
index 0000000..2f7a3f5
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/execute_script/execute_script.js
@@ -0,0 +1,10 @@
+/*
+ * Copyright (c) 2010 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.
+ */
+
+// Let the background page know this content script executed.
+chrome.extension.sendRequest({greeting: "hello"}, function(response) {
+ console.log(response.farewell);
+});
diff --git a/chrome/test/data/extensions/api_test/all_urls/execute_script/manifest.json b/chrome/test/data/extensions/api_test/all_urls/execute_script/manifest.json
new file mode 100644
index 0000000..aa6f8ed4
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/execute_script/manifest.json
@@ -0,0 +1,7 @@
+{
+ "background_page": "background.html",
+ "description": "Test whether whitelisted extensions can run scripts everywhere using executeScript",
+ "name": "AllUrls execute permissions",
+ "permissions": [ "tabs", "<all_urls>" ],
+ "version": "1.0"
+}
diff --git a/chrome/test/data/extensions/api_test/all_urls/index.html b/chrome/test/data/extensions/api_test/all_urls/index.html
new file mode 100644
index 0000000..5e1bd81
--- /dev/null
+++ b/chrome/test/data/extensions/api_test/all_urls/index.html
@@ -0,0 +1 @@
+<html>This page only serves as a target for scripting.</html> \ No newline at end of file