From b83e2fece42898daecf7df874a9310d0eb05da22 Mon Sep 17 00:00:00 2001 From: TheEmeraldStarr <46467239+Epicloudygamer@users.noreply.github.com> Date: Tue, 13 Oct 2020 09:34:59 -0700 Subject: [PATCH] Updated Alloy (v2.3) --- app.js | 539 ++++++++++++++++++++--------------------- blocklist.json | 4 +- package.json | 5 +- utils/assets/inject.js | 32 ++- ws-proxy.js | 87 +++++++ 5 files changed, 391 insertions(+), 276 deletions(-) create mode 100644 ws-proxy.js diff --git a/app.js b/app.js index 3af5e7b8..d9ab09e4 100644 --- a/app.js +++ b/app.js @@ -1,310 +1,307 @@ -const express = require('express'), - app = express(), - http = require('http'), - https = require('https'), - fs = require('fs'), - querystring = require('querystring'), - session = require('express-session'), - sanitizer = require('sanitizer'), - fetch = require('node-fetch'); + const express = require('express'), + app = express(), + http = require('http'), + https = require('https'), + fs = require('fs'), + querystring = require('querystring'), + session = require('express-session'), + sanitizer = require('sanitizer'), + websocket = require('./ws-proxy.js'), + fetch = require('node-fetch'); -const config = JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf8' })); -if (!config.prefix.startsWith('/')) { - config.prefix = `/${config.prefix}`; -} + const config = JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf8' })); + if (!config.prefix.startsWith('/')) { + config.prefix = `/${config.prefix}`; + } -if (!config.prefix.endsWith('/')) { - config.prefix = `${config.prefix}/`; -} + if (!config.prefix.endsWith('/')) { + config.prefix = `${config.prefix}/`; + } -let server; -let server_protocol; -const server_options = { - key: fs.readFileSync('./ssl/default.key'), - cert: fs.readFileSync('./ssl/default.crt') -} -if (config.ssl == true) { - server = https.createServer(server_options, app); - server_protocol = 'https://'; -} else { - server = http.createServer(app); - server_protocol = 'http://'; -}; + let server; + let server_protocol; + const server_options = { + key: fs.readFileSync('./ssl/default.key'), + cert: fs.readFileSync('./ssl/default.crt') + } + if (config.ssl == true) { server = https.createServer(server_options, app); + server_protocol = 'https://'; } else { server = http.createServer(app); + server_protocol = 'http://'; }; + + // WebSocket Proxying + websocket(server); + + console.log(`Alloy Proxy now running on ${server_protocol}0.0.0.0:${config.port}! Proxy prefix is "${config.prefix}"!`); + server.listen(process.env.PORT || config.port); + + btoa = (str) => { + str = new Buffer.from(str).toString('base64'); + return str; + }; + + atob = (str) => { + str = new Buffer.from(str, 'base64').toString('utf-8'); + return str; + }; + + rewrite_url = (dataURL, option) => { + var websiteURL; + var websitePath; + if (option == 'decode') { + websiteURL = atob(dataURL.split('/').splice(0, 1).join('/')); + websitePath = '/' + dataURL.split('/').splice(1).join('/'); + } else { + websiteURL = btoa(dataURL.split('/').splice(0, 3).join('/')); + websitePath = '/' + dataURL.split('/').splice(3).join('/'); + } + if (websitePath == '/') { return `${websiteURL}`; } else return `${websiteURL}${websitePath}`; + }; + + var login = require('./auth'); + + app.use(session({ + secret: 'alloy', + saveUninitialized: true, + resave: true + })); + // We made our own version of body-parser instead, due to issues. + app.use((req, res, next) => { + if (req.method == 'POST') { + req.raw_body = ''; + req.on('data', chunk => { + req.raw_body += chunk.toString(); // convert Buffer to string + }); + req.on('end', () => { + req.str_body = req.raw_body; + try { + req.body = JSON.parse(req.raw_body); + } catch (err) { + req.body = {} + } + next(); + }); + } else return next(); + }); + + app.use(`${config.prefix}utils/`, async(req, res, next) => { + if (req.url.startsWith('/assets/')) { res.sendFile(__dirname + '/utils' + req.url); } + if (req.query.url) { + let url = atob(req.query.url); + if (url.startsWith('https://') || url.startsWith('http://')) { + url = url; + } else if (url.startsWith('//')) { + url = 'http:' + url; + } else { + url = 'http://' + url; + } + return res.redirect(307, config.prefix + rewrite_url(url)); + } + }); + + app.post(`${config.prefix}session/`, async(req, res, next) => { + let url = querystring.parse(req.raw_body).url; + if (url.startsWith('//')) { url = 'http:' + url; } else if (url.startsWith('https://') || url.startsWith('http://')) { url = url } else { url = 'http://' + url }; + return res.redirect(config.prefix + rewrite_url(url)); + }); + + app.use(config.prefix, async(req, res, next) => { + var proxy = {}; + proxy.url = rewrite_url(req.url.slice(1), 'decode'); + proxy.url = { + href: proxy.url, + hostname: proxy.url.split('/').splice(2).splice(0, 1).join('/'), + origin: proxy.url.split('/').splice(0, 3).join('/'), + encoded_origin: btoa(proxy.url.split('/').splice(0, 3).join('/')), + path: '/' + proxy.url.split('/').splice(3).join('/'), + protocol: proxy.url.split('\:').splice(0, 1).join(''), + } + + proxy.url.encoded_origin = btoa(proxy.url.origin); + + proxy.requestHeaders = req.headers; + proxy.requestHeaders['host'] = proxy.url.hostname; + if (proxy.requestHeaders['referer']) { + let referer = '/' + String(proxy.requestHeaders['referer']).split('/').splice(3).join('/'); + + referer = rewrite_url(referer.replace(config.prefix, ''), 'decode'); + + if (referer.startsWith('https://') || referer.startsWith('http://')) { + referer = referer; + + } else referer = proxy.url.href; + + proxy.requestHeaders['referer'] = referer; + } -console.log(`Alloy Proxy now running on ${server_protocol}0.0.0.0:${config.port}! Proxy prefix is "${config.prefix}"!`); -server.listen(process.env.PORT || config.port); + if (proxy.requestHeaders['origin']) { + let origin = '/' + String(proxy.requestHeaders['origin']).split('/').splice(3).join('/'); + origin = rewrite_url(origin.replace(config.prefix, ''), 'decode'); -var login = require('./auth'); + if (origin.startsWith('https://') || origin.startsWith('http://')) { + origin = origin.split('/').splice(0, 3).join('/'); -btoa = (str) => { - str = new Buffer.from(str).toString('base64'); - return str; -}; + } else origin = proxy.url.origin; -atob = (str) => { - str = new Buffer.from(str, 'base64').toString('utf-8'); - return str; -}; + proxy.requestHeaders['origin'] = origin; + } + if (proxy.requestHeaders.cookie) { + delete proxy.requestHeaders.cookie; + } + const httpAgent = new http.Agent({ + keepAlive: true + }); + const httpsAgent = new https.Agent({ + rejectUnauthorized: false, + keepAlive: true + }); + proxy.options = { + method: req.method, + headers: proxy.requestHeaders, + redirect: 'manual', + agent: function(_parsedURL) { + if (_parsedURL.protocol == 'http:') { + return httpAgent; + } else { + return httpsAgent; + } + } + }; -rewrite_url = (dataURL, option) => { - var websiteURL; - var websitePath; - if (option == 'decode') { - websiteURL = atob(dataURL.split('/').splice(0, 1).join('/')); - websitePath = '/' + dataURL.split('/').splice(1).join('/'); - } else { - websiteURL = btoa(dataURL.split('/').splice(0, 3).join('/')); - websitePath = '/' + dataURL.split('/').splice(3).join('/'); - } - if (websitePath == '/') { return `${websiteURL}`; } else return `${websiteURL}${websitePath}`; -}; + if (req.method == 'POST') { + proxy.options.body = req.str_body; + } + if (proxy.url.hostname == 'discord.com' && proxy.url.path == '/') { return res.redirect(307, config.prefix + rewrite_url('https://discord.com/login')); }; -app.use(session({ - secret: 'alloy', - saveUninitialized: true, - resave: true -})); -// We made our own version of body-parser instead, due to issues. -app.use((req, res, next) => { - if (req.method == 'POST') { - req.raw_body = ''; - req.on('data', chunk => { - req.raw_body += chunk.toString(); // convert Buffer to string - }); - req.on('end', () => { - req.str_body = req.raw_body; - try { - req.body = JSON.parse(req.raw_body); - } catch (err) { - req.body = {} - } - next(); - }); - } else return next(); -}); + if (proxy.url.hostname == 'www.reddit.com') { return res.redirect(307, config.prefix + rewrite_url('https://old.reddit.com')); }; -app.use(`${config.prefix}utils/`, async(req, res, next) => { - if (req.url.startsWith('/assets/')) { res.sendFile(__dirname + '/utils' + req.url); } - if (req.query.url) { - let url = atob(req.query.url); - if (url.startsWith('https://') || url.startsWith('http://')) { - url = url; - } else if (url.startsWith('//')) { - url = 'http:' + url; - } else { - url = 'http://' + url; - } - return res.redirect(307, config.prefix + rewrite_url(url)); - } -}); + if (!req.url.slice(1).startsWith(`${proxy.url.encoded_origin}/`)) { return res.redirect(307, config.prefix + proxy.url.encoded_origin + '/'); }; -app.post(`${config.prefix}session/`, async(req, res, next) => { - let url = querystring.parse(req.raw_body).url; - if (url.startsWith('//')) { url = 'http:' + url; } else if (url.startsWith('https://') || url.startsWith('http://')) { url = url } else { url = 'http://' + url }; - return res.redirect(config.prefix + rewrite_url(url)); -}); + const blocklist = JSON.parse(fs.readFileSync('./blocklist.json', { encoding: 'utf8' })); -app.use(config.prefix, async(req, res, next) => { - var proxy = {}; - proxy.url = rewrite_url(req.url.slice(1), 'decode'); - proxy.url = { - href: proxy.url, - hostname: proxy.url.split('/').splice(2).splice(0, 1).join('/'), - origin: proxy.url.split('/').splice(0, 3).join('/'), - encoded_origin: btoa(proxy.url.split('/').splice(0, 3).join('/')), - path: '/' + proxy.url.split('/').splice(3).join('/'), - protocol: proxy.url.split('\:').splice(0, 1).join(''), - } + let is_blocked = false; - proxy.url.encoded_origin = btoa(proxy.url.origin); + Array.from(blocklist).forEach(blocked_hostname => { + if (proxy.url.hostname == blocked_hostname) { + is_blocked = true; + } + }); - proxy.requestHeaders = req.headers; - proxy.requestHeaders['host'] = proxy.url.hostname; - if (proxy.requestHeaders['referer']) { - let referer = '/' + String(proxy.requestHeaders['referer']).split('/').splice(3).join('/'); + if (is_blocked == true) { return res.send(fs.readFileSync('./utils/error/error.html', 'utf8').toString().replace('%ERROR%', `Error 401: The website '${sanitizer.sanitize(proxy.url.hostname)}' is not permitted!`)) } - referer = rewrite_url(referer.replace(config.prefix, ''), 'decode'); + proxy.response = await fetch(proxy.url.href, proxy.options).catch(err => res.send(fs.readFileSync('./utils/error/error.html', 'utf8').toString().replace('%ERROR%', `Error 400: Could not make request to '${sanitizer.sanitize(proxy.url.href)}'!`))); - if (referer.startsWith('https://') || referer.startsWith('http://')) { - referer = referer; + if (typeof proxy.response.buffer != 'function') return; - } else referer = proxy.url.href; + proxy.buffer = await proxy.response.buffer(); - proxy.requestHeaders['referer'] = referer; - } + proxy.content_type = 'text/plain'; + proxy.response.headers.forEach((e, i, a) => { + if (i == 'content-type') proxy.content_type = e; + }); + if (proxy.content_type == null || typeof proxy.content_type == 'undefined') proxy.content_type = 'text/html'; - if (proxy.requestHeaders['origin']) { - let origin = '/' + String(proxy.requestHeaders['origin']).split('/').splice(3).join('/'); + proxy.sendResponse = proxy.buffer; - origin = rewrite_url(origin.replace(config.prefix, ''), 'decode'); + // Parsing the headers from the response to remove square brackets so we can set them as the response headers. + proxy.headers = Object.fromEntries( + Object.entries(JSON.parse(JSON.stringify(proxy.response.headers.raw()))) + .map(([key, val]) => [key, val[0]]) + ); - if (origin.startsWith('https://') || origin.startsWith('http://')) { + // Parsing all the headers to remove all of the bad headers that could affect proxies performance. + Object.entries(proxy.headers).forEach(([header_name, header_value]) => { + if (header_name.startsWith('content-encoding') || header_name.startsWith('x-') || header_name.startsWith('cf-') || header_name.startsWith('strict-transport-security') || header_name.startsWith('content-security-policy')) { + delete proxy.headers[header_name]; + } + }); - origin = origin.split('/').splice(0, 3).join('/'); + // If theres a location for a redirect in the response, then the proxy will get the response location then redirect you to the proxied version of the url. + if (proxy.response.headers.get('location')) { + return res.redirect(307, config.prefix + rewrite_url(String(proxy.response.headers.get('location')))); + } - } else origin = proxy.url.origin; + res.status(proxy.response.status); + res.set(proxy.headers); + res.contentType(proxy.content_type); + if (proxy.content_type.startsWith('text/html')) { + req.session.url = proxy.url.origin; + proxy.sendResponse = proxy.sendResponse.toString() + .replace(/integrity="(.*?)"/gi, '') + .replace(/nonce="(.*?)"/gi, '') + .replace(/(href|src|poster|data|action|srcset)="\/\/(.*?)"/gi, `$1` + `="http://` + `$2` + `"`) + .replace(/(href|src|poster|data|action|srcset)='\/\/(.*?)'/gi, `$1` + `='http://` + `$2` + `'`) + .replace(/(href|src|poster|data|action|srcset)="\/(.*?)"/gi, `$1` + `="${config.prefix}${proxy.url.encoded_origin}/` + `$2` + `"`) + .replace(/(href|src|poster|data|action|srcset)='\/(.*?)'/gi, `$1` + `='${config.prefix}${proxy.url.encoded_origin}/` + `$2` + `'`) + .replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) { + str = str.split(`'`).slice(1).slice(0, -1).join(``); + return `'${config.prefix}${rewrite_url(str)}'` + }) + .replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) { + str = str.split(`"`).slice(1).slice(0, -1).join(``); + return `"${config.prefix}${rewrite_url(str)}"` + }) + .replace(/(window|document).location.href/gi, `"${proxy.url.href}"`) + .replace(/(window|document).location.hostname/gi, `"${proxy.url.hostname}"`) + .replace(/(window|document).location.pathname/gi, `"${proxy.url.path}"`) + .replace(/location.href/gi, `"${proxy.url.href}"`) + .replace(/location.hostname/gi, `"${proxy.url.hostname}"`) + .replace(/location.pathname/gi, `"${proxy.url.path}"`) + .replace(//gi, ``); - proxy.requestHeaders['origin'] = origin; - } - if (proxy.requestHeaders.cookie) { - delete proxy.requestHeaders.cookie; - } - const httpAgent = new http.Agent({ - keepAlive: true - }); - const httpsAgent = new https.Agent({ - rejectUnauthorized: false, - keepAlive: true - }); - proxy.options = { - method: req.method, - headers: proxy.requestHeaders, - redirect: 'manual', - agent: function(_parsedURL) { - if (_parsedURL.protocol == 'http:') { - return httpAgent; - } else { - return httpsAgent; - } - } - }; + // Temp hotfix for Youtube search bar until my script injection can fix it. - if (req.method == 'POST') { - proxy.options.body = req.str_body; - } - if (proxy.url.hostname == 'discord.com' && proxy.url.path == '/') { return res.redirect(307, config.prefix + rewrite_url('https://discord.com/login')); }; + if (proxy.url.hostname == 'www.youtube.com') { proxy.sendResponse = proxy.sendResponse.replace(/\/results/gi, `${config.prefix}${proxy.url.encoded_origin}/results`); }; + } else if (proxy.content_type.startsWith('text/css')) { + proxy.sendResponse = proxy.sendResponse.toString() + .replace(/url\("\/\/(.*?)"\)/gi, `url("http://` + `$1` + `")`) + .replace(/url\('\/\/(.*?)'\)/gi, `url('http://` + `$1` + `')`) + .replace(/url\(\/\/(.*?)\)/gi, `url(http://` + `$1` + `)`) + .replace(/url\("\/(.*?)"\)/gi, `url("${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `")`) + .replace(/url\('\/(.*?)'\)/gi, `url('${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `')`) + .replace(/url\(\/(.*?)\)/gi, `url(${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `)`) + .replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) { + str = str.split(`"`).slice(1).slice(0, -1).join(``); + return `"${config.prefix}${rewrite_url(str)}"` + }) + .replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) { + str = str.split(`'`).slice(1).slice(0, -1).join(``); + return `'${config.prefix}${rewrite_url(str)}'` + }) + .replace(/\((https:\/\/|http:\/\/)(.*?)\)/gi, function(str) { + str = str.split(`(`).slice(1).join(``).split(')').slice(0, -1).join(''); + return `(${config.prefix}${rewrite_url(str)})` + }); - if (proxy.url.hostname == 'www.reddit.com') { return res.redirect(307, config.prefix + rewrite_url('https://old.reddit.com')); }; + }; + // We send the response from the server rewritten. + res.send(proxy.sendResponse); + }); - if (!req.url.slice(1).startsWith(`${proxy.url.encoded_origin}/`)) { return res.redirect(307, config.prefix + proxy.url.encoded_origin + '/'); }; + app.use('/', express.static('public')); - const blocklist = JSON.parse(fs.readFileSync('./blocklist.json', { encoding: 'utf8' })); + app.use(async(req, res, next) => { + if (req.headers['referer']) { - let is_blocked = false; + let referer = '/' + String(req.headers['referer']).split('/').splice(3).join('/'); - Array.from(blocklist).forEach(blocked_hostname => { - if (proxy.url.hostname == blocked_hostname) { - is_blocked = true; - } - }); + referer = rewrite_url(referer.replace(config.prefix, ''), 'decode').split('/').splice(0, 3).join('/'); - if (is_blocked == true) { return res.send(fs.readFileSync('./utils/error/error.html', 'utf8').toString().replace('%ERROR%', `Error 401: The website '${sanitizer.sanitize(proxy.url.hostname)}' is not permitted!`)) } + if (referer.startsWith('https://') || referer.startsWith('http://')) { + res.redirect(307, config.prefix + btoa(referer) + req.url) + } else { + if (req.session.url) { - proxy.response = await fetch(proxy.url.href, proxy.options).catch(err => res.send(fs.readFileSync('./utils/error/error.html', 'utf8').toString().replace('%ERROR%', `Error 400: Could not make request to '${sanitizer.sanitize(proxy.url.href)}'!`))); + res.redirect(307, config.prefix + btoa(req.session.url) + req.url) - if (typeof proxy.response.buffer != 'function') return; + } else return next(); + } + } else if (req.session.url) { - proxy.buffer = await proxy.response.buffer(); + res.redirect(307, config.prefix + btoa(req.session.url) + req.url) - proxy.content_type = 'text/plain'; - - proxy.response.headers.forEach((e, i, a) => { - if (i == 'content-type') proxy.content_type = e; - }); - if (proxy.content_type == null || typeof proxy.content_type == 'undefined') proxy.content_type = 'text/html'; - - proxy.sendResponse = proxy.buffer; - - // Parsing the headers from the response to remove square brackets so we can set them as the response headers. - proxy.headers = Object.fromEntries( - Object.entries(JSON.parse(JSON.stringify(proxy.response.headers.raw()))) - .map(([key, val]) => [key, val[0]]) - ); - - // Parsing all the headers to remove all of the bad headers that could affect proxies performance. - Object.entries(proxy.headers).forEach(([header_name, header_value]) => { - if (header_name.startsWith('content-encoding') || header_name.startsWith('x-') || header_name.startsWith('cf-') || header_name.startsWith('strict-transport-security') || header_name.startsWith('content-security-policy')) { - delete proxy.headers[header_name]; - } - }); - - // If theres a location for a redirect in the response, then the proxy will get the response location then redirect you to the proxied version of the url. - if (proxy.response.headers.get('location')) { - return res.redirect(307, config.prefix + rewrite_url(String(proxy.response.headers.get('location')))); - } - - res.status(proxy.response.status); - res.set(proxy.headers); - res.contentType(proxy.content_type); - if (proxy.content_type.startsWith('text/html')) { - req.session.url = proxy.url.origin; - proxy.sendResponse = proxy.sendResponse.toString() - .replace(/integrity="(.*?)"/gi, '') - .replace(/nonce="(.*?)"/gi, '') - .replace(/(href|src|poster|data|action|srcset)="\/\/(.*?)"/gi, `$1` + `="http://` + `$2` + `"`) - .replace(/(href|src|poster|data|action|srcset)='\/\/(.*?)'/gi, `$1` + `='http://` + `$2` + `'`) - .replace(/(href|src|poster|data|action|srcset)="\/(.*?)"/gi, `$1` + `="${config.prefix}${proxy.url.encoded_origin}/` + `$2` + `"`) - .replace(/(href|src|poster|data|action|srcset)='\/(.*?)'/gi, `$1` + `='${config.prefix}${proxy.url.encoded_origin}/` + `$2` + `'`) - .replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) { - str = str.split(`'`).slice(1).slice(0, -1).join(``); - return `'${config.prefix}${rewrite_url(str)}'` - }) - .replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) { - str = str.split(`"`).slice(1).slice(0, -1).join(``); - return `"${config.prefix}${rewrite_url(str)}"` - }) - .replace(/(window|document).location.href/gi, `"${proxy.url.href}"`) - .replace(/(window|document).location.hostname/gi, `"${proxy.url.hostname}"`) - .replace(/(window|document).location.pathname/gi, `"${proxy.url.path}"`) - .replace(/location.href/gi, `"${proxy.url.href}"`) - .replace(/location.hostname/gi, `"${proxy.url.hostname}"`) - .replace(/location.pathname/gi, `"${proxy.url.path}"`) - .replace(//gi, ``); - - // Temp hotfix for Youtube search bar until my script injection can fix it. - - if (proxy.url.hostname == 'www.youtube.com') { proxy.sendResponse = proxy.sendResponse.replace(/\/results/gi, `${config.prefix}${proxy.url.encoded_origin}/results`); }; - } else if (proxy.content_type.startsWith('text/css')) { - proxy.sendResponse = proxy.sendResponse.toString() - .replace(/url\("\/\/(.*?)"\)/gi, `url("http://` + `$1` + `")`) - .replace(/url\('\/\/(.*?)'\)/gi, `url('http://` + `$1` + `')`) - .replace(/url\(\/\/(.*?)\)/gi, `url(http://` + `$1` + `)`) - .replace(/url\("\/(.*?)"\)/gi, `url("${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `")`) - .replace(/url\('\/(.*?)'\)/gi, `url('${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `')`) - .replace(/url\(\/(.*?)\)/gi, `url(${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `)`) - .replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) { - str = str.split(`"`).slice(1).slice(0, -1).join(``); - return `"${config.prefix}${rewrite_url(str)}"` - }) - .replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) { - str = str.split(`'`).slice(1).slice(0, -1).join(``); - return `'${config.prefix}${rewrite_url(str)}'` - }) - .replace(/\((https:\/\/|http:\/\/)(.*?)\)/gi, function(str) { - str = str.split(`(`).slice(1).join(``).split(')').slice(0, -1).join(''); - return `(${config.prefix}${rewrite_url(str)})` - }); - - }; - // We send the response from the server rewritten. - res.send(proxy.sendResponse); -}); - -app.use('/', express.static('public')); - -app.use(async(req, res, next) => { - if (req.headers['referer']) { - - let referer = '/' + String(req.headers['referer']).split('/').splice(3).join('/'); - - referer = rewrite_url(referer.replace(config.prefix, ''), 'decode').split('/').splice(0, 3).join('/'); - - if (referer.startsWith('https://') || referer.startsWith('http://')) { - res.redirect(307, config.prefix + btoa(referer) + req.url) - } else { - if (req.session.url) { - - res.redirect(307, config.prefix + btoa(req.session.url) + req.url) - - } else return next(); - } - } else if (req.session.url) { - - res.redirect(307, config.prefix + btoa(req.session.url) + req.url) - - } else return next(); -}); \ No newline at end of file + } else return next(); + }); \ No newline at end of file diff --git a/blocklist.json b/blocklist.json index 093b2077..4676dedc 100644 --- a/blocklist.json +++ b/blocklist.json @@ -1,3 +1,3 @@ [ - "example.com" -] \ No newline at end of file + "add-your-website-url.blocked" +] diff --git a/package.json b/package.json index 6493c266..0c3b2325 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "alloy-proxy", - "version": "2.2.0", + "version": "2.3.0", "description": "A web proxy capable of proxying websites!", "main": "app.js", "scripts": { @@ -21,6 +21,7 @@ "node-fetch": "^2.6.1", "sanitizer": "^0.1.3", "session": "^0.1.0", - "cookies": "0.4" + "cookies": "0.4", + "ws": "^7.3.1" } } \ No newline at end of file diff --git a/utils/assets/inject.js b/utils/assets/inject.js index 391b9ac0..e539cb77 100644 --- a/utils/assets/inject.js +++ b/utils/assets/inject.js @@ -71,9 +71,39 @@ let setattribute_rewrite = window.Element.prototype.setAttribute; window.Element return setattribute_rewrite.apply(this, arguments) } +// Rewriting all incoming websocket request. + + WebSocket = new Proxy(WebSocket, { + + construct(target, args_array) { + + var protocol; + + if (location.protocol == 'https:') { protocol = 'wss://' } else { protocol = 'ws://' } + + args_array[0] = protocol + location.origin.split('/').splice(2).join('/') + prefix + 'ws/' + btoa(args_array[0]); + + return new target(args_array); + } + + }); + + // Rewriting incoming pushstate. + + history.pushState = new Proxy(history.pushState, { + + apply: (target, thisArg, args_array) => { + + args_array[2] = rewrite_url(args_array[2]) + + return target.apply(thisArg, args_array) + } + + }); + var previousState = window.history.state; setInterval(function() { if (!window.location.pathname.startsWith(`${prefix}${btoa(url.origin)}/`)) { history.replaceState('', '', `${prefix}${btoa(url.origin)}/${window.location.href.split('/').splice(3).join('/')}`); } -}, 0.1); \ No newline at end of file +}, 0.1); diff --git a/ws-proxy.js b/ws-proxy.js new file mode 100644 index 00000000..1c8f2aac --- /dev/null +++ b/ws-proxy.js @@ -0,0 +1,87 @@ + const WebSocket = require('ws'), + fs = require('fs'); + + const config = JSON.parse(fs.readFileSync('./config.json', {encoding:'utf8'})); + + if (!config.prefix.startsWith('/')) { + + config.prefix = `/${config.prefix}`; + + } + + if (!config.prefix.endsWith('/')) { + + config.prefix = `${config.prefix}/`; + + } + + btoa = (str) => { + + str = new Buffer.from(str).toString('base64'); + + return str; + + }; + + atob = (str) => { + + str = new Buffer.from(str, 'base64').toString('utf-8'); + + return str; + + }; + + module.exports = (server) => { + + const wss = new WebSocket.Server({ server: server }); + + wss.on('connection', (cli, req) => { + + try { + + const svr = new WebSocket(atob(req.url.toString().replace(`${config.prefix}ws/`, ''))); + + svr.on('message', (data) => { + + try { cli.send(data) } catch(err){} + + }); + + svr.on('open', () => { + + cli.on('message', (data) => { + + svr.send(data) + + }); + + }); + + + cli.on('close', (code) => { + + try { svr.close(code); } catch(err) { svr.close(1006) }; + + }); + + svr.on('close', (code) => { + + try { cli.close(code); } catch(err) { cli.close(1006) }; + + }); + + cli.on('error', (err) => { + + try { svr.close(1001); } catch(err) { svr.close(1006) }; + + }); + + svr.on('error', (err) => { + + try { cli.close(1001); } catch(err) { cli.close(1006) }; + + }); + + } catch(err) { cli.close(1001); } + }); + }