diff options
author | Ajay Ramachandran <[email protected]> | 2022-06-02 21:42:19 -0400 |
---|---|---|
committer | GitHub <[email protected]> | 2022-06-02 21:42:19 -0400 |
commit | 47d4812b92c8a157af2c662aa2eb0600cca50bff (patch) | |
tree | 39136bc0f4f718702f92bb52084c4e5163cea134 | |
parent | ff87a42147b4aaa3a075726c57b0d054755ef2ea (diff) | |
parent | 6202a4d0a3206a3ffa41d0cbacca9a89f6d54c8c (diff) | |
download | SponsorBlock-47d4812b92c8a157af2c662aa2eb0600cca50bff.tar.gz SponsorBlock-47d4812b92c8a157af2c662aa2eb0600cca50bff.zip |
Merge pull request #1322 from NDevTK/master
Move popup to iframe and restrict embeds
-rw-r--r-- | public/popup.html | 6 | ||||
-rw-r--r-- | src/background.ts | 15 | ||||
-rw-r--r-- | src/content.ts | 113 | ||||
-rw-r--r-- | src/help.ts | 8 | ||||
-rw-r--r-- | src/messageTypes.ts | 3 | ||||
-rw-r--r-- | src/options.ts | 3 | ||||
-rw-r--r-- | src/permissions.ts | 3 | ||||
-rw-r--r-- | src/popup.ts | 82 | ||||
-rw-r--r-- | src/utils.ts | 25 | ||||
-rw-r--r-- | src/utils/pageUtils.ts | 25 |
10 files changed, 136 insertions, 147 deletions
diff --git a/public/popup.html b/public/popup.html index b1a241c4..59d58565 100644 --- a/public/popup.html +++ b/public/popup.html @@ -8,9 +8,13 @@ <link id="sponsorBlockStyleSheet" href="popup.css" rel="stylesheet"> </head> - <body id="sponsorBlockPopupBody"> + <body id="sponsorBlockPopupBody" style="visibility: hidden"> <div id="sponsorblockPopup" class="sponsorBlockPageBody sb-preload"> + <button id="sbCloseButton" title="__MSG_closePopup__" class="sbCloseButton hidden"> + <img src="icons/close.png" width="15" height="15"> + </button> + <div id="sbBetaServerWarning" class="hidden" title="__MSG_openOptionsPage__"> __MSG_betaServerWarning__ </div> diff --git a/src/background.ts b/src/background.ts index d576fba1..aa94df5e 100644 --- a/src/background.ts +++ b/src/background.ts @@ -84,7 +84,20 @@ chrome.runtime.onMessage.addListener(function (request, _, callback) { case "unregisterContentScript": unregisterFirefoxContentScript(request.id) return false; - } + case "tabs": + chrome.tabs.query({ + active: true, + currentWindow: true + }, tabs => { + chrome.tabs.sendMessage( + tabs[0].id, + request.data, + (response) => callback(response) + ); + } + ); + return true; + } }); //add help page on install diff --git a/src/content.ts b/src/content.ts index e89bbb2a..75f16766 100644 --- a/src/content.ts +++ b/src/content.ts @@ -5,8 +5,6 @@ import { ContentContainer, Keybind } from "./types"; import Utils from "./utils"; const utils = new Utils(); -import runThePopup from "./popup"; - import PreviewBar, {PreviewBarSegment} from "./js-components/previewBar"; import SkipNotice from "./render/SkipNotice"; import SkipNoticeComponent from "./components/SkipNoticeComponent"; @@ -219,6 +217,9 @@ function messageListener(request: Message, sender: unknown, sendResponse: (respo utils.addHiddenSegment(sponsorVideoID, request.UUID, request.type); updatePreviewBar(); break; + case "closePopup": + closeInfoMenu(); + break; } } @@ -1686,73 +1687,30 @@ function openInfoMenu() { //hide info button if (playerButtons.info) playerButtons.info.button.style.display = "none"; - sendRequestToCustomServer('GET', chrome.extension.getURL("popup.html"), function(xmlhttp) { - if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { - const popup = document.createElement("div"); - popup.id = "sponsorBlockPopupContainer"; - - let htmlData = xmlhttp.responseText; - // Hack to replace head data (title, favicon) - htmlData = htmlData.replace(/<head>[\S\s]*<\/head>/gi, ""); - // Hack to replace body and html tag with div - htmlData = htmlData.replace(/<body/gi, "<div"); - htmlData = htmlData.replace(/<\/body/gi, "</div"); - htmlData = htmlData.replace(/<html/gi, "<div"); - htmlData = htmlData.replace(/<\/html/gi, "</div"); - - popup.innerHTML = htmlData; - - //close button - const closeButton = document.createElement("button"); - const closeButtonIcon = document.createElement("img"); - closeButtonIcon.src = chrome.extension.getURL("icons/close.png"); - closeButtonIcon.width = 15; - closeButtonIcon.height = 15; - closeButton.appendChild(closeButtonIcon); - closeButton.setAttribute("title", chrome.i18n.getMessage("closePopup")); - closeButton.classList.add("sbCloseButton"); - closeButton.addEventListener("click", closeInfoMenu); - - //add the close button - popup.prepend(closeButton); - - const parentNodes = document.querySelectorAll("#secondary"); - let parentNode = null; - for (let i = 0; i < parentNodes.length; i++) { - if (parentNodes[i].firstElementChild !== null) { - parentNode = parentNodes[i]; - } - } - if (parentNode == null) { - //old youtube theme - parentNode = document.getElementById("watch7-sidebar-contents"); - } - - //make the logo source not 404 - //query selector must be used since getElementByID doesn't work on a node and this isn't added to the document yet - const logo = <HTMLImageElement> popup.querySelector("#sponsorBlockPopupLogo"); - const settings = <HTMLImageElement> popup.querySelector("#sbPopupIconSettings"); - const edit = <HTMLImageElement> popup.querySelector("#sbPopupIconEdit"); - const copy = <HTMLImageElement> popup.querySelector("#sbPopupIconCopyUserID"); - const check = <HTMLImageElement> popup.querySelector("#sbPopupIconCheck"); - const refreshSegments = <HTMLImageElement> popup.querySelector("#refreshSegments"); - const heart = <HTMLImageElement> popup.querySelector(".sbHeart"); - const close = <HTMLImageElement> popup.querySelector("#sbCloseDonate"); - logo.src = chrome.extension.getURL("icons/IconSponsorBlocker256px.png"); - settings.src = chrome.extension.getURL("icons/settings.svg"); - edit.src = chrome.extension.getURL("icons/pencil.svg"); - copy.src = chrome.extension.getURL("icons/clipboard.svg"); - check.src = chrome.extension.getURL("icons/check.svg"); - heart.src = chrome.extension.getURL("icons/heart.svg"); - close.src = chrome.extension.getURL("icons/close.png"); - refreshSegments.src = chrome.extension.getURL("icons/refresh.svg"); - - parentNode.insertBefore(popup, parentNode.firstChild); - - //run the popup init script - runThePopup(messageListener); + + const popup = document.createElement("div"); + popup.id = "sponsorBlockPopupContainer"; + + const frame = document.createElement("iframe"); + frame.width = "374"; + frame.height = "500"; + frame.addEventListener("load", () => frame.contentWindow.postMessage("", "*")); + frame.src = chrome.extension.getURL("popup.html"); + popup.appendChild(frame); + + const parentNodes = document.querySelectorAll("#secondary"); + let parentNode = null; + for (let i = 0; i < parentNodes.length; i++) { + if (parentNodes[i].firstElementChild !== null) { + parentNode = parentNodes[i]; } - }); + } + if (parentNode == null) { + //old youtube theme + parentNode = document.getElementById("watch7-sidebar-contents"); + } + + parentNode.insertBefore(popup, parentNode.firstChild); } function closeInfoMenu() { @@ -2113,25 +2071,6 @@ function addCSS() { } } -function sendRequestToCustomServer(type, fullAddress, callback) { - const xmlhttp = new XMLHttpRequest(); - - xmlhttp.open(type, fullAddress, true); - - if (callback != undefined) { - xmlhttp.onreadystatechange = function () { - callback(xmlhttp, false); - }; - - xmlhttp.onerror = function() { - callback(xmlhttp, true); - }; - } - - //submit this request - xmlhttp.send(); -} - /** * Update the isAdPlaying flag and hide preview bar/controls if ad is playing */ diff --git a/src/help.ts b/src/help.ts index 6f3945df..9cc6b4bd 100644 --- a/src/help.ts +++ b/src/help.ts @@ -1,15 +1,15 @@ import Config from "./config"; import { showDonationLink } from "./utils/configUtils"; -import Utils from "./utils"; -const utils = new Utils(); +import { localizeHtmlPage } from "./utils/pageUtils"; +import { GenericUtils } from "./utils/genericUtils"; window.addEventListener('DOMContentLoaded', init); async function init() { - utils.localizeHtmlPage(); + localizeHtmlPage(); - await utils.wait(() => Config.config !== null); + await GenericUtils.wait(() => Config.config !== null); if (!Config.config.darkMode) { document.documentElement.setAttribute("data-theme", "light"); diff --git a/src/messageTypes.ts b/src/messageTypes.ts index adabbee5..45941ee4 100644 --- a/src/messageTypes.ts +++ b/src/messageTypes.ts @@ -16,7 +16,8 @@ interface DefaultMessage { | "getChannelID" | "isChannelWhitelisted" | "submitTimes" - | "refreshSegments"; + | "refreshSegments" + | "closePopup"; } interface BoolValueMessage { diff --git a/src/options.ts b/src/options.ts index a1ddc234..8d074e38 100644 --- a/src/options.ts +++ b/src/options.ts @@ -12,13 +12,14 @@ import Utils from "./utils"; import CategoryChooser from "./render/CategoryChooser"; import KeybindComponent from "./components/KeybindComponent"; import { showDonationLink } from "./utils/configUtils"; +import { localizeHtmlPage } from "./utils/pageUtils"; const utils = new Utils(); let embed = false; window.addEventListener('DOMContentLoaded', init); async function init() { - utils.localizeHtmlPage(); + localizeHtmlPage(); // selected tab if (location.hash != "") { diff --git a/src/permissions.ts b/src/permissions.ts index 558f0c3f..05da496e 100644 --- a/src/permissions.ts +++ b/src/permissions.ts @@ -1,5 +1,6 @@ import Config from "./config"; import Utils from "./utils"; +import { localizeHtmlPage } from "./utils/pageUtils"; const utils = new Utils(); // This is needed, if Config is not imported before Utils, things break. @@ -9,7 +10,7 @@ Config.config; window.addEventListener('DOMContentLoaded', init); async function init() { - utils.localizeHtmlPage(); + localizeHtmlPage(); const domains = document.location.hash.replace("#", "").split(","); diff --git a/src/popup.ts b/src/popup.ts index 504229fc..92b5fe01 100644 --- a/src/popup.ts +++ b/src/popup.ts @@ -6,6 +6,7 @@ import { Message, MessageResponse, IsInfoFoundMessageResponse } from "./messageT import { showDonationLink } from "./utils/configUtils"; import { AnimationUtils } from "./utils/animationUtils"; import { GenericUtils } from "./utils/genericUtils"; +import { localizeHtmlPage } from "./utils/pageUtils"; const utils = new Utils(); interface MessageListener { @@ -22,13 +23,15 @@ class MessageHandler { sendMessage(id: number, request: Message, callback?) { if (this.messageListener) { this.messageListener(request, null, callback); - } else { + } else if (chrome.tabs) { chrome.tabs.sendMessage(id, request, callback); + } else { + chrome.runtime.sendMessage({ message: "tabs", data: request }, callback); } } query(config, callback) { - if (this.messageListener) { + if (this.messageListener || !chrome.tabs) { // Send back dummy info callback([{ url: document.URL, @@ -41,15 +44,17 @@ class MessageHandler { } } - +// To prevent clickjacking +let allowPopup = window === window.top; +window.addEventListener("message", async (e) => { + if (e.source !== window.parent) return; + if (e.origin.endsWith('.youtube.com')) return allowPopup = true; +}); //make this a function to allow this to run on the content page async function runThePopup(messageListener?: MessageListener): Promise<void> { const messageHandler = new MessageHandler(messageListener); - - utils.localizeHtmlPage(); - - await utils.wait(() => Config.config !== null); + localizeHtmlPage(); type InputPageElements = { whitelistToggle?: HTMLInputElement, @@ -58,6 +63,15 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { }; type PageElements = { [key: string]: HTMLElement } & InputPageElements + /** If true, the content script is in the process of creating a new segment. */ + let creatingSegment = false; + + //the start and end time pairs (2d) + let sponsorTimes: SponsorTime[] = []; + + //current video ID of this tab + let currentVideoID = null; + const PageElements: PageElements = {}; [ @@ -112,9 +126,24 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { "sponsorTimesDonateContainer", "sbConsiderDonateLink", "sbCloseDonate", - "sbBetaServerWarning" + "sbBetaServerWarning", + "sbCloseButton" ].forEach(id => PageElements[id] = document.getElementById(id)); + getSegmentsFromContentScript(false); + await utils.wait(() => Config.config !== null && allowPopup, 5000, 5); + document.querySelector("body").style.removeProperty("visibility"); + + PageElements.sbCloseButton.addEventListener("click", () => { + sendTabMessage({ + message: "closePopup" + }); + }); + + if (window !== window.top) { + PageElements.sbCloseButton.classList.remove("hidden"); + } + // Hide donate button if wanted (Safari, or user choice) if (!showDonationLink()) { PageElements.sbDonate.style.display = "none"; @@ -151,15 +180,6 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { PageElements.refreshSegmentsButton.addEventListener("click", refreshSegments); PageElements.sbPopupIconCopyUserID.addEventListener("click", async () => navigator.clipboard.writeText(await utils.getHash(Config.config.userID))); - /** If true, the content script is in the process of creating a new segment. */ - let creatingSegment = false; - - //the start and end time pairs (2d) - let sponsorTimes: SponsorTime[] = []; - - //current video ID of this tab - let currentVideoID = null; - //show proper disable skipping button const disableSkipping = Config.config.disableSkipping; if (disableSkipping != undefined && disableSkipping) { @@ -239,8 +259,6 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { // Must be delayed so it only happens once loaded setTimeout(() => PageElements.sponsorblockPopup.classList.remove("preload"), 250); - getSegmentsFromContentScript(false); - function showDonateWidget(viewCount: number) { if (Config.config.showDonationLink && Config.config.donateClicked <= 0 && Config.config.showPopupDonationCount < 5 && viewCount < 50000 && !Config.config.isVip && Config.config.skipCount > 10) { @@ -272,13 +290,14 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { }); } - function loadTabData(tabs, updating: boolean): void { + async function loadTabData(tabs, updating: boolean): Promise<void> { if (!currentVideoID) { //this isn't a YouTube video then displayNoVideo(); return; } + await utils.wait(() => Config.config !== null, 5000, 10); sponsorTimes = Config.config.unsubmittedSegments[currentVideoID] ?? []; updateSegmentEditingUI(); @@ -578,6 +597,22 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { chrome.runtime.sendMessage({ "message": "openHelp" }); } + function sendTabMessage(data: Message): Promise<unknown> { + return new Promise((resolve) => { + messageHandler.query({ + active: true, + currentWindow: true + }, tabs => { + messageHandler.sendMessage( + tabs[0].id, + data, + (response) => resolve(response) + ); + } + ); + }); + } + //make the options username setting option visible function setUsernameButton() { PageElements.usernameInput.value = PageElements.usernameValue.innerText; @@ -822,9 +857,4 @@ async function runThePopup(messageListener?: MessageListener): Promise<void> { //end of function } -if (chrome.tabs != undefined) { - //this means it is actually opened in the popup - runThePopup(); -} - -export default runThePopup; +runThePopup(); diff --git a/src/utils.ts b/src/utils.ts index d89e1a3d..f72f4dd0 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -256,31 +256,6 @@ export default class Utils { } } - localizeHtmlPage(): void { - //Localize by replacing __MSG_***__ meta tags - const localizedMessage = this.getLocalizedMessage(document.title); - if (localizedMessage) document.title = localizedMessage; - const objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children; - for (let j = 0; j < objects.length; j++) { - const obj = objects[j]; - const localizedMessage = this.getLocalizedMessage(obj.innerHTML.toString()); - if (localizedMessage) obj.innerHTML = localizedMessage; - } - } - - getLocalizedMessage(text: string): string | false { - const valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) { - return v1 ? chrome.i18n.getMessage(v1).replace(/</g, "<") - .replace(/"/g, """).replace(/\n/g, "<br/>") : ""; - }); - - if(valNewH != text) { - return valNewH; - } else { - return false; - } - } - /** * @returns {String[]} Domains in regex form */ diff --git a/src/utils/pageUtils.ts b/src/utils/pageUtils.ts index 8f484d73..2cd07b87 100644 --- a/src/utils/pageUtils.ts +++ b/src/utils/pageUtils.ts @@ -61,4 +61,29 @@ export function getHashParams(): Record<string, unknown> { } return {}; +} + +export function localizeHtmlPage(): void { + //Localize by replacing __MSG_***__ meta tags + const localizedMessage = getLocalizedMessage(document.title); + if (localizedMessage) document.title = localizedMessage; + const objects = document.getElementsByClassName("sponsorBlockPageBody")[0].children; + for (let j = 0; j < objects.length; j++) { + const obj = objects[j]; + const localizedMessage = getLocalizedMessage(obj.innerHTML.toString()); + if (localizedMessage) obj.innerHTML = localizedMessage; + } +} + +export function getLocalizedMessage(text: string): string | false { + const valNewH = text.replace(/__MSG_(\w+)__/g, function(match, v1) { + return v1 ? chrome.i18n.getMessage(v1).replace(/</g, "<") + .replace(/"/g, """).replace(/\n/g, "<br/>") : ""; + }); + + if (valNewH != text) { + return valNewH; + } else { + return false; + } }
\ No newline at end of file |