diff options
author | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-03 09:03:41 +0000 |
---|---|---|
committer | finnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-03 09:03:41 +0000 |
commit | 56585ef925940e248319b9d6098ae64011e4abea (patch) | |
tree | 63c0041c16603f7fbb9fd0d64440a809e9c19327 /chrome | |
parent | 6abefa7f2d50f1d55c93a0d0b4b5a7cc4ec1507f (diff) | |
download | chromium_src-56585ef925940e248319b9d6098ae64011e4abea.zip chromium_src-56585ef925940e248319b9d6098ae64011e4abea.tar.gz chromium_src-56585ef925940e248319b9d6098ae64011e4abea.tar.bz2 |
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
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61323 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
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 |