diff options
Diffstat (limited to 'chrome/browser/extensions')
12 files changed, 696 insertions, 25 deletions
diff --git a/chrome/browser/extensions/active_tab_permission_manager.cc b/chrome/browser/extensions/active_tab_permission_manager.cc new file mode 100644 index 0000000..29d9311 --- /dev/null +++ b/chrome/browser/extensions/active_tab_permission_manager.cc @@ -0,0 +1,122 @@ +// Copyright (c) 2012 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/extensions/active_tab_permission_manager.h" + +#include "chrome/browser/extensions/extension_tab_helper.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/tab_contents/tab_contents.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_messages.h" +#include "chrome/common/extensions/extension_permission_set.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/web_contents.h" + +using content::RenderProcessHost; +using content::WebContentsObserver; + +namespace extensions { + +ActiveTabPermissionManager::ActiveTabPermissionManager( + TabContents* tab_contents) + : WebContentsObserver(tab_contents->web_contents()), + tab_contents_(tab_contents) { + InsertActiveURL(web_contents()->GetURL()); + registrar_.Add(this, + chrome::NOTIFICATION_EXTENSION_UNLOADED, + content::Source<Profile>(tab_contents->profile())); +} + +ActiveTabPermissionManager::~ActiveTabPermissionManager() {} + +void ActiveTabPermissionManager::GrantIfRequested(const Extension* extension) { + if (!extension->HasAPIPermission(ExtensionAPIPermission::kActiveTab)) + return; + + if (active_urls_.is_empty()) + return; + + // Only need to check the number of permissions here rather than the URLs + // themselves, because the set can only ever grow. + const URLPatternSet* old_permissions = + extension->GetTabSpecificHostPermissions(tab_id()); + if (old_permissions && (old_permissions->size() == active_urls_.size())) + return; + + granted_.Insert(extension); + extension->SetTabSpecificHostPermissions(tab_id(), active_urls_); + Send(new ExtensionMsg_UpdateTabSpecificPermissions(GetPageID(), + tab_id(), + extension->id(), + active_urls_)); +} + +void ActiveTabPermissionManager::DidCommitProvisionalLoadForFrame( + int64 frame_id, + bool is_main_frame, + const GURL& url, + content::PageTransition transition_type, + content::RenderViewHost* render_view_host) { + if (is_main_frame) + ClearActiveURLsAndNotify(); + InsertActiveURL(url); +} + +void ActiveTabPermissionManager::WebContentsDestroyed( + content::WebContents* web_contents) { + ClearActiveURLsAndNotify(); +} + +void ActiveTabPermissionManager::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK_EQ(type, chrome::NOTIFICATION_EXTENSION_UNLOADED); + const Extension* extension = + content::Details<UnloadedExtensionInfo>(details)->extension; + extension->ClearTabSpecificHostPermissions(tab_id()); + std::vector<std::string> single_id(1, extension->id()); + Send(new ExtensionMsg_ClearTabSpecificPermissions(tab_id(), single_id)); + granted_.Remove(extension->id()); +} + +void ActiveTabPermissionManager::ClearActiveURLsAndNotify() { + active_urls_.ClearPatterns(); + + if (granted_.is_empty()) + return; + + std::vector<std::string> extension_ids; + + for (ExtensionSet::const_iterator it = granted_.begin(); + it != granted_.end(); ++it) { + (*it)->ClearTabSpecificHostPermissions(tab_id()); + extension_ids.push_back((*it)->id()); + } + + Send(new ExtensionMsg_ClearTabSpecificPermissions(tab_id(), extension_ids)); + granted_.Clear(); +} + +void ActiveTabPermissionManager::InsertActiveURL(const GURL& url) { + URLPattern pattern(UserScript::kValidUserScriptSchemes); + if (pattern.Parse(url.spec()) == URLPattern::PARSE_SUCCESS) + active_urls_.AddPattern(pattern); +} + +int32 ActiveTabPermissionManager::tab_id() { + return tab_contents_->extension_tab_helper()->tab_id(); +} + +int32 ActiveTabPermissionManager::GetPageID() { + return tab_contents_->web_contents()->GetController().GetActiveEntry()-> + GetPageID(); +} + +} // namespace extensions diff --git a/chrome/browser/extensions/active_tab_permission_manager.h b/chrome/browser/extensions/active_tab_permission_manager.h new file mode 100644 index 0000000..1dffe55 --- /dev/null +++ b/chrome/browser/extensions/active_tab_permission_manager.h @@ -0,0 +1,93 @@ +// Copyright (c) 2012 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. + +#ifndef CHROME_BROWSER_EXTENSIONS_ACTIVE_TAB_PERMISSION_MANAGER_H_ +#define CHROME_BROWSER_EXTENSIONS_ACTIVE_TAB_PERMISSION_MANAGER_H_ +#pragma once + +#include <set> +#include <string> + +#include "chrome/common/extensions/extension_set.h" +#include "chrome/common/extensions/url_pattern_set.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents_observer.h" + +class TabContents; + +namespace extensions { + +class Extension; + +// Responsible for granting and revoking tab-specific permissions to extensions +// with the activeTab permission. +class ActiveTabPermissionManager : public content::WebContentsObserver, + public content::NotificationObserver { + public: + explicit ActiveTabPermissionManager(TabContents* tab_contents); + virtual ~ActiveTabPermissionManager(); + + // If |extension| has the activeTab permission, grants tab-specific + // permissions to it until the next page navigation or refresh. + void GrantIfRequested(const Extension* extension); + + // content::WebContentsObserver implementation. + // + // This is public to be called from ActiveTabTest as a way to fake creating + // frames on this tab. It's a bit fragile but there doesn't seem to be any + // other way to do it. + virtual void DidCommitProvisionalLoadForFrame( + int64 frame_id, + bool is_main_frame, + const GURL& url, + content::PageTransition transition_type, + content::RenderViewHost* render_view_host) OVERRIDE; + + private: + // More content::WebContentsObserver. + virtual void WebContentsDestroyed(content::WebContents* web_contents) + OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // Clears any granted tab-specific permissions for all extensions and + // notifies renderers. + void ClearActiveURLsAndNotify(); + + // Inserts a URL pattern giving access to the entire origin for |url|. + void InsertActiveURL(const GURL& url); + + // Gets the tab's id. + int tab_id(); + + // Gets the current page id. + int32 GetPageID(); + + // Our owning TabContents. + TabContents* tab_contents_; + + // The URLPatternSet for frames that are active on the current page. This is + // cleared on navigation. + // + // Note that concerned code probably only cares about the origins of these + // URLs, but let them deal with that. + URLPatternSet active_urls_; + + // Extensions with the activeTab permission that have been granted + // tab-specific permissions until the next navigation/refresh. + ExtensionSet granted_; + + // Listen to extension unloaded notifications. + content::NotificationRegistrar registrar_; + + DISALLOW_COPY_AND_ASSIGN(ActiveTabPermissionManager); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_ACTIVE_TAB_PERMISSION_MANAGER_H_ diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc new file mode 100644 index 0000000..881829ce --- /dev/null +++ b/chrome/browser/extensions/active_tab_unittest.cc @@ -0,0 +1,424 @@ +// Copyright (c) 2012 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 <string> + +#include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/values.h" +#include "chrome/browser/extensions/active_tab_permission_manager.h" +#include "chrome/browser/extensions/extension_tab_helper.h" +#include "chrome/browser/ui/tab_contents/tab_contents.h" +#include "chrome/browser/ui/tab_contents/test_tab_contents.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/extensions/extension.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/page_transition_types.h" +#include "content/public/test/test_browser_thread.h" + +using base::DictionaryValue; +using base::ListValue; +using content::BrowserThread; +using content::NavigationController; + +namespace extensions { +namespace { + +scoped_refptr<const Extension> CreateTestExtension( + const std::string& name, + bool has_active_tab_permission) { + DictionaryValue manifest; + manifest.SetString("name", name); + manifest.SetString("version", "1.0.0"); + manifest.SetInteger("manifest_version", 2); + + if (has_active_tab_permission) { + scoped_ptr<ListValue> permissions(new ListValue()); + permissions->Append(Value::CreateStringValue("activeTab")); + manifest.Set("permissions", permissions.release()); + } + + std::string error; + scoped_refptr<const Extension> extension = Extension::Create( + FilePath(), + Extension::INTERNAL, + manifest, + 0, // no flags. + name, + &error); + CHECK_EQ("", error); + return extension; +} + +class ActiveTabTest : public TabContentsTestHarness { + public: + ActiveTabTest() + : extension(CreateTestExtension("extension", true)), + another_extension(CreateTestExtension("another", true)), + extension_without_active_tab( + CreateTestExtension("without activeTab", false)), + ui_thread_(BrowserThread::UI, MessageLoop::current()) {} + + protected: + int tab_id() { + return tab_contents()->extension_tab_helper()->tab_id(); + } + + ActiveTabPermissionManager* active_tab_permission_manager() { + return tab_contents()->extension_tab_helper()-> + active_tab_permission_manager(); + } + + bool IsAllowed(const scoped_refptr<const Extension>& extension, + const GURL& url) { + return IsAllowed(extension, url, tab_id()); + } + + bool IsAllowed(const scoped_refptr<const Extension>& extension, + const GURL& url, + int tab_id) { + return (extension->CanExecuteScriptOnPage(url, tab_id, NULL, NULL) && + extension->CanCaptureVisiblePage(url, tab_id, NULL)); + } + + bool IsBlocked(const scoped_refptr<const Extension>& extension, + const GURL& url) { + return IsBlocked(extension, url, tab_id()); + } + + bool IsBlocked(const scoped_refptr<const Extension>& extension, + const GURL& url, + int tab_id) { + return (!extension->CanExecuteScriptOnPage(url, tab_id, NULL, NULL) && + !extension->CanCaptureVisiblePage(url, tab_id, NULL)); + } + + // Fakes loading a new frame on the page using the WebContentsObserver + // interface. + // TODO(kalman): if somebody can tell me a way to do this from the + // TabContentsTestHarness (or any other test harness) then pray tell. + void AddFrame(const GURL& url) { + active_tab_permission_manager()->DidCommitProvisionalLoadForFrame( + 0, // frame_id + false, // is_main_frame + url, + content::PAGE_TRANSITION_AUTO_SUBFRAME, + NULL); // render_view_host + } + + // An extension with the activeTab permission. + scoped_refptr<const Extension> extension; + + // Another extension with activeTab (for good measure). + scoped_refptr<const Extension> another_extension; + + // An extension without the activeTab permission. + scoped_refptr<const Extension> extension_without_active_tab; + + private: + content::TestBrowserThread ui_thread_; +}; + +TEST_F(ActiveTabTest, GrantToSinglePage) { + GURL google("http://www.google.com"); + NavigateAndCommit(google); + + // No access unless it's been granted. + EXPECT_TRUE(IsBlocked(extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested( + extension_without_active_tab); + + // Granted to extension and extension_without_active_tab, but the latter + // doesn't have the activeTab permission so not granted. + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + // Other subdomains shouldn't be given access. + GURL mail_google("http://mail.google.com"); + EXPECT_TRUE(IsBlocked(extension, mail_google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + // Reloading the page should clear the active permissions. + Reload(); + + EXPECT_TRUE(IsBlocked(extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + // But they should still be able to be granted again. + active_tab_permission_manager()->GrantIfRequested(extension); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + // And grant a few more times redundantly for good measure. + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsAllowed(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + // Navigating to a new URL should clear the active permissions. + GURL chromium("http://www.chromium.org"); + NavigateAndCommit(chromium); + + EXPECT_TRUE(IsBlocked(extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + EXPECT_TRUE(IsBlocked(extension, chromium)); + EXPECT_TRUE(IsBlocked(another_extension, chromium)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium)); + + // Should be able to grant to multiple extensions at the same time (if they + // have the activeTab permission, of course). + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + active_tab_permission_manager()->GrantIfRequested( + extension_without_active_tab); + + EXPECT_TRUE(IsBlocked(extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + EXPECT_TRUE(IsAllowed(extension, chromium)); + EXPECT_TRUE(IsAllowed(another_extension, chromium)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium)); + + // Should be able to go back to URLs that were previously cleared. + NavigateAndCommit(google); + + active_tab_permission_manager()->GrantIfRequested(extension); + active_tab_permission_manager()->GrantIfRequested(another_extension); + active_tab_permission_manager()->GrantIfRequested( + extension_without_active_tab); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsAllowed(another_extension, google)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, google)); + + EXPECT_TRUE(IsBlocked(extension, chromium)); + EXPECT_TRUE(IsBlocked(another_extension, chromium)); + EXPECT_TRUE(IsBlocked(extension_without_active_tab, chromium)); +}; + +TEST_F(ActiveTabTest, GrantToMultiplePages) { + GURL google("http://www.google.com"); + NavigateAndCommit(google); + + active_tab_permission_manager()->GrantIfRequested(extension); + + // Adding a frame after access was granted shouldn't give it access. + GURL chromium("http://www.chromium.org"); + AddFrame(chromium); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsBlocked(extension, chromium)); + + // Granting access to another extension should give it access to both the + // main and sub-frames, but still not to the first extension. + active_tab_permission_manager()->GrantIfRequested(another_extension); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsBlocked(extension, chromium)); + EXPECT_TRUE(IsAllowed(another_extension, google)); + EXPECT_TRUE(IsAllowed(another_extension, chromium)); + + // Granting access to the first extension should now give it access to the + // frame. + active_tab_permission_manager()->GrantIfRequested(extension); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsAllowed(extension, chromium)); + EXPECT_TRUE(IsAllowed(another_extension, google)); + EXPECT_TRUE(IsAllowed(another_extension, chromium)); + + // Reloading should clear all access. + Reload(); + + EXPECT_TRUE(IsBlocked(extension, google)); + EXPECT_TRUE(IsBlocked(extension, chromium)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, chromium)); + + // And after granting, no access to the frames that were there. + active_tab_permission_manager()->GrantIfRequested(extension); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsBlocked(extension, chromium)); + EXPECT_TRUE(IsBlocked(another_extension, google)); + EXPECT_TRUE(IsBlocked(another_extension, chromium)); + + // Having lots of frames on the same page should behave as expected. + GURL chromium_index("http://www.chromium.org/index.html"); + GURL chromium_about("http://www.chromium.org/about.html"); + GURL chromium_blank("http://www.chromium.org/blank.html"); + GURL gmail("http://www.gmail.com"); + GURL mail_google("http://mail.google.com"); + GURL plus_google("http://plus.google.com"); + GURL codereview_appspot("http://codereview.appspot.com"); + GURL omahaproxy_appspot("http://omahaproxy.appspot.com"); + + AddFrame(chromium_index); + AddFrame(chromium_about); + AddFrame(gmail); + AddFrame(mail_google); + + EXPECT_TRUE(IsBlocked(extension, chromium_index)); + EXPECT_TRUE(IsBlocked(extension, chromium_about)); + EXPECT_TRUE(IsBlocked(extension, chromium_blank)); + EXPECT_TRUE(IsBlocked(extension, gmail)); + EXPECT_TRUE(IsBlocked(extension, mail_google)); + EXPECT_TRUE(IsBlocked(extension, plus_google)); + EXPECT_TRUE(IsBlocked(extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(extension, omahaproxy_appspot)); + + EXPECT_TRUE(IsBlocked(another_extension, chromium_index)); + EXPECT_TRUE(IsBlocked(another_extension, chromium_about)); + EXPECT_TRUE(IsBlocked(another_extension, chromium_blank)); + EXPECT_TRUE(IsBlocked(another_extension, gmail)); + EXPECT_TRUE(IsBlocked(another_extension, mail_google)); + EXPECT_TRUE(IsBlocked(another_extension, plus_google)); + EXPECT_TRUE(IsBlocked(another_extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(another_extension, omahaproxy_appspot)); + + active_tab_permission_manager()->GrantIfRequested(extension); + + AddFrame(chromium_blank); + AddFrame(plus_google); + AddFrame(codereview_appspot); + + EXPECT_TRUE(IsAllowed(extension, chromium_index)); + EXPECT_TRUE(IsAllowed(extension, chromium_about)); + // Even though chromium_blank hasn't been given granted, this will work + // because it's on the same origin as the other codereview URLs. + // because k$b + EXPECT_TRUE(IsAllowed(extension, chromium_blank)); + EXPECT_TRUE(IsAllowed(extension, gmail)); + EXPECT_TRUE(IsAllowed(extension, mail_google)); + EXPECT_TRUE(IsBlocked(extension, plus_google)); + EXPECT_TRUE(IsBlocked(extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(extension, omahaproxy_appspot)); + + EXPECT_TRUE(IsBlocked(another_extension, chromium_index)); + EXPECT_TRUE(IsBlocked(another_extension, chromium_about)); + EXPECT_TRUE(IsBlocked(another_extension, chromium_blank)); + EXPECT_TRUE(IsBlocked(another_extension, gmail)); + EXPECT_TRUE(IsBlocked(another_extension, mail_google)); + EXPECT_TRUE(IsBlocked(another_extension, plus_google)); + EXPECT_TRUE(IsBlocked(another_extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(another_extension, omahaproxy_appspot)); + + active_tab_permission_manager()->GrantIfRequested(another_extension); + + AddFrame(omahaproxy_appspot); + + EXPECT_TRUE(IsAllowed(extension, chromium_index)); + EXPECT_TRUE(IsAllowed(extension, chromium_about)); + EXPECT_TRUE(IsAllowed(extension, chromium_blank)); + EXPECT_TRUE(IsAllowed(extension, gmail)); + EXPECT_TRUE(IsAllowed(extension, mail_google)); + EXPECT_TRUE(IsBlocked(extension, plus_google)); + EXPECT_TRUE(IsBlocked(extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(extension, omahaproxy_appspot)); + + EXPECT_TRUE(IsAllowed(another_extension, chromium_index)); + EXPECT_TRUE(IsAllowed(another_extension, chromium_about)); + EXPECT_TRUE(IsAllowed(another_extension, chromium_blank)); + EXPECT_TRUE(IsAllowed(another_extension, gmail)); + EXPECT_TRUE(IsAllowed(another_extension, mail_google)); + EXPECT_TRUE(IsAllowed(another_extension, plus_google)); + EXPECT_TRUE(IsAllowed(another_extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(another_extension, omahaproxy_appspot)); + + active_tab_permission_manager()->GrantIfRequested(extension); + + EXPECT_TRUE(IsAllowed(extension, chromium_index)); + EXPECT_TRUE(IsAllowed(extension, chromium_about)); + EXPECT_TRUE(IsAllowed(extension, chromium_blank)); + EXPECT_TRUE(IsAllowed(extension, gmail)); + EXPECT_TRUE(IsAllowed(extension, mail_google)); + EXPECT_TRUE(IsAllowed(extension, plus_google)); + EXPECT_TRUE(IsAllowed(extension, codereview_appspot)); + EXPECT_TRUE(IsAllowed(extension, omahaproxy_appspot)); + + EXPECT_TRUE(IsAllowed(another_extension, chromium_index)); + EXPECT_TRUE(IsAllowed(another_extension, chromium_about)); + EXPECT_TRUE(IsAllowed(another_extension, chromium_blank)); + EXPECT_TRUE(IsAllowed(another_extension, gmail)); + EXPECT_TRUE(IsAllowed(another_extension, mail_google)); + EXPECT_TRUE(IsAllowed(another_extension, plus_google)); + EXPECT_TRUE(IsAllowed(another_extension, codereview_appspot)); + EXPECT_TRUE(IsBlocked(another_extension, omahaproxy_appspot)); +} + +TEST_F(ActiveTabTest, Uninstalling) { + // Some semi-arbitrary setup. + GURL google("http://www.google.com"); + NavigateAndCommit(google); + + GURL chromium("http://www.chromium.org"); + AddFrame(chromium); + + active_tab_permission_manager()->GrantIfRequested(extension); + + GURL gmail("http://www.gmail.com"); + AddFrame(gmail); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsAllowed(extension, chromium)); + EXPECT_TRUE(IsBlocked(extension, gmail)); + + // Uninstalling the extension should clear its tab permissions. + UnloadedExtensionInfo details( + extension, + extension_misc::UNLOAD_REASON_DISABLE); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_EXTENSION_UNLOADED, + content::Source<Profile>(tab_contents()->profile()), + content::Details<UnloadedExtensionInfo>(&details)); + + EXPECT_TRUE(IsBlocked(extension, google)); + EXPECT_TRUE(IsBlocked(extension, chromium)); + EXPECT_TRUE(IsBlocked(extension, gmail)); + + // Granting the extension again should give them back. + active_tab_permission_manager()->GrantIfRequested(extension); + + EXPECT_TRUE(IsAllowed(extension, google)); + EXPECT_TRUE(IsAllowed(extension, chromium)); + EXPECT_TRUE(IsAllowed(extension, gmail)); +} + +TEST_F(ActiveTabTest, OnlyActiveTab) { + GURL google("http://www.google.com"); + NavigateAndCommit(google); + + active_tab_permission_manager()->GrantIfRequested(extension); + + EXPECT_TRUE(IsAllowed(extension, google, tab_id())); + EXPECT_TRUE(IsBlocked(extension, google, tab_id() + 1)); +} + +} // namespace +} // namespace extensions diff --git a/chrome/browser/extensions/api/offscreen_tabs/offscreen_tabs_api.cc b/chrome/browser/extensions/api/offscreen_tabs/offscreen_tabs_api.cc index a5e8c17..71b9fd9 100644 --- a/chrome/browser/extensions/api/offscreen_tabs/offscreen_tabs_api.cc +++ b/chrome/browser/extensions/api/offscreen_tabs/offscreen_tabs_api.cc @@ -801,7 +801,7 @@ bool UpdateOffscreenTabFunction::RunImpl() { tab_contents_ = offscreen_tab->tab_contents(); bool is_async = false; - if (!UpdateURLIfPresent(update_props, &is_async)) + if (!UpdateURLIfPresent(update_props, offscreen_tab_id, &is_async)) return false; // Update the width and height, if specified. diff --git a/chrome/browser/extensions/api/tabs/execute_code_in_tab_function.cc b/chrome/browser/extensions/api/tabs/execute_code_in_tab_function.cc index 9cd9c3f..cdcbd0d 100644 --- a/chrome/browser/extensions/api/tabs/execute_code_in_tab_function.cc +++ b/chrome/browser/extensions/api/tabs/execute_code_in_tab_function.cc @@ -90,7 +90,7 @@ bool ExecuteCodeInTabFunction::RunImpl() { CHECK(browser); CHECK(contents); if (!GetExtension()->CanExecuteScriptOnPage( - contents->web_contents()->GetURL(), NULL, &error_)) { + contents->web_contents()->GetURL(), execute_tab_id_, NULL, &error_)) { return false; } @@ -120,11 +120,8 @@ bool ExecuteCodeInTabFunction::RunImpl() { return false; } - if (!code_string.empty()) { - if (!Execute(code_string)) - return false; - return true; - } + if (!code_string.empty()) + return Execute(code_string); std::string relative_path; if (script_info->HasKey(keys::kFileKey)) { @@ -204,7 +201,8 @@ void ExecuteCodeInTabFunction::LocalizeCSS( void ExecuteCodeInTabFunction::DidLoadAndLocalizeFile(bool success, const std::string& data) { if (success) { - Execute(data); + if (!Execute(data)) + SendResponse(false); } else { #if defined(OS_POSIX) // TODO(viettrungluu): bug: there's no particular reason the path should be @@ -227,16 +225,12 @@ bool ExecuteCodeInTabFunction::Execute(const std::string& code_string) { execute_tab_id_, profile(), include_incognito(), &browser, NULL, &contents, NULL) && contents && browser; - if (!success) { - SendResponse(false); + if (!success) return false; - } const extensions::Extension* extension = GetExtension(); - if (!extension) { - SendResponse(false); + if (!extension) return false; - } ScriptExecutor::ScriptType script_type = ScriptExecutor::JAVASCRIPT; std::string function_name = name(); diff --git a/chrome/browser/extensions/api/tabs/tabs.cc b/chrome/browser/extensions/api/tabs/tabs.cc index 77eb4df..ec6e2de 100644 --- a/chrome/browser/extensions/api/tabs/tabs.cc +++ b/chrome/browser/extensions/api/tabs/tabs.cc @@ -1191,7 +1191,7 @@ bool UpdateTabFunction::RunImpl() { error_ = keys::kNoSelectedTabError; return false; } - tab_id = ExtensionTabUtil::GetTabId(contents->web_contents()); + tab_id = contents->extension_tab_helper()->tab_id(); } else { EXTENSION_FUNCTION_VALIDATE(tab_value->GetAsInteger(&tab_id)); } @@ -1211,7 +1211,7 @@ bool UpdateTabFunction::RunImpl() { // Navigate the tab to a new location if the url is different. bool is_async = false; - if (!UpdateURLIfPresent(update_props, &is_async)) + if (!UpdateURLIfPresent(update_props, tab_id, &is_async)) return false; bool active = false; @@ -1275,6 +1275,7 @@ bool UpdateTabFunction::RunImpl() { } bool UpdateTabFunction::UpdateURLIfPresent(DictionaryValue* update_props, + int tab_id, bool* is_async) { if (!update_props->HasKey(keys::kUrlKey)) return true; @@ -1301,7 +1302,7 @@ bool UpdateTabFunction::UpdateURLIfPresent(DictionaryValue* update_props, // we need to check host permissions before allowing them. if (url.SchemeIs(chrome::kJavaScriptScheme)) { if (!GetExtension()->CanExecuteScriptOnPage( - tab_contents_->web_contents()->GetURL(), NULL, &error_)) { + tab_contents_->web_contents()->GetURL(), tab_id, NULL, &error_)) { return false; } @@ -1614,8 +1615,12 @@ bool CaptureVisibleTabFunction::RunImpl() { // captureVisibleTab() can return an image containing sensitive information // that the browser would otherwise protect. Ensure the extension has // permission to do this. - if (!GetExtension()->CanCaptureVisiblePage(web_contents->GetURL(), &error_)) + if (!GetExtension()->CanCaptureVisiblePage( + web_contents->GetURL(), + tab_contents->extension_tab_helper()->tab_id(), + &error_)) { return false; + } RenderViewHost* render_view_host = web_contents->GetRenderViewHost(); content::RenderWidgetHostView* view = render_view_host->GetView(); diff --git a/chrome/browser/extensions/api/tabs/tabs.h b/chrome/browser/extensions/api/tabs/tabs.h index 0fe56f8..14276a0 100644 --- a/chrome/browser/extensions/api/tabs/tabs.h +++ b/chrome/browser/extensions/api/tabs/tabs.h @@ -121,6 +121,7 @@ class UpdateTabFunction : public AsyncExtensionFunction { protected: virtual ~UpdateTabFunction() {} virtual bool UpdateURLIfPresent(base::DictionaryValue* update_props, + int tab_id, bool* is_async); virtual void PopulateResult(); diff --git a/chrome/browser/extensions/extension_tab_helper.cc b/chrome/browser/extensions/extension_tab_helper.cc index 0a57770..2e4682f 100644 --- a/chrome/browser/extensions/extension_tab_helper.cc +++ b/chrome/browser/extensions/extension_tab_helper.cc @@ -30,11 +30,12 @@ #include "content/public/browser/web_contents.h" #include "ui/gfx/image/image.h" +using content::RenderViewHost; using content::WebContents; using extensions::Extension; +using extensions::PageActionController; using extensions::ScriptBadgeController; using extensions::ScriptExecutorImpl; -using extensions::PageActionController; namespace { @@ -48,7 +49,8 @@ ExtensionTabHelper::ExtensionTabHelper(TabContents* tab_contents) extension_app_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST( extension_function_dispatcher_(tab_contents->profile(), this)), - tab_contents_(tab_contents) { + tab_contents_(tab_contents), + active_tab_permission_manager_(tab_contents) { if (extensions::switch_utils::IsActionBoxEnabled()) { script_badge_controller_ = new ScriptBadgeController(tab_contents); } else { @@ -75,6 +77,14 @@ void ExtensionTabHelper::GetApplicationInfo(int32 page_id) { Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id)); } +int ExtensionTabHelper::tab_id() const { + return tab_contents_->restore_tab_helper()->session_id().id(); +} + +int ExtensionTabHelper::window_id() const { + return tab_contents_->restore_tab_helper()->window_id().id(); +} + void ExtensionTabHelper::SetExtensionApp(const Extension* extension) { DCHECK(!extension || extension->GetFullLaunchURL().is_valid()); extension_app_ = extension; @@ -121,6 +131,11 @@ extensions::LocationBarController* return location_bar_controller_.get(); } +void ExtensionTabHelper::RenderViewCreated(RenderViewHost* render_view_host) { + render_view_host->Send( + new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(), tab_id())); +} + void ExtensionTabHelper::DidNavigateMainFrame( const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) { diff --git a/chrome/browser/extensions/extension_tab_helper.h b/chrome/browser/extensions/extension_tab_helper.h index 6aa2bca..ffcca1c 100644 --- a/chrome/browser/extensions/extension_tab_helper.h +++ b/chrome/browser/extensions/extension_tab_helper.h @@ -9,6 +9,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" +#include "chrome/browser/extensions/active_tab_permission_manager.h" #include "chrome/browser/extensions/app_notify_channel_setup.h" #include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/extensions/image_loading_tracker.h" @@ -58,6 +59,12 @@ class ExtensionTabHelper // the data is available. void GetApplicationInfo(int32 page_id); + // Gets the ID of the tab. + int tab_id() const; + + // Gets the window ID of the tab. + int window_id() const; + // App extensions ------------------------------------------------------------ // Sets the extension denoting this as an app. If |extension| is non-null this @@ -102,12 +109,18 @@ class ExtensionTabHelper extensions::LocationBarController* location_bar_controller(); + extensions::ActiveTabPermissionManager* active_tab_permission_manager() { + return &active_tab_permission_manager_; + } + // Sets a non-extension app icon associated with WebContents and fires an // INVALIDATE_TYPE_TITLE navigation state change to trigger repaint of title. void SetAppIcon(const SkBitmap& app_icon); private: // content::WebContentsObserver overrides. + virtual void RenderViewCreated( + content::RenderViewHost* render_view_host) OVERRIDE; virtual void DidNavigateMainFrame( const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) OVERRIDE; @@ -196,6 +209,8 @@ class ExtensionTabHelper scoped_ptr<extensions::LocationBarController> location_bar_controller_; scoped_refptr<extensions::ScriptBadgeController> script_badge_controller_; + extensions::ActiveTabPermissionManager active_tab_permission_manager_; + DISALLOW_COPY_AND_ASSIGN(ExtensionTabHelper); }; diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc index d2cd5b3..e8251a0 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc @@ -5,6 +5,7 @@ #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" +#include "chrome/browser/extensions/extension_tab_helper.h" #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/restore_tab_helper.h" @@ -41,20 +42,18 @@ int ExtensionTabUtil::GetWindowIdOfTabStripModel( return -1; } -// TODO(sky): this function should really take a TabContents. int ExtensionTabUtil::GetTabId(const WebContents* web_contents) { const TabContents* tab = TabContents::FromWebContents(web_contents); - return tab ? tab->restore_tab_helper()->session_id().id() : -1; + return tab ? tab->extension_tab_helper()->tab_id() : -1; } std::string ExtensionTabUtil::GetTabStatusText(bool is_loading) { return is_loading ? keys::kStatusValueLoading : keys::kStatusValueComplete; } -// TODO(sky): this function should really take a TabContents. int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) { const TabContents* tab = TabContents::FromWebContents(web_contents); - return tab ? tab->restore_tab_helper()->window_id().id() : -1; + return tab ? tab->extension_tab_helper()->window_id() : -1; } DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents) { diff --git a/chrome/browser/extensions/extension_toolbar_model.cc b/chrome/browser/extensions/extension_toolbar_model.cc index d8e0ed0..cc6e6474 100644 --- a/chrome/browser/extensions/extension_toolbar_model.cc +++ b/chrome/browser/extensions/extension_toolbar_model.cc @@ -7,6 +7,7 @@ #include "chrome/browser/extensions/extension_browser_event_router.h" #include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extension_service.h" +#include "chrome/browser/extensions/extension_tab_helper.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" @@ -95,6 +96,9 @@ ExtensionToolbarModel::Action ExtensionToolbarModel::ExecuteBrowserAction( if (tab_id < 0) return ACTION_NONE; + tab_contents->extension_tab_helper()->active_tab_permission_manager()-> + GrantIfRequested(extension); + ExtensionAction* browser_action = extension->browser_action(); if (browser_action->HasPopup(tab_id)) { if (popup_url_out) diff --git a/chrome/browser/extensions/script_badge_controller.cc b/chrome/browser/extensions/script_badge_controller.cc index eb3c28d..7efd6a9 100644 --- a/chrome/browser/extensions/script_badge_controller.cc +++ b/chrome/browser/extensions/script_badge_controller.cc @@ -89,7 +89,6 @@ void ScriptBadgeController::ExecuteScript( run_at, world_type, this_callback); - } void ScriptBadgeController::OnExecuteScriptFinished( |