Updated Local Alloy Proxy v2.2

v2.2
This commit is contained in:
TheEmeraldStarr 2020-10-02 08:32:55 -07:00
parent c5189dfcc1
commit 3ce747eacc
8 changed files with 475 additions and 592 deletions

View file

@ -1,209 +0,0 @@
// Ajax Rewriting
let apData = document.getElementById('alloyData');
let urlData = apData.getAttribute('data-alloyURL');
function rewriteURL(url, encoding) {
var websiteURL
if (encoding == 'base64') {
websiteURL = btoa(url.split('/').splice(0, 3).join('/'))
} else {
websiteURL = url.split('/').splice(0, 3).join('/')
}
const path = '/' + url.split('/').splice(3).join('/')
var rewritten
if (path == '/') {
rewritten = '/fetch/' + websiteURL
} else {
rewritten = `/fetch/${websiteURL}${path}`
}
return rewritten
}
let ajaxRewrite = window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
if (url.startsWith(`${window.location.protocol}//${window.location.hostname}`) && !url.startsWith(`${window.location.protocol}//${window.location.hostname}/fetch/`)) {
url = `/fetch/${urlData}/` + url.split('/').splice(3).join('/')
} else if (url.startsWith('http')) {
const hostname = url.split('/').slice(0, 3).join('/')
const path = url.split('/').slice(3).join('/')
const encodedHost = btoa(hostname)
const fullURL = encodedHost + '/' + path
url = '/fetch/' + fullURL
} else if (url.startsWith('//')) {
const encodedURL = btoa('http:' + url)
url = '/alloy/?url=' + encodedURL
} else if (url.startsWith('/')) {
if (url.startsWith('/fetch')) {
url = url
} else if (url.startsWith('/alloy')) {
url = url
} else {
let apData = document.getElementById('alloyData');
let urlData = apData.getAttribute('data-alloyURL');
url = '/fetch/' + urlData + url
}
}
return ajaxRewrite.apply(this, arguments);
}
let windowFetchRewrite = window.fetch;window.fetch = function(url) {
if (url.startsWith(`https://${window.location.hostname}`)) {
url = url
} else if (url.startsWith('http')) {
const hostname = url.split('/').slice(0, 3).join('/')
const path = url.split('/').slice(3).join('/')
const encodedHost = btoa(hostname)
const fullURL = encodedHost + '/' + path
url = '/fetch/' + fullURL
} else if (url.startsWith('//')) {
const encodedURL = btoa('http:' + url)
url = '/alloy/?url=' + encodedURL
} else if (url.startsWith('/')) {
if (url.startsWith('/fetch')) {
url = url
} else if (url.startsWith('/alloy')) {
url = url
} else {
let apData = document.getElementById('alloyData');
let urlData = apData.getAttribute('data-alloyURL');
url = '/fetch/' + urlData + url
}
}
return windowFetchRewrite.apply(this, arguments);
}
//Create Element rewriting
var original = document.createElement;
document.createElement = function (tag) {
var element = original.call(document, tag);
if (tag.toLowerCase() === 'script') {
Object.defineProperty(element.__proto__, 'src', {
set: function(newValue) {
if (newValue.startsWith('/fetch/')) {
element.setAttribute('src', newValue)
} else if (newValue.startsWith('/alloy/')) {
element.setAttribute('src', newValue)
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
element.setAttribute('src', newValue)
} else if (newValue.startsWith('//')) {
const encodedURL = btoa('http:' + newValue)
element.setAttribute('src', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('https://')) {
const encodedURL = btoa(newValue)
element.setAttribute('src', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('http://')) {
const encodedURL = btoa(newValue)
element.setAttribute('src', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('/')) {
element.setAttribute('src', '/fetch/' + urlData + newValue)
} else {
element.setAttribute('src', newValue)
}
}
});
} else if (tag.toLowerCase() === 'iframe') {
Object.defineProperty(element.__proto__, 'src', {
set: function(newValue) {
if (newValue.startsWith('/fetch/')) {
element.setAttribute('src', newValue)
} else if (newValue.startsWith('/alloy/')) {
element.setAttribute('src', newValue)
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
element.setAttribute('src', newValue)
} else if (newValue.startsWith('//')) {
const encodedURL = btoa('http:' + newValue)
element.setAttribute('src', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('https://')) {
const encodedURL = btoa(newValue)
element.setAttribute('src', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('http://')) {
const encodedURL = btoa(newValue)
element.setAttribute('src', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('/')) {
element.setAttribute('src', '/fetch/' + urlData + newValue)
} else {
element.setAttribute('src', newValue)
}
}
});
}
else if (tag.toLowerCase() === 'link') {
Object.defineProperty(element.__proto__, 'href', {
set: function(newValue) {
if (newValue.startsWith('/fetch/')) {
element.setAttribute('href', newValue)
} else if (newValue.startsWith('/alloy/')) {
element.setAttribute('href', newValue)
} else if (newValue.startsWith(`https://${window.location.hostname}`)) {
element.setAttribute('href', newValue)
} else if (newValue.startsWith('//')) {
const encodedURL = btoa('http:' + newValue)
element.setAttribute('href', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('https://')) {
const encodedURL = btoa(newValue)
element.setAttribute('href', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('http://')) {
const encodedURL = btoa(newValue)
element.setAttribute('href', '/alloy/?url=' + encodedURL)
} else if (newValue.startsWith('/')) {
element.setAttribute('href', '/fetch/' + urlData + newValue)
} else {
element.setAttribute('href', newValue)
}
}
});
}
return element;
}
let setAttributeRewrite = window.Element.prototype.setAttribute;window.Element.prototype.setAttribute = function(name, value) {
switch(name) {
case 'src':
if (value.startsWith('/fetch/')) {
value = value
} else if (value.startsWith('/alloy/')) {
value = value
} else if (value.startsWith('//')) {
value = rewriteURL('http:' + value, 'base64')
} else if (value.startsWith('/')) {
value = rewriteURL(urlData + value)
break;
} else if (value.startsWith('https://') || value.startsWith('http://')) {
value = rewriteURL(value, 'base64')
} else {
value = value
}
break;
case 'href':
if (value.startsWith('/fetch/')) {
value = value
} else if (value.startsWith('//')) {
value = rewriteURL('http:' + value, 'base64')
} else if (value.startsWith('/')) {
value = rewriteURL(urlData + value)
break;
} else if (value.startsWith('https://') || value.startsWith('http://')) {
value = rewriteURL(value, 'base64')
} else {
value = value
}
break;
}
return setAttributeRewrite.apply(this, arguments);
}
var previousState = window.history.state;
setInterval(function() {
if (!window.location.pathname.startsWith(`/fetch/${urlData}/`)) {
history.replaceState('', '', `/fetch/${urlData}/${window.location.href.split('/').splice(3).join('/')}`);
}
}, 0.1);

498
app.js
View file

@ -1,166 +1,161 @@
var https = require('https'); const express = require('express'),
var http = require('http'); app = express(),
var fetch = require('node-fetch'); http = require('http'),
var express = require('express'); https = require('https'),
var fs = require('fs'); fs = require('fs'),
var app = express(); querystring = require('querystring'),
var cookieParser = require('cookie-parser'); session = require('express-session'),
var session = require('express-session'); sanitizer = require('sanitizer'),
var xss = require("xss"); fetch = require('node-fetch');
var config = JSON.parse(fs.readFileSync('config.json', 'utf-8')), const config = JSON.parse(fs.readFileSync('./config.json', {encoding:'utf8'}));
httpsAgent = new https.Agent({ if (!config.prefix.startsWith('/')) {
rejectUnauthorized: false, config.prefix = `/${config.prefix}`;
keepAlive: true, }
}),
httpAgent = new http.Agent({
rejectUnauthorized: false,
keepAlive: true,
}),
ssl = { key: fs.readFileSync('ssl/default.key', 'utf8'), cert: fs.readFileSync('ssl/default.crt', 'utf8') },
server,
port = process.env.PORT || config.port,
ready = (() => {
var a = 'http://', b = config.listenip;
if (config.ssl) a = 'https://';
if (b == '0.0.0.0' || b == '127.0.0.1') b = 'localhost';
console.log('AlloyProxy is now running at', a + b + ':' + port);
});
http.globalAgent.maxSockets = Infinity; if (!config.prefix.endsWith('/')) {
https.globalAgent.maxSockets = Infinity; config.prefix = `${config.prefix}/`;
}
if (config.ssl) server = https.createServer(ssl, app).listen(port, config.listenip, ready); let server;
else server = http.createServer(app).listen(port, config.listenip, ready); 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://';};
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}`;
};
app.use(cookieParser());
app.use(session({ app.use(session({
secret: 'alloy', secret: 'alloy',
saveUninitialized: true, saveUninitialized: true,
resave: true resave: true
})); }));
// We made our own version of body-parser instead, due to issues.
app.use((req, res, next) => { app.use((req, res, next) => {
// nice bodyparser alternative that wont cough up errors if (req.method == 'POST') {
req.raw_body = '';
req.setEncoding('utf8'); req.on('data', chunk => {
req.raw_body = '' req.raw_body += chunk.toString(); // convert Buffer to string
req.body = new Object()
req.on('data', chunk=>{ req.raw_body += chunk });
req.on('end', ()=>{
req.str_body = req.raw_body.toString('utf8');
try{
var result = new Object();
req.str_body.split('&').forEach((pair)=>{
pair = pair.split('=');
req.body[pair[0]] = decodeURIComponent(pair[1] || '');
}); });
req.on('end', () => {
req.str_body = req.raw_body;
try {
req.body = JSON.parse(req.raw_body);
} catch(err) { } catch(err) {
req.body = {} req.body = {}
} }
next();
return next();
}); });
} else return next();
}); });
function base64Encode(data) { app.use(`${config.prefix}utils/`, async(req, res, next) => {
return new Buffer.from(data).toString('base64') if (req.url.startsWith('/assets/')){res.sendFile(__dirname + '/utils' + req.url);}
} if (req.query.url) {
let url = atob(req.query.url);
// How to use: base64Decode('string') will return any input base64 decoded if (url.startsWith('https://') || url.startsWith('http://')) {
function base64Decode(data) { url = url;
return new Buffer.from(data, 'base64').toString('ascii') } else if (url.startsWith('//')) {
} url = 'http:' + url;
// How to use: rewritingURL('https://example.org/assets/main.js') will rewrite any external URL. Output: aHR0cHM6Ly9leGFtcGxlLm9yZw==/assets/main.js
function rewriteURL(dataURL, option) {
var websiteURL
var websitePath
if (option == 'decode') {
websiteURL = base64Decode(dataURL.split('/').splice(0, 1).join('/'))
websitePath = '/' + dataURL.split('/').splice(1).join('/')
} else { } else {
websiteURL = base64Encode(dataURL.split('/').splice(0, 3).join('/')) url = 'http://' + url;
websitePath = '/' + dataURL.split('/').splice(3).join('/')
} }
if (websitePath == '/') { return res.redirect(307, config.prefix + rewrite_url(url));
return `${websiteURL}` }
} else return `${websiteURL}${websitePath}` });
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(''),
} }
// To be used with res.send() to send error. Example: res.send(error('404', 'No valid directory or file was found!')) proxy.url.encoded_origin = btoa(proxy.url.origin);
function error(statusCode, info) {
if (statusCode && info) {
return fs.readFileSync('alloy/assets/error.html', 'utf8').toString().replace('%ERROR%', `Error ${statusCode}: ${info}`)
}
if (info && !statusCode) {
return (fs.readFileSync('alloy/assets/error.html', 'utf8').toString().replace('%ERROR%', `Error: ${info}`))
}
if (statusCode && !info) {
return (fs.readFileSync('alloy/assets/error.html', 'utf8').toString().replace('%ERROR%', `Error ${statusCode}`))
}
return (fs.readFileSync('public/assets/error.html', 'utf8').toString().replace('%ERROR%', `An error has occurred!`))
}
// Post data to set URl's for reverse proxy URL's, or safer redirecting to proxied websites.
app.post('/createSession', async (req, res) => {
if (req.body.url.startsWith('//')) {
req.body.url = 'http:' + req.body.url;
} else if (req.body.url.startsWith('https://') || req.body.url.startsWith('http://')) {
req.body.url = req.body.url;
} else {
req.body.url = 'http://' + req.body.url;
}
if (req.body.rv) {
req.session.rvURL = String(req.body.url).split('/').splice(0, 3).join('/')
return res.redirect('/fetch/rv/' + String(req.body.url).split('/').splice(3).join('/'))
} else {
return res.redirect('/fetch/' + rewriteURL(String(req.body.url)))
}
})
// Custom prefix support will be in full effect soon! proxy.requestHeaders = req.headers;
var prefix = '/fetch'; proxy.requestHeaders['host'] = proxy.url.hostname;
if (proxy.requestHeaders['referer']) {
let referer = '/' + String(proxy.requestHeaders['referer']).split('/').splice(3).join('/');
app.use(prefix, async (req, res, next) => { referer = rewrite_url(referer.replace(config.prefix, ''), 'decode');
var location = rewriteURL(req.url.slice(1), 'decode');
if (req.url.startsWith('/rv') && !req.session.rvURL) { if (referer.startsWith('https://') || referer.startsWith('http://')) {
res.send(error('400', 'No valid session URL for reverse proxy mode was found!')) referer = referer;
} else referer = proxy.url.href;
proxy.requestHeaders['referer'] = referer;
} }
if (req.url.startsWith('/rv') && req.session.rvURL) {
location = req.session.rvURL + req.url.slice(3)
if (proxy.requestHeaders['origin']) {
let origin = '/' + String(proxy.requestHeaders['origin']).split('/').splice(3).join('/');
origin = rewrite_url(origin.replace(config.prefix, ''), 'decode');
if (origin.startsWith('https://') || origin.startsWith('http://')) {
origin = origin.split('/').splice(0, 3).join('/');
} else origin = proxy.url.origin;
proxy.requestHeaders['origin'] = origin;
} }
location = {
href: location, if (proxy.requestHeaders.cookie) {
hostname : location.split('/').splice(2).splice(0, 1).join('/'), delete proxy.requestHeaders.cookie;
origin : location.split('/').splice(0, 3).join('/'),
origin_encoded : base64Encode(location.split('/').splice(0, 3).join('/')),
path : '/' + location.split('/').splice(3).join('/'),
protocol : location.split('\:').splice(0, 1).join(''),
} }
var httpAgent = new http.Agent({ const httpAgent = new http.Agent({
keepAlive: true keepAlive: true
}); });
var httpsAgent = new https.Agent({ const httpsAgent = new https.Agent({
keepAlive: true keepAlive: true
}); });
proxy.options = {
// We are using the clients request headers as the headers to send the request so that headers such as Authorization will be passed through in a XML or fetch() request.
// The host header has to be set to the websites host and not the apps hostname so that there won't be issues.
var fetchHeaders = req.headers
fetchHeaders['referer'] = location.href
fetchHeaders['origin'] = location.origin
fetchHeaders['host'] = location.hostname
// Cookie header causing issues sometimes :cursed:
if (fetchHeaders['cookie']) {
delete fetchHeaders['cookie']
}
var options = {
method: req.method, method: req.method,
headers: fetchHeaders, headers: proxy.requestHeaders,
redirect: 'manual', redirect: 'manual',
agent: function(_parsedURL) { agent: function(_parsedURL) {
if (_parsedURL.protocol == 'http:') { if (_parsedURL.protocol == 'http:') {
@ -172,176 +167,125 @@ app.use(prefix, async (req, res, next) => {
}; };
if (req.method == 'POST') { if (req.method == 'POST') {
try { proxy.options.body = req.str_body;
// str_body is a string containing the requests body
options['body'] = req.str_body;
}catch(err){
return;
} }
} if (proxy.url.hostname == 'discord.com' && proxy.url.path == '/') { return res.redirect(307, config.prefix + rewrite_url('https://discord.com/login'));};
// Makes sure to use the session URL that is contained so RV mode works.
if (req.url.startsWith('/rv')) {
location.origin_encoded = 'rv'
}
if (!req.url.startsWith(`/${location.origin_encoded}/`)) {
try{
return res.redirect(307,`/fetch/${location.origin_encoded}/`)
}catch(err){
return;
}
}
// Custom fixes for websites such as Discord and Reddit.
if (location.href == 'https://discord.com' || location.href == 'https://discord.com/new') {
return res.redirect(307, `/fetch/${location.origin_encoded}/login`)
}
if (location.origin == 'https://www.reddit.com') {
if (req.url.startsWith('/rv') && req.session.rvURL) {
req.session.rvURL = 'https://old.reddit.com'
return res.redirect(307, '/fetch/rv' + location.path)
}
return res.redirect(307, '/fetch/' + base64Encode('https://old.reddit.com') + location.path)
}
// This is where I am making the request, and getting the buffer and headers.
const response = await fetch(location.href, options).catch(err => res.send(error('404', `"${xss(location.href)}" was not found!`)));
if(typeof response.buffer != 'function')return;
var resbody = await response.buffer();
var contentType = 'text/plain'
response.headers.forEach((e, i, a) => { if (proxy.url.hostname == 'www.reddit.com') { return res.redirect(307, config.prefix + rewrite_url('https://old.reddit.com'));};
if (i == 'content-type') contentType = e;
if (!req.url.slice(1).startsWith(`${proxy.url.encoded_origin}/`)) { return res.redirect(307, config.prefix + proxy.url.encoded_origin + '/');};
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(typeof proxy.response.buffer != 'function')return;
proxy.buffer = await proxy.response.buffer();
proxy.content_type = 'text/plain';
proxy.response.headers.forEach((e, i, a) => {
if (i == 'content-type') proxy.content_type = e;
}); });
if (contentType == null || typeof contentType == 'undefined') ct = 'text/html'; if (proxy.content_type == null || typeof proxy.content_type == 'undefined') proxy.content_type = 'text/html';
var serverHeaders = Object.fromEntries(
Object.entries(JSON.parse(JSON.stringify(response.headers.raw()))) 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]]) .map(([key, val]) => [key, val[0]])
); );
// Making sure redirects are proxied.
if (serverHeaders['location']) {
if (req.url.startsWith('/rv') && req.session.rvURL) {
req.session.rvURL = String(serverHeaders['location']).split('/').splice(0, 3).join('/')
return res.redirect(307, '/fetch/rv/' + String(serverHeaders['location']).split('/').splice(3).join('/'))
} else return res.redirect(307, '/fetch/' + rewriteURL(String(serverHeaders['location'])))
}
// These headers can be conflicting.
delete serverHeaders['content-encoding']
delete serverHeaders['x-frame-options']
delete serverHeaders['strict-transport-security']
delete serverHeaders['content-security-policy']
delete serverHeaders['location']
// Setting status, headers, and content-type. // Parsing all the headers to remove all of the bad headers that could affect proxies performance.
res.status(response.status) Object.entries(proxy.headers).forEach(([header_name, header_value]) => {
res.set(serverHeaders) 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')) {
res.contentType(contentType) delete proxy.headers[header_name];
if (response.redirected == true) {
if (req.url.startsWith('/rv') && req.session.rvURL) {
req.session.rvURL = response.url.split('/').splice(0, 3).join('/')
return res.redirect(307, '/fetch/rv/' + response.url.split('/').splice(3).join('/'))
} else return res.redirect(307, '/fetch/' + rewriteURL(response.url))
} }
if (contentType.startsWith('text/html')) { });
req.session.fetchURL = location.origin_encoded
resbody = resbody.toString() // 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(/integrity="(.*?)"/gi, '')
.replace(/nonce="(.*?)"/gi, '') .replace(/nonce="(.*?)"/gi, '')
.replace(/(href|src|poster|data|action)="\/\/(.*?)"/gi, `$1` + `="http://` + `$2` + `"`) .replace(/(href|src|poster|data|action|srcset)="\/\/(.*?)"/gi, `$1` + `="http://` + `$2` + `"`)
.replace(/(href|src|poster|data|action)='\/\/(.*?)'/gi, `$1` + `='http://` + `$2` + `'`) .replace(/(href|src|poster|data|action|srcset)='\/\/(.*?)'/gi, `$1` + `='http://` + `$2` + `'`)
.replace(/(href|src|poster|data|action)="\/(.*?)"/gi, `$1` + `="/fetch/${location.origin_encoded}/` + `$2` + `"`) .replace(/(href|src|poster|data|action|srcset)="\/(.*?)"/gi, `$1` + `="${config.prefix}${proxy.url.encoded_origin}/` + `$2` + `"`)
.replace(/(href|src|poster|data|action)='\/(.*?)'/gi, `$1` + `='/fetch/${location.origin_encoded}/` + `$2` + `'`) .replace(/(href|src|poster|data|action|srcset)='\/(.*?)'/gi, `$1` + `='${config.prefix}${proxy.url.encoded_origin}/` + `$2` + `'`)
.replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) { .replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) {
str = str.split(`'`).slice(1).slice(0, -1).join(``); str = str.split(`'`).slice(1).slice(0, -1).join(``);
return `'/fetch/${rewriteURL(str)}'` return `'${config.prefix}${rewrite_url(str)}'`
}) })
.replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) { .replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) {
str = str.split(`"`).slice(1).slice(0, -1).join(``); str = str.split(`"`).slice(1).slice(0, -1).join(``);
return `"/fetch/${rewriteURL(str)}"` return `"${config.prefix}${rewrite_url(str)}"`
}) })
.replace(/(window|document).location.href/gi, `"${location.href}"`) .replace(/(window|document).location.href/gi, `"${proxy.url.href}"`)
.replace(/(window|document).location.hostname/gi, `"${location.hostname}"`) .replace(/(window|document).location.hostname/gi, `"${proxy.url.hostname}"`)
.replace(/(window|document).location.pathname/gi, `"${location.path}"`) .replace(/(window|document).location.pathname/gi, `"${proxy.url.path}"`)
.replace(/location.href/gi, `"${location.href}"`) .replace(/location.href/gi, `"${proxy.url.href}"`)
.replace(/location.hostname/gi, `"${location.hostname}"`) .replace(/location.hostname/gi, `"${proxy.url.hostname}"`)
.replace(/location.pathname/gi, `"${location.path}"`) .replace(/location.pathname/gi, `"${proxy.url.path}"`)
.replace(/<html(.*?)>/gi, '<html' + '$1' + '><script id="alloyData" data-alloyURL="' + location.origin_encoded + '"' + ' src="/alloy/assets/inject.js"></script>') .replace(/<html(.*?)>/gi, `<html` + '$1' + `><script src="${config.prefix}utils/assets/inject.js" id="_alloy_data" prefix="${config.prefix}" url="${btoa(proxy.url.href)}"></script>`);
} else if (contentType.startsWith('text/css')) { // Temp hotfix for Youtube search bar until my script injection can fix it.
resbody = resbody.toString()
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('http://` + `$1` + `')`)
.replace(/url\(\/\/(.*?)\)/gi, `url(http://` + `$1` + `)`) .replace(/url\(\/\/(.*?)\)/gi, `url(http://` + `$1` + `)`)
.replace(/url\("\/(.*?)"\)/gi, `url("/fetch/${location.origin_encoded}/` + `$1` + `")`) .replace(/url\("\/(.*?)"\)/gi, `url("${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `")`)
.replace(/url\('\/(.*?)'\)/gi, `url('/fetch/${location.origin_encoded}/` + `$1` + `')`) .replace(/url\('\/(.*?)'\)/gi, `url('${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `')`)
.replace(/url\(\/(.*?)\)/gi, `url(/fetch/${location.origin_encoded}/` + `$1` + `)`) .replace(/url\(\/(.*?)\)/gi, `url(${config.prefix}${proxy.url.encoded_origin}/` + `$1` + `)`)
.replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) { .replace(/"(https:\/\/|http:\/\/)(.*?)"/gi, function(str) {
str = str.split(`"`).slice(1).slice(0, -1).join(``); str = str.split(`"`).slice(1).slice(0, -1).join(``);
return `"/fetch/${rewriteURL(str)}"` return `"${config.prefix}${rewrite_url(str)}"`
}) })
.replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) { .replace(/'(https:\/\/|http:\/\/)(.*?)'/gi, function(str) {
str = str.split(`'`).slice(1).slice(0, -1).join(``); str = str.split(`'`).slice(1).slice(0, -1).join(``);
return `'/fetch/${rewriteURL(str)}'` return `'${config.prefix}${rewrite_url(str)}'`
}) })
.replace(/\((https:\/\/|http:\/\/)(.*?)\)/gi, function(str) { .replace(/\((https:\/\/|http:\/\/)(.*?)\)/gi, function(str) {
str = str.split(`(`).slice(1).join(``).split(')').slice(0, -1).join(''); str = str.split(`(`).slice(1).join(``).split(')').slice(0, -1).join('');
return `(/fetch/${rewriteURL(str)})` return `(${config.prefix}${rewrite_url(str)})`
}) });
} else if (contentType.startsWith('text/javascript') || contentType.startsWith('application/javascript')) { };
resbody = resbody.toString() // We send the response from the server rewritten.
.replace(/xhttp.open\("GET",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhttp.open("GET",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true') res.send(proxy.sendResponse);
.replace(/xhttp.open\("POST",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhttp.open("POST",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true') });
.replace(/xhttp.open\("OPTIONS",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhttp.open("OPTIONS",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
app.use('/', express.static('public'));
.replace(/xhr.open\("GET",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhr.open("GET",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true')
.replace(/xhr.open\("POST",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhr.open("POST",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true') app.use(async(req, res, next) => {
.replace(/xhr.open\("OPTIONS",(.*?)"http(.*?)"(.*?),(.*?)true\);/gi, ' xhr.open("OPTIONS",' + '$1' + '"/alloy/url/http' + '$2' + '"' + '$3' + ',' + '$4' + 'true') if (req.headers['referer']) {
.replace(/ajax\("http:\/\/(.*?)"\)/gi, 'ajax("/alloy/url/http://' + '$1' + '")')
.replace(/ajax\("https:\/\/(.*?)"\)/gi, 'ajax("/alloy/url/https://' + '$1' + '")') let referer = '/' + String(req.headers['referer']).split('/').splice(3).join('/');
}
res.send(resbody) referer = rewrite_url(referer.replace(config.prefix, ''), 'decode').split('/').splice(0, 3).join('/');
})
if (referer.startsWith('https://') || referer.startsWith('http://')) {
app.use('/alloy/url/',function (req, res, next) { res.redirect(307, config.prefix + btoa(referer) + req.url)
const mainurl = req.url.split('/').slice(1).join('/') } else {
const host = mainurl.split('/').slice(0, 3).join('/') if (req.session.url) {
const buff = new Buffer(host);
const host64 = buff.toString('base64'); res.redirect(307, config.prefix + btoa(req.session.url) + req.url)
const path = mainurl.split('/').slice(3).join('/')
const fullURL = host64 + '/' + path } else return next();
res.redirect(307, '/fetch/' + fullURL) }
}) } else if (req.session.url) {
// Utils section. Where stuff such as inject scripts are found! res.redirect(307, config.prefix + btoa(req.session.url) + req.url)
app.use('/alloy/',function (req, res, next) {
} else return next();
if (req.query.url) {
var clientInput = base64Decode(req.query.url)
var fetchURL;
if (clientInput.startsWith('//')) {
fetchURL = rewriteURL('http:' + clientInput)
} else if (clientInput.startsWith('http://') || clientInput.startsWith('https://')) {
fetchURL = rewriteURL(clientInput)
} else {
fetchURL = rewriteURL('http://' + clientInput)
}
return res.redirect(307, '/fetch/' + fetchURL)
}
res.sendFile(__dirname + '/alloy' + req.url, function (err) {
if (err) {
if (req.session.fetchURL) {
return res.redirect(307, '/fetch/' + req.session.fetchURL + req.url)
} else return res.redirect(307, '/')
}
})
})
app.use(function (req, res, next) {
res.sendFile(__dirname + '/public' + req.url, function (err) {
if (err) {
if (req.session.fetchURL) {
return res.redirect(307, '/fetch/' + req.session.fetchURL + req.url)
} else return res.redirect(307, '/')
}
})
}); });

View file

@ -1,7 +1,7 @@
{ {
"name": "Holy Unblocker", "name": "Alloy Proxy",
"description": "A website that can be used to bypass web filters; both extension and firewall. Alloy Proxy hosted locally. (Can be used as a template.)", "description": "A node.js web proxy featuring URL encoding, and amazing compatablity!",
"repository": "https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic/", "repository": "https://github.com/titaniumnetwork-dev/alloyproxy/",
"logo": "https://www.holyubofficial.ml/assets/img/i.png", "logo": "https://avatars1.githubusercontent.com/u/47227492?s=200&v=4",
"keywords": ["node", "proxy", "unblocker" , "webproxy" , "games" , "holyunblocker" , "alloy"] "keywords": ["node", "proxy", "unblocker"]
} }

View file

@ -1,5 +1,5 @@
{ {
"listenip":"0.0.0.0", "port": "8080",
"port":8080, "prefix": "/proxy/",
"ssl": false "ssl": false
} }

130
package-lock.json generated
View file

@ -1,6 +1,6 @@
{ {
"name": "alloyproxy", "name": "alloy-proxy",
"version": "1.0.0", "version": "2.3.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -18,6 +18,11 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
}, },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"body-parser": { "body-parser": {
"version": "1.19.0", "version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
@ -35,15 +40,24 @@
"type-is": "~1.6.17" "type-is": "~1.6.17"
} }
}, },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"bytes": { "bytes": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
}, },
"commander": { "concat-map": {
"version": "2.20.3", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
}, },
"content-disposition": { "content-disposition": {
"version": "0.5.3", "version": "0.5.3",
@ -77,11 +91,6 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
}, },
"cssfilter": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4="
},
"debug": { "debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -100,6 +109,11 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
}, },
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
},
"ee-first": { "ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -184,6 +198,11 @@
} }
} }
}, },
"eyes": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz",
"integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
},
"finalhandler": { "finalhandler": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
@ -198,11 +217,6 @@
"unpipe": "~1.0.0" "unpipe": "~1.0.0"
} }
}, },
"follow-redirects": {
"version": "1.13.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz",
"integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA=="
},
"forwarded": { "forwarded": {
"version": "0.1.2", "version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@ -213,6 +227,24 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
}, },
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"http-errors": { "http-errors": {
"version": "1.7.2", "version": "1.7.2",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
@ -233,6 +265,15 @@
"safer-buffer": ">= 2.1.2 < 3" "safer-buffer": ">= 2.1.2 < 3"
} }
}, },
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
@ -276,6 +317,14 @@
"mime-db": "1.44.0" "mime-db": "1.44.0"
} }
}, },
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"ms": { "ms": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
@ -304,16 +353,24 @@
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
}, },
"parse-raw-http": { "once": {
"version": "0.0.1", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/parse-raw-http/-/parse-raw-http-0.0.1.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-GndQvIQXviId7eHnc+fEcmtEjkj1tQ96EhNOplPwXA8L1jgOnrlx/xLmmOEew8Yj4ZoZpmoAh0IvypAaeMbILg==" "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
}, },
"parseurl": { "parseurl": {
"version": "1.3.3", "version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
}, },
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-to-regexp": { "path-to-regexp": {
"version": "0.1.7", "version": "0.1.7",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
@ -364,6 +421,11 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"sanitizer": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/sanitizer/-/sanitizer-0.1.3.tgz",
"integrity": "sha1-1PCvdHXZp7ryqeWmEXGLqheKOeE="
},
"send": { "send": {
"version": "0.17.1", "version": "0.17.1",
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
@ -402,6 +464,14 @@
"send": "0.17.1" "send": "0.17.1"
} }
}, },
"session": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/session/-/session-0.1.0.tgz",
"integrity": "sha1-aumqbyYJO+Me0gBbzUJq6AqjoIU=",
"requires": {
"vows": "*"
}
},
"setprototypeof": { "setprototypeof": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
@ -449,14 +519,20 @@
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
}, },
"xss": { "vows": {
"version": "1.0.8", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.8.tgz", "resolved": "https://registry.npmjs.org/vows/-/vows-0.8.3.tgz",
"integrity": "sha512-3MgPdaXV8rfQ/pNn16Eio6VXYPTkqwa0vc7GkiymmY/DqR1SE/7VPAAVZz1GJsJFrllMYO3RHfEaiUGjab6TNw==", "integrity": "sha512-PVIxa/ovXhrw5gA3mz6M+ZF3PHlqX4tutR2p/y9NWPAaFVKcWBE8b2ktfr0opQM/qFmcOVWKjSCJVjnYOvjXhw==",
"requires": { "requires": {
"commander": "^2.20.3", "diff": "^4.0.1",
"cssfilter": "0.0.10" "eyes": "~0.1.6",
} "glob": "^7.1.2"
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
} }
} }
} }

