mirror of
https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
synced 2025-05-13 03:50:02 -04:00
Updated Alloy (v2.3)
This commit is contained in:
parent
c15aef5eb2
commit
b83e2fece4
5 changed files with 391 additions and 276 deletions
539
app.js
539
app.js
|
@ -1,310 +1,307 @@
|
||||||
const express = require('express'),
|
const express = require('express'),
|
||||||
app = express(),
|
app = express(),
|
||||||
http = require('http'),
|
http = require('http'),
|
||||||
https = require('https'),
|
https = require('https'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
querystring = require('querystring'),
|
querystring = require('querystring'),
|
||||||
session = require('express-session'),
|
session = require('express-session'),
|
||||||
sanitizer = require('sanitizer'),
|
sanitizer = require('sanitizer'),
|
||||||
fetch = require('node-fetch');
|
websocket = require('./ws-proxy.js'),
|
||||||
|
fetch = require('node-fetch');
|
||||||
|
|
||||||
const config = JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf8' }));
|
const config = JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf8' }));
|
||||||
if (!config.prefix.startsWith('/')) {
|
if (!config.prefix.startsWith('/')) {
|
||||||
config.prefix = `/${config.prefix}`;
|
config.prefix = `/${config.prefix}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.prefix.endsWith('/')) {
|
if (!config.prefix.endsWith('/')) {
|
||||||
config.prefix = `${config.prefix}/`;
|
config.prefix = `${config.prefix}/`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let server;
|
let server;
|
||||||
let server_protocol;
|
let server_protocol;
|
||||||
const server_options = {
|
const server_options = {
|
||||||
key: fs.readFileSync('./ssl/default.key'),
|
key: fs.readFileSync('./ssl/default.key'),
|
||||||
cert: fs.readFileSync('./ssl/default.crt')
|
cert: fs.readFileSync('./ssl/default.crt')
|
||||||
}
|
}
|
||||||
if (config.ssl == true) {
|
if (config.ssl == true) { server = https.createServer(server_options, app);
|
||||||
server = https.createServer(server_options, app);
|
server_protocol = 'https://'; } else { server = http.createServer(app);
|
||||||
server_protocol = 'https://';
|
server_protocol = 'http://'; };
|
||||||
} else {
|
|
||||||
server = http.createServer(app);
|
// WebSocket Proxying
|
||||||
server_protocol = 'http://';
|
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}"!`);
|
if (proxy.requestHeaders['origin']) {
|
||||||
server.listen(process.env.PORT || config.port);
|
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) => {
|
} else origin = proxy.url.origin;
|
||||||
str = new Buffer.from(str).toString('base64');
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
atob = (str) => {
|
proxy.requestHeaders['origin'] = origin;
|
||||||
str = new Buffer.from(str, 'base64').toString('utf-8');
|
}
|
||||||
return str;
|
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) => {
|
if (req.method == 'POST') {
|
||||||
var websiteURL;
|
proxy.options.body = req.str_body;
|
||||||
var websitePath;
|
}
|
||||||
if (option == 'decode') {
|
if (proxy.url.hostname == 'discord.com' && proxy.url.path == '/') { return res.redirect(307, config.prefix + rewrite_url('https://discord.com/login')); };
|
||||||
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(session({
|
if (proxy.url.hostname == 'www.reddit.com') { return res.redirect(307, config.prefix + rewrite_url('https://old.reddit.com')); };
|
||||||
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.slice(1).startsWith(`${proxy.url.encoded_origin}/`)) { return res.redirect(307, config.prefix + proxy.url.encoded_origin + '/'); };
|
||||||
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) => {
|
const blocklist = JSON.parse(fs.readFileSync('./blocklist.json', { encoding: 'utf8' }));
|
||||||
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) => {
|
let is_blocked = false;
|
||||||
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);
|
Array.from(blocklist).forEach(blocked_hostname => {
|
||||||
|
if (proxy.url.hostname == blocked_hostname) {
|
||||||
|
is_blocked = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
proxy.requestHeaders = req.headers;
|
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!`)) }
|
||||||
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');
|
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://')) {
|
if (typeof proxy.response.buffer != 'function') return;
|
||||||
referer = referer;
|
|
||||||
|
|
||||||
} 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']) {
|
proxy.sendResponse = proxy.buffer;
|
||||||
let origin = '/' + String(proxy.requestHeaders['origin']).split('/').splice(3).join('/');
|
|
||||||
|
|
||||||
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(/<html(.*?)>/gi, `<html` + '$1' + `><script src="${config.prefix}utils/assets/inject.js" id="_alloy_data" prefix="${config.prefix}" url="${btoa(proxy.url.href)}"></script>`);
|
||||||
|
|
||||||
proxy.requestHeaders['origin'] = origin;
|
// Temp hotfix for Youtube search bar until my script injection can fix it.
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (req.method == 'POST') {
|
if (proxy.url.hostname == 'www.youtube.com') { proxy.sendResponse = proxy.sendResponse.replace(/\/results/gi, `${config.prefix}${proxy.url.encoded_origin}/results`); };
|
||||||
proxy.options.body = req.str_body;
|
} else if (proxy.content_type.startsWith('text/css')) {
|
||||||
}
|
proxy.sendResponse = proxy.sendResponse.toString()
|
||||||
if (proxy.url.hostname == 'discord.com' && proxy.url.path == '/') { return res.redirect(307, config.prefix + rewrite_url('https://discord.com/login')); };
|
.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 => {
|
referer = rewrite_url(referer.replace(config.prefix, ''), 'decode').split('/').splice(0, 3).join('/');
|
||||||
if (proxy.url.hostname == blocked_hostname) {
|
|
||||||
is_blocked = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
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';
|
} else return next();
|
||||||
|
});
|
||||||
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(/<html(.*?)>/gi, `<html` + '$1' + `><script src="${config.prefix}utils/assets/inject.js" id="_alloy_data" prefix="${config.prefix}" url="${btoa(proxy.url.href)}"></script>`);
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
});
|
|
|
@ -1,3 +1,3 @@
|
||||||
[
|
[
|
||||||
"example.com"
|
"add-your-website-url.blocked"
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "alloy-proxy",
|
"name": "alloy-proxy",
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"description": "A web proxy capable of proxying websites!",
|
"description": "A web proxy capable of proxying websites!",
|
||||||
"main": "app.js",
|
"main": "app.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -21,6 +21,7 @@
|
||||||
"node-fetch": "^2.6.1",
|
"node-fetch": "^2.6.1",
|
||||||
"sanitizer": "^0.1.3",
|
"sanitizer": "^0.1.3",
|
||||||
"session": "^0.1.0",
|
"session": "^0.1.0",
|
||||||
"cookies": "0.4"
|
"cookies": "0.4",
|
||||||
|
"ws": "^7.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -71,9 +71,39 @@ let setattribute_rewrite = window.Element.prototype.setAttribute; window.Element
|
||||||
return setattribute_rewrite.apply(this, arguments)
|
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;
|
var previousState = window.history.state;
|
||||||
setInterval(function() {
|
setInterval(function() {
|
||||||
if (!window.location.pathname.startsWith(`${prefix}${btoa(url.origin)}/`)) {
|
if (!window.location.pathname.startsWith(`${prefix}${btoa(url.origin)}/`)) {
|
||||||
history.replaceState('', '', `${prefix}${btoa(url.origin)}/${window.location.href.split('/').splice(3).join('/')}`);
|
history.replaceState('', '', `${prefix}${btoa(url.origin)}/${window.location.href.split('/').splice(3).join('/')}`);
|
||||||
}
|
}
|
||||||
}, 0.1);
|
}, 0.1);
|
||||||
|
|
87
ws-proxy.js
Normal file
87
ws-proxy.js
Normal file
|
@ -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); }
|
||||||
|
});
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue