diff options
author | Hygna <hygna@proton.me> | 2022-09-09 15:55:33 +0100 |
---|---|---|
committer | Hygna <hygna@proton.me> | 2022-09-09 15:55:33 +0100 |
commit | 4cab752e05dd479c4c3da7c06c276de51ca9f637 (patch) | |
tree | 8f42c2edea9aca343d5d8cf4f2e813a79d6f0d9f | |
parent | Make redirect not return on a single instance frontend (diff) | |
download | libredirect-4cab752e05dd479c4c3da7c06c276de51ca9f637.zip |
All irregular url structures completed
-rw-r--r-- | src/assets/javascripts/services.js | 259 | ||||
-rw-r--r-- | src/config/config.json | 2 | ||||
-rw-r--r-- | src/pages/background/background.js | 499 |
3 files changed, 505 insertions, 255 deletions
diff --git a/src/assets/javascripts/services.js b/src/assets/javascripts/services.js index 973e44b4..9c880432 100644 --- a/src/assets/javascripts/services.js +++ b/src/assets/javascripts/services.js @@ -6,11 +6,13 @@ let config function getConfig() { return new Promise(async resolve => { + let data fetch("/config/config.json") .then(response => response.text()) .then(data => { - config = JSON.parse(data) + data = JSON.parse(data) }) + config = data resolve() }) } @@ -25,7 +27,6 @@ function init() { networkFallback = r.networkFallback }) //cur = current - getConfig() for (service in config.services) { redirects = {} browser.storage.local.get([`disable${camelCase(service)}`, `${service}Redirects`, `${service}RedirectType,`, `${service}Frontend`], r => { @@ -46,6 +47,8 @@ function init() { }) } +getConfig() +console.log(config) init() browser.storage.onChanged.addListener(init) @@ -54,9 +57,13 @@ function redirect(url, type, initiator) { if (url.pathname == "/") return for (service in config.services) { if (disabled && !disableOverride) continue + let targets = service.targets + if (targets == "datajson") { + browser.storage.local.get(`${service}Targets`, (targets = r[service + "Targets"])) + } + if (initiator && (all().includes(initiator.origin) || targets.includes(initiator.host))) continue - //if (!targets.some(rx => rx.test(url.href))) continue - if (!target.test(url)) continue + if (!targets.some(rx => rx.test(url.href))) continue if (type != redirectType && type != "both") continue browser.storage.local.get(`${service}Frontend`, (frontend = r[service + "Frontend"])) let instanceList = redirects[frontend][curNetwork] @@ -64,6 +71,26 @@ function redirect(url, type, initiator) { if (instanceList.length === 0 && redirects.indexOf(frontend) != -1) return randomInstance = utils.getRandomInstance(instanceList) } + + // Here is a (temperory) space for defining constants required in 2 or more switch cases. + // When possible, try have the two switch cases share all their code as done with searx and searxng. + // Do not do that when they do not share 100% of their code. + + const mapCentreRegex = /@(-?\d[0-9.]*),(-?\d[0-9.]*),(\d{1,2})[.z]/ + const dataLatLngRegex = /!3d(-?[0-9]{1,}.[0-9]{1,})!4d(-?[0-9]{1,}.[0-9]{1,})/ + const placeRegex = /\/place\/(.*)\// + function convertMapCentre() { + let [, lat, lon, zoom] = 0 + if (url.pathname.match(mapCentreRegex)) { + // Set map centre if present + ;[, lat, lon, zoom] = url.pathname.match(mapCentreRegex) + } else if (url.searchParams.has("center")) { + ;[lat, lon] = url.searchParams.get("center").split(",") + zoom = url.searchParams.get("zoom") ?? "17" + } + return [zoom, lon, lat] + } + switch (frontend) { // This is where all instance-specific code must be ran to convert the service url to one that can be understood by the frontend. case "beatbump": @@ -108,9 +135,229 @@ function redirect(url, type, initiator) { return `freetube://https://youtube.com${url.pathname}${url.search}` case "simplyTranslate": return `${randomInstance}/${url.search}` + case "osm": { + if (initiator && initiator.host === "earth.google.com") return + travelModes = { + driving: "fossgis_osrm_car", + walking: "fossgis_osrm_foot", + bicycling: "fossgis_osrm_bike", + transit: "fossgis_osrm_car", // not implemented on OSM, default to car. + } + + function addressToLatLng(address) { + const xmlhttp = new XMLHttpRequest() + xmlhttp.open("GET", `https://nominatim.openstreetmap.org/search/${address}?format=json&limit=1`, false) + xmlhttp.send() + if (xmlhttp.status === 200) { + const json = JSON.parse(xmlhttp.responseText)[0] + if (json) { + console.log("json", json) + return [`${json.lat},${json.lon}`, `${json.boundingbox[2]},${json.boundingbox[1]},${json.boundingbox[3]},${json.boundingbox[0]}`] + } + } + console.info("Error: Status is " + xmlhttp.status) + } + + let mapCentre = "#" + let prefs = {} + + const mapCentreData = convertMapCentre() + if (mapCentreData[0] && mapCentreData[1] && mapCentreData[2]) mapCentre = `#map=${mapCentreData[0]}/${mapCentreData[1]}/${mapCentreData[2]}` + if (url.searchParams.get("layer")) prefs.layers = osmLayers[url.searchParams.get("layer")] + + if (url.pathname.includes("/embed")) { + // Handle Google Maps Embed API + // https://www.google.com/maps/embed/v1/place?key=AIzaSyD4iE2xVSpkLLOXoyqT-RuPwURN3ddScAI&q=Eiffel+Tower,Paris+France + //console.log("embed life") + + let query = "" + if (url.searchParams.has("q")) query = url.searchParams.get("q") + else if (url.searchParams.has("query")) query = url.searchParams.has("query") + else if (url.searchParams.has("pb")) + try { + query = url.searchParams.get("pb").split(/!2s(.*?)!/)[1] + } catch (error) { + console.error(error) + } // Unable to find map marker in URL. + + let [coords, boundingbox] = addressToLatLng(query) + prefs.bbox = boundingbox + prefs.marker = coords + prefs.layer = "mapnik" + let prefsEncoded = new URLSearchParams(prefs).toString() + return `${randomInstance}/export/embed.html?${prefsEncoded}` + } else if (url.pathname.includes("/dir")) { + // Handle Google Maps Directions + // https://www.google.com/maps/dir/?api=1&origin=Space+Needle+Seattle+WA&destination=Pike+Place+Market+Seattle+WA&travelmode=bicycling + + let travMod = url.searchParams.get("travelmode") + if (url.searchParams.has("travelmode")) prefs.engine = travelModes[travMod] + + let orgVal = url.searchParams.get("origin") + let destVal = url.searchParams.get("destination") + + let org + addressToLatLng(orgVal, a => (org = a)) + let dest + addressToLatLng(destVal, a => (dest = a)) + prefs.route = `${org};${dest}` + + let prefsEncoded = new URLSearchParams(prefs).toString() + return `${randomInstance}/directions?${prefsEncoded}${mapCentre}` + } else if (url.pathname.includes("data=") && url.pathname.match(dataLatLngRegex)) { + // Get marker from data attribute + // https://www.google.com/maps/place/41%C2%B001'58.2%22N+40%C2%B029'18.2%22E/@41.032833,40.4862063,17z/data=!3m1!4b1!4m6!3m5!1s0x0:0xf64286eaf72fc49d!7e2!8m2!3d41.0328329!4d40.4883948 + //console.log("data life") + + let [, mlat, mlon] = url.pathname.match(dataLatLngRegex) + + return `${randomInstance}/search?query=${mlat}%2C${mlon}` + } else if (url.searchParams.has("ll")) { + // Get marker from ll param + // https://maps.google.com/?ll=38.882147,-76.99017 + //console.log("ll life") + + const [mlat, mlon] = url.searchParams.get("ll").split(",") + + return `${randomInstance}/search?query=${mlat}%2C${mlon}` + } else if (url.searchParams.has("viewpoint")) { + // Get marker from viewpoint param. + // https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.857832,2.295226&heading=-45&pitch=38&fov=80 + //console.log("viewpoint life") + + const [mlat, mlon] = url.searchParams.get("viewpoint").split(",") + + return `${randomInstance}/search?query=${mlat}%2C${mlon}` + } else { + // Use query as search if present. + //console.log("normal life") + + let query + if (url.searchParams.has("q")) query = url.searchParams.get("q") + else if (url.searchParams.has("query")) query = url.searchParams.get("query") + else if (url.pathname.match(placeRegex)) query = url.pathname.match(placeRegex)[1] + + let prefsEncoded = new URLSearchParams(prefs).toString() + if (query) return `${randomInstance}/search?query="${query}${mapCentre}&${prefsEncoded}` + } + + let prefsEncoded = new URLSearchParams(prefs).toString() + console.log("mapCentre", mapCentre) + console.log("prefs", prefs) + console.log("prefsEncoded", prefsEncoded) + return `${randomInstance}/${mapCentre}&${prefsEncoded}` + } + case "facil": { + if (initiator && initiator.host === "earth.google.com") return + let travelModes = { + driving: "car", + walking: "pedestrian", + bicycling: "bicycle", + transit: "car", // not implemented on Facil, default to car. + } + const mapCentreData = convertMapCentre() + let mapCentre = "#" + if (mapCentreData[0] && mapCentreData[1] && mapCentreData[2]) mapCentre = `#${mapCentreData[0]}/${mapCentreData[1]}/${mapCentreData[2]}` + + if (url.pathname.includes("/embed")) { + // Handle Google Maps Embed API + // https://www.google.com/maps/embed/v1/place?key=AIzaSyD4iE2xVSpkLLOXoyqT-RuPwURN3ddScAI&q=Eiffel+Tower,Paris+France + //console.log("embed life") + + let query = "" + if (url.searchParams.has("q")) query = url.searchParams.get("q") + else if (url.searchParams.has("query")) query = url.searchParams.has("query") + else if (url.searchParams.has("pb")) + try { + query = url.searchParams.get("pb").split(/!2s(.*?)!/)[1] + } catch (error) { + console.error(error) + } // Unable to find map marker in URL. + + return `${randomInstance}/#q=${query}` + } else if (url.pathname.includes("/dir")) { + // Handle Google Maps Directions + // https://www.google.com/maps/dir/?api=1&origin=Space+Needle+Seattle+WA&destination=Pike+Place+Market+Seattle+WA&travelmode=bicycling + + let travMod = url.searchParams.get("travelmode") + + let orgVal = url.searchParams.get("origin") + let destVal = url.searchParams.get("destination") + + return `${randomInstance}/#q=${orgVal}%20to%20${destVal}%20by%20${travelModes[travMod]}` + } else if (url.pathname.includes("data=") && url.pathname.match(dataLatLngRegex)) { + // Get marker from data attribute + // https://www.google.com/maps/place/41%C2%B001'58.2%22N+40%C2%B029'18.2%22E/@41.032833,40.4862063,17z/data=!3m1!4b1!4m6!3m5!1s0x0:0xf64286eaf72fc49d!7e2!8m2!3d41.0328329!4d40.4883948 + //console.log("data life") + + let [, mlat, mlon] = url.pathname.match(dataLatLngRegex) + + return `${randomInstance}/#q=${mlat}%2C${mlon}` + } else if (url.searchParams.has("ll")) { + // Get marker from ll param + // https://maps.google.com/?ll=38.882147,-76.99017 + //console.log("ll life") + + const [mlat, mlon] = url.searchParams.get("ll").split(",") + + return `${randomInstance}/#q=${mlat}%2C${mlon}` + } else if (url.searchParams.has("viewpoint")) { + // Get marker from viewpoint param. + // https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.857832,2.295226&heading=-45&pitch=38&fov=80 + //console.log("viewpoint life") + + const [mlat, mlon] = url.searchParams.get("viewpoint").split(",") + + return `${randomInstance}/#q=${mlat}%2C${mlon}` + } else { + // Use query as search if present. + //console.log("normal life") + + let query + if (url.searchParams.has("q")) query = url.searchParams.get("q") + else if (url.searchParams.has("query")) query = url.searchParams.get("query") + else if (url.pathname.match(placeRegex)) query = url.pathname.match(placeRegex)[1] + + if (query) return `${randomInstance}/${mapCentre}/Mpnk/${query}` + } + } + case "wikiless": + let GETArguments = [] + if (url.search.length > 0) { + let search = url.search.substring(1) //get rid of '?' + let argstrings = search.split("&") + for (let i = 0; i < argstrings.length; i++) { + let args = argstrings[i].split("=") + GETArguments.push([args[0], args[1]]) + } + } + + let link = `${randomInstance}${url.pathname}` + let urlSplit = url.host.split(".") + if (urlSplit[0] != "wikipedia" && urlSplit[0] != "www") { + if (urlSplit[0] == "m") GETArguments.push(["mobileaction", "toggle_view_mobile"]) + else GETArguments.push(["lang", urlSplit[0]]) + if (urlSplit[1] == "m") GETArguments.push(["mobileaction", "toggle_view_mobile"]) + // wikiless doesn't have mobile view support yet + } + for (let i = 0; i < GETArguments.length; i++) link += (i == 0 ? "?" : "&") + GETArguments[i][0] + "=" + GETArguments[i][1] + return link + + case "lingva": + let params_arr = url.search.split("&") + params_arr[0] = params_arr[0].substring(1) + let params = {} + for (let i = 0; i < params_arr.length; i++) { + let pair = params_arr[i].split("=") + params[pair[0]] = pair[1] + } + if (params.sl && params.tl && params.text) { + return `${randomInstance}/${params.sl}/${params.tl}/${params.text}` + } + return randomInstance default: return `${randomInstance}${url.pathname}${url.search}` - } // TODO: Wikiless, All youtube frontends by changing regex, lingva + } } function initDefaults() { @@ -124,7 +371,7 @@ function initDefaults() { for (service in config.services) { for (defaultOption in service.defaults) { browser.storage.local.set({ - [defaultOption]: defaultOption.value, + [defaultOption]: service.defaults[defaultOption], }) } for (frontend in service.frontends) { diff --git a/src/config/config.json b/src/config/config.json index db991772..3d4d3f8b 100644 --- a/src/config/config.json +++ b/src/config/config.json @@ -64,7 +64,7 @@ }, "singleInstanceFrontends": ["freetube", "yatte"], "targets": [ - "^https?:\\/{2}(www\\.|music\\.|m\\.|)youtube.com(\\/.*|$)", + "^https?:\\/{2}(www\\.|music\\.|m\\.|)youtube.com(\\(?!iframe_api)/.*|$)", "^https?:\\/{2}img\\.youtube.com\\/vi\\/.*\\/..*", "^https?:\\/{2}(i|s)\\.ytimg.com\\/vi\\/.*\\/..*", "^https?:\\/{2}(www\\.|music\\.|)youtube.com\\/watch?v=..*", diff --git a/src/pages/background/background.js b/src/pages/background/background.js index 87d498e4..e93e3d03 100644 --- a/src/pages/background/background.js +++ b/src/pages/background/background.js @@ -1,248 +1,251 @@ -"use strict" - -import generalHelper from "../../assets/javascripts/general.js" -import utils from "../../assets/javascripts/utils.js" - -import youtubeHelper from "../../assets/javascripts/youtube/youtube.js" -import youtubeMusicHelper from "../../assets/javascripts/youtubeMusic.js" -import twitterHelper from "../../assets/javascripts/twitter.js" -import instagramHelper from "../../assets/javascripts/instagram.js" -import redditHelper from "../../assets/javascripts/reddit.js" -import searchHelper from "../../assets/javascripts/search.js" -import translateHelper from "../../assets/javascripts/translate/translate.js" -import mapsHelper from "../../assets/javascripts/maps.js" -import wikipediaHelper from "../../assets/javascripts/wikipedia.js" -import mediumHelper from "../../assets/javascripts/medium.js" -import quoraHelper from "../../assets/javascripts/quora.js" -import libremdbHelper from "../../assets/javascripts/imdb.js" -import reutersHelper from "../../assets/javascripts/reuters.js" -import imgurHelper from "../../assets/javascripts/imgur.js" -import tiktokHelper from "../../assets/javascripts/tiktok.js" -import sendTargetsHelper from "../../assets/javascripts/sendTargets.js" -import peertubeHelper from "../../assets/javascripts/peertube.js" -import lbryHelper from "../../assets/javascripts/lbry.js" - -import servicesHelper from "../../assets/javascripts/services.js" - -window.browser = window.browser || window.chrome - -browser.runtime.onInstalled.addListener(details => { - function initDefaults() { - fetch("/instances/blacklist.json") - .then(response => response.text()) - .then(async data => { - browser.storage.local.clear(() => { - browser.storage.local.set({ cloudflareBlackList: JSON.parse(data).cloudflare }, () => { - browser.storage.local.set({ authenticateBlackList: JSON.parse(data).authenticate }, () => { - browser.storage.local.set({ offlineBlackList: JSON.parse(data).offline }, () => { - generalHelper.initDefaults() - youtubeHelper.initDefaults() - youtubeMusicHelper.initDefaults() - twitterHelper.initDefaults() - instagramHelper.initDefaults() - mapsHelper.initDefaults() - searchHelper.initDefaults() - translateHelper.initDefaults() - mediumHelper.initDefaults() - quoraHelper.initDefaults() - libremdbHelper.initDefaults() - reutersHelper.initDefaults() - redditHelper.initDefaults() - wikipediaHelper.initDefaults() - imgurHelper.initDefaults() - tiktokHelper.initDefaults() - sendTargetsHelper.initDefaults() - peertubeHelper.initDefaults() - lbryHelper.initDefaults() - }) - }) - }) - }) - }) - } - if (details.reason == "install") initDefaults() - - // if (details.reason == 'install' || (details.reason == "update" && details.previousVersion != browser.runtime.getManifest().version)) { - // if (details.reason == "update") - // browser.storage.local.get(null, r => { - // if (r.theme) { - // const old = encodeURIComponent(JSON.stringify(r)) - // browser.tabs.create({ url: browser.runtime.getURL(`/pages/background/reset_warning.html?data=${old}`) }); - // } - // initDefaults(); - // }) - // else initDefaults(); - // } -}) - -let BYPASSTABs = [] -browser.webRequest.onBeforeRequest.addListener( - details => { - const url = new URL(details.url) - if (new RegExp(/^chrome-extension:\/{2}.*\/instances\/.*.json$/).test(url.href) && details.type == "xmlhttprequest") return - let initiator - try { - if (details.originUrl) initiator = new URL(details.originUrl) - else if (details.initiator) initiator = new URL(details.initiator) - } catch { - return null - } - - /* - let newUrl = youtubeMusicHelper.redirect(url, details.type) - if (!newUrl) newUrl = youtubeHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = twitterHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = instagramHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = mapsHelper.redirect(url, initiator) - if (!newUrl) newUrl = redditHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = mediumHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = quoraHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = libremdbHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = reutersHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = imgurHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = tiktokHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = sendTargetsHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = peertubeHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = lbryHelper.redirect(url, details.type, initiator) - if (!newUrl) newUrl = translateHelper.redirect(url) - if (!newUrl) newUrl = searchHelper.redirect(url) - if (!newUrl) newUrl = wikipediaHelper.redirect(url) - */ - let newUrl = servicesHelper.redirect(url, details.type, initiator) - - if (details.frameAncestors && details.frameAncestors.length > 0 && generalHelper.isException(new URL(details.frameAncestors[0].url))) newUrl = null - - if (generalHelper.isException(url)) newUrl = "BYPASSTAB" - if (BYPASSTABs.includes(details.tabId)) newUrl = null - - if (newUrl) { - if (newUrl === "CANCEL") { - console.log(`Canceled ${url}`) - return { cancel: true } - } - if (newUrl === "BYPASSTAB") { - console.log(`Bypassed ${details.tabId} ${url}`) - if (!BYPASSTABs.includes(details.tabId)) BYPASSTABs.push(details.tabId) - return null - } - console.info("Redirecting", url.href, "=>", newUrl) - return { redirectUrl: newUrl } - } - return null - }, - { urls: ["<all_urls>"] }, - ["blocking"] -) - -browser.tabs.onRemoved.addListener(tabId => { - const i = BYPASSTABs.indexOf(tabId) - if (i > -1) { - BYPASSTABs.splice(i, 1) - console.log("Removed BYPASSTABs", tabId) - } -}) - -browser.webRequest.onHeadersReceived.addListener( - e => { - let response = youtubeHelper.removeXFrameOptions(e) - if (!response) response = twitterHelper.removeXFrameOptions(e) - return response - }, - { urls: ["<all_urls>"] }, - ["blocking", "responseHeaders"] -) - -async function redirectOfflineInstance(url, tabId) { - let newUrl = await youtubeHelper.switchInstance(url, true) - if (!newUrl) newUrl = await twitterHelper.switchInstance(url, true) - if (!newUrl) newUrl = await instagramHelper.switchInstance(url, true) - if (!newUrl) newUrl = await redditHelper.switchInstance(url, true) - if (!newUrl) newUrl = await searchHelper.switchInstance(url, true) - if (!newUrl) newUrl = await translateHelper.switchInstance(url, true) - if (!newUrl) newUrl = await mediumHelper.switchInstance(url, true) - if (!newUrl) newUrl = await quoraHelper.switchInstance(url, true) - if (!newUrl) newUrl = await libremdbHelper.switchInstance(url, true) - if (!newUrl) newUrl = await tiktokHelper.switchInstance(url, true) - if (!newUrl) newUrl = await imgurHelper.switchInstance(url, true) - if (!newUrl) newUrl = await wikipediaHelper.switchInstance(url, true) - if (!newUrl) newUrl = await peertubeHelper.switchInstance(url, true) - if (!newUrl) newUrl = await lbryHelper.switchInstance(url, true) - if (!newUrl) newUrl = await youtubeMusicHelper.switchInstance(url, true) - - if (newUrl) { - if (counter >= 5) { - browser.tabs.update(tabId, { - url: `/pages/errors/instance_offline.html?url=${encodeURIComponent(newUrl)}`, - }) - counter = 0 - } else { - browser.tabs.update(tabId, { url: newUrl }) - counter++ - } - } -} -let counter = 0 - -function isAutoRedirect() { - return new Promise(resolve => browser.storage.local.get("autoRedirect", r => resolve(r.autoRedirect == true))) -} - -browser.webRequest.onResponseStarted.addListener( - async details => { - if (!(await isAutoRedirect())) return null - if (details.type == "main_frame" && details.statusCode >= 500) redirectOfflineInstance(new URL(details.url), details.tabId) - }, - { urls: ["<all_urls>"] } -) - -browser.webRequest.onErrorOccurred.addListener( - async details => { - if (!(await isAutoRedirect())) return - if (details.type == "main_frame") redirectOfflineInstance(new URL(details.url), details.tabId) - }, - { urls: ["<all_urls>"] } -) - -browser.commands.onCommand.addListener(command => { - if (command === "switchInstance") utils.switchInstance() - else if (command == "copyRaw") utils.copyRaw() - else if (command == "unify") utils.unify() -}) - -browser.contextMenus.create({ - id: "settings", - title: browser.i18n.getMessage("Settings"), - contexts: ["browser_action"], -}) - -browser.contextMenus.create({ - id: "switchInstance", - title: browser.i18n.getMessage("switchInstance"), - contexts: ["browser_action"], -}) - -browser.contextMenus.create({ - id: "copyRaw", - title: browser.i18n.getMessage("copyRaw"), - contexts: ["browser_action"], -}) - -browser.contextMenus.create({ - id: "unify", - title: browser.i18n.getMessage("unifySettings"), - contexts: ["browser_action"], -}) - -browser.contextMenus.onClicked.addListener(info => { - if (info.menuItemId == "switchInstance") utils.switchInstance() - else if (info.menuItemId == "settings") browser.runtime.openOptionsPage() - else if (info.menuItemId == "copyRaw") utils.copyRaw() - else if (info.menuItemId == "unify") utils.unify() -}) - -browser.runtime.onMessage.addListener((message, sender, sendResponse) => { - if (message.function === "unify") utils.unify(false).then(r => sendResponse({ response: r })) - return true -}) - -browser.storage.local.set({ version: browser.runtime.getManifest().version }) +"use strict" + +import generalHelper from "../../assets/javascripts/general.js" +import utils from "../../assets/javascripts/utils.js" + +import youtubeHelper from "../../assets/javascripts/youtube/youtube.js" +import youtubeMusicHelper from "../../assets/javascripts/youtubeMusic.js" +import twitterHelper from "../../assets/javascripts/twitter.js" +import instagramHelper from "../../assets/javascripts/instagram.js" +import redditHelper from "../../assets/javascripts/reddit.js" +import searchHelper from "../../assets/javascripts/search.js" +import translateHelper from "../../assets/javascripts/translate/translate.js" +import mapsHelper from "../../assets/javascripts/maps.js" +import wikipediaHelper from "../../assets/javascripts/wikipedia.js" +import mediumHelper from "../../assets/javascripts/medium.js" +import quoraHelper from "../../assets/javascripts/quora.js" +import libremdbHelper from "../../assets/javascripts/imdb.js" +import reutersHelper from "../../assets/javascripts/reuters.js" +import imgurHelper from "../../assets/javascripts/imgur.js" +import tiktokHelper from "../../assets/javascripts/tiktok.js" +import sendTargetsHelper from "../../assets/javascripts/sendTargets.js" +import peertubeHelper from "../../assets/javascripts/peertube.js" +import lbryHelper from "../../assets/javascripts/lbry.js" + +import servicesHelper from "../../assets/javascripts/services.js" + +window.browser = window.browser || window.chrome + +browser.runtime.onInstalled.addListener(details => { + function initDefaults() { + fetch("/instances/blacklist.json") + .then(response => response.text()) + .then(async data => { + browser.storage.local.clear(() => { + browser.storage.local.set({ cloudflareBlackList: JSON.parse(data).cloudflare }, () => { + browser.storage.local.set({ authenticateBlackList: JSON.parse(data).authenticate }, () => { + browser.storage.local.set({ offlineBlackList: JSON.parse(data).offline }, () => { + generalHelper.initDefaults() + /* + youtubeHelper.initDefaults() + youtubeMusicHelper.initDefaults() + twitterHelper.initDefaults() + instagramHelper.initDefaults() + mapsHelper.initDefaults() + searchHelper.initDefaults() + translateHelper.initDefaults() + mediumHelper.initDefaults() + quoraHelper.initDefaults() + libremdbHelper.initDefaults() + reutersHelper.initDefaults() + redditHelper.initDefaults() + wikipediaHelper.initDefaults() + imgurHelper.initDefaults() + tiktokHelper.initDefaults() + sendTargetsHelper.initDefaults() + peertubeHelper.initDefaults() + lbryHelper.initDefaults() + */ + servicesHelper.initDefaults() + }) + }) + }) + }) + }) + } + if (details.reason == "install") initDefaults() + + // if (details.reason == 'install' || (details.reason == "update" && details.previousVersion != browser.runtime.getManifest().version)) { + // if (details.reason == "update") + // browser.storage.local.get(null, r => { + // if (r.theme) { + // const old = encodeURIComponent(JSON.stringify(r)) + // browser.tabs.create({ url: browser.runtime.getURL(`/pages/background/reset_warning.html?data=${old}`) }); + // } + // initDefaults(); + // }) + // else initDefaults(); + // } +}) + +let BYPASSTABs = [] +browser.webRequest.onBeforeRequest.addListener( + details => { + const url = new URL(details.url) + if (new RegExp(/^chrome-extension:\/{2}.*\/instances\/.*.json$/).test(url.href) && details.type == "xmlhttprequest") return + let initiator + try { + if (details.originUrl) initiator = new URL(details.originUrl) + else if (details.initiator) initiator = new URL(details.initiator) + } catch { + return null + } + + /* + let newUrl = youtubeMusicHelper.redirect(url, details.type) + if (!newUrl) newUrl = youtubeHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = twitterHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = instagramHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = mapsHelper.redirect(url, initiator) + if (!newUrl) newUrl = redditHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = mediumHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = quoraHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = libremdbHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = reutersHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = imgurHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = tiktokHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = sendTargetsHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = peertubeHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = lbryHelper.redirect(url, details.type, initiator) + if (!newUrl) newUrl = translateHelper.redirect(url) + if (!newUrl) newUrl = searchHelper.redirect(url) + if (!newUrl) newUrl = wikipediaHelper.redirect(url) + */ + let newUrl = servicesHelper.redirect(url, details.type, initiator) + + if (details.frameAncestors && details.frameAncestors.length > 0 && generalHelper.isException(new URL(details.frameAncestors[0].url))) newUrl = null + + if (generalHelper.isException(url)) newUrl = "BYPASSTAB" + if (BYPASSTABs.includes(details.tabId)) newUrl = null + + if (newUrl) { + if (newUrl === "CANCEL") { + console.log(`Canceled ${url}`) + return { cancel: true } + } + if (newUrl === "BYPASSTAB") { + console.log(`Bypassed ${details.tabId} ${url}`) + if (!BYPASSTABs.includes(details.tabId)) BYPASSTABs.push(details.tabId) + return null + } + console.info("Redirecting", url.href, "=>", newUrl) + return { redirectUrl: newUrl } + } + return null + }, + { urls: ["<all_urls>"] }, + ["blocking"] +) + +browser.tabs.onRemoved.addListener(tabId => { + const i = BYPASSTABs.indexOf(tabId) + if (i > -1) { + BYPASSTABs.splice(i, 1) + console.log("Removed BYPASSTABs", tabId) + } +}) + +browser.webRequest.onHeadersReceived.addListener( + e => { + let response = youtubeHelper.removeXFrameOptions(e) + if (!response) response = twitterHelper.removeXFrameOptions(e) + return response + }, + { urls: ["<all_urls>"] }, + ["blocking", "responseHeaders"] +) + +async function redirectOfflineInstance(url, tabId) { + let newUrl = await youtubeHelper.switchInstance(url, true) + if (!newUrl) newUrl = await twitterHelper.switchInstance(url, true) + if (!newUrl) newUrl = await instagramHelper.switchInstance(url, true) + if (!newUrl) newUrl = await redditHelper.switchInstance(url, true) + if (!newUrl) newUrl = await searchHelper.switchInstance(url, true) + if (!newUrl) newUrl = await translateHelper.switchInstance(url, true) + if (!newUrl) newUrl = await mediumHelper.switchInstance(url, true) + if (!newUrl) newUrl = await quoraHelper.switchInstance(url, true) + if (!newUrl) newUrl = await libremdbHelper.switchInstance(url, true) + if (!newUrl) newUrl = await tiktokHelper.switchInstance(url, true) + if (!newUrl) newUrl = await imgurHelper.switchInstance(url, true) + if (!newUrl) newUrl = await wikipediaHelper.switchInstance(url, true) + if (!newUrl) newUrl = await peertubeHelper.switchInstance(url, true) + if (!newUrl) newUrl = await lbryHelper.switchInstance(url, true) + if (!newUrl) newUrl = await youtubeMusicHelper.switchInstance(url, true) + + if (newUrl) { + if (counter >= 5) { + browser.tabs.update(tabId, { + url: `/pages/errors/instance_offline.html?url=${encodeURIComponent(newUrl)}`, + }) + counter = 0 + } else { + browser.tabs.update(tabId, { url: newUrl }) + counter++ + } + } +} +let counter = 0 + +function isAutoRedirect() { + return new Promise(resolve => browser.storage.local.get("autoRedirect", r => resolve(r.autoRedirect == true))) +} + +browser.webRequest.onResponseStarted.addListener( + async details => { + if (!(await isAutoRedirect())) return null + if (details.type == "main_frame" && details.statusCode >= 500) redirectOfflineInstance(new URL(details.url), details.tabId) + }, + { urls: ["<all_urls>"] } +) + +browser.webRequest.onErrorOccurred.addListener( + async details => { + if (!(await isAutoRedirect())) return + if (details.type == "main_frame") redirectOfflineInstance(new URL(details.url), details.tabId) + }, + { urls: ["<all_urls>"] } +) + +browser.commands.onCommand.addListener(command => { + if (command === "switchInstance") utils.switchInstance() + else if (command == "copyRaw") utils.copyRaw() + else if (command == "unify") utils.unify() +}) + +browser.contextMenus.create({ + id: "settings", + title: browser.i18n.getMessage("Settings"), + contexts: ["browser_action"], +}) + +browser.contextMenus.create({ + id: "switchInstance", + title: browser.i18n.getMessage("switchInstance"), + contexts: ["browser_action"], +}) + +browser.contextMenus.create({ + id: "copyRaw", + title: browser.i18n.getMessage("copyRaw"), + contexts: ["browser_action"], +}) + +browser.contextMenus.create({ + id: "unify", + title: browser.i18n.getMessage("unifySettings"), + contexts: ["browser_action"], +}) + +browser.contextMenus.onClicked.addListener(info => { + if (info.menuItemId == "switchInstance") utils.switchInstance() + else if (info.menuItemId == "settings") browser.runtime.openOptionsPage() + else if (info.menuItemId == "copyRaw") utils.copyRaw() + else if (info.menuItemId == "unify") utils.unify() +}) + +browser.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message.function === "unify") utils.unify(false).then(r => sendResponse({ response: r })) + return true +}) + +browser.storage.local.set({ version: browser.runtime.getManifest().version }) |