diff --git a/extension/config.js b/extension/config.js index 14e69bc..43eff63 100644 --- a/extension/config.js +++ b/extension/config.js @@ -1,5 +1,9 @@ +const vendor = (BrowserDetect.browser == "Firefox" ? browser : chrome); +const manifestData = vendor.runtime.getManifest(); +const version = manifestData.version; + var config = {}; -config.version = "2.8.0"; +config.version = version; config.min_port = 8913; config.max_port = 8918; config.host_local = "localhost"; diff --git a/extension/focus-connection.js b/extension/focus-connection.js index 034d215..7832e9d 100644 --- a/extension/focus-connection.js +++ b/extension/focus-connection.js @@ -5,6 +5,7 @@ // function FocusConnection() { + this.isFocusing = false; this.version = "0.0"; this.platform = "unknown"; this.min_port = config.min_port; @@ -21,16 +22,36 @@ function FocusConnection() { console.log("Creating new Focus connection to " + endpoint); - var allowedMsgs = ["focus", "unfocus"]; - - // Overridden by browser extensions - this.focus = function() {}; - this.unfocus = function() {}; - this.cleanup = function() {}; + var allowedMsgs = ["focus", "unfocus", "block"]; var ws = new ReconnectingWebSocket(endpoint); - ws.ping = function() { + this.focus = () => { + console.log("Focus"); + this.isFocusing = true; + this.onfocus(); + }; + + this.unfocus = function () { + console.log("Unfocus"); + this.isFocusing = false; + }; + + this.cleanup = function () { + console.log("Cleanup"); + this.isFocusing = false; + }; + + this.check = function (tabId, url) { + if (!this.isFocusing) return false; + ws.send(JSON.stringify({ + "msg": "check", + "tabId": tabId, + "url": url + })); + }; + + ws.ping = function () { console.log("Sending ping to Focus"); ws.send(JSON.stringify({ "msg": "ping", @@ -39,12 +60,12 @@ function FocusConnection() { })); }; - ws.onopen = function() { + ws.onopen = function () { console.log("Websocket is open"); ws.ping(); - }; + } - ws.onerror = function(err) { + ws.onerror = function (err) { console.log("Websocket error: " + err); self.port = self.port - 1; if (self.port < self.min_port) { @@ -55,12 +76,12 @@ function FocusConnection() { self.cleanup(); }; - ws.onclose = function() { + ws.onclose = function () { console.log("Websocket is closed"); self.cleanup(); }; - ws.onmessage = function(evt) { + ws.onmessage = function (evt) { console.log("Received message from server"); try { diff --git a/extension/focus.js b/extension/focus.js index ca7528d..fb9b0a6 100644 --- a/extension/focus.js +++ b/extension/focus.js @@ -1,103 +1,60 @@ -var vendor = getBrowserType(); +const blockURL = vendor.extension.getURL("/block.html"); -var conn = new FocusConnection(); +const conn = new FocusConnection(); conn.version = config.version; conn.platform = BrowserDetect.browser; -var isWhitelist = false; -var isFocusing = false; -var enableCloseBrowserTabs = false; -var redirectURL; -var regexSites = []; -var compiledRegexSites = []; -function reset() { - isWhitelist = false; - isFocusing = false; - regexSites = []; - compiledRegexSites = []; -} - -conn.focus = function (data) { - - regexSites = []; - compiledRegexSites = []; - - if (!data.regexSites || data.regexSites.length == 0) { - return; - } - - console.log("Focusing"); - - isWhitelist = data.whitelist; - regexSites = data.regexSites; - compiledRegexSites = compileRegexSites(data.regexSites); - isFocusing = true; - redirectURL = data.redirectURL; - - var filters = { urls: [""], types: ["main_frame", "sub_frame"] }; - var extraInfoSpec = ["blocking"]; - - reloadShouldBeBlockedPages(compiledRegexSites); - - processTabs(); -}; - -conn.unfocus = function () { - console.log("Unfocusing"); - reset(); - reloadBlockedPages(); -}; - -conn.cleanup = function () { - console.log("Cleaning up request handler"); - reset(); -}; - -conn.connect(); -conn.focus({ regexSites: [{ regexUrlStr: ".*reddit.com.*" }] }); +function processFrontmostTab() { + console.log("Processing front-most tab"); + vendor.windows.getCurrent({ populate: true }, function (currentWindow) { + for (var i = 0; i < currentWindow.tabs.length; i++) { + const tab = currentWindow.tabs[i]; + if (tab.active) { + processTab(tab.id, tab.url); + break; + } + } + }); +} function handleBeforeNavigate(navDetails) { - if (!isFocusing) { return } - //console.log("handleBeforeNavigate"); + if (!conn.isFocusing) { return } if (navDetails.frameId == 0) { - checkTabURL(navDetails.tabId, navDetails.url); + processTab(navDetails.tabId, navDetails.url); } } -function processTabs() { - //console.log("processTabs"); +function convertRedirectURLToLocalTemplate(redirectURL) { + const url = new URL(redirectURL); + const templateURL = new URL(blockURL); + templateURL.search = url.search; + return templateURL.toString(); +} - vendor.tabs.query({}, function (tabs) { - if (vendor.runtime.lastError) { - console.log("error fetching tabs", error); - return; - } - for (let tab of tabs) { - checkTabURL(tab.id, tab.url); - } - }); +function processTab(tabId, url) { + if (url.indexOf(blockURL) == 0) return; + conn.check(tabId, url); } -function checkTabURL(tabId, url) { - if (url.indexOf("about:") == 0) { - return false; - } +vendor.webNavigation.onBeforeNavigate.addListener(handleBeforeNavigate); - if (urlIsBlocked(url, compiledRegexSites, isWhitelist)) { - const quote = "Hello"; - const author = "World"; - var blockURL = chrome.extension.getURL('/block.html'); - var newURL = `${blockURL}?url=${encodeURIComponent(url)}"e=${encodeURIComponent(quote)}&author=${encodeURIComponent(author)}`; - chrome.tabs.update(tabId, { url: newURL }); - return true; - } +conn.block = function (data) { + if (!data.url) return; + if (!data.redirectURL) return; + if (!data.tabId) return; + console.log(`blocking ${data.url}`); - return false; -} + const redirectURL = convertRedirectURLToLocalTemplate(data.redirectURL); -vendor.webNavigation.onBeforeNavigate.addListener(handleBeforeNavigate); + vendor.tabs.update(data.tabId, { url: redirectURL }); +}; + +conn.onfocus = function () { + processFrontmostTab(); +} +conn.connect(); diff --git a/extension/manifest.json b/extension/manifest.json index 33b57d5..23923d3 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -14,7 +14,6 @@ "scripts": [ "browserdetect.js", "config.js", - "utils.js", "reconnecting-websocket.js", "focus-connection.js", "focus.js" diff --git a/extension/utils.js b/extension/utils.js deleted file mode 100644 index d4d06d8..0000000 --- a/extension/utils.js +++ /dev/null @@ -1,135 +0,0 @@ -// Quick & easy browser check... chrome uses chrome. object, everything else uses browser. -function getBrowserType() { - if (BrowserDetect.browser == "Firefox") { - return browser - } else { - return chrome; - } -} - -// https://stackoverflow.com/a/26420284/637173 -function patternToRegExp(pattern) { - if (pattern == "") return /^(?:http|https|file|ftp):\/\/.*/; - - var split = /^(\*|http|https|file|ftp):\/\/(.*)$/.exec(pattern); - if (!split) throw Error("Invalid schema in " + pattern); - var schema = split[1]; - var fullpath = split[2]; - - var split = /^([^\/]*)\/(.*)$/.exec(fullpath); - if (!split) throw Error("No path specified in " + pattern); - var host = split[1]; - var path = split[2]; - - // File - if (schema == "file" && host != "") - throw Error("Non-empty host for file schema in " + pattern); - - if (schema != "file" && host == "") - throw Error("No host specified in " + pattern); - - if (!(/^(\*|\*\.[^*]+|[^*]*)$/.exec(host))) - throw Error("Illegal wildcard in host in " + pattern); - - var reString = "^"; - reString += (schema == "*") ? "https*" : schema; - reString += ":\\/\\/"; - // Not overly concerned with intricacies - // of domain name restrictions and IDN - // as we're not testing domain validity - reString += host.replace(/\*\.?/, "[^\\/]*"); - reString += "(:\\d+)?"; - reString += "\\/"; - reString += path.replace("*", ".*"); - reString += "$"; - - return RegExp(reString); -} - -function urlIsBlockedPage(url) { - for (const block_url of config.block_urls) { - if (url.startsWith(block_url)) { - return true; - } - } - - return false; -} - -function urlIsBlocked(url, compiledRegexSites, isWhitelisted) { - if (url == null) return false; - if (url.indexOf("moz-extension://") == 0) return false; - - var isBlocked; - if (isWhitelisted) { - isBlocked = true; - } else { - isBlocked = false; - } - - for (var compiledRegexSite of compiledRegexSites) { - if (compiledRegexSite.compiledRegex.test(url)) { - if (compiledRegexSite.whitelist) { - return false; - } - - isBlocked = true; - } - } - - return isBlocked; -} - -function getFocusURLFromProxyURL(blockedURL) { - if (!urlIsBlockedPage(blockedURL)) { - return null; - } - - var url = new URL(blockedURL); - var focusURL = url.searchParams.get("focus_url"); - if (!focusURL) { - return null; - } - - return focusURL; -} - -function forAllTabs(cb) { - var vendor = getBrowserType(); - vendor.tabs.query({ discarded: false }, function (tabs) { - for (var tab of tabs) { - cb(tab); - } - }); -} - -function reloadBlockedPages() { - forAllTabs((tab) => { - if (urlIsBlockedPage(tab.url)) { - chrome.tabs.reload(tab.id); - } - }); -} - -function reloadShouldBeBlockedPages(compiledRegexSites) { - forAllTabs((tab) => { - if (urlIsBlockedPage(tab.url)) { - var blockedUrl = getFocusURLFromProxyURL(tab.url); - if (!urlIsBlocked(blockedUrl, compiledRegexSites, isWhitelist)) { - chrome.tabs.reload(tab.id); - } - } else { - if (urlIsBlocked(tab.url, compiledRegexSites, isWhitelist)) { - chrome.tabs.reload(tab.id); - } - } - }); -} - - -function compileRegexSites(rawRegexSites) { - return rawRegexSites.map((regexSite) => { - regexSite.compiledRegex = new RegExp(regexSite.regexUrlStr); - return regexSite; - }); -}