diff options
author | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-04 07:32:09 +0000 |
---|---|---|
committer | aa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-04 07:32:09 +0000 |
commit | f34706be3d46c4b7f0aaf243c1e27e0015665838 (patch) | |
tree | 851eacebcb3020db16704066794c559b6cdd4874 | |
parent | 930a7dbf4eccca3a5cb7671965bd9a38957c08cb (diff) | |
download | chromium_src-f34706be3d46c4b7f0aaf243c1e27e0015665838.zip chromium_src-f34706be3d46c4b7f0aaf243c1e27e0015665838.tar.gz chromium_src-f34706be3d46c4b7f0aaf243c1e27e0015665838.tar.bz2 |
Remove permission warnings from most tabs and windows APIs.
Patch contributed by 'Chris Hebert <chebert@chromium.org>'.
See http://codereview.chromium.org/10829186/
BUG=137404
TBR=jennb,derat,chebert
Review URL: https://chromiumcodereview.appspot.com/10920070
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154730 0039d316-1c4b-4281-b951-d872f2087c98
38 files changed, 323 insertions, 185 deletions
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc index e22e8ec..6320644 100644 --- a/chrome/browser/extensions/all_urls_apitest.cc +++ b/chrome/browser/extensions/all_urls_apitest.cc @@ -83,7 +83,7 @@ IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, WhitelistedExtension) { // 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. + // First load the two extensions. FilePath extension_dir1 = test_data_dir_.AppendASCII("all_urls") .AppendASCII("content_script"); FilePath extension_dir2 = test_data_dir_.AppendASCII("all_urls") diff --git a/chrome/browser/extensions/api/messaging/message_service.cc b/chrome/browser/extensions/api/messaging/message_service.cc index 807cc4d..b5ed615 100644 --- a/chrome/browser/extensions/api/messaging/message_service.cc +++ b/chrome/browser/extensions/api/messaging/message_service.cc @@ -219,8 +219,10 @@ void MessageService::OpenChannelToExtension( // Include info about the opener's tab (if it was a tab). std::string tab_json = "null"; if (source_contents) { - scoped_ptr<DictionaryValue> tab_value( - ExtensionTabUtil::CreateTabValue(source_contents)); + scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue( + source_contents, + profile->GetExtensionService()->extensions()->GetByID( + source_extension_id))); base::JSONWriter::Write(tab_value.get(), &tab_json); } @@ -271,8 +273,10 @@ void MessageService::OpenChannelToTab( // Include info about the opener's tab (if it was a tab). std::string tab_json = "null"; if (source_contents) { - scoped_ptr<DictionaryValue> tab_value( - ExtensionTabUtil::CreateTabValue(source_contents)); + scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue( + source_contents, + profile->GetExtensionService()->extensions()->GetByID( + extension_id))); base::JSONWriter::Write(tab_value.get(), &tab_json); } diff --git a/chrome/browser/extensions/api/permissions/permissions_apitest.cc b/chrome/browser/extensions/api/permissions/permissions_apitest.cc index 3744a85..3e856ab 100644 --- a/chrome/browser/extensions/api/permissions/permissions_apitest.cc +++ b/chrome/browser/extensions/api/permissions/permissions_apitest.cc @@ -73,7 +73,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_AlwaysAllowed) { IN_PROC_BROWSER_TEST_F(ExtensionApiTest, OptionalPermissionsGranted) { // Mark all the tested APIs as granted to bypass the confirmation UI. APIPermissionSet apis; - apis.insert(APIPermission::kTab); + apis.insert(APIPermission::kBookmark); URLPatternSet explicit_hosts; AddPattern(&explicit_hosts, "http://*.c.com/*"); scoped_refptr<PermissionSet> granted_permissions = diff --git a/chrome/browser/extensions/api/tabs/tabs.cc b/chrome/browser/extensions/api/tabs/tabs.cc index 78d1881..45cb097 100644 --- a/chrome/browser/extensions/api/tabs/tabs.cc +++ b/chrome/browser/extensions/api/tabs/tabs.cc @@ -263,7 +263,7 @@ bool GetWindowFunction::RunImpl() { return false; if (populate_tabs) - SetResult(controller->CreateWindowValueWithTabs()); + SetResult(controller->CreateWindowValueWithTabs(GetExtension())); else SetResult(controller->CreateWindowValue()); return true; @@ -284,7 +284,7 @@ bool GetCurrentWindowFunction::RunImpl() { return false; } if (populate_tabs) - SetResult(controller->CreateWindowValueWithTabs()); + SetResult(controller->CreateWindowValueWithTabs(GetExtension())); else SetResult(controller->CreateWindowValue()); return true; @@ -311,7 +311,7 @@ bool GetLastFocusedWindowFunction::RunImpl() { WindowController* controller = browser->extension_window_controller(); if (populate_tabs) - SetResult(controller->CreateWindowValueWithTabs()); + SetResult(controller->CreateWindowValueWithTabs(GetExtension())); else SetResult(controller->CreateWindowValue()); return true; @@ -334,7 +334,7 @@ bool GetAllWindowsFunction::RunImpl() { if (!this->CanOperateOnWindow(*iter)) continue; if (populate_tabs) - window_list->Append((*iter)->CreateWindowValueWithTabs()); + window_list->Append((*iter)->CreateWindowValueWithTabs(GetExtension())); else window_list->Append((*iter)->CreateWindowValue()); } @@ -586,7 +586,8 @@ bool CreateWindowFunction::RunImpl() { panel->Show(); SetResult( - panel->extension_window_controller()->CreateWindowValueWithTabs()); + panel->extension_window_controller()->CreateWindowValueWithTabs( + GetExtension())); return true; } #endif @@ -638,7 +639,8 @@ bool CreateWindowFunction::RunImpl() { SetResult(Value::CreateNullValue()); } else { SetResult( - new_window->extension_window_controller()->CreateWindowValueWithTabs()); + new_window->extension_window_controller()->CreateWindowValueWithTabs( + GetExtension())); } return true; @@ -819,7 +821,8 @@ bool GetSelectedTabFunction::RunImpl() { } SetResult(ExtensionTabUtil::CreateTabValue(contents->web_contents(), tab_strip, - tab_strip->active_index())); + tab_strip->active_index(), + GetExtension())); return true; } @@ -833,7 +836,7 @@ bool GetAllTabsInWindowFunction::RunImpl() { if (!GetBrowserFromWindowID(this, window_id, &browser)) return false; - SetResult(ExtensionTabUtil::CreateTabList(browser)); + SetResult(ExtensionTabUtil::CreateTabList(browser, GetExtension())); return true; } @@ -944,7 +947,7 @@ bool QueryTabsFunction::RunImpl() { continue; result->Append(ExtensionTabUtil::CreateTabValue( - web_contents, tab_strip, i)); + web_contents, tab_strip, i, GetExtension())); } } @@ -1019,13 +1022,11 @@ bool CreateTabFunction::RunImpl() { // be used instead). bool active = true; if (args->HasKey(keys::kSelectedKey)) - EXTENSION_FUNCTION_VALIDATE( - args->GetBoolean(keys::kSelectedKey, &active)); + EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kSelectedKey, &active)); // The 'active' property has replaced the 'selected' property. if (args->HasKey(keys::kActiveKey)) - EXTENSION_FUNCTION_VALIDATE( - args->GetBoolean(keys::kActiveKey, &active)); + EXTENSION_FUNCTION_VALIDATE(args->GetBoolean(keys::kActiveKey, &active)); // Default to not pinning the tab. Setting the 'pinned' property to true // will override this default. @@ -1081,7 +1082,7 @@ bool CreateTabFunction::RunImpl() { if (has_callback()) { SetResult(ExtensionTabUtil::CreateTabValue( params.target_contents->web_contents(), - tab_strip, new_index)); + tab_strip, new_index, GetExtension())); } return true; @@ -1100,7 +1101,8 @@ bool GetTabFunction::RunImpl() { SetResult(ExtensionTabUtil::CreateTabValue(contents->web_contents(), tab_strip, - tab_index)); + tab_index, + GetExtension())); return true; } @@ -1109,7 +1111,7 @@ bool GetCurrentTabFunction::RunImpl() { WebContents* contents = dispatcher()->delegate()->GetAssociatedWebContents(); if (contents) - SetResult(ExtensionTabUtil::CreateTabValue(contents)); + SetResult(ExtensionTabUtil::CreateTabValue(contents, GetExtension())); return true; } @@ -1166,7 +1168,8 @@ bool HighlightTabsFunction::RunImpl() { selection.set_active(active_index); browser->tab_strip_model()->SetSelectionFromModel(selection); SetResult( - browser->extension_window_controller()->CreateWindowValueWithTabs()); + browser->extension_window_controller()->CreateWindowValueWithTabs( + GetExtension())); return true; } @@ -1342,11 +1345,8 @@ void UpdateTabFunction::PopulateResult() { if (!has_callback()) return; - if (GetExtension()->HasAPIPermission(extensions::APIPermission::kTab)) { - SetResult(ExtensionTabUtil::CreateTabValue(tab_contents_->web_contents())); - } else { - SetResult(Value::CreateNullValue()); - } + SetResult(ExtensionTabUtil::CreateTabValue(tab_contents_->web_contents(), + GetExtension())); } void UpdateTabFunction::OnExecuteCodeFinished(const std::string& error, @@ -1438,9 +1438,13 @@ bool MoveTabsFunction::RunImpl() { target_tab_strip->InsertTabContentsAt( new_index, contents, TabStripModel::ADD_NONE); - if (has_callback()) + if (has_callback()) { tab_values.Append(ExtensionTabUtil::CreateTabValue( - contents->web_contents(), target_tab_strip, new_index)); + contents->web_contents(), + target_tab_strip, + new_index, + GetExtension())); + } continue; } @@ -1456,9 +1460,11 @@ bool MoveTabsFunction::RunImpl() { if (new_index != tab_index) source_tab_strip->MoveTabContentsAt(tab_index, new_index, false); - if (has_callback()) + if (has_callback()) { tab_values.Append(ExtensionTabUtil::CreateTabValue( - contents->web_contents(), source_tab_strip, new_index)); + contents->web_contents(), source_tab_strip, new_index, + GetExtension())); + } } if (!has_callback()) diff --git a/chrome/browser/extensions/api/tabs/tabs_test.cc b/chrome/browser/extensions/api/tabs/tabs_test.cc index 1f74f52..dfe8f62 100644 --- a/chrome/browser/extensions/api/tabs/tabs_test.cc +++ b/chrome/browser/extensions/api/tabs/tabs_test.cc @@ -37,6 +37,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { // Invalid window ID error. scoped_refptr<GetWindowFunction> function = new GetWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError( function.get(), @@ -52,6 +54,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { bounds = browser()->window()->GetBounds(); function = new GetWindowFunction(); + function->set_extension(extension.get()); scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -67,6 +70,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { // With "populate" enabled. function = new GetWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -91,6 +95,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { Browser* popup_browser = new Browser( Browser::CreateParams(Browser::TYPE_POPUP, browser()->profile())); function = new GetWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -103,6 +108,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { Browser* panel_browser = new Browser( Browser::CreateParams(Browser::TYPE_PANEL, browser()->profile())); function = new GetWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -117,6 +123,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { // Without "include_incognito". function = new GetWindowFunction(); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError( function.get(), @@ -126,6 +133,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetWindow) { // With "include_incognito". function = new GetWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -143,6 +151,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetCurrentWindow) { // Get the current window using new_browser. scoped_refptr<GetCurrentWindowFunction> function = new GetCurrentWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult(function.get(), "[]", @@ -156,6 +166,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetCurrentWindow) { // Get the current window using the old window and make the tabs populated. function = new GetCurrentWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult(function.get(), "[{\"populate\": true}]", @@ -176,6 +187,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetLastFocusedWindow) { scoped_refptr<GetLastFocusedWindowFunction> function = new GetLastFocusedWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult(function.get(), "[]", @@ -188,6 +201,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetLastFocusedWindow) { EXPECT_FALSE(result.get()->GetList(keys::kTabsKey, &tabs)); function = new GetLastFocusedWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult(function.get(), "[{\"populate\": true}]", @@ -212,6 +226,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) { } scoped_refptr<GetAllWindowsFunction> function = new GetAllWindowsFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); scoped_ptr<base::ListValue> result(utils::ToList( utils::RunFunctionAndReturnSingleResult(function.get(), "[]", @@ -233,6 +249,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, GetAllWindows) { result_ids.clear(); function = new GetAllWindowsFunction(); + function->set_extension(extension.get()); result.reset(utils::ToList( utils::RunFunctionAndReturnSingleResult(function.get(), "[{\"populate\": true}]", @@ -263,11 +280,14 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, UpdateNoPermissions) { // Without a callback the function will not generate a result. update_tab_function->set_has_callback(true); - scoped_ptr<base::Value> result(utils::RunFunctionAndReturnSingleResult( + scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( + utils::RunFunctionAndReturnSingleResult( update_tab_function.get(), - "[null, {\"url\": \"neutrinos\"}]", - browser())); - EXPECT_EQ(base::Value::TYPE_NULL, result->GetType()); + "[null, {\"url\": \"about:blank\", \"pinned\": true}]", + browser()))); + // The url is stripped since the extension does not have tab permissions. + EXPECT_FALSE(result->HasKey("url")); + EXPECT_TRUE(utils::GetBoolean(result.get(), "pinned")); } IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, @@ -278,7 +298,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(), IncognitoModePrefs::FORCED); // Run without an explicit "incognito" param. - scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction(); + scoped_refptr<CreateWindowFunction> function(new CreateWindowFunction()); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -296,6 +318,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, Browser* incognito_browser = CreateIncognitoBrowser(); // Run without an explicit "incognito" param. function = new CreateWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult( function.get(), @@ -317,6 +340,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, IncognitoModePrefs::FORCED); // Run without an explicit "incognito" param. scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); scoped_ptr<base::DictionaryValue> result(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult(function.get(), kEmptyArgs, @@ -333,6 +358,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, Browser* incognito_browser = CreateIncognitoBrowser(); // Run without an explicit "incognito" param. function = new CreateWindowFunction(); + function->set_extension(extension.get()); result.reset(utils::ToDictionary( utils::RunFunctionAndReturnSingleResult(function.get(), kEmptyArgs, @@ -355,6 +381,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, // Run with an explicit "incognito" param. scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError(function.get(), kArgsWithExplicitIncognitoParam, @@ -365,6 +393,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, Browser* incognito_browser = CreateIncognitoBrowser(); // Run with an explicit "incognito" param. function = new CreateWindowFunction(); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError(function.get(), kArgsWithExplicitIncognitoParam, @@ -383,6 +412,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, IncognitoModePrefs::DISABLED); // Run in normal window. scoped_refptr<CreateWindowFunction> function = new CreateWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError(function.get(), kArgs, @@ -391,6 +422,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, // Run in incognito window. function = new CreateWindowFunction(); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError(function.get(), kArgs, @@ -409,6 +441,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) { // Get tabs in the 'current' window called from non-focused browser. scoped_refptr<QueryTabsFunction> function = new QueryTabsFunction(); + function->set_extension(utils::CreateEmptyExtension().get()); scoped_ptr<base::ListValue> result(utils::ToList( utils::RunFunctionAndReturnSingleResult(function.get(), "[{\"currentWindow\":true}]", @@ -425,6 +458,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryCurrentWindowTabs) { // Get tabs NOT in the 'current' window called from non-focused browser. function = new QueryTabsFunction(); + function->set_extension(utils::CreateEmptyExtension().get()); result.reset(utils::ToList( utils::RunFunctionAndReturnSingleResult(function.get(), "[{\"currentWindow\":false}]", @@ -506,6 +540,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DontCreateTabInClosingPopupWindow) { chrome::CloseWindow(popup_browser); scoped_refptr<CreateTabFunction> create_tab_function(new CreateTabFunction()); + create_tab_function->set_extension(utils::CreateEmptyExtension().get()); // Without a callback the function will not generate a result. create_tab_function->set_has_callback(true); @@ -527,6 +562,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) { static const char kArgsMinimizedWithFocus[] = "[%u, {\"state\": \"minimized\", \"focused\": true}]"; scoped_refptr<UpdateWindowFunction> function = new UpdateWindowFunction(); + scoped_refptr<extensions::Extension> extension(utils::CreateEmptyExtension()); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError( function.get(), @@ -537,6 +574,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) { static const char kArgsMaximizedWithoutFocus[] = "[%u, {\"state\": \"maximized\", \"focused\": false}]"; function = new UpdateWindowFunction(); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError( function.get(), @@ -547,6 +585,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) { static const char kArgsMinimizedWithBounds[] = "[%u, {\"state\": \"minimized\", \"width\": 500}]"; function = new UpdateWindowFunction(); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError( function.get(), @@ -557,6 +596,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, InvalidUpdateWindowState) { static const char kArgsMaximizedWithBounds[] = "[%u, {\"state\": \"maximized\", \"width\": 500}]"; function = new UpdateWindowFunction(); + function->set_extension(extension.get()); EXPECT_TRUE(MatchPattern( utils::RunFunctionAndReturnError( function.get(), diff --git a/chrome/browser/extensions/browser_event_router.cc b/chrome/browser/extensions/browser_event_router.cc index 1aa89c5..af5cf9b 100644 --- a/chrome/browser/extensions/browser_event_router.cc +++ b/chrome/browser/extensions/browser_event_router.cc @@ -384,18 +384,35 @@ void BrowserEventRouter::DispatchEventWithTab( const char* event_name, const WebContents* web_contents, bool active, - EventRouter::UserGestureState user_gesture) { + EventRouter::UserGestureState user_gesture, + scoped_ptr<ListValue> event_args) { if (!profile_->IsSameProfile(profile)) return; - scoped_ptr<ListValue> args(new ListValue()); - args->Append(ExtensionTabUtil::CreateTabValueActive( - web_contents, active)); if (!extension_id.empty()) { - DispatchEventToExtension(profile, extension_id, event_name, args.Pass(), - user_gesture); + event_args->Append(ExtensionTabUtil::CreateTabValueActive( + web_contents, + active, + profile->GetExtensionService()->extensions()->GetByID(extension_id))); + DispatchEventToExtension(profile, extension_id, event_name, + event_args.Pass(), user_gesture); } else { - DispatchEvent(profile, event_name, args.Pass(), user_gesture); + const EventListenerMap::ListenerList& listeners( + ExtensionSystem::Get(profile)->event_router()-> + listeners().GetEventListenersByName(event_name)); + + for (EventListenerMap::ListenerList::const_iterator it = listeners.begin(); + it != listeners.end(); + ++it) { + scoped_ptr<ListValue> args(event_args->DeepCopy()); + args->Append(ExtensionTabUtil::CreateTabValueActive( + web_contents, + active, + profile->GetExtensionService()->extensions()->GetByID( + (*it)->extension_id))); + DispatchEventToExtension(profile, (*it)->extension_id, event_name, + args.Pass(), user_gesture); + } } } @@ -427,11 +444,10 @@ void BrowserEventRouter::DispatchTabUpdatedEvent( args->Append(changed_properties); // Third arg: An object containing the state of the tab. - args->Append(ExtensionTabUtil::CreateTabValue(contents)); - Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext()); - DispatchEvent(profile, events::kOnTabUpdated, args.Pass(), - EventRouter::USER_GESTURE_UNKNOWN); + + DispatchEventWithTab(profile, "", events::kOnTabUpdated, contents, true, + EventRouter::USER_GESTURE_UNKNOWN, args.Pass()); } BrowserEventRouter::TabEntry* BrowserEventRouter::GetTabEntry( diff --git a/chrome/browser/extensions/browser_event_router.h b/chrome/browser/extensions/browser_event_router.h index c9edaee..69732c2 100644 --- a/chrome/browser/extensions/browser_event_router.h +++ b/chrome/browser/extensions/browser_event_router.h @@ -127,7 +127,20 @@ class BrowserEventRouter : public TabStripModelObserver, const char* event_name, const content::WebContents* web_contents, bool active, - EventRouter::UserGestureState user_gesture); + EventRouter::UserGestureState user_gesture, + scoped_ptr<ListValue> event_args); + + // DispatchEvent with a tab value appended as the last argument. + void DispatchEventWithTab(Profile* profile, + const std::string& extension_id, + const char* event_name, + const content::WebContents* web_contents, + bool active, + EventRouter::UserGestureState user_gesture) { + DispatchEventWithTab(profile, extension_id, event_name, web_contents, + active, user_gesture, + scoped_ptr<ListValue>(new ListValue).Pass()); + } void DispatchSimpleBrowserEvent(Profile* profile, const int window_id, diff --git a/chrome/browser/extensions/browser_extension_window_controller.cc b/chrome/browser/extensions/browser_extension_window_controller.cc index 54792bc..817971d 100644 --- a/chrome/browser/extensions/browser_extension_window_controller.cc +++ b/chrome/browser/extensions/browser_extension_window_controller.cc @@ -48,10 +48,12 @@ BrowserExtensionWindowController::CreateWindowValue() const { } base::DictionaryValue* -BrowserExtensionWindowController::CreateWindowValueWithTabs() const { +BrowserExtensionWindowController::CreateWindowValueWithTabs( + const extensions::Extension* extension) const { DictionaryValue* result = CreateWindowValue(); - result->Set(keys::kTabsKey, ExtensionTabUtil::CreateTabList(browser_)); + result->Set(keys::kTabsKey, ExtensionTabUtil::CreateTabList(browser_, + extension)); return result; } diff --git a/chrome/browser/extensions/browser_extension_window_controller.h b/chrome/browser/extensions/browser_extension_window_controller.h index 9837422..a1e220a 100644 --- a/chrome/browser/extensions/browser_extension_window_controller.h +++ b/chrome/browser/extensions/browser_extension_window_controller.h @@ -9,6 +9,10 @@ class Browser; +namespace extensions { +class Extension; +} + class BrowserExtensionWindowController : public extensions::WindowController { public: explicit BrowserExtensionWindowController(Browser* browser); @@ -18,7 +22,8 @@ class BrowserExtensionWindowController : public extensions::WindowController { virtual int GetWindowId() const OVERRIDE; virtual std::string GetWindowTypeText() const OVERRIDE; virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE; - virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE; + virtual base::DictionaryValue* CreateWindowValueWithTabs( + const extensions::Extension* extension) const OVERRIDE; virtual bool CanClose(Reason* reason) const OVERRIDE; virtual void SetFullscreenMode(bool is_fullscreen, const GURL& extension_url) const OVERRIDE; diff --git a/chrome/browser/extensions/event_listener_map.h b/chrome/browser/extensions/event_listener_map.h index 6c5c304..d252900 100644 --- a/chrome/browser/extensions/event_listener_map.h +++ b/chrome/browser/extensions/event_listener_map.h @@ -93,8 +93,11 @@ class EventListenerMap { bool RemoveListener(const EventListener* listener); // Returns the set of listeners that want to be notified of |event|. - std::set<const EventListener*> GetEventListeners( - const Event& event); + std::set<const EventListener*> GetEventListeners(const Event& event); + + const ListenerList& GetEventListenersByName(const std::string& event_name) { + return listeners_[event_name]; + } // Removes all listeners with process equal to |process|. void RemoveListenersForProcess(const content::RenderProcessHost* process); diff --git a/chrome/browser/extensions/event_router.cc b/chrome/browser/extensions/event_router.cc index 8be11a6..4e65e6d 100644 --- a/chrome/browser/extensions/event_router.cc +++ b/chrome/browser/extensions/event_router.cc @@ -523,9 +523,10 @@ void EventRouter::DispatchPendingEvent(const linked_ptr<Event>& event, return; if (listeners_.HasProcessListener(host->render_process_host(), - host->extension()->id())) + host->extension()->id())) { DispatchEventToProcess(host->extension()->id(), host->render_process_host(), event); + } } void EventRouter::Observe(int type, diff --git a/chrome/browser/extensions/event_router.h b/chrome/browser/extensions/event_router.h index 97d2254..891f34d 100644 --- a/chrome/browser/extensions/event_router.h +++ b/chrome/browser/extensions/event_router.h @@ -68,6 +68,8 @@ class EventRouter : public content::NotificationObserver, content::RenderProcessHost* process, const std::string& extension_id); + EventListenerMap& listeners() { return listeners_; } + // Add or remove the extension as having a lazy background page that listens // to the event. The difference from the above methods is that these will be // remembered even after the process goes away. We use this list to decide diff --git a/chrome/browser/extensions/execute_script_apitest.cc b/chrome/browser/extensions/execute_script_apitest.cc index 1edb440..c441644 100644 --- a/chrome/browser/extensions/execute_script_apitest.cc +++ b/chrome/browser/extensions/execute_script_apitest.cc @@ -36,8 +36,7 @@ IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptPermissions) { } // If failing, mark disabled and update http://crbug.com/84760. -IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, - ExecuteScriptFileAfterClose) { +IN_PROC_BROWSER_TEST_F(ExecuteScriptApiTest, ExecuteScriptFileAfterClose) { host_resolver()->AddRule("b.com", "127.0.0.1"); ASSERT_TRUE(StartTestServer()); ASSERT_TRUE(RunExtensionTest("executescript/file_after_close")) << message_; diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc index 8d49ea7..7af6607 100644 --- a/chrome/browser/extensions/extension_tab_util.cc +++ b/chrome/browser/extensions/extension_tab_util.cc @@ -20,6 +20,7 @@ #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_manifest_constants.h" +#include "chrome/common/extensions/permissions/api_permission.h" #include "chrome/common/url_constants.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/navigation_entry.h" @@ -30,6 +31,8 @@ namespace keys = extensions::tabs_constants; using content::NavigationEntry; using content::WebContents; +using extensions::APIPermission; +using extensions::Extension; int ExtensionTabUtil::GetWindowId(const Browser* browser) { return browser->session_id().id(); @@ -58,38 +61,49 @@ int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) { TabContents::FromWebContents(web_contents)); } -DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents) { +DictionaryValue* ExtensionTabUtil::CreateTabValue( + const WebContents* contents, + const Extension* extension) { // Find the tab strip and index of this guy. TabStripModel* tab_strip = NULL; int tab_index; - if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index)) - return ExtensionTabUtil::CreateTabValue(contents, tab_strip, tab_index); + if (ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index)) { + return ExtensionTabUtil::CreateTabValue(contents, + tab_strip, + tab_index, + extension); + } // Couldn't find it. This can happen if the tab is being dragged. - return ExtensionTabUtil::CreateTabValue(contents, NULL, -1); + return ExtensionTabUtil::CreateTabValue(contents, NULL, -1, extension); } -ListValue* ExtensionTabUtil::CreateTabList(const Browser* browser) { +ListValue* ExtensionTabUtil::CreateTabList( + const Browser* browser, + const Extension* extension) { ListValue* tab_list = new ListValue(); TabStripModel* tab_strip = browser->tab_strip_model(); for (int i = 0; i < tab_strip->count(); ++i) { - tab_list->Append(ExtensionTabUtil::CreateTabValue( - tab_strip->GetTabContentsAt(i)->web_contents(), tab_strip, i)); + tab_list->Append(CreateTabValue( + tab_strip->GetTabContentsAt(i)->web_contents(), + tab_strip, + i, + extension)); } return tab_list; } -DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents, - TabStripModel* tab_strip, - int tab_index) { +DictionaryValue* ExtensionTabUtil::CreateTabValue( + const WebContents* contents, + TabStripModel* tab_strip, + int tab_index, + const Extension* extension) { DictionaryValue* result = new DictionaryValue(); bool is_loading = contents->IsLoading(); - result->SetInteger(keys::kIdKey, ExtensionTabUtil::GetTabId(contents)); + result->SetInteger(keys::kIdKey, GetTabId(contents)); result->SetInteger(keys::kIndexKey, tab_index); - result->SetInteger(keys::kWindowIdKey, - ExtensionTabUtil::GetWindowIdOfTab(contents)); - result->SetString(keys::kUrlKey, contents->GetURL().spec()); + result->SetInteger(keys::kWindowIdKey, GetWindowIdOfTab(contents)); result->SetString(keys::kStatusKey, GetTabStatusText(is_loading)); result->SetBoolean(keys::kActiveKey, tab_strip && tab_index == tab_strip->active_index()); @@ -99,24 +113,42 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents, tab_strip && tab_strip->IsTabSelected(tab_index)); result->SetBoolean(keys::kPinnedKey, tab_strip && tab_strip->IsTabPinned(tab_index)); - result->SetString(keys::kTitleKey, contents->GetTitle()); result->SetBoolean(keys::kIncognitoKey, contents->GetBrowserContext()->IsOffTheRecord()); + // Only add privacy-sensitive data if the requesting extension has the tabs + // permission. + bool has_permission = false; + if (extension) { + if (tab_index >= 0) { + has_permission = + extension->HasAPIPermissionForTab( + tab_index, APIPermission::kTab) || + extension->HasAPIPermissionForTab( + tab_index, APIPermission::kWebNavigation); + } else { + has_permission = + extension->HasAPIPermission(APIPermission::kTab) || + extension->HasAPIPermission(APIPermission::kWebNavigation); + } + } + + if (has_permission) { + result->SetString(keys::kUrlKey, contents->GetURL().spec()); + result->SetString(keys::kTitleKey, contents->GetTitle()); + if (!is_loading) { + NavigationEntry* entry = contents->GetController().GetActiveEntry(); + if (entry && entry->GetFavicon().valid) + result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec()); + } + } + if (tab_strip) { content::NavigationController* opener = tab_strip->GetOpenerOfTabContentsAt(tab_index); if (opener) { result->SetInteger(keys::kOpenerTabIdKey, - ExtensionTabUtil::GetTabId(opener->GetWebContents())); - } - } - - if (!is_loading) { - NavigationEntry* entry = contents->GetController().GetActiveEntry(); - if (entry) { - if (entry->GetFavicon().valid) - result->SetString(keys::kFaviconUrlKey, entry->GetFavicon().url.spec()); + GetTabId(opener->GetWebContents())); } } @@ -125,8 +157,9 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents, DictionaryValue* ExtensionTabUtil::CreateTabValueActive( const WebContents* contents, - bool active) { - DictionaryValue* result = ExtensionTabUtil::CreateTabValue(contents); + bool active, + const extensions::Extension* extension) { + DictionaryValue* result = CreateTabValue(contents, extension); result->SetBoolean(keys::kSelectedKey, active); return result; } @@ -161,7 +194,7 @@ bool ExtensionTabUtil::GetDefaultTab(Browser* browser, *contents = chrome::GetActiveTabContents(browser); if (*contents) { if (tab_id) - *tab_id = ExtensionTabUtil::GetTabId((*contents)->web_contents()); + *tab_id = GetTabId((*contents)->web_contents()); return true; } diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h index ec87b26..0261164 100644 --- a/chrome/browser/extensions/extension_tab_util.h +++ b/chrome/browser/extensions/extension_tab_util.h @@ -42,17 +42,22 @@ class ExtensionTabUtil { static int GetTabId(const content::WebContents* web_contents); static std::string GetTabStatusText(bool is_loading); static int GetWindowIdOfTab(const content::WebContents* web_contents); - static base::ListValue* CreateTabList(const Browser* browser); + static base::ListValue* CreateTabList( + const Browser* browser, + const extensions::Extension* extension); static base::DictionaryValue* CreateTabValue( - const content::WebContents* web_contents); + const content::WebContents* web_contents, + const extensions::Extension* extension); static base::DictionaryValue* CreateTabValue( const content::WebContents* web_contents, TabStripModel* tab_strip, - int tab_index); + int tab_index, + const extensions::Extension* extension); // Create a tab value, overriding its kSelectedKey to the provided boolean. static base::DictionaryValue* CreateTabValueActive( const content::WebContents* web_contents, - bool active); + bool active, + const extensions::Extension* extension); // Gets the |tab_strip_model| and |tab_index| for the given |web_contents|. static bool GetTabStripModel(const content::WebContents* web_contents, diff --git a/chrome/browser/extensions/extension_tab_util_android.cc b/chrome/browser/extensions/extension_tab_util_android.cc index 2d8d641..2e0b51a 100644 --- a/chrome/browser/extensions/extension_tab_util_android.cc +++ b/chrome/browser/extensions/extension_tab_util_android.cc @@ -32,26 +32,33 @@ int ExtensionTabUtil::GetWindowIdOfTab(const WebContents* web_contents) { return -1; } -DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents) { +DictionaryValue* ExtensionTabUtil::CreateTabValue( + const WebContents* contents, + const extensions::Extension* extension) { NOTIMPLEMENTED(); return NULL; } -ListValue* ExtensionTabUtil::CreateTabList(const Browser* browser) { +ListValue* ExtensionTabUtil::CreateTabList( + const Browser* browser, + const extensions::Extension* extension) { NOTIMPLEMENTED(); return NULL; } -DictionaryValue* ExtensionTabUtil::CreateTabValue(const WebContents* contents, - TabStripModel* tab_strip, - int tab_index) { +DictionaryValue* ExtensionTabUtil::CreateTabValue( + const WebContents* contents, + TabStripModel* tab_strip, + int tab_index, + const extensions::Extension* extension) { NOTIMPLEMENTED(); return NULL; } DictionaryValue* ExtensionTabUtil::CreateTabValueActive( const WebContents* contents, - bool active) { + bool active, + const extensions::Extension* extension) { NOTIMPLEMENTED(); return NULL; } diff --git a/chrome/browser/extensions/extension_tabs_apitest.cc b/chrome/browser/extensions/extension_tabs_apitest.cc index f08f8ef..4c921aa 100644 --- a/chrome/browser/extensions/extension_tabs_apitest.cc +++ b/chrome/browser/extensions/extension_tabs_apitest.cc @@ -237,6 +237,5 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_GetViewsOfCreatedWindow) { } // Adding a new test? Awesome. But API tests are the old hotness. The -// new hotness is extension_test_utils. See extension_tabs_test.cc for -// an example. We are trying to phase out many uses of API tests as -// they tend to be flaky. +// new hotness is extension_test_utils. See tabs_test.cc for an example. +// We are trying to phase out many uses of API tests as they tend to be flaky. diff --git a/chrome/browser/extensions/menu_manager.cc b/chrome/browser/extensions/menu_manager.cc index 9e29835..e8d3689 100644 --- a/chrome/browser/extensions/menu_manager.cc +++ b/chrome/browser/extensions/menu_manager.cc @@ -644,7 +644,7 @@ void MenuManager::ExecuteCommand(Profile* profile, if (!extension || !extension->is_platform_app()) { // Note: web_contents only NULL in unit tests :( if (web_contents) - args->Append(ExtensionTabUtil::CreateTabValue(web_contents)); + args->Append(ExtensionTabUtil::CreateTabValue(web_contents, extension)); else args->Append(new DictionaryValue()); } diff --git a/chrome/browser/extensions/window_controller.h b/chrome/browser/extensions/window_controller.h index e6e4554..ec9f6e2 100644 --- a/chrome/browser/extensions/window_controller.h +++ b/chrome/browser/extensions/window_controller.h @@ -57,7 +57,8 @@ class WindowController { virtual base::DictionaryValue* CreateWindowValue() const; // Populates a dictionary for the Window object, including a list of tabs. - virtual base::DictionaryValue* CreateWindowValueWithTabs() const = 0; + virtual base::DictionaryValue* CreateWindowValueWithTabs( + const extensions::Extension* extension) const = 0; // Returns false if the window is in a state where closing the window is not // permitted and sets |reason| if not NULL. diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc index af6adf1..0dac7b5 100644 --- a/chrome/browser/ui/panels/panel.cc +++ b/chrome/browser/ui/panels/panel.cc @@ -38,6 +38,10 @@ using content::RenderViewHost; using content::UserMetricsAction; +namespace extensions { +class Extension; +} + namespace panel_internal { class PanelExtensionWindowController : public extensions::WindowController { @@ -48,7 +52,8 @@ class PanelExtensionWindowController : public extensions::WindowController { // Overridden from extensions::WindowController. virtual int GetWindowId() const OVERRIDE; virtual std::string GetWindowTypeText() const OVERRIDE; - virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE; + virtual base::DictionaryValue* CreateWindowValueWithTabs( + const extensions::Extension* extension) const OVERRIDE; virtual bool CanClose(Reason* reason) const OVERRIDE; virtual void SetFullscreenMode(bool is_fullscreen, const GURL& extension_url) const OVERRIDE; @@ -80,12 +85,11 @@ std::string PanelExtensionWindowController::GetWindowTypeText() const { } base::DictionaryValue* -PanelExtensionWindowController::CreateWindowValueWithTabs() const { +PanelExtensionWindowController::CreateWindowValueWithTabs( + const extensions::Extension* extension) const { base::DictionaryValue* result = CreateWindowValue(); - // Safe to include info about the web contents as this is only called - // by the extension that owns this window. See IsVisibleToExtension(). - // TODO(jennb): DCHECK this after chebert's patch 10829186 lands. + DCHECK(IsVisibleToExtension(extension)); content::WebContents* web_contents = panel_->GetWebContents(); if (web_contents) { DictionaryValue* tab_value = new DictionaryValue(); diff --git a/chrome/browser/ui/views/ash/panel_view_aura.cc b/chrome/browser/ui/views/ash/panel_view_aura.cc index bc5346d..cda8cab 100644 --- a/chrome/browser/ui/views/ash/panel_view_aura.cc +++ b/chrome/browser/ui/views/ash/panel_view_aura.cc @@ -189,7 +189,8 @@ class PanelExtensionWindowController : public extensions::WindowController { virtual int GetWindowId() const OVERRIDE; virtual std::string GetWindowTypeText() const OVERRIDE; virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE; - virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE; + virtual base::DictionaryValue* CreateWindowValueWithTabs( + const extensions::Extension* extension) const OVERRIDE; virtual bool CanClose(Reason* reason) const OVERRIDE; virtual void SetFullscreenMode(bool is_fullscreen, const GURL& extension_url) const OVERRIDE; @@ -231,7 +232,8 @@ PanelExtensionWindowController::CreateWindowValue() const { } base::DictionaryValue* -PanelExtensionWindowController::CreateWindowValueWithTabs() const { +PanelExtensionWindowController::CreateWindowValueWithTabs( + const extensions::Extension* extension) const { DictionaryValue* result = CreateWindowValue(); // TODO(stevenjb): Implement tab interface for Aura panels. diff --git a/chrome/common/extensions/api/tabs.json b/chrome/common/extensions/api/tabs.json index 537e11a..bacd2c9 100644 --- a/chrome/common/extensions/api/tabs.json +++ b/chrome/common/extensions/api/tabs.json @@ -19,9 +19,9 @@ "highlighted": {"type": "boolean", "description": "Whether the tab is highlighted."}, "active": {"type": "boolean", "description": "Whether the tab is active in its window."}, "pinned": {"type": "boolean", "description": "Whether the tab is pinned."}, - "url": {"type": "string", "description": "The URL the tab is displaying."}, - "title": {"type": "string", "optional": true, "description": "The title of the tab. This may not be available if the tab is loading."}, - "favIconUrl": {"type": "string", "optional": true, "description": "The URL of the tab's favicon. This may not be available if the tab is loading."}, + "url": {"type": "string", "optional": true, "description": "The URL the tab is displaying. This will only be present if the extension has the 'tabs' or 'webNavigation' permission."}, + "title": {"type": "string", "optional": true, "optional": true, "description": "The title of the tab. This will only be present if the extension has the 'tabs' or 'webNavigation' permission. It may also be an empty string if the tab is loading."}, + "favIconUrl": {"type": "string", "optional": true, "optional": true, "description": "The URL of the tab's favicon. This will only be present if the extension has the 'tabs' or 'webNavigation' permission. It may also be an empty string if the tab is loading."}, "status": {"type": "string", "optional": true, "description": "Either <em>loading</em> or <em>complete</em>."}, "incognito": {"type": "boolean", "description": "Whether the tab is in an incognito window."} } diff --git a/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json b/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json index a42819b..8288e96 100644 --- a/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json +++ b/chrome/common/extensions/docs/examples/api/bookmarks/basic/manifest.json @@ -3,7 +3,7 @@ "version": "1.0", "description": "A browser action with a popup dump of all bookmarks, including search, add, edit and delete.", "permissions": [ - "bookmarks", "tabs" + "bookmarks" ], "browser_action": { "default_title": "My Bookmarks.", diff --git a/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json b/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json index 801182d..8a68222 100644 --- a/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json +++ b/chrome/common/extensions/docs/examples/api/browserAction/make_page_red/manifest.json @@ -3,7 +3,7 @@ "version": "1.0", "background": { "scripts": ["background.js"] }, "permissions": [ - "tabs", "http://*/*" + "http://*/*" ], "browser_action": { "name": "Make this page red", diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc index e43ed7e..ebe75be 100644 --- a/chrome/common/extensions/extension_unittest.cc +++ b/chrome/common/extensions/extension_unittest.cc @@ -597,7 +597,6 @@ TEST(ExtensionTest, ApiPermissions) { { "bookmarks", false }, { "cookies", false }, { "history", false }, - { "tabs.onUpdated", false }, // Make sure we find the module name after stripping '.' and '/'. { "browserAction/abcd/onClick", true }, { "browserAction.abcd.onClick", true }, @@ -606,7 +605,8 @@ TEST(ExtensionTest, ApiPermissions) { { "tabs.onRemoved", true}, { "tabs.remove", true}, { "tabs.update", true}, - { "tabs.getSelected", false}, + { "tabs.getSelected", true}, + { "tabs.onUpdated", true }, // Test getPermissionWarnings functions. Only one requires permissions. { "management.getPermissionWarningsById", false }, { "management.getPermissionWarningsByManifest", true }, diff --git a/chrome/common/extensions/permissions/permission_set.cc b/chrome/common/extensions/permissions/permission_set.cc index 66c0e9c..4c80084 100644 --- a/chrome/common/extensions/permissions/permission_set.cc +++ b/chrome/common/extensions/permissions/permission_set.cc @@ -47,8 +47,10 @@ const char* kNonPermissionModuleNames[] = { "permissions", "runtime", "scriptBadge", + "tabs", "test", - "types" + "types", + "windows" }; const size_t kNumNonPermissionModuleNames = arraysize(kNonPermissionModuleNames); @@ -64,10 +66,6 @@ const char* kNonPermissionFunctionNames[] = { "app.installState", "app.runningState", "management.getPermissionWarningsByManifest", - "tabs.create", - "tabs.onRemoved", - "tabs.remove", - "tabs.update", }; const size_t kNumNonPermissionFunctionNames = arraysize(kNonPermissionFunctionNames); diff --git a/chrome/common/extensions/permissions/permission_set_unittest.cc b/chrome/common/extensions/permissions/permission_set_unittest.cc index fd6a3fa..9e19045 100644 --- a/chrome/common/extensions/permissions/permission_set_unittest.cc +++ b/chrome/common/extensions/permissions/permission_set_unittest.cc @@ -764,20 +764,21 @@ TEST(PermissionsTest, DefaultFunctionAccess) { { "bookmarks", false }, { "cookies", false }, { "history", false }, - { "tabs.onUpdated", false }, // Make sure we find the module name after stripping '.' and '/'. { "browserAction/abcd/onClick", true }, { "browserAction.abcd.onClick", true }, // Test Tabs functions. { "tabs.create", true}, { "tabs.update", true}, - { "tabs.getSelected", false}, + { "tabs.getSelected", true}, + { "tabs.onUpdated", true }, }; scoped_refptr<PermissionSet> empty = new PermissionSet(); for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) { EXPECT_EQ(kTests[i].expect_success, - empty->HasAccessToFunction(kTests[i].permission_name)); + empty->HasAccessToFunction(kTests[i].permission_name)) + << "Permission being tested: " << kTests[i].permission_name; } } diff --git a/chrome/renderer/extensions/dispatcher.cc b/chrome/renderer/extensions/dispatcher.cc index a99c159..e69857e 100644 --- a/chrome/renderer/extensions/dispatcher.cc +++ b/chrome/renderer/extensions/dispatcher.cc @@ -1066,19 +1066,7 @@ bool Dispatcher::CheckCurrentContextAccessToExtensionAPI( return false; } - // We need to whitelist tabs.executeScript and tabs.insertCSS because they - // are granted under special circumstances with the activeTab permission - // (note that the browser checks too, so this isn't a security problem). - // - // Only the browser knows which tab this call will be sent to... sometimes we - // *could* figure it out (if the extension gives an explicit tab ID in the - // call), but the expected case will be the extension passing through -1, - // meaning the active tab, and only the browser safely knows what this is. - bool skip_permission_check = (function_name == "tabs.executeScript") || - (function_name == "tabs.insertCSS"); - - if (!skip_permission_check && - !context->extension()->HasAPIPermission(function_name)) { + if (!context->extension()->HasAPIPermission(function_name)) { static const char kMessage[] = "You do not have permission to use '%s'. Be sure to declare" " in your manifest what permissions you need."; diff --git a/chrome/test/data/extensions/api_test/active_tab/background.js b/chrome/test/data/extensions/api_test/active_tab/background.js index 4a0df82..b102f0c 100644 --- a/chrome/test/data/extensions/api_test/active_tab/background.js +++ b/chrome/test/data/extensions/api_test/active_tab/background.js @@ -17,7 +17,9 @@ chrome.browserAction.onClicked.addListener(function() { chrome.webNavigation.onCompleted.addListener(function(details) { inject(function() { - chrome.test.assertLastError("Access to extension API denied."); + chrome.test.assertLastError('Cannot access contents of url "' + + details.url + + '". Extension manifest must request permission to access this host.'); if (details.url.indexOf("final_page") >= 0) theOnlyTestDone(); else 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 index 816150c..6b6b0a8 100644 --- 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 @@ -6,6 +6,7 @@ "js": [ "content_script.js" ], "matches": [ "<all_urls>" ] } ], + "permissions": [ "tabs" ], "description": "Test whether whitelisted extensions can run scripts everywhere using content script", "name": "AllUrls content script permissions", "manifest_version": 2, diff --git a/chrome/test/data/extensions/api_test/events/background.js b/chrome/test/data/extensions/api_test/events/background.js index 4477c20..dee47d8 100644 --- a/chrome/test/data/extensions/api_test/events/background.js +++ b/chrome/test/data/extensions/api_test/events/background.js @@ -8,15 +8,16 @@ chrome.test.runTests([ function attachAndDetachNoPermisssions() { function dummy() {}; try { - chrome.tabs.onUpdated.addListener(dummy); + chrome.management.onEnabled.addListener(dummy); chrome.test.fail(); } catch (e) { chrome.test.assertTrue( e.message.search("You do not have permission") >= 0, e.message); } - chrome.test.assertFalse(chrome.tabs.onUpdated.hasListeners()); - chrome.tabs.onUpdated.removeListener(dummy); // browser should not DCHECK + chrome.test.assertFalse(chrome.management.onEnabled.hasListeners()); + // Browser should not DCHECK. + chrome.management.onEnabled.removeListener(dummy); chrome.test.succeed(); }, diff --git a/chrome/test/data/extensions/api_test/permissions/disabled/background.js b/chrome/test/data/extensions/api_test/permissions/disabled/background.js index e130a1f..f269a3c 100644 --- a/chrome/test/data/extensions/api_test/permissions/disabled/background.js +++ b/chrome/test/data/extensions/api_test/permissions/disabled/background.js @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// All of the calls to chrome.* functions should fail, since this extension -// has requested no permissions. +// All of the calls to chrome.* functions should fail, with the exception of +// chrome.tabs.*, since this extension has requested no permissions. chrome.test.runTests([ function history() { @@ -27,13 +27,17 @@ chrome.test.runTests([ } }, + // Tabs functionality should be enabled even if the tabs permissions are not + // present. function tabs() { try { - chrome.tabs.getSelected(null, function(results) { - chrome.test.fail(); + chrome.tabs.create({'url': '1'}, function(tab) { + // Tabs strip sensitive data without permissions. + chrome.test.assertFalse('url' in tab); + chrome.test.succeed(); }); } catch (e) { - chrome.test.succeed(); + chrome.test.fail(); } }, diff --git a/chrome/test/data/extensions/api_test/permissions/optional/background.js b/chrome/test/data/extensions/api_test/permissions/optional/background.js index fecfce5..99af450 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional/background.js @@ -12,8 +12,8 @@ var listenOnce = chrome.test.listenOnce; var NOT_OPTIONAL_ERROR = "Optional permissions must be listed in extension manifest."; -var NO_TABS_PERMISSION = - "You do not have permission to use 'windows.getAll'."; +var NO_BOOKMARKS_PERMISSION = + "You do not have permission to use 'bookmarks.getTree'."; var REQUIRED_ERROR = "You cannot remove required permissions."; @@ -31,8 +31,8 @@ var initialPermissions = { origins: ['http://a.com/*'] }; -var permissionsWithTabs = { - permissions: ['management', 'tabs'], +var permissionsWithBookmarks = { + permissions: ['management', 'bookmarks'], origins: ['http://a.com/*'] } @@ -116,41 +116,42 @@ chrome.test.getConfig(function(config) { // defined in "optional_permissions". function requestNonOptional() { chrome.permissions.request( - {permissions: ['bookmarks']}, fail(NOT_OPTIONAL_ERROR)); + {permissions: ['history']}, fail(NOT_OPTIONAL_ERROR)); chrome.permissions.request( {origins: ['http://*.b.com/*']}, fail(NOT_OPTIONAL_ERROR)); chrome.permissions.request( - {permissions: ['tabs'], origins: ['http://*.b.com/*']}, + {permissions: ['history'], origins: ['http://*.b.com/*']}, fail(NOT_OPTIONAL_ERROR)); }, - // We should be able to request the tabs API since it's in the granted + // We should be able to request the bookmarks API since it's in the granted // permissions list (see permissions_apitest.cc). - function requestTabs() { - // chrome.windows is a optional permission, so the API definition should + function requestBookmarks() { + // chrome.bookmarks is a optional permission, so the API definition should // exist but its use disallowed. - assertTrue(!!chrome.windows); + assertTrue(!!chrome.bookmarks); try { - chrome.windows.getAll({populate: true}, function() { - chrome.test.fail("Should not have tabs API permission."); + chrome.bookmarks.getTree(function() { + chrome.test.fail("Should not have bookmarks API permission."); }); } catch (e) { - assertTrue(e.message.indexOf(NO_TABS_PERMISSION) == 0); + assertTrue(e.message.indexOf(NO_BOOKMARKS_PERMISSION) == 0); } listenOnce(chrome.permissions.onAdded, function(permissions) { assertTrue(permissions.permissions.length == 1); - assertTrue(permissions.permissions[0] == 'tabs'); + assertTrue(permissions.permissions[0] == 'bookmarks'); }); chrome.permissions.request( - {permissions:['tabs']}, + {permissions:['bookmarks']}, pass(function(granted) { assertTrue(granted); - chrome.windows.getAll({populate: true}, pass(function(windows) { + chrome.bookmarks.getTree(pass(function(result) { assertTrue(true); })); chrome.permissions.getAll(pass(function(permissions) { - assertTrue(checkPermSetsEq(permissionsWithTabs, permissions)); + assertTrue(checkPermSetsEq(permissionsWithBookmarks, + permissions)); })); })); }, @@ -172,7 +173,7 @@ chrome.test.getConfig(function(config) { chrome.permissions.remove( {origins: ['http://a.com/*']}, fail(REQUIRED_ERROR)); chrome.permissions.remove( - {permissions: ['tabs'], origins: ['http://a.com/*']}, + {permissions: ['bookmarks'], origins: ['http://a.com/*']}, fail(REQUIRED_ERROR)); }, @@ -189,27 +190,27 @@ chrome.test.getConfig(function(config) { pass(function(removed) { assertTrue(removed); })); }, - function removeTabs() { - chrome.windows.getAll({populate: true}, pass(function(windows) { + function removeBookmarks() { + chrome.bookmarks.getTree(pass(function(result) { assertTrue(true); })); listenOnce(chrome.permissions.onRemoved, function(permissions) { assertTrue(permissions.permissions.length == 1); - assertTrue(permissions.permissions[0] == 'tabs'); + assertTrue(permissions.permissions[0] == 'bookmarks'); }); chrome.permissions.remove( - {permissions:['tabs']}, + {permissions:['bookmarks']}, pass(function() { chrome.permissions.getAll(pass(function(permissions) { assertTrue(checkPermSetsEq(initialPermissions, permissions)); })); try { - chrome.windows.getAll({populate: true}, function() { - chrome.test.fail("Should not have tabs API permission."); + chrome.bookmarks.getTree(function() { + chrome.test.fail("Should not have bookmarks API permission."); }); } catch (e) { - assertTrue(e.message.indexOf(NO_TABS_PERMISSION) == 0); + assertTrue(e.message.indexOf(NO_BOOKMARKS_PERMISSION) == 0); } })); }, @@ -298,26 +299,26 @@ chrome.test.getConfig(function(config) { function eventListenerPermissions() { listenOnce(chrome.permissions.onAdded, function(permissions) { - chrome.windows.getAll({populate: true}, pass(function() { + chrome.bookmarks.getTree(pass(function() { assertTrue(true); })); }); listenOnce(chrome.permissions.onRemoved, function(permissions) { try { - chrome.windows.getAll({populate: true}, function() { - chrome.test.fail("Should not have tabs API permission."); + chrome.bookmarks.getTree(function() { + chrome.test.fail("Should not have bookmakrs API permission."); }); } catch (e) { - assertTrue(e.message.indexOf(NO_TABS_PERMISSION) == 0); + assertTrue(e.message.indexOf(NO_BOOKMARKS_PERMISSION) == 0); } }); chrome.permissions.request( - {permissions: ['tabs', 'management']}, pass(function(granted) { + {permissions: ['bookmarks', 'management']}, pass(function(granted) { assertTrue(granted); chrome.permissions.remove( - {permissions: ['tabs']}, pass(function() { + {permissions: ['bookmarks']}, pass(function() { assertTrue(true); })); })); diff --git a/chrome/test/data/extensions/api_test/permissions/optional/manifest.json b/chrome/test/data/extensions/api_test/permissions/optional/manifest.json index 5449678..3611f72 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional/manifest.json +++ b/chrome/test/data/extensions/api_test/permissions/optional/manifest.json @@ -12,7 +12,7 @@ "http://a.com/*" ], "optional_permissions": [ - "tabs", + "bookmarks", "management", "notifications", "background", diff --git a/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js b/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js index 28cae61..6de0e90 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_deny/background.js @@ -6,8 +6,8 @@ var assertFalse = chrome.test.assertFalse; var assertTrue = chrome.test.assertTrue; var pass = chrome.test.callbackPass; -var NO_TABS_PERMISSION = - "You do not have permission to use 'windows.getAll'."; +var NO_BOOKMARKS_PERMISSION = + "You do not have permission to use 'bookmarks.getTree'."; chrome.test.getConfig(function(config) { @@ -37,7 +37,7 @@ chrome.test.getConfig(function(config) { chrome.test.runTests([ function denyRequest() { chrome.permissions.request( - {permissions: ['tabs'], origins: ['http://*.c.com/*']}, + {permissions: ['bookmarks'], origins: ['http://*.c.com/*']}, pass(function(granted) { // They were not granted, and there should be no error. assertFalse(granted); @@ -45,15 +45,15 @@ chrome.test.getConfig(function(config) { // Make sure they weren't granted... chrome.permissions.contains( - {permissions: ['tabs'], origins:['http://*.c.com/*']}, + {permissions: ['bookmarks'], origins:['http://*.c.com/*']}, pass(function(result) { assertFalse(result); })); try { - chrome.windows.getAll({populate: true}, function() { - chrome.test.fail("Should not have tabs API permission."); + chrome.bookmarks.getTree(function() { + chrome.test.fail("Should not have bookmarks API permission."); }); } catch (e) { - assertTrue(e.message.indexOf(NO_TABS_PERMISSION) == 0); + assertTrue(e.message.indexOf(NO_BOOKMARKS_PERMISSION) == 0); } doReq('http://b.c.com/', pass(function(result) { diff --git a/chrome/test/data/extensions/api_test/permissions/optional_deny/manifest.json b/chrome/test/data/extensions/api_test/permissions/optional_deny/manifest.json index 4a0f4e5..949174f 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_deny/manifest.json +++ b/chrome/test/data/extensions/api_test/permissions/optional_deny/manifest.json @@ -7,5 +7,5 @@ "scripts": ["background.js"] }, "permissions": ["http://a.com/*", "management"], - "optional_permissions": ["tabs", "management", "http://*.c.com/*"] + "optional_permissions": ["bookmarks", "management", "http://*.c.com/*"] } diff --git a/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js b/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js index a6f2937..ddda1f6 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js +++ b/chrome/test/data/extensions/api_test/permissions/optional_gesture/background.js @@ -10,7 +10,7 @@ chrome.test.getConfig(function(config) { chrome.test.runTests([ function testGesture() { chrome.permissions.request( - {permissions: ['tabs']}, + {permissions: ['bookmarks']}, fail(GESTURE_ERROR)); } ]); diff --git a/chrome/test/data/extensions/api_test/permissions/optional_gesture/manifest.json b/chrome/test/data/extensions/api_test/permissions/optional_gesture/manifest.json index 9282102..72b6d8e 100644 --- a/chrome/test/data/extensions/api_test/permissions/optional_gesture/manifest.json +++ b/chrome/test/data/extensions/api_test/permissions/optional_gesture/manifest.json @@ -6,5 +6,5 @@ "background": { "scripts": ["background.js"] }, - "optional_permissions": ["tabs"] + "optional_permissions": ["bookmarks"] } |