View file

@ -1,33 +1,25 @@
{ {
"name": "alloyproxy", "name": "alloy-proxy",
"version": "1.0.0", "version": "2.2.0",
"description": "A powerful web proxy!", "description": "A web proxy capable of proxying websites!",
"main": "app.js", "main": "app.js",
"scripts": { "scripts": {
"test": "proxy", "test": "test",
"start": "node app.js" "start": "node app.js"
}, },
"repository": {
"type": "git",
"url": "git+https://github.com/titaniumnetwork-dev/alloyproxy.git"
},
"keywords": [ "keywords": [
"web-proxy" "proxy",
"node.js",
"unblocker"
], ],
"author": "titaniumnetwork-dev", "author": "Titanium Network",
"license": "ISC", "license": "ISC",
"bugs": {
"url": "https://github.com/titaniumnetwork-dev/alloyproxy/issues"
},
"homepage": "https://github.com/titaniumnetwork-dev/alloyproxy#readme",
"dependencies": { "dependencies": {
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"express": "^4.17.1", "express": "^4.17.1",
"express-session": "^1.17.1", "express-session": "^1.17.1",
"follow-redirects": "^1.13.0", "node-fetch": "^2.6.1",
"node-fetch": ">=2.6.1", "sanitizer": "^0.1.3",
"parse-raw-http": "0.0.1", "session": "^0.1.0"
"xss": "^1.0.8"
} }
} }

