diff options
Diffstat (limited to 'toolkit/components/extensions/test/mochitest/test_ext_tabs_permissions.html')
-rw-r--r-- | toolkit/components/extensions/test/mochitest/test_ext_tabs_permissions.html | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/mochitest/test_ext_tabs_permissions.html b/toolkit/components/extensions/test/mochitest/test_ext_tabs_permissions.html new file mode 100644 index 0000000000..217139f12b --- /dev/null +++ b/toolkit/components/extensions/test/mochitest/test_ext_tabs_permissions.html @@ -0,0 +1,752 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Tabs permissions test</title> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script> + <script type="text/javascript" src="head.js"></script> + <link rel="stylesheet" href="/tests/SimpleTest/test.css"/> +</head> +<body> + +<script type="text/javascript"> +"use strict"; + +const URL1 = + "https://www.example.com/tests/toolkit/components/extensions/test/mochitest/file_tabs_permission_page1.html"; +const URL2 = + "https://example.net/tests/toolkit/components/extensions/test/mochitest/file_tabs_permission_page2.html"; + +const helperExtensionDef = { + manifest: { + permissions: ["webNavigation", "<all_urls>"], + }, + + async background() { + browser.test.onMessage.addListener(async message => { + switch (message.subject) { + case "createTab": { + const tabLoaded = new Promise(resolve => { + browser.webNavigation.onCompleted.addListener(function listener( + details + ) { + if (details.url === message.data.url) { + browser.webNavigation.onCompleted.removeListener(listener); + resolve(); + } + }); + }); + + const tab = await browser.tabs.create({ url: message.data.url }); + await tabLoaded; + browser.test.sendMessage("tabCreated", tab.id); + break; + } + + case "changeTabURL": { + const tabLoaded = new Promise(resolve => { + browser.webNavigation.onCompleted.addListener(function listener( + details + ) { + if (details.url === message.data.url) { + browser.webNavigation.onCompleted.removeListener(listener); + resolve(); + } + }); + }); + + await browser.tabs.update(message.data.tabId, { + url: message.data.url, + }); + await tabLoaded; + browser.test.sendMessage("tabURLChanged", message.data.tabId); + break; + } + + case "changeTabHashAndTitle": { + const tabChanged = new Promise(resolve => { + let hasURLChangeInfo = false, + hasTitleChangeInfo = false; + browser.tabs.onUpdated.addListener(function listener( + tabId, + changeInfo, + tab + ) { + if (changeInfo.url?.endsWith(message.data.urlHash)) { + hasURLChangeInfo = true; + } + if (changeInfo.title === message.data.title) { + hasTitleChangeInfo = true; + } + if (hasURLChangeInfo && hasTitleChangeInfo) { + browser.tabs.onUpdated.removeListener(listener); + resolve(); + } + }); + }); + + await browser.tabs.executeScript(message.data.tabId, { + code: ` + document.location.hash = ${JSON.stringify(message.data.urlHash)}; + document.title = ${JSON.stringify(message.data.title)}; + `, + }); + await tabChanged; + browser.test.sendMessage("tabHashAndTitleChanged"); + break; + } + + case "removeTab": { + await browser.tabs.remove(message.data.tabId); + browser.test.sendMessage("tabRemoved"); + break; + } + + default: + browser.test.fail(`Received unexpected message: ${message}`); + } + }); + }, +}; + +/* + * Test tabs.query function + * Check if the correct tabs are queried by url or title based on the granted permissions + */ +async function test_query(testCases, permissions) { + const helperExtension = ExtensionTestUtils.loadExtension(helperExtensionDef); + + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions, + }, + + async background() { + // wait for start message + const [testCases, tabIdFromURL1, tabIdFromURL2] = await new Promise( + resolve => { + browser.test.onMessage.addListener(message => resolve(message)); + } + ); + + for (const testCase of testCases) { + const query = testCase.query; + const matchingTabs = testCase.matchingTabs; + + let tabQuery = await browser.tabs.query(query); + // ignore other tabs in the window + tabQuery = tabQuery.filter(tab => { + return tab.id === tabIdFromURL1 || tab.id === tabIdFromURL2; + }); + + browser.test.assertEq(matchingTabs, tabQuery.length, `Tabs queried`); + } + // send end message + browser.test.notifyPass("tabs.query"); + }, + }); + + await helperExtension.startup(); + await extension.startup(); + + helperExtension.sendMessage({ + subject: "createTab", + data: { url: URL1 }, + }); + const tabIdFromURL1 = await helperExtension.awaitMessage("tabCreated"); + + helperExtension.sendMessage({ + subject: "createTab", + data: { url: URL2 }, + }); + const tabIdFromURL2 = await helperExtension.awaitMessage("tabCreated"); + + if (permissions.includes("activeTab")) { + extension.grantActiveTab(tabIdFromURL2); + } + + extension.sendMessage([testCases, tabIdFromURL1, tabIdFromURL2]); + await extension.awaitFinish("tabs.query"); + + helperExtension.sendMessage({ + subject: "removeTab", + data: { tabId: tabIdFromURL1 }, + }); + await helperExtension.awaitMessage("tabRemoved"); + + helperExtension.sendMessage({ + subject: "removeTab", + data: { tabId: tabIdFromURL2 }, + }); + await helperExtension.awaitMessage("tabRemoved"); + + await extension.unload(); + await helperExtension.unload(); +} + +// https://www.example.com host permission +add_task(function query_with_host_permission_url1() { + return test_query( + [ + { + query: { url: "*://www.example.com/*" }, + matchingTabs: 1, + }, + { + query: { url: "<all_urls>" }, + matchingTabs: 1, + }, + { + query: { url: ["*://www.example.com/*", "*://example.net/*"] }, + matchingTabs: 1, + }, + { + query: { title: "The Title" }, + matchingTabs: 1, + }, + { + query: { title: "Another Title" }, + matchingTabs: 0, + }, + { + query: {}, + matchingTabs: 2, + }, + ], + ["*://www.example.com/*"] + ); +}); + +// https://example.net host permission +add_task(function query_with_host_permission_url2() { + return test_query( + [ + { + query: { url: "*://www.example.com/*" }, + matchingTabs: 0, + }, + { + query: { url: "<all_urls>" }, + matchingTabs: 1, + }, + { + query: { url: ["*://www.example.com/*", "*://example.net/*"] }, + matchingTabs: 1, + }, + { + query: { title: "The Title" }, + matchingTabs: 0, + }, + { + query: { title: "Another Title" }, + matchingTabs: 1, + }, + { + query: {}, + matchingTabs: 2, + }, + ], + ["*://example.net/*"] + ); +}); + +// <all_urls> permission +add_task(function query_with_host_permission_all_urls() { + return test_query( + [ + { + query: { url: "*://www.example.com/*" }, + matchingTabs: 1, + }, + { + query: { url: "<all_urls>" }, + matchingTabs: 2, + }, + { + query: { url: ["*://www.example.com/*", "*://example.net/*"] }, + matchingTabs: 2, + }, + { + query: { title: "The Title" }, + matchingTabs: 1, + }, + { + query: { title: "Another Title" }, + matchingTabs: 1, + }, + { + query: {}, + matchingTabs: 2, + }, + ], + ["<all_urls>"] + ); +}); + +// tabs permission +add_task(function query_with_tabs_permission() { + return test_query( + [ + { + query: { url: "*://www.example.com/*" }, + matchingTabs: 1, + }, + { + query: { url: "<all_urls>" }, + matchingTabs: 2, + }, + { + query: { url: ["*://www.example.com/*", "*://example.net/*"] }, + matchingTabs: 2, + }, + { + query: { title: "The Title" }, + matchingTabs: 1, + }, + { + query: { title: "Another Title" }, + matchingTabs: 1, + }, + { + query: {}, + matchingTabs: 2, + }, + ], + ["tabs"] + ); +}); + +// activeTab permission +add_task(function query_with_activeTab_permission() { + return test_query( + [ + { + query: { url: "*://www.example.com/*" }, + matchingTabs: 0, + }, + { + query: { url: "<all_urls>" }, + matchingTabs: 1, + }, + { + query: { url: ["*://www.example.com/*", "*://example.net/*"] }, + matchingTabs: 1, + }, + { + query: { title: "The Title" }, + matchingTabs: 0, + }, + { + query: { title: "Another Title" }, + matchingTabs: 1, + }, + { + query: {}, + matchingTabs: 2, + }, + ], + ["activeTab"] + ); +}); +// no permission +add_task(function query_without_permission() { + return test_query( + [ + { + query: { url: "*://www.example.com/*" }, + matchingTabs: 0, + }, + { + query: { url: "<all_urls>" }, + matchingTabs: 0, + }, + { + query: { url: ["*://www.example.com/*", "*://example.net/*"] }, + matchingTabs: 0, + }, + { + query: { title: "The Title" }, + matchingTabs: 0, + }, + { + query: { title: "Another Title" }, + matchingTabs: 0, + }, + { + query: {}, + matchingTabs: 2, + }, + ], + [] + ); +}); + +/* + * Test tabs.onUpdate and tabs.get function + * Check if the changeInfo or tab object contains the restricted properties + * url and title only when the right permissions are granted + * The tab is updated without causing navigation in order to also test activeTab permission + */ +async function test_restricted_properties( + permissions, + hasRestrictedProperties +) { + const helperExtension = ExtensionTestUtils.loadExtension(helperExtensionDef); + + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions, + }, + + async background() { + // wait for test start signal and data + const [ + hasRestrictedProperties, + tabId, + urlHash, + title, + ] = await new Promise(resolve => { + browser.test.onMessage.addListener(message => { + resolve(message); + }); + }); + + let hasURLChangeInfo = false, + hasTitleChangeInfo = false; + function onUpdateListener(tabId, changeInfo, tab) { + if (changeInfo.url?.endsWith(urlHash)) { + hasURLChangeInfo = true; + } + if (changeInfo.title === title) { + hasTitleChangeInfo = true; + } + } + browser.tabs.onUpdated.addListener(onUpdateListener); + + // wait for test evaluation signal and data + await new Promise(resolve => { + browser.test.onMessage.addListener(message => { + if (message === "collectTestResults") { + resolve(message); + } + }); + browser.test.sendMessage("waitingForTabPropertyChanges"); + }); + + // check onUpdate changeInfo + browser.test.assertEq( + hasRestrictedProperties, + hasURLChangeInfo, + `Has changeInfo property "url"` + ); + browser.test.assertEq( + hasRestrictedProperties, + hasTitleChangeInfo, + `Has changeInfo property "title"` + ); + // check tab properties + const tabGet = await browser.tabs.get(tabId); + browser.test.assertEq( + hasRestrictedProperties, + !!tabGet.url?.endsWith(urlHash), + `Has tab property "url"` + ); + browser.test.assertEq( + hasRestrictedProperties, + tabGet.title === title, + `Has tab property "title"` + ); + // send end message + browser.test.notifyPass("tabs.restricted_properties"); + }, + }); + + const urlHash = "#ChangedURL"; + const title = "Changed Title"; + + await helperExtension.startup(); + await extension.startup(); + + helperExtension.sendMessage({ + subject: "createTab", + data: { url: URL1 }, + }); + const tabId = await helperExtension.awaitMessage("tabCreated"); + + if (permissions.includes("activeTab")) { + extension.grantActiveTab(tabId); + } + // send test start signal and data + extension.sendMessage([hasRestrictedProperties, tabId, urlHash, title]); + await extension.awaitMessage("waitingForTabPropertyChanges"); + + helperExtension.sendMessage({ + subject: "changeTabHashAndTitle", + data: { + tabId, + urlHash, + title, + }, + }); + await helperExtension.awaitMessage("tabHashAndTitleChanged"); + + // send end signal and evaluate results + extension.sendMessage("collectTestResults"); + await extension.awaitFinish("tabs.restricted_properties"); + + helperExtension.sendMessage({ + subject: "removeTab", + data: { tabId }, + }); + await helperExtension.awaitMessage("tabRemoved"); + + await extension.unload(); + await helperExtension.unload(); +} + +// https://www.example.com host permission +add_task(function has_restricted_properties_with_host_permission_url1() { + return test_restricted_properties(["*://www.example.com/*"], true); +}); +// https://example.net host permission +add_task(function has_restricted_properties_with_host_permission_url2() { + return test_restricted_properties(["*://example.net/*"], false); +}); +// <all_urls> permission +add_task(function has_restricted_properties_with_host_permission_all_urls() { + return test_restricted_properties(["<all_urls>"], true); +}); +// tabs permission +add_task(function has_restricted_properties_with_tabs_permission() { + return test_restricted_properties(["tabs"], true); +}); +// activeTab permission +add_task(function has_restricted_properties_with_activeTab_permission() { + return test_restricted_properties(["activeTab"], true); +}).skip(); // TODO bug 1686080: support changeInfo.url with activeTab +// no permission +add_task(function has_restricted_properties_without_permission() { + return test_restricted_properties([], false); +}); + + +/* + * Test tabs.onUpdate filter functionality + * Check if the restricted filter properties only work if the + * right permissions are granted + */ +async function test_onUpdateFilter(testCases, permissions) { + // Filters for onUpdated are not supported on Android. + if (AppConstants.platform === "android") { + return; + } + + const helperExtension = ExtensionTestUtils.loadExtension(helperExtensionDef); + + const extension = ExtensionTestUtils.loadExtension({ + manifest: { + permissions, + }, + + async background() { + let listenerGotCalled = false; + function onUpdateListener(tabId, changeInfo, tab) { + listenerGotCalled = true; + } + + browser.test.onMessage.addListener(async message => { + switch (message.subject) { + case "setup": { + browser.tabs.onUpdated.addListener( + onUpdateListener, + message.data.filter + ); + browser.test.sendMessage("done"); + break; + } + + case "collectTestResults": { + browser.test.assertEq( + message.data.expectEvent, + listenerGotCalled, + `Update listener called` + ); + browser.tabs.onUpdated.removeListener(onUpdateListener); + listenerGotCalled = false; + browser.test.sendMessage("done"); + break; + } + + default: + browser.test.fail(`Received unexpected message: ${message}`); + } + }); + }, + }); + + await helperExtension.startup(); + await extension.startup(); + + for (const testCase of testCases) { + helperExtension.sendMessage({ + subject: "createTab", + data: { url: URL1 }, + }); + const tabId = await helperExtension.awaitMessage("tabCreated"); + + extension.sendMessage({ + subject: "setup", + data: { + filter: testCase.filter, + }, + }); + await extension.awaitMessage("done"); + + helperExtension.sendMessage({ + subject: "changeTabURL", + data: { + tabId, + url: URL2, + }, + }); + await helperExtension.awaitMessage("tabURLChanged"); + + extension.sendMessage({ + subject: "collectTestResults", + data: { + expectEvent: testCase.expectEvent, + }, + }); + await extension.awaitMessage("done"); + + helperExtension.sendMessage({ + subject: "removeTab", + data: { tabId }, + }); + await helperExtension.awaitMessage("tabRemoved"); + } + + await extension.unload(); + await helperExtension.unload(); +} + +// https://mozilla.org host permission +add_task(function onUpdateFilter_with_host_permission_url3() { + return test_onUpdateFilter( + [ + { + filter: { urls: ["*://mozilla.org/*"] }, + expectEvent: false, + }, + { + filter: { urls: ["<all_urls>"] }, + expectEvent: false, + }, + { + filter: { urls: ["*://mozilla.org/*", "*://example.net/*"] }, + expectEvent: false, + }, + { + filter: { properties: ["title"] }, + expectEvent: false, + }, + { + filter: {}, + expectEvent: true, + }, + ], + ["*://mozilla.org/*"] + ); +}); + +// https://example.net host permission +add_task(function onUpdateFilter_with_host_permission_url2() { + return test_onUpdateFilter( + [ + { + filter: { urls: ["*://mozilla.org/*"] }, + expectEvent: false, + }, + { + filter: { urls: ["<all_urls>"] }, + expectEvent: true, + }, + { + filter: { urls: ["*://mozilla.org/*", "*://example.net/*"] }, + expectEvent: true, + }, + { + filter: { properties: ["title"] }, + expectEvent: true, + }, + { + filter: {}, + expectEvent: true, + }, + ], + ["*://example.net/*"] + ); +}); + +// <all_urls> permission +add_task(function onUpdateFilter_with_host_permission_all_urls() { + return test_onUpdateFilter( + [ + { + filter: { urls: ["*://mozilla.org/*"] }, + expectEvent: false, + }, + { + filter: { urls: ["<all_urls>"] }, + expectEvent: true, + }, + { + filter: { urls: ["*://mozilla.org/*", "*://example.net/*"] }, + expectEvent: true, + }, + { + filter: { properties: ["title"] }, + expectEvent: true, + }, + { + filter: {}, + expectEvent: true, + }, + ], + ["<all_urls>"] + ); +}); + +// tabs permission +add_task(function onUpdateFilter_with_tabs_permission() { + return test_onUpdateFilter( + [ + { + filter: { urls: ["*://mozilla.org/*"] }, + expectEvent: false, + }, + { + filter: { urls: ["<all_urls>"] }, + expectEvent: true, + }, + { + filter: { urls: ["*://mozilla.org/*", "*://example.net/*"] }, + expectEvent: true, + }, + { + filter: { properties: ["title"] }, + expectEvent: true, + }, + { + filter: {}, + expectEvent: true, + }, + ], + ["tabs"] + ); +}); + +</script> + +</body> +</html> |