aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAjay Ramachandran <[email protected]>2022-06-02 21:42:19 -0400
committerGitHub <[email protected]>2022-06-02 21:42:19 -0400
commit47d4812b92c8a157af2c662aa2eb0600cca50bff (patch)
tree39136bc0f4f718702f92bb52084c4e5163cea134
parentff87a42147b4aaa3a075726c57b0d054755ef2ea (diff)
parent6202a4d0a3206a3ffa41d0cbacca9a89f6d54c8c (diff)
downloadSponsorBlock-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.html6
-rw-r--r--src/background.ts15
-rw-r--r--src/content.ts113
-rw-r--r--src/help.ts8
-rw-r--r--src/messageTypes.ts3
-rw-r--r--src/options.ts3
-rw-r--r--src/permissions.ts3
-rw-r--r--src/popup.ts82
-rw-r--r--src/utils.ts25
-rw-r--r--src/utils/pageUtils.ts25
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, "&#60;")
- .replace(/"/g, "&quot;").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, "&#60;")
+ .replace(/"/g, "&quot;").replace(/\n/g, "<br/>") : "";
+ });
+
+ if (valNewH != text) {
+ return valNewH;
+ } else {
+ return false;
+ }
} \ No newline at end of file