From 7ffc4d5315150945bf9f3a043482e75a1e863da3 Mon Sep 17 00:00:00 2001 From: Nikkel Mollenhauer <57323886+NikkelM@users.noreply.github.com> Date: Thu, 19 Dec 2024 13:54:30 +0100 Subject: [PATCH 1/3] Removed non-required tabs permission --- src/background.js | 3 ++- src/html/popup/popup.js | 7 ++++--- src/html/welcome.js | 28 +++++++++++++--------------- static/firefox-manifest-extra.json | 3 --- static/manifest.json | 6 ++++-- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/src/background.js b/src/background.js index e4cd897c..13015f0d 100644 --- a/src/background.js +++ b/src/background.js @@ -24,7 +24,7 @@ async function initExtension() { await setSyncStorageValue("previousVersion", manifestData.version); const welcomeUrl = chrome.runtime.getURL("html/welcome.html"); await chrome.tabs.create({ url: welcomeUrl }); - } else if (isFirefox && !await browser.permissions.contains({ permissions: ["tabs"], origins: ["*://*.youtube.com/*"] })) { + } else if (isFirefox && !await browser.permissions.contains({ origins: ["*://*.youtube.com/*"] })) { console.log("The extension is running in Firefox and does not have the required permissions."); const welcomeUrl = chrome.runtime.getURL("html/welcome.html"); await chrome.tabs.create({ url: welcomeUrl }); @@ -360,6 +360,7 @@ function rot13(message, encrypt) { } // Get all tabs whose url is a YouTube page. Content scripts cannot access the chrome.tabs API +// We are allowed to query tabs for which we have host permissions even without the tabs permission async function getAllYouTubeTabs() { return await chrome.tabs.query({ url: "*://*.youtube.com/*" }); } diff --git a/src/html/popup/popup.js b/src/html/popup/popup.js index c9cb16d0..cbba3869 100644 --- a/src/html/popup/popup.js +++ b/src/html/popup/popup.js @@ -374,6 +374,7 @@ async function setPopupDomElementEventListeners(domElements) { const shufflingPageIsShuffling = await chrome.runtime.sendMessage({ command: "getShufflingPageShuffleStatus" }); // If the page is not shuffling, close it if it exists, as that means an error was encountered if (!shufflingPageIsShuffling) { + // TODO: Try to get the exact page we want (extension ID needed) const tabs = await chrome.tabs.query({}); for (const tab of tabs) { if (tab.url === shufflingPage) { @@ -459,11 +460,11 @@ async function setPopupDomElementEventListeners(domElements) { // When the popup is opened, checks if an overlay should be shown async function determineOverlayVisibility(domElements) { // If we are on Firefox and have not been granted permissions, show the overlay and then ask for permissions - if (isFirefox && !await browser.permissions.contains({ permissions: ["tabs"], origins: ["*://*.youtube.com/*"] })) { + if (isFirefox && !await browser.permissions.contains({ origins: ["*://*.youtube.com/*"] })) { domElements.firefoxPermissionsNeededDiv.classList.remove("hidden"); domElements.firefoxPermissionsNeededButton.addEventListener("click", async function () { - browser.permissions.request({ permissions: ["tabs"], origins: ["*://*.youtube.com/*"] }); + browser.permissions.request({ origins: ["*://*.youtube.com/*"] }); window.close(); }); } else { @@ -506,7 +507,7 @@ async function updateDomElementsDependentOnChannel(domElements) { updateChannelSettingsDropdownMenu(domElements); // ----- Popup shuffle button ----- - domElements.popupShuffleButton.innerText = configSync.currentChannelName ? `Shuffle from: ${configSync.currentChannelName}`: "This will be a shuffle button!"; + domElements.popupShuffleButton.innerText = configSync.currentChannelName ? `Shuffle from: ${configSync.currentChannelName}` : "This will be a shuffle button!"; } async function updateChannelSettingsDropdownMenu(domElements) { diff --git a/src/html/welcome.js b/src/html/welcome.js index 6366856a..2e500735 100644 --- a/src/html/welcome.js +++ b/src/html/welcome.js @@ -8,18 +8,17 @@ const isFirefox = typeof browser !== "undefined"; const domElements = getDomElements(); let mayShowReloadAllYouTubePagesDiv = false; -chrome.tabs.query({}, function (tabs) { - for (let i = 0; i <= tabs.length - 1; i++) { - if (tabs[i].url.split("/")[2]?.includes("youtube")) { - mayShowReloadAllYouTubePagesDiv = true; - // Immediately show if we are not waiting for Firefox permissions - if (!isFirefox) { - domElements.needToReloadYouTubePagesDiv.classList.remove("hidden"); - } - break; +let tabs = await chrome.runtime.sendMessage({ command: "getAllYouTubeTabs" }) ?? []; +for (let i = 0; i <= tabs.length - 1; i++) { + if (tabs[i].url.split("/")[2]?.includes("youtube")) { + mayShowReloadAllYouTubePagesDiv = true; + // Immediately show if we are not waiting for Firefox permissions + if (!isFirefox || await browser.permissions.contains({ origins: ["*://*.youtube.com/*"] })) { + domElements.needToReloadYouTubePagesDiv.classList.remove("hidden"); } + break; } -}); +} // --- Set headers --- const currentVersion = chrome.runtime.getManifest().version_name ?? chrome.runtime.getManifest().version; @@ -66,7 +65,7 @@ function getDomElements() { // Set event listeners for DOM elements async function setPopupDomElementEventListeners(domElements) { // Firefox permissions button - if (isFirefox && !await browser.permissions.contains({ permissions: ["tabs"], origins: ["*://*.youtube.com/*"] })) { + if (isFirefox && !await browser.permissions.contains({ origins: ["*://*.youtube.com/*"] })) { domElements.firefoxPermissionsDiv.classList.remove("hidden"); // This is so important that we will use a browser alert window to make sure the user sees and acknowledges it @@ -76,7 +75,7 @@ async function setPopupDomElementEventListeners(domElements) { domElements.giveFirefoxPermissionsButton.addEventListener("click", async function () { await requestFirefoxPermissions(); // If permissions were not granted we must ask again, without them the extension does not work - if (!await browser.permissions.contains({ permissions: ["tabs"], origins: ["*://*.youtube.com/*"] })) { + if (!await browser.permissions.contains({ origins: ["*://*.youtube.com/*"] })) { alert("You need to grant the extension permission to run on YouTube in order to use it. Please grant permissions.") } else { domElements.firefoxPermissionsDiv.classList.add("hidden"); @@ -89,7 +88,7 @@ async function setPopupDomElementEventListeners(domElements) { // Reload all YouTube pages button domElements.reloadAllYouTubePagesButton.addEventListener("click", async function () { - let tabs = await chrome.tabs.query({}); + let tabs = await chrome.runtime.sendMessage({ command: "getAllYouTubeTabs" }) ?? []; for (let i = 0; i <= tabs.length - 1; i++) { if (tabs[i].url.split("/")[2]?.includes("youtube")) { chrome.tabs.reload(tabs[i].id); @@ -125,8 +124,7 @@ async function setPopupDomElementEventListeners(domElements) { async function requestFirefoxPermissions() { const permissionsToRequest = { - permissions: ["tabs"], origins: ["*://*.youtube.com/*"] } await browser.permissions.request(permissionsToRequest); -} \ No newline at end of file +} diff --git a/static/firefox-manifest-extra.json b/static/firefox-manifest-extra.json index ac1fd7dd..46a58b5a 100644 --- a/static/firefox-manifest-extra.json +++ b/static/firefox-manifest-extra.json @@ -9,9 +9,6 @@ "id": "RandomYouTubeVideo@NikkelM" } }, - "optional_permissions": [ - "tabs" - ], "options_ui": { "page": "html/popup.html" } diff --git a/static/manifest.json b/static/manifest.json index 414ec9f0..20426edd 100644 --- a/static/manifest.json +++ b/static/manifest.json @@ -16,8 +16,10 @@ } ], "permissions": [ - "storage", - "tabs" + "storage" + ], + "host_permissions": [ + "*://*.youtube.com/*" ], "action": { "default_popup": "html/popup.html", From 0261e9ff49a09b9eb37d0eab8224b66c410a08bf Mon Sep 17 00:00:00 2001 From: Nikkel Mollenhauer <57323886+NikkelM@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:25:00 +0100 Subject: [PATCH 2/3] Refactored tryFocusingTab to only query the requested tab URL (pattern) --- CHANGELOG.md | 8 ++++++-- src/html/htmlUtils.js | 6 +++++- src/html/popup/popup.js | 11 +++++------ src/html/shufflingPage.js | 6 +++--- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7034d2b2..67d9439b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ # Changelog -## v3.1.11 +## v3.1.12 +- Removed "tabs" permission from the extension, enhancing privacy. + + +## v3.1.11 + - Changed the default settings to not open shuffled videos in a new tab. - Moved the informative text about remaining YouTube API quota to the advanced settings menu. - Updated the welcome page for a better experience. - ## v3.1.10 diff --git a/src/html/htmlUtils.js b/src/html/htmlUtils.js index 43753622..84efb301 100644 --- a/src/html/htmlUtils.js +++ b/src/html/htmlUtils.js @@ -67,9 +67,13 @@ function adjustParentContainerHeight(childElement, heightChange) { } // ----- Tab interaction ----- +// For Chromium, we are not allowed to query our own tabs, so this will always return mustOpenTab = true for Chromium with the current use cases +// This is not a big problem, as we only use it to query if the changelog page is already open, or the shuffling page had an error and should be automatically closed export async function tryFocusingTab(tabUrl) { let mustOpenTab = true; - let tabs = await chrome.tabs.query({}); + // Only query for the requested URL (pattern), as we have not been granted the tabs permission which would allow querying all tabs + let tabs = await chrome.tabs.query({ url: tabUrl }); + for (let i = 0; i <= tabs.length - 1; i++) { if (tabs[i].url === tabUrl) { // An instance of the page already exists, so don't create a new one diff --git a/src/html/popup/popup.js b/src/html/popup/popup.js index cbba3869..72235ead 100644 --- a/src/html/popup/popup.js +++ b/src/html/popup/popup.js @@ -368,25 +368,24 @@ async function setPopupDomElementEventListeners(domElements) { // Popup shuffle button domElements.popupShuffleButton.addEventListener("click", async function () { - const shufflingPage = chrome.runtime.getURL("html/shufflingPage.html"); + const shufflingPageUrl = chrome.runtime.getURL("html/shufflingPage.html"); // Get the status of the shufflingPage, if it exists const shufflingPageIsShuffling = await chrome.runtime.sendMessage({ command: "getShufflingPageShuffleStatus" }); // If the page is not shuffling, close it if it exists, as that means an error was encountered if (!shufflingPageIsShuffling) { - // TODO: Try to get the exact page we want (extension ID needed) - const tabs = await chrome.tabs.query({}); + const tabs = await chrome.tabs.query({ url: shufflingPageUrl }); for (const tab of tabs) { - if (tab.url === shufflingPage) { + if (tab.url === shufflingPageUrl) { chrome.tabs.remove(tab.id); break; } } } - let mustOpenTab = await tryFocusingTab(shufflingPage); + let mustOpenTab = await tryFocusingTab(shufflingPageUrl); if (mustOpenTab) { - await chrome.tabs.create({ url: shufflingPage }); + await chrome.tabs.create({ url: shufflingPageUrl }); } // Close the popup diff --git a/src/html/shufflingPage.js b/src/html/shufflingPage.js index d4c56af8..12fa5d83 100644 --- a/src/html/shufflingPage.js +++ b/src/html/shufflingPage.js @@ -64,10 +64,10 @@ async function setDomElementEventListeners(domElements) { domElements.viewChangelogButton.addEventListener("click", async function () { await setSyncStorageValue("lastViewedChangelogVersion", chrome.runtime.getManifest().version); - const tabUrl = chrome.runtime.getURL("html/changelog.html"); - let mustOpenTab = await tryFocusingTab(tabUrl); + const changelogUrl = chrome.runtime.getURL("html/changelog.html"); + let mustOpenTab = await tryFocusingTab(changelogUrl); if (mustOpenTab) { - window.open(tabUrl, "_blank"); + window.open(changelogUrl, "_blank"); } }); } From 0c2be8693145a1a9f03dd710847ce0718f9106dc Mon Sep 17 00:00:00 2001 From: Nikkel Mollenhauer <57323886+NikkelM@users.noreply.github.com> Date: Thu, 19 Dec 2024 14:30:53 +0100 Subject: [PATCH 3/3] Bumped version --- package-lock.json | 4 ++-- package.json | 2 +- static/manifest.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index abd3ab47..c82b3b01 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "random-youtube-video", - "version": "3.1.10", + "version": "3.1.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "random-youtube-video", - "version": "3.1.10", + "version": "3.1.12", "dependencies": { "@babel/runtime": "^7.18.6", "firebase": "^9.22.0" diff --git a/package.json b/package.json index 8e577593..79a741c0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "random-youtube-video", - "version": "3.1.11", + "version": "3.1.12", "description": "Customize, shuffle and play random videos from any YouTube channel.", "scripts": { "dev": "concurrently \"npm run dev:chromium\" \"npm run dev:firefox\"", diff --git a/static/manifest.json b/static/manifest.json index 20426edd..f70a1ee7 100644 --- a/static/manifest.json +++ b/static/manifest.json @@ -1,8 +1,8 @@ { "name": "Random YouTube Video", "description": "Customize, shuffle and play random videos from any YouTube channel.", - "version": "3.1.11", - "version_name": "3.1.11", + "version": "3.1.12", + "version_name": "3.1.12", "manifest_version": 3, "content_scripts": [ {