79
utils/assets/inject.js Normal file
View file

@ -0,0 +1,79 @@
var alloy_data = document.querySelector('#_alloy_data');
var url = alloy_data.getAttribute('url');
var prefix = alloy_data.getAttribute('prefix');
url = new URL(atob(url))
rewrite_url = (str) => {
proxied_url = '';
if (str.startsWith(window.location.origin + '/') && !str.startsWith(window.location.origin + prefix)) {
str = '/' + str.split('/').splice(3).join('/');
}
if (str.startsWith('//')) {
str = 'http:' + str;
} else if (str.startsWith('/') && !str.startsWith(prefix)) {
str = url.origin + str
}
if (str.startsWith('https://') || str.startsWith('http://')) {
path = "/" + str.split('/').splice(3).join('/');
origin = btoa(str.split('/').splice(0, 3).join('/'));
return proxied_url = prefix + origin + path
} else {
proxied_url = str;
}
return proxied_url;
}
let fetch_rewrite = window.fetch; window.fetch = function(url, options) {
url = rewrite_url(url);
return fetch_rewrite.apply(this, arguments);
}
let xml_rewrite = window.XMLHttpRequest.prototype.open;window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {
url = rewrite_url(url);
return xml_rewrite.apply(this, arguments);
}
let createelement_rewrite = document.createElement; document.createElement = function(tag) {
var element = createelement_rewrite.call(document, tag);
if (tag.toLowerCase() === 'script' || tag.toLowerCase() === 'iframe' || tag.toLowerCase() === 'embed') {
Object.defineProperty(element.__proto__, 'src', {
set: function(value) {
value = rewrite_url(value)
element.setAttribute('src', value)
}
});
} else if (tag.toLowerCase() === 'link') {
Object.defineProperty(element.__proto__, 'href', {
set: function(value) {
value = rewrite_url(value)
element.setAttribute('href', value)
}
});
} else if (tag.toLowerCase() === 'form') {
Object.defineProperty(element.__proto__, 'action', {
set: function(value) {
value = rewrite_url(value)
element.setAttribute('action', value)
}
});
}
return element;
}
let setattribute_rewrite = window.Element.prototype.setAttribute; window.Element.prototype.setAttribute = function(attribute, href) {
if (attribute == ('src') || attribute == ('href') || attribute == ('action')) {
href = rewrite_url(href)
} else href = href;
return setattribute_rewrite.apply(this, arguments)
}
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);

View file

@ -1,3 +1,4 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">