diff options
24 files changed, 206 insertions, 34 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 7aebf70..b72ba48 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -3547,6 +3547,9 @@ each locale. --> <message name="IDS_EXTENSIONS_ENABLE_INCOGNITO" desc="The checkbox for enabling extensions in incognito."> Allow in incognito </message> + <message name="IDS_EXTENSIONS_ALLOW_FILE_ACCESS" desc="The checkbox for allowing an extension access to run scripts on file URLs."> + Allow access to file URLs + </message> <message name="IDS_EXTENSIONS_INCOGNITO_WARNING" desc="Warns the user that Chrome cannot prevent extensions from recording history in incognito mode. Displayed in extensions management UI after an extension is selected to be run in incognito mode."> <ph name="BEGIN_BOLD"><b></ph>Warning:<ph name="END_BOLD"></b></ph> Google Chrome cannot prevent extensions from recording your browsing history. To disable this extension in incognito mode, unselect this option. </message> diff --git a/chrome/browser/extensions/execute_code_in_tab_function.cc b/chrome/browser/extensions/execute_code_in_tab_function.cc index c391db8..44de6bf 100644 --- a/chrome/browser/extensions/execute_code_in_tab_function.cc +++ b/chrome/browser/extensions/execute_code_in_tab_function.cc @@ -9,6 +9,7 @@ #include "chrome/browser/browser.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" +#include "chrome/browser/extensions/extensions_service.h" #include "chrome/browser/extensions/file_reader.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/extensions/extension.h" @@ -66,7 +67,8 @@ 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 (!GetExtension()->CanExecuteScriptOnHost(contents->GetURL(), &error_)) + if (!profile()->GetExtensionsService()->CanExecuteScriptOnHost( + GetExtension(), contents->GetURL(), &error_)) return false; if (script_info->HasKey(keys::kAllFramesKey)) { diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc index e73b2f6..0f9661c 100644 --- a/chrome/browser/extensions/extension_prefs.cc +++ b/chrome/browser/extensions/extension_prefs.cc @@ -67,6 +67,10 @@ const wchar_t kIdleInstallInfoFetchTime[] = L"fetch_time"; // A preference that, if true, will allow this extension to run in incognito // mode. const wchar_t kPrefIncognitoEnabled[] = L"incognito"; + +// A preference to control whether an extension is allowed to inject script in +// pages with file URLs. +const wchar_t kPrefAllowFileAccess[] = L"allowFileAccess"; } //////////////////////////////////////////////////////////////////////////////// @@ -352,6 +356,17 @@ void ExtensionPrefs::SetIsIncognitoEnabled(const std::string& extension_id, prefs_->SavePersistentPrefs(); } +bool ExtensionPrefs::AllowFileAccess(const std::string& extension_id) { + return ReadExtensionPrefBoolean(extension_id, kPrefAllowFileAccess); +} + +void ExtensionPrefs::SetAllowFileAccess(const std::string& extension_id, + bool allow) { + UpdateExtensionPref(extension_id, kPrefAllowFileAccess, + Value::CreateBooleanValue(allow)); + prefs_->SavePersistentPrefs(); +} + void ExtensionPrefs::GetKilledExtensionIds(std::set<std::string>* killed_ids) { const DictionaryValue* dict = prefs_->GetDictionary(kExtensionsPref); if (!dict || dict->empty()) diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h index 3f352e7ad..77487e9 100644 --- a/chrome/browser/extensions/extension_prefs.h +++ b/chrome/browser/extensions/extension_prefs.h @@ -105,6 +105,11 @@ class ExtensionPrefs { bool IsIncognitoEnabled(const std::string& extension_id); void SetIsIncognitoEnabled(const std::string& extension_id, bool enabled); + // Returns true if the user has chosen to allow this extension to inject + // scripts into pages with file URLs. + bool AllowFileAccess(const std::string& extension_id); + void SetAllowFileAccess(const std::string& extension_id, bool allow); + // Saves ExtensionInfo for each installed extension with the path to the // version directory and the location. Blacklisted extensions won't be saved // and neither will external extensions the user has explicitly uninstalled. diff --git a/chrome/browser/extensions/extension_startup_browsertest.cc b/chrome/browser/extensions/extension_startup_browsertest.cc index ed62a40..7566caa 100644 --- a/chrome/browser/extensions/extension_startup_browsertest.cc +++ b/chrome/browser/extensions/extension_startup_browsertest.cc @@ -63,6 +63,7 @@ class ExtensionStartupTestBase : public InProcessBrowserTest { if (!load_extension_.value().empty()) { command_line->AppendSwitchWithValue(switches::kLoadExtension, load_extension_.ToWStringHack()); + command_line->AppendSwitch(switches::kDisableExtensionsFileAccessCheck); } } @@ -143,6 +144,23 @@ IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, Test) { TestInjection(true, true); } +// Tests that disallowing file access on an extension prevents it from injecting +// script into a page with a file URL. +IN_PROC_BROWSER_TEST_F(ExtensionsStartupTest, NoFileAccess) { + WaitForServicesToStart(4, true); // 1 component extension and 3 others. + + ExtensionsService* service = browser()->profile()->GetExtensionsService(); + for (size_t i = 0; i < service->extensions()->size(); ++i) { + if (service->AllowFileAccess(service->extensions()->at(i))) { + service->SetAllowFileAccess(service->extensions()->at(i), false); + ui_test_utils::WaitForNotification( + NotificationType::USER_SCRIPTS_UPDATED); + } + } + + TestInjection(false, false); +} + // ExtensionsLoadTest // Ensures that we can startup the browser with --load-extension and see them // run. diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc index 71a8753..0f58360 100644 --- a/chrome/browser/extensions/extension_tabs_module.cc +++ b/chrome/browser/extensions/extension_tabs_module.cc @@ -646,7 +646,8 @@ 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 (!GetExtension()->CanExecuteScriptOnHost(contents->GetURL(), &error_)) + if (!profile()->GetExtensionsService()->CanExecuteScriptOnHost( + GetExtension(), contents->GetURL(), &error_)) return false; // TODO(aa): How does controller queue URLs? Is there any chance that this diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc index 99dcd9c..02a7366 100644 --- a/chrome/browser/extensions/extensions_service.cc +++ b/chrome/browser/extensions/extensions_service.cc @@ -38,6 +38,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_constants.h" +#include "chrome/common/extensions/extension_error_utils.h" #include "chrome/common/extensions/extension_file_util.h" #include "chrome/common/extensions/extension_l10n_util.h" #include "chrome/common/notification_service.h" @@ -675,6 +676,42 @@ void ExtensionsService::SetIsIncognitoEnabled(Extension* extension, NotifyExtensionLoaded(extension); } +bool ExtensionsService::AllowFileAccess(const Extension* extension) { + return (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableExtensionsFileAccessCheck) || + extension_prefs_->AllowFileAccess(extension->id())); +} + +void ExtensionsService::SetAllowFileAccess(Extension* extension, bool allow) { + extension_prefs_->SetAllowFileAccess(extension->id(), allow); + NotificationService::current()->Notify( + NotificationType::EXTENSION_USER_SCRIPTS_UPDATED, + Source<Profile>(profile_), + 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()) { + 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 c7e0609..07bfa8b 100644 --- a/chrome/browser/extensions/extensions_service.h +++ b/chrome/browser/extensions/extensions_service.h @@ -155,6 +155,17 @@ class ExtensionsService bool IsIncognitoEnabled(const Extension* extension); void SetIsIncognitoEnabled(Extension* extension, bool enabled); + // Whether this extension can inject scripts into pages with file URLs. + 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/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc index 9ad2e78..84a6f33c 100644 --- a/chrome/browser/extensions/extensions_ui.cc +++ b/chrome/browser/extensions/extensions_ui.cc @@ -125,6 +125,8 @@ void ExtensionsUIHTMLSource::StartDataRequest(const std::string& path, l10n_util::GetString(IDS_EXTENSIONS_ENABLE)); localized_strings.SetString(L"enableIncognito", l10n_util::GetString(IDS_EXTENSIONS_ENABLE_INCOGNITO)); + localized_strings.SetString(L"allowFileAccess", + l10n_util::GetString(IDS_EXTENSIONS_ALLOW_FILE_ACCESS)); localized_strings.SetString(L"incognitoWarning", l10n_util::GetString(IDS_EXTENSIONS_INCOGNITO_WARNING)); localized_strings.SetString(L"reload", @@ -282,6 +284,8 @@ void ExtensionsDOMHandler::RegisterMessages() { NewCallback(this, &ExtensionsDOMHandler::HandleEnableMessage)); dom_ui_->RegisterMessageCallback("enableIncognito", NewCallback(this, &ExtensionsDOMHandler::HandleEnableIncognitoMessage)); + dom_ui_->RegisterMessageCallback("allowFileAccess", + NewCallback(this, &ExtensionsDOMHandler::HandleAllowFileAccessMessage)); dom_ui_->RegisterMessageCallback("uninstall", NewCallback(this, &ExtensionsDOMHandler::HandleUninstallMessage)); dom_ui_->RegisterMessageCallback("options", @@ -493,6 +497,20 @@ void ExtensionsDOMHandler::HandleEnableIncognitoMessage(const Value* value) { ignore_notifications_ = false; } +void ExtensionsDOMHandler::HandleAllowFileAccessMessage(const Value* value) { + CHECK(value->IsType(Value::TYPE_LIST)); + const ListValue* list = static_cast<const ListValue*>(value); + CHECK(list->GetSize() == 2); + std::string extension_id, allow_str; + CHECK(list->GetString(0, &extension_id)); + CHECK(list->GetString(1, &allow_str)); + Extension* extension = extensions_service_->GetExtensionById(extension_id, + true); + DCHECK(extension); + + extensions_service_->SetAllowFileAccess(extension, allow_str == "true"); +} + void ExtensionsDOMHandler::HandleUninstallMessage(const Value* value) { CHECK(value->IsType(Value::TYPE_LIST)); const ListValue* list = static_cast<const ListValue*>(value); @@ -767,9 +785,23 @@ DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue( return script_data; } +static bool ExtensionWantsFileAccess(const Extension* extension) { + for (UserScriptList::const_iterator it = extension->content_scripts().begin(); + it != extension->content_scripts().end(); ++it) { + for (UserScript::PatternList::const_iterator pattern = + it->url_patterns().begin(); + pattern != it->url_patterns().end(); ++pattern) { + if (pattern->scheme() == chrome::kFileScheme) + return true; + } + } + + return false; +} + // Static DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue( - ExtensionsService* service, const Extension *extension, + ExtensionsService* service, const Extension* extension, const std::vector<ExtensionPage>& pages, bool enabled) { DictionaryValue* extension_data = new DictionaryValue(); @@ -780,6 +812,10 @@ DictionaryValue* ExtensionsDOMHandler::CreateExtensionDetailValue( extension_data->SetBoolean(L"enabled", enabled); extension_data->SetBoolean(L"enabledIncognito", service ? service->IsIncognitoEnabled(extension) : false); + extension_data->SetBoolean(L"wantsFileAccess", + ExtensionWantsFileAccess(extension)); + extension_data->SetBoolean(L"allowFileAccess", + service ? service->AllowFileAccess(extension) : false); extension_data->SetBoolean(L"allow_reload", extension->location() == Extension::LOAD); diff --git a/chrome/browser/extensions/extensions_ui.h b/chrome/browser/extensions/extensions_ui.h index e85e586..120f08a 100644 --- a/chrome/browser/extensions/extensions_ui.h +++ b/chrome/browser/extensions/extensions_ui.h @@ -149,6 +149,9 @@ class ExtensionsDOMHandler // Callback for "enableIncognito" message. void HandleEnableIncognitoMessage(const Value* value); + // Callback for "allowFileAcces" message. + void HandleAllowFileAccessMessage(const Value* value); + // Callback for "uninstall" message. void HandleUninstallMessage(const Value* value); diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc index 608f9db..c651c2e 100644 --- a/chrome/browser/extensions/user_script_master.cc +++ b/chrome/browser/extensions/user_script_master.cc @@ -306,6 +306,8 @@ UserScriptMaster::UserScriptMaster(const FilePath& script_dir, Profile* profile) Source<Profile>(profile_)); registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, Source<Profile>(profile_)); + registrar_.Add(this, NotificationType::EXTENSION_USER_SCRIPTS_UPDATED, + Source<Profile>(profile_)); } UserScriptMaster::~UserScriptMaster() { @@ -348,11 +350,14 @@ void UserScriptMaster::Observe(NotificationType type, Extension* extension = Details<Extension>(details).ptr(); bool incognito_enabled = profile_->GetExtensionsService()-> IsIncognitoEnabled(extension); + bool allow_file_access = profile_->GetExtensionsService()-> + AllowFileAccess(extension); const UserScriptList& scripts = extension->content_scripts(); for (UserScriptList::const_iterator iter = scripts.begin(); iter != scripts.end(); ++iter) { lone_scripts_.push_back(*iter); lone_scripts_.back().set_incognito_enabled(incognito_enabled); + lone_scripts_.back().set_allow_file_access(allow_file_access); } if (extensions_service_ready_) StartScan(); @@ -375,6 +380,23 @@ void UserScriptMaster::Observe(NotificationType type, break; } + case NotificationType::EXTENSION_USER_SCRIPTS_UPDATED: { + Extension* extension = Details<Extension>(details).ptr(); + UserScriptList new_lone_scripts; + bool incognito_enabled = profile_->GetExtensionsService()-> + IsIncognitoEnabled(extension); + bool allow_file_access = profile_->GetExtensionsService()-> + AllowFileAccess(extension); + for (UserScriptList::iterator iter = lone_scripts_.begin(); + iter != lone_scripts_.end(); ++iter) { + if (iter->extension_id() == extension->id()) { + iter->set_incognito_enabled(incognito_enabled); + iter->set_allow_file_access(allow_file_access); + } + } + StartScan(); + break; + } default: DCHECK(false); diff --git a/chrome/browser/resources/extensions_ui.html b/chrome/browser/resources/extensions_ui.html index 3ae9d1e..1db6d5a 100644 --- a/chrome/browser/resources/extensions_ui.html +++ b/chrome/browser/resources/extensions_ui.html @@ -352,6 +352,8 @@ var extensionDataFormat = { 'version': '1.0.231', 'enabled': 'true', 'enabledIncognito': 'false', + 'wantsFileAccess': 'false', + 'allowFileAccess': 'false', 'allow_reload': true, 'order': 1, 'options_url': 'options.html', @@ -392,6 +394,8 @@ var extensionDataFormat = { 'version': '1.0.231', 'enabled': 'true', 'enabledIncognito': 'false', + 'wantsFileAccess': 'false', + 'allowFileAccess': 'false', 'allow_reload': false, 'order': 2, 'icon': '', @@ -580,10 +584,16 @@ function handleToggleExtensionIncognito(node) { } /** + * Handles the 'allowFileAccess' checkbox getting changed. + */ +function handleToggleAllowFileAccess(node) { + chrome.send('allowFileAccess', [node.extensionId, String(node.checked)]); +} + +/** * Handles an 'uninstall' button getting clicked. */ function handleUninstallExtension(node) { - // Tell the C++ ExtensionDOMHandler to uninstall an extension. chrome.send('uninstall', [node.extensionId]); } @@ -882,14 +892,21 @@ document.addEventListener('DOMContentLoaded', requestExtensionsData); i18n-content="options" >OPTIONS</a> <label - jsdisplay="enabled" - onclick="handleToggleExtensionIncognito(this.getElementsByTagName('input')[0])"> + jsdisplay="enabled"> <input type="checkbox" jsvalues=".extensionId:id;.enabled:enabled" jsdisplay="enabled" jseval="this.checked = enabledIncognito" onchange="handleToggleExtensionIncognito(this)"> <span i18n-content="enableIncognito">ALLOW THIS EXTENSION TO RUN IN INCOGNITO</span></label> + <label + jsdisplay="enabled && wantsFileAccess"> + <input type="checkbox" + jsvalues=".extensionId:id;.enabled:enabled;.wantsFileAccess:wantsFileAccess" + jsdisplay="enabled && wantsFileAccess" + jseval="this.checked = allowFileAccess" + onchange="handleToggleAllowFileAccess(this)"> + <span i18n-content="allowFileAccess">ALLOW THIS EXTENSION ACCESS TO FILE URLS</span></label> </span> </div> <div class="incognitoWarning"> diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index 9852c97..c6bb2fe 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -136,6 +136,11 @@ const char kDisableDevTools[] = "disable-dev-tools"; // Disable extensions. const char kDisableExtensions[] = "disable-extensions"; +// Disable checking for user opt-in for extensions that want to inject script +// into file URLs (ie, always allow it). This is used during automated testing. +const char kDisableExtensionsFileAccessCheck[] = + "disable-extensions-file-access-check"; + // Suppresses support for the Geolocation javascript API. const char kDisableGeolocation[] = "disable-geolocation"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 80df849..6aa3b40 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -53,6 +53,7 @@ extern const char kDisableDatabases[]; extern const char kDisableDesktopNotifications[]; extern const char kDisableDevTools[]; extern const char kDisableExtensions[]; +extern const char kDisableExtensionsFileAccessCheck[]; extern const char kDisableGeolocation[]; extern const char kDisableHangMonitor[]; extern const char kDisableInternalFlash[]; diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc index 1460ac5..47216fc 100644 --- a/chrome/common/extensions/extension.cc +++ b/chrome/common/extensions/extension.cc @@ -1654,27 +1654,6 @@ bool Extension::HasHostPermission(const GURL& url) const { return false; } -bool Extension::CanExecuteScriptOnHost(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(ChromeStoreURL()).host()) { - if (error) - *error = errors::kCannotScriptGallery; - return false; - } - - if (HasHostPermission(url)) - return true; - - if (error) { - *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage, - url.spec()); - } - - return false; -} - const std::set<std::string> Extension::GetEffectiveHostPermissions() const { std::set<std::string> effective_hosts; diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h index d0642dc..1af1d23 100644 --- a/chrome/common/extensions/extension.h +++ b/chrome/common/extensions/extension.h @@ -253,12 +253,6 @@ class Extension { return host_permissions_; } - // 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(const GURL& url, std::string* error) const; - // Returns true if the extension has the specified API permission. bool HasApiPermission(const std::string& permission) const { return std::find(api_permissions_.begin(), api_permissions_.end(), diff --git a/chrome/common/extensions/user_script.cc b/chrome/common/extensions/user_script.cc index 5ed2040..b55a10c 100644 --- a/chrome/common/extensions/user_script.cc +++ b/chrome/common/extensions/user_script.cc @@ -81,6 +81,7 @@ void UserScript::Pickle(::Pickle* pickle) const { pickle->WriteBool(emulate_greasemonkey()); pickle->WriteBool(match_all_frames()); pickle->WriteBool(is_incognito_enabled()); + pickle->WriteBool(allow_file_access()); // Write globs. std::vector<std::string>::const_iterator glob; @@ -126,6 +127,7 @@ void UserScript::Unpickle(const ::Pickle& pickle, void** iter) { CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_)); CHECK(pickle.ReadBool(iter, &match_all_frames_)); CHECK(pickle.ReadBool(iter, &incognito_enabled_)); + CHECK(pickle.ReadBool(iter, &allow_file_access_)); // Read globs. size_t num_globs = 0; diff --git a/chrome/common/extensions/user_script.h b/chrome/common/extensions/user_script.h index 6bf30ee..ac8f836 100644 --- a/chrome/common/extensions/user_script.h +++ b/chrome/common/extensions/user_script.h @@ -102,7 +102,8 @@ class UserScript { // Greasemonkey and probably more useful for typical scripts. UserScript() : run_location_(DOCUMENT_IDLE), emulate_greasemonkey_(false), - match_all_frames_(false), incognito_enabled_(false) { + match_all_frames_(false), incognito_enabled_(false), + allow_file_access_(false) { } const std::string& name_space() const { return name_space_; } @@ -170,6 +171,9 @@ class UserScript { bool is_incognito_enabled() const { return incognito_enabled_; } void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; } + bool allow_file_access() const { return allow_file_access_; } + void set_allow_file_access(bool allowed) { allow_file_access_ = allowed; } + bool is_standalone() const { return extension_id_.empty(); } // Returns true if the script should be applied to the specified URL, false @@ -232,6 +236,9 @@ class UserScript { // True if the script should be injected into an incognito tab. bool incognito_enabled_; + + // True if the user agreed to allow this script access to file URLs. + bool allow_file_access_; }; typedef std::vector<UserScript> UserScriptList; diff --git a/chrome/common/notification_type.h b/chrome/common/notification_type.h index 464f629..3c96a1a 100644 --- a/chrome/common/notification_type.h +++ b/chrome/common/notification_type.h @@ -787,6 +787,10 @@ class NotificationType { // Same as above, but for a disabled extension. EXTENSION_UNLOADED_DISABLED, + // Sent when an extension has updated its user scripts. The details are an + // Extension, and the source is a Profile. + EXTENSION_USER_SCRIPTS_UPDATED, + // Sent after a new ExtensionFunctionDispatcher is created. The details are // an ExtensionFunctionDispatcher* and the source is a Profile*. This is // similar in timing to EXTENSION_HOST_CREATED, but also fires when an diff --git a/chrome/renderer/user_script_slave.cc b/chrome/renderer/user_script_slave.cc index 11ad1f2..c5812ad 100644 --- a/chrome/renderer/user_script_slave.cc +++ b/chrome/renderer/user_script_slave.cc @@ -167,6 +167,9 @@ bool UserScriptSlave::InjectScripts(WebFrame* frame, if (!script->MatchesUrl(frame->url())) continue; // This frame doesn't match the script url pattern, skip it. + if (frame_url.SchemeIsFile() && !script->allow_file_access()) + continue; // This script isn't allowed to run on file URLs. + // CSS files are always injected on document start before js scripts. if (location == UserScript::DOCUMENT_START) { num_css += script->css_scripts().size(); diff --git a/chrome/test/data/extensions/good/Preferences b/chrome/test/data/extensions/good/Preferences index 7aad8c2..6d5c369 100644 --- a/chrome/test/data/extensions/good/Preferences +++ b/chrome/test/data/extensions/good/Preferences @@ -5,6 +5,7 @@ "location": 1, "path": "behllobkkfkfnphdnhnkndlbkcpglgmj/1.0.0.0", "state": 1, + "allowFileAccess": true, "manifest": { "key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDuUZGKCDbff6IRaxa4Pue7PPkxwPaNhGT3JEqppEsNWFjM80imEdqMbf3lrWqEfaHgaNku7nlpwPO1mu3/4Hr+XdNa5MhfnOnuPee4hyTLwOs3Vzz81wpbdzUxZSi2OmqMyI5oTaBYICfNHLwcuc65N5dbt6WKGeKgTpp4v7j7zwIDAQAB", "version": "1.0.0.0", diff --git a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json index be1fbd2..6de443b 100644 --- a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json +++ b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension1.json @@ -8,6 +8,8 @@ "allow_reload": false, "order": 2, "enabledIncognito": false, + "wantsFileAccess": true, + "allowFileAccess": false, "content_scripts": [ { "matches": ["file://*", "http://*.google.com/*", "https://*.google.com/*"], diff --git a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json index 6b5f26f..cbbc5fc 100644 --- a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json +++ b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension2.json @@ -8,6 +8,8 @@ "allow_reload": false, "order": 2, "enabledIncognito": false, + "wantsFileAccess": false, + "allowFileAccess": false, "content_scripts": [], "views": [ { diff --git a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json index df765e2..aef2f0d 100644 --- a/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json +++ b/chrome/test/data/extensions/ui/create_extension_detail_value_expected_output/good-extension3.json @@ -8,6 +8,8 @@ "allow_reload": false, "order": 2, "enabledIncognito": false, + "wantsFileAccess": false, + "allowFileAccess": false, "content_scripts": [], "views": [], "hasPopupAction": false, |