From 65605917a410c5f176c081d865751c788d465c94 Mon Sep 17 00:00:00 2001 From: Green! <81369743+GreenyDEV@users.noreply.github.com> Date: Mon, 1 Aug 2022 15:39:15 -0400 Subject: [PATCH] Update cyclone.js --- static/cyclone.js | 619 ++++++++++++++++++++++++---------------------- 1 file changed, 322 insertions(+), 297 deletions(-) diff --git a/static/cyclone.js b/static/cyclone.js index 36b8c82..7c8a57f 100644 --- a/static/cyclone.js +++ b/static/cyclone.js @@ -3,279 +3,302 @@ const config = { } class Cyclone { - constructor() { - this.tmp = location.pathname.split('/service')[1] + constructor() { + this.tmp = location.pathname.split('/service')[1] - this.tmp = this.tmp.substring(1, this.tmp.length); - this.tmp = this.tmp.replace("http://", '') - this.tmp = this.tmp.replace("https://", '') - this.tmp = this.tmp.replace("http:/", '') - this.tmp = this.tmp.replace("https:/", '') - this.tmp = location.protocol + "//" + this.tmp + this.tmp = this.tmp.substring(1, this.tmp.length); + this.tmp = this.tmp.replace("http://", '') + this.tmp = this.tmp.replace("https://", '') + this.tmp = this.tmp.replace("http:/", '') + this.tmp = this.tmp.replace("https:/", '') + this.tmp = location.protocol + "//" + this.tmp - document._location = new URL(this.tmp); + document._location = new URL(this.tmp); + var l = new URL(this.tmp); - this.url = new URL(document._location.href); + this.url = new URL(document._location.href); - this.prefix = location.pathname.split('/')[1] - this.bareEndpoint = location.host + "/" + this.prefix + this.prefix = location.pathname.split('/')[1] + this.bareEndpoint = location.host + "/" + this.prefix - if (this.url.pathname == "/") { - this.paths = ['/'] - } else { - this.paths = this.url.pathname.split('/') - } - this.host = 'https://' + this.url.host + if (this.url.pathname == "/") { + this.paths = ['/'] + } else { + this.paths = this.url.pathname.split('/') + } + this.host = 'https://' + this.url.host - this.targetAttrs = ['href', 'src', 'action', 'srcdoc', 'srcset']; + this.targetAttrs = ['href', 'src', 'action', 'srcdoc', 'srcset']; - if (!document.cycloneInjected) { - console.log("Cyclone Injected with paths of:", this.paths, this.url.pathname) - document.cycloneInjected = true - } + if (!document.cycloneInjected) { + console.log("Cyclone Injected with paths of:", this.paths, this.url.pathname) + document.cycloneInjected = true + } - /*const LocationHandler = { - get(target, prop, reciver) { - return loc[prop] - }, - set(target, prop, val) { - return 'hi' - } - } - document._location = new Proxy(LocationHandler, loc)*/ - } + const LocationHandler = { + get(target, prop, reciver) { + return document._location[prop] + }, + set(target, prop, val) { + return false + } + } - rewriteUrl(link) { - if (!link) { - link = ""; - } + //const locProxy = new Proxy(document.location, LocationHandler) + Object.defineProperty(document, '_location', { + writable: true, + configurable: true, + enumerable: true, + value: l + }); + Object.defineProperty(window.document, '_location', { + writable: true, + configurable: true, + enumerable: true, + value: l + }); + Object.defineProperty(window, '_location', { + writable: true, + configurable: true, + enumerable: true, + value: l + }); + } - var rewritten; + rewriteUrl(link) { + if (!link) { + link = ""; + } - if (link.startsWith('https://') || link.startsWith('http://') || link.startsWith('//')) { - if (link.startsWith('//')) { - rewritten = 'https:' + link; - } else { - rewritten = link; - }; - } else { - if (link.startsWith('.')) { - let offset = 1; - if (link.startsWith('..')) { - offset = 2; - } - let file = link.substr(link.indexOf('.') + 1 + offset, link.length) + var rewritten; - rewritten = this.url.hostname + file - } else { - if (link.startsWith('/')) { - rewritten = this.host + link - } else { - rewritten = this.host + '/' + link; - } - } - } + if (link.startsWith('https://') || link.startsWith('http://') || link.startsWith('//')) { + if (link.startsWith('//')) { + rewritten = 'https:' + link; + } else { + rewritten = link; + }; + } else { + if (link.startsWith('.')) { + let offset = 1; + if (link.startsWith('..')) { + offset = 2; + } + let file = link.substr(link.indexOf('.') + 1 + offset, link.length) - var exceptions = ['about:', 'mailto:', 'javascript:', 'data:'] - let needstowrite = true; - for (let i = 0; i < exceptions.length; i++) { - if (link.startsWith(exceptions[i])) { - needstowrite = false - } - } + rewritten = this.url.hostname + file + } else { + if (link.startsWith('/')) { + rewritten = this.host + link + } else { + rewritten = this.host + '/' + link; + } + } + } + + var exceptions = ['about:', 'mailto:', 'javascript:', 'data:'] + let needstowrite = true; + for (let i = 0; i < exceptions.length; i++) { + if (link.startsWith(exceptions[i])) { + needstowrite = false + } + } - if (needstowrite) { - rewritten = location.protocol + '//' + this.bareEndpoint + '/' + rewritten - return rewritten; - } else { - return link; - } - } + if (needstowrite) { + rewritten = location.protocol + '//' + this.bareEndpoint + '/' + rewritten + return rewritten; + } else { + return link; + } + } - rewriteSrcset(sample) { - return sample.split(',').map(e => { - return (e.split(' ').map(a => { - if (a.startsWith('http') || (a.startsWith('/') && !a.startsWith(this.prefix))) { - var url = this.rewriteUrl(url); - } - return a.replace(a, (url || a)) - }).join(' ')) - }).join(',') - } + rewriteSrcset(sample) { + return sample.split(',').map(e => { + return (e.split(' ').map(a => { + if (a.startsWith('http') || (a.startsWith('/') && !a.startsWith(this.prefix))) { + var url = this.rewriteUrl(url); + } + return a.replace(a, (url || a)) + }).join(' ')) + }).join(',') + } } // Rewriting of data types // CSS class CSSRewriter extends Cyclone { - rewriteCSS(tag) { - var styles = window.getComputedStyle(tag) - var _values = styles['_values'] + rewriteCSS(tag) { + var styles = window.getComputedStyle(tag) + var _values = styles['_values'] - var prop = styles.getPropertyValue('background-image') - var name = "background-image" + var prop = styles.getPropertyValue('background-image') + var name = "background-image" - if (prop == "") { - if (!styles.getPropertyValue('background') == "") { - prop = styles.getPropertyValue('background') - name = "background" - } else { - name = ""; - prop = ""; - } - } + if (prop == "") { + if (!styles.getPropertyValue('background') == "") { + prop = styles.getPropertyValue('background') + name = "background" + } else { + name = ""; + prop = ""; + } + } - if (prop.includes("url(")) { - var start = prop.indexOf('url(') + 4 - var end = prop.indexOf(')') - 4 + if (prop.includes("url(")) { + var start = prop.indexOf('url(') + 4 + var end = prop.indexOf(')') - 4 - var url = prop.substring(start, end).toString('ascii'); + var url = prop.substring(start, end).toString('ascii'); - if (url.startsWith(location.origin)) { - url = url.split(location.origin) - } else { - url = url.slice(url.indexOf(location.origin)); - } + if (url.startsWith(location.origin)) { + url = url.split(location.origin) + } else { + url = url.slice(url.indexOf(location.origin)); + } - url = this.rewriteUrl(url) - tag.style[name] = url - } - } + url = this.rewriteUrl(url) + tag.style[name] = url + } + } } // JS class JavaScriptRewriter extends Cyclone { - constructor(proxy) { - super(); - //Proxied methods - this.setAttrCy = HTMLElement.prototype.setAttribute; - this.getAttrCy = HTMLElement.prototype.getAttribute; - this.proxy = proxy - } + constructor(proxy) { + super(); + //Proxied methods + this.setAttrCy = HTMLElement.prototype.setAttribute; + this.getAttrCy = HTMLElement.prototype.getAttribute; + this.proxy = proxy + } - rewriteJavascript(js) { - var javascript = js.replace('window.location', 'document._dlocation') - javascript = javascript.replace('document.location', 'document._dlocation') - javascript = javascript.replace('location.', 'document._location.') - return javascript - } + rewriteJavascript(js) { + var javascript = js.replace(/window\.location/g, 'window._dlocation') + javascript = javascript.replace(/document\.location/g, 'document._dlocation') + javascript = javascript.replace(/location\./g, '_location.') + return javascript + } - setAttribute(attr, value, mode) { - const setAttrCy = HTMLElement.prototype.setAttribute; + setAttribute(attr, value, mode) { + const setAttrCy = HTMLElement.prototype.setAttribute; - if (mode) { - this.setAttrCy.call(this, attr, value); - } else { - var url = attr - if (cyclone.targetAttrs.includes(attr)) { - url = cyclone.rewriteUrl(url); - } + if (mode) { + this.setAttrCy.call(this, attr, value); + } else { + var url = attr + if (cyclone.targetAttrs.includes(attr)) { + url = cyclone.rewriteUrl(url); + } - setAttrCy.call(this, attr, value); - } - } + setAttrCy.call(this, attr, value); + } + } - getAttribute(attrN, mode) { - const getAttrCy = HTMLElement.prototype.getAttribute; + getAttribute(attrN, mode) { + const getAttrCy = HTMLElement.prototype.getAttribute; - if (mode) { - return getAttrCy.call(this, attrN); - } else { - var val = getAttrCy.call(this, attrN); - if (cyclone.targetAttrs.includes(attrN)) { - val = getAttrCy.call(this, 'data-origin-' + attrN); - } + if (mode) { + return getAttrCy.call(this, attrN); + } else { + var val = getAttrCy.call(this, attrN); + if (cyclone.targetAttrs.includes(attrN)) { + val = getAttrCy.call(this, 'data-origin-' + attrN); + } - return val; - } - } + return val; + } + } } // HTML class HTMLRewriter extends Cyclone { - rewriteElement(element) { - var targetAttrs = this.targetAttrs; - var attrs; - try { - attrs = [...element.attributes || {}].reduce((attrs, attribute) => { - attrs[attribute.name] = attribute.value; - return attrs; - }, {}); - } catch { - attrs = {}; - } + rewriteElement(element) { + var targetAttrs = this.targetAttrs; + var attrs; + try { + attrs = [...element.attributes || {}].reduce((attrs, attribute) => { + attrs[attribute.name] = attribute.value; + return attrs; + }, {}); + } catch { + attrs = {}; + } - var elementAttributes = []; + if (element.__proto__.getAttribute) { + var jsWrite = new JavaScriptRewriter(); + var elementAttributes = []; + + for (var i = 0; i < targetAttrs.length; i++) { + var attr = targetAttrs[i] + var attrName = Object.keys(attrs)[i]; + var data = { + name: attr, + value: element.getAttribute('data-origin-' + attr, 'cyclone') || element.getAttribute(attr, 'cyclone') + } + + if (data.value) { + elementAttributes.push(data); + } + + if (element.nonce) { + element.setAttribute('nononce', element.nonce, '') + element.removeAttribute('nonce') + } + if (element.integrity) { + element.setAttribute('nointegrity', element.integrity, '') + element.removeAttribute('integrity') + } + + if (element.tagName == "script") { + if (!element.getAttribute('src')) { + var jsRewrite = new JavaScriptRewriter(); + element.innerHTML = jsRewrite.rewriteJavascript(element.innerHTML) + } + } + + // Css + var cssRewrite = new CSSRewriter(); + cssRewrite.rewriteCSS(element) + } + + for (var i = 0; i < elementAttributes.length; i++) { + var attr = elementAttributes[i]; + var attrName = attr.name; + var value = attr.value; + + var bareValue = this.rewriteUrl(value); + if (attrName == "srcset" || attrName == 'srcset') { + bareValue = this.rewriteSrcset(value); + } + + element.setAttribute(attrName, bareValue); + element.setAttribute("data-origin-" + attrName, value); + } + } + } - for (var i = 0; i < targetAttrs.length; i++) { - var attr = targetAttrs[i] - var attrName = Object.keys(attrs)[i]; - var data = { - name: attr, - value: element.getAttribute('data-origin-' + attr) || element.getAttribute(attr) - } + rewriteDocument() { + var docElements = document.querySelectorAll('*'); + for (var i = 0; i < docElements.length; i++) { + var element = docElements[i]; - if (data.value) { - elementAttributes.push(data); - } + this.rewriteElement(element) + } + } - if (element.nonce) { - element.setAttribute('nononce', element.nonce) - element.removeAttribute('nonce') - } - if (element.integrity) { - element.setAttribute('nointegrity', element.integrity) - element.removeAttribute('integrity') - } + rewriteiFrame(iframe) { + var frameDoc = (iframe.contentWindow || iframe.contentDocument || iframe.document); - if (element.tagName == "script") { - if (!element.getAttribute('src')) { - var jsRewrite = new JavaScriptRewriter(); - element.innerHTML = jsRewrite.rewriteJavascript(element.innerHTML) - } - } + let tags = frameDoc.querySelectorAll('*') - // Css - var cssRewrite = new CSSRewriter(); - cssRewrite.rewriteCSS(element) - } - - for (var i = 0; i < elementAttributes.length; i++) { - var attr = elementAttributes[i] - var attrName = attr.name; - var value = attr.value; - - var bareValue = this.rewriteUrl(value); - if (attrName == "srcset") { - this.rewriteSrcset(value); - } - - element.setAttribute(attrName, bareValue); - element.setAttribute("data-origin-" + attrName, value); - } - } - - rewriteDocument() { - var docElements = document.querySelectorAll('*'); - for (var i = 0; i < docElements.length; i++) { - var element = docElements[i]; - - this.rewriteElement(element) - } - } - - rewriteiFrame(iframe) { - var frameDoc = (iframe.contentWindow || iframe.contentDocument || iframe.document); - - let tags = frameDoc.querySelectorAll('*') - - for (var i = 0; i < tags.length; i++) { - var tag = tags[i] - this.rewriteElement(tag) - } - } + for (var i = 0; i < tags.length; i++) { + var tag = tags[i] + this.rewriteElement(tag) + } + } } const cyclone = new Cyclone(); @@ -284,52 +307,58 @@ const htmlRewriter = new HTMLRewriter(); const FetchIntercept = window.fetch; window.fetch = async (...args) => { - let [resource, config] = args; - resource = cyclone.rewriteUrl(resource); + let [resource, config] = args; + resource = cyclone.rewriteUrl(resource); - const response = await FetchIntercept(resource, config); - return response; + const response = await FetchIntercept(resource, config); + return response; } const MessageIntercept = window.postMessage; +const messageInterceptionFunc = (...args) => { + let [message, target, config] = args; + target = cyclone.rewriteUrl(target); -window.postMessage = (...args) => { - let [message, target, config] = args; - target = cyclone.rewriteUrl(target); - - const response = MessageIntercept(message, target, config); - return response; + const response = MessageIntercept(message, target, config); + console.log(response); + return response; } +Object.defineProperty(window, 'postMessage', { + writable: false, + value: messageInterceptionFunc +} +) + var CWOriginal = Object.getOwnPropertyDescriptor(window.HTMLIFrameElement.prototype, 'contentWindow') Object.defineProperty(window.HTMLIFrameElement.prototype, 'contentWindow', { - get() { - var iWindow = CWOriginal.get.call(this); - htmlRewriter.rewriteiFrame(iWindow); + get() { + var iWindow = CWOriginal.get.call(this); + htmlRewriter.rewriteiFrame(iWindow); - return iWindow - }, - set() { - return false; - } + return iWindow + }, + set() { + return false; + } }) const open = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url, ...rest) { - url = cyclone.rewriteUrl(url) + url = cyclone.rewriteUrl(url) - return open.call(this, method, url, ...rest); + return open.call(this, method, url, ...rest); }; var oPush = window.history.pushState; var oPlace = window.history.replaceState; function CycloneStates(dat, unused, url) { - var cyUrl = cyclone.rewriteUrl(url); + var cyUrl = cyclone.rewriteUrl(url); - oPush.call(this, dat, unused, cyUrl); + oPush.call(this, dat, unused, cyUrl); } window.history.pushState = CycloneStates @@ -339,33 +368,33 @@ history.replaceState = CycloneStates const OriginalWebsocket = window.WebSocket const ProxiedWebSocket = function() { - const ws = new OriginalWebsocket(...arguments) + const ws = new OriginalWebsocket(...arguments) - const originalAddEventListener = ws.addEventListener - const proxiedAddEventListener = function() { - if (arguments[0] === "message") { - const cb = arguments[1] - arguments[1] = function() { - var origin = arguments[0].origin - arguments[0].origin = cyclone.rewriteUrl(origin); + const originalAddEventListener = ws.addEventListener + const proxiedAddEventListener = function() { + if (arguments[0] === "message") { + const cb = arguments[1] + arguments[1] = function() { + var origin = arguments[0].origin + arguments[0].origin = cyclone.rewriteUrl(origin); - return cb.apply(this, arguments) - } - } - return originalAddEventListener.apply(this, arguments) - } - ws.addEventListener = proxiedAddEventListener + return cb.apply(this, arguments) + } + } + return originalAddEventListener.apply(this, arguments) + } + ws.addEventListener = proxiedAddEventListener - Object.defineProperty(ws, "onmessage", { - set(func) { - return proxiedAddEventListener.apply(this, [ - "message", - func, - false - ]); - } - }); - return ws; + Object.defineProperty(ws, "onmessage", { + set(func) { + return proxiedAddEventListener.apply(this, [ + "message", + func, + false + ]); + } + }); + return ws; }; window.WebSocket = ProxiedWebSocket; @@ -373,45 +402,41 @@ window.WebSocket = ProxiedWebSocket; const nwtb = window.open function openNewTab(url, target, features) { - url = cyclone.rewriteUrl(url) - nwtb(url, target, features) + url = cyclone.rewriteUrl(url) + nwtb(url, target, features) } window.open = openNewTab; window.onload = function() { - for (var i = 0; i < 12; i++) { - setTimeout(()=>{ - htmlRewriter.rewriteDocument(); - },500) - } - - setInterval(function() { - htmlRewriter.rewriteDocument(); - }, 3000); + for (var i = 0; i < 50; i++) { + setTimeout(() => { + htmlRewriter.rewriteDocument(); + }, 500) + } } let mutationE = new MutationObserver((mutationList, observer) => { - for (const mutation of mutationList) { - mutation.addedNodes.forEach(node => { - htmlRewriter.rewriteElement(node); - }); - } + for (const mutation of mutationList) { + mutation.addedNodes.forEach(node => { + htmlRewriter.rewriteElement(node); + }); + } }).observe(document, { - childList: true, - subtree: true + childList: true, + subtree: true }) //For intercepting all requests if (!document.serviceWorkerRegistered) { - if ('serviceWorker' in navigator) { - window.addEventListener('load', function() { - navigator.serviceWorker.register(location.origin + '/cySw.js').then(function(registration) { - console.log('Service worker registered with scope: ', registration.scope); - }, function(err) { - console.log('ServiceWorker registration failed: ', err); - }); - }); - } - document.serviceWorkerRegistered = true + if ('serviceWorker' in navigator) { + window.addEventListener('load', function() { + navigator.serviceWorker.register(location.origin + '/cySw.js').then(function(registration) { + console.log('Service worker registered with scope: ', registration.scope); + }, function(err) { + console.log('ServiceWorker registration failed: ', err); + }); + }); + } + document.serviceWorkerRegistered = true }