Minor Edits

This commit is contained in:
TheEmeraldStarr 2021-02-28 12:01:47 -08:00
parent eeaa56dfe4
commit 27b55eb78e
12 changed files with 1102 additions and 5 deletions

4
app.js
View file

@ -2,7 +2,7 @@
/* Author : QuiteAFancyEmerald, YÖCTDÖNALD'S and SexyDuceDuce with help from Divide
/* MIT license: http://opensource.org/licenses/MIT
/* ----------------------------------------------- */
const [express, alloy, http, fs, path, char_insert] = [require('express'), require('alloyproxy'), require('http'), require('fs'), require('path'), require('./src/charinsert.js')], [app, config] = [express(), JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf8' }))], server = http.createServer(app), localprox = new alloy({
const [express, alloy, http, fs, path, char_insert] = [require('express'), require('./src/alloyproxy'), require('http'), require('fs'), require('path'), require('./src/charinsert.js')], [app, config] = [express(), JSON.parse(fs.readFileSync('./config.json', { encoding: 'utf8' }))], server = http.createServer(app), localprox = new alloy({
prefix: '/fetch/',
error: (proxy) => { proxy.res.send(fs.readFileSync('./views/error.html', { encoding: 'utf8' }).replace('%ERR%', proxy.error.info.message.replace(/</gi, '<&zwnj;').replace(/>/gi, '>&zwnj;'))); }, // Doing replace functions on "<" and ">" to prevent XSS.
request: [],
@ -237,4 +237,4 @@ atob = (str) => {
return str;
};
*/
*/

View file

@ -16,7 +16,7 @@
"author": "Titanium Network",
"license": "MIT",
"dependencies": {
"alloyproxy": "^1.1.0",
"ws": "^7.4.3",
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"express-session": "^1.17.1",

156
src/alloyproxy/README.md Normal file
View file

@ -0,0 +1,156 @@
# AlloyProxy
Module specialized in proxying websites to unblock the web.
## Table of contents:
- [Setup](#how-to-use)
- [Module Use](#module-use)
- [Sample Implementation](#sample-express-application)
- [Sample Implementation Extended](#sample-implementation)
- [Configurations](#configurations)
- [General Use](#general-use)
- [Extended Configuration Information](#extended-configuration-information)
- [Websocket Proxy Information](#websocket-proxy-information)
### Module Use
1. `npm install alloyproxy`
2. Set all of your configs in the main file for the Node app.
3. Start up your app and unblock a website at `/prefix/[BASE64 ENCODED WEBSITE ORIGIN]/`. The path of the website does not have to be B64 encoded.
A good example of what code to use is here using the Express.js framework.
### Sample Express Application
1. Navigate to the `/examples/` folder.
2. Do the following commands:
```
cd examples/express
npm install
npm start
```
The demo application will run at `localhost:8080` by default however the port can be configured in `config.json`.
The static folder provides you with the base site if you wish to go manual about this.
### Sample Implementation
Add this to your server-side script ex. "app.js".
```
// Note: make sure you use Alloy before any other Express middleware that sends responses to client or handles POST data.
const Alloy = require('alloyproxy'),
http = require('http'),
express = require('express'),
app = express();
const server = http.createServer(app);
const Unblocker = new Alloy({
prefix: '/fetch/',
request: [],
response: [],
injection: true,
});
// The main part of the proxy.
app.use(Unblocker.app);
// WebSocket handler.
Unblocker.ws(server);
server.listen('8080')
```
## Configurations
### General Use
```
prefix: '/prefix/',
blocklist: [],
// error: (proxy) => { return proxy.res.end('proxy.error.info.message') }, Custom error handling which is optional.
request: [], // Add custom functions before request is made or modify the request.
response: [], // Add custom functions after the request is made or modify the response.
injection: true, // Script injection which is helpful in rewriting window.fetch() and all kinds of client-side JS requests.
requestAgent: null, // Set a custom agent to use in the request.
// userAgent: Uses the clients "User-Agent" request header by default. More customizable using the "request" option in the configs.
localAddress: [] // Neat feature in basic http(s).request() to choose what IP to use to make the request. Will be randomized if there is multiple.
```
### Extended Configuration Information
To use the "request" and "response" options in the config. You must make a function like this for example.
```
customFunction = (proxy) => {
if (proxy.url.hostname == 'example.org' && proxy.response.headers['content-type'].startsWith('text/html')) {
return proxy.sendResponse == proxy.sendResponse.toString().replace(/example/gi, 'cat :3');
};
};
new Alloy({
prefix: '/prefix/',
blocklist: [],
// error: (proxy) => { return proxy.res.end('proxy.error.info.message') }, Custom error handling which is optional.
request: [], // Add custom functions before request is made or modify the request.
response: [
customFunction
], // Add custom functions after the request is made or modify the response.
injection: true, // Script injection which is helpful in rewriting window.fetch() and all kinds of client-side JS requests.
requestAgent: null, // Set a custom agent to use in the request.
// userAgent: Uses the clients "User-Agent" request header by default. More customizable using the "request" option in the configs.
localAddress: [] // Neat feature in basic http(s).request() to choose what IP to use to make the request. Will be randomized if there is multiple.
})
```
What this will do is when the hostname of a website being accessed is `example.org`. The console sends you "weee :3". If you want a preview of what options you have, heres a list. :)
```
// Basic HTTP functions.
proxy.req // This is the request option in HTTP servers. If Express.js is being used, you can use Express.js functions.
proxy.res // This is the response option in HTTP servers. If Express.js is being used, you can use Express.js functions.
proxy.next() // This is only avaliable in Express.js . If used in native HTTP, the app will display blank text as a filler.
// Request
proxy.request.headers // A modified version of the client's request headers used in sending the request.
proxy.request.method // The clients request method.
proxy.request.body // The POST body of a POST / PATCH request.
// Response
proxy.response // The entire response of the website. Contains headers, JSON / text response, and all Node.js http(s).request() response data.
proxy.response.headers // Response headers the website gave back. Is modified to filter out bad headers, and rewrite "Set-Cookie" header.
proxy.sendResponse // The modified response buffer the website gave back. You can modify it in anyway you desire. :)
// Errors
proxy.error.status // Outputs "true" when theres an error.
proxy.error.info // Gives information about an error.
proxy.error.info.code // Gives error code. Error codes such as "ENOTFOUND" mean a website could not be found. "BLOCKED" means a website is blocked.
proxy.error.info.message // Gives error message.
proxy.blocked.status // Outputs "true" when a filtered hostname is detected.
```
## Websocket Proxy Information
Alloy does come with a built in websocket proxy. To use it, you must have an HTTP server already defined. The example of using Alloy as Express middleware already uses the websocket proxy.

View file

@ -0,0 +1,29 @@
// Note: make sure you use Alloy before any other Express middleware that sends responses to client or handles POST data.
const Alloy = require('alloyproxy'),
http = require('http'),
express = require('express'),
app = express();
const server = http.createServer(app);
const Unblocker = new Alloy({
prefix: '/fetch/',
request: [],
response: [],
injection: true,
});
// The main part of the proxy.
app.use(Unblocker.app);
// Do your stuff here! :3
// WebSocket handler.
Unblocker.ws(server);
server.listen('8080')

33
src/alloyproxy/index.js Normal file
View file

@ -0,0 +1,33 @@
module.exports = class {
constructor(config) {
// If parts of the config are messing. The parts are filled with placeholders.
if (!config) config = {};
if (!config.prefix) config.prefix = '/get/';
if (!config.prefix.startsWith('/')) config.prefix = '/' + config.prefix;
if (!config.prefix.endsWith('/')) config.prefix = config.prefix + '/';
if (!config.blocklist) config.blocklist = [];
if (!config.request) config.request = [];
if (!config.response) config.response = [];
this.config = config;
// Main proxy.
this.app = require('./libs/proxy.js')(config);
// WebSocket Proxy.
this.ws = (server) => require('./libs/websocket.js')(server, config);
}
}

View file

@ -0,0 +1,275 @@
const sendRequest = require('./requests.js'),
rewrite = require('./rewriting.js'),
fs = require('fs'),
bodyParser = (req) => {
return new Promise(resolve => {
var body = '';
req.on('data', chunk => {
body += chunk;
}).on('end', () => {
resolve(body);
});
});
};
module.exports = (config) => {
return async (req, res, next) => {
// To have compatibility with both native Node.js HTTP and Express.js.
if (typeof next != 'function') next = () => res.end('');
if (typeof config.injection == 'undefined' || typeof config.injection == 'null') config.injection = true;
if (req.url.startsWith(config.prefix) && config.injection == true) {
// Setting up public directory for injection scripts.
if (req.url.startsWith(`${config.prefix}static/`)) {
path = req.url.toString().replace(`${config.prefix}static`, '');
if (path.includes('?')) path = path.split('?').splice(0, 1).join('');
if (path.includes('#')) path = path.split('#').splice(0, 1).join('');
try {
return res.end(fs.readFileSync(__dirname + `/static${path}`, {
encoding: 'utf8'
}));
} catch (err) {
return res.end('')
};
}
// Setting configurations for errors, requests, urls, and blocklist.
var proxy = {
request: {
// Defined later on. Uses clients request headers as the headers used when making the request to the server, although its slightly modifed to work.
headers: {},
// Using the clients request method as the method used when making the request to the server.0
method: req.method,
// When this is true, the response of websites with invalid SSL certs will not be given.
rejectUnauthorized: false
},
error: {
status: false,
info: null
},
blocked: {
status: false,
},
prefix: config.prefix,
// Can be used to create extra functions.
req: req,
res: res,
next: next,
};
try { proxy.url = new URL(rewrite.url(req.url.replace(config.prefix, ''), 'decode')); } catch(err) {
proxy.error.status = true;
// Using 404 error as a filler for this.
proxy.error.info = {
code: 'ENOTFOUND',
message: `Could not make ${req.method} request to "${rewrite.url(req.url.replace(config.prefix, ''), 'decode')}".`
};
if (config.error) return config.error(proxy);
return res.end(proxy.error.info.message.replace(/</gi, '<&zwnj;').replace(/>/gi, '>&zwnj;'));
};
proxy.injection = config.injection;
Object.entries(req.headers).forEach(([header_name, header_value]) => proxy.request.headers[header_name] = header_value);
delete proxy.request.headers['host'];
// Rewriting "Referer" and "Origin" headers to be accurate as possible in the request.
if (proxy.request.headers['referer']) proxy.request.headers['referer'] = rewrite.referer(proxy.request.headers['referer'], proxy)
if (proxy.request.headers['origin']) proxy.request.headers['origin'] = rewrite.origin(proxy.request.headers['origin'], proxy)
// Forcing character limit on Cookie header because too many cookies in the header can lead to a "Header Overflow" error. Will most likely be replaced in the future.
if (proxy.request.headers['cookie']) {
var new_cookie = [],
cookie_array = proxy.request.headers['cookie'].split('; ');
cookie_array.forEach(cookie => {
cookie_name = cookie.split('=').splice(0, 1).join();
cookie_value = cookie.split('=').splice(1).join();
if (proxy.url.hostname.includes(cookie_name.split('@').splice(1).join())) new_cookie.push(cookie_name.split('@').splice(0, 1).join() + '=' + cookie_value);
});
proxy.request.headers['cookie'] = new_cookie.join('; ');
}
// If theres a user agent in the config, use that user agent instead of using the browsers user agent by default.
if (config.userAgent) proxy.request.headers['user-agent'] = config.useragent;
if (config.requestAgent) proxy.request['agent'] = config.requestAgent;
delete proxy.request.headers['accept-encoding'];
// Getting data from our body parser for HTTP (POST / PATCH) requests.
if (req.method == 'POST' || req.method == 'PATCH') proxy.request.body = await bodyParser(req);
config.blocklist.forEach(hostname => {
if (proxy.url.hostname == hostname) {
proxy.error.status = true;
proxy.blocked.status = true;
proxy.error.info = {
code: 'BLOCKED',
message: `Could not make ${req.method} request to "${rewrite.url(req.url.replace(config.prefix, ''), 'decode')}".`
}
}
});
// If URL hostname has been detected as blocked, the app blocks all further functions and sends a different response to the client.
if (proxy.blocked.status == true) {
if (config.error) return config.error(proxy);
return res.end(proxy.error.info.message.replace(/</gi, '<&zwnj;').replace(/>/gi, '>&zwnj;'));
}
// In http.request(), there is a feature to choose what IP you want to use when making the request. This is useful when your server has additional IP's.
// When there is multiple IP's in the array, the proxy randomizes which one to use. This is useful to bypass Youtube's request checking.
if (config.localAddress) proxy.request.localAddress = config.localAddress[Math.floor(Math.random() * config.localAddress.length)]
// Allowing custom functions to be set before the request is made.
config.request.forEach(customFunction => customFunction(proxy));
// The request is made to the website, and is awaiting response.
// Error handling.
if (!req.url.startsWith(config.prefix + btoa(proxy.url.origin) + '/')) {
res.writeHead(307, {
Location: config.prefix + btoa(proxy.url.origin) + '/'
});
return res.end();
};
proxy.response = await sendRequest(proxy.url.href, proxy.request).catch(err => {
proxy.error.status = true;
proxy.error.info = {
code: err.code,
message: `Could not make ${req.method} request to "${rewrite.url(req.url.replace(config.prefix, ''), 'decode')}".`
};
});
if (proxy.error.status == true) {
if (config.error) return config.error(proxy);
return res.end(proxy.error.info.message.replace(/</gi, '<&zwnj;').replace(/>/gi, '>&zwnj;'));
}
proxy.sendResponse = await proxy.response.buffer;
// Filtering out bad headers, setting redirect locations, and rewriting cookies.
rewrite.headers(proxy);
// Setting response status and headers.
res.writeHead(proxy.response.statusCode, proxy.response.headers);
// When rewriting, the "Content-Type" header is extracted, and if it matches ("text/html" | "text/css") the response body gets rewritten. But when the request is POST, "Content-Type" is undefined so we set the header to "text/html" which won't effect POST responses.
if (typeof proxy.response.headers['content-type'] == 'null' || typeof proxy.response.headers['content-type'] == 'undefined') proxy.response.headers['content-type'] = 'text/html';
// Rewriting body based off of "Content-Type" header to not mess up any images or javascript types.
if (proxy.response.headers['content-type'].startsWith('text/html') || proxy.response.headers['content-type'].startsWith('text/css')) {
proxy.sendResponse = rewrite.body(proxy.sendResponse.toString(), proxy)
};
// Allowing custom functions to be set after response is made and rewritten.
config.response.forEach(customFunction => customFunction(proxy));
// Sending response to the client.
res.end(proxy.sendResponse);
} else next();
};
}

View file

@ -0,0 +1,142 @@
const http = require('http'),
https = require('https'),
zlib = require('zlib');
module.exports = (url, options) => {
if (!options) options = {};
var request = {};
request.options = options;
var protocol;
if (url.startsWith('https://')) {
protocol = https
} else protocol = http;
return new Promise((resolve, error) => {
var req = protocol.request(url, request.options, res => {
var response = res;
response.json = new Promise(resolve => {
var body = '',
json = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try {
json = JSON.parse(body);
} catch (err) {
json = {};
}
resolve(json);
});
});
response.text = new Promise(resolve => {
var data = '',
text = '';
res.on('data', chunk => data = chunk.toString());
res.on('end', () => {
text = data;
resolve(text);
});
});
response.buffer = new Promise(resolve => {
var buffer = [];
res.on('data', binary => {
buffer.push(binary)
}).on('end', () => {
buffer = Buffer.concat(buffer)
switch (res.headers['content-encoding']) {
case 'gzip':
case 'x-gzip':
zlib.gunzip(buffer, (err, buffer) => {
resolve(buffer);
});
break;
case 'deflate':
case 'x-deflate':
zlib.inflate(buffer, (err, buffer) => {
resolve(buffer);
});
break;
case 'br':
zlib.BrotliDecompress(buffer, (err, buffer) => {
resolve(buffer);
});
break;
default:
resolve(buffer);
break;
};
});
});
resolve(response);
});
req.on('error', err => {
error(err);
});
if (options.body) {
req.write(options.body);
req.end();
} else req.end();
});
}

View file

@ -0,0 +1,187 @@
// Base64 encoding and decoding functions.
btoa = (str) => {
str = new Buffer.from(str).toString('base64');
return str;
};
atob = (str) => {
str = new Buffer.from(str, 'base64').toString('utf-8');
return str;
};
// Rewriting URL's.
url = (url, type) => {
if (url.startsWith('//')) url = 'http:' + url;
var origin, path;
switch (type) {
case 'decode':
origin = atob(url.split('/').splice(0, 1).join('/'));
path = '/' + url.split('/').splice(1).join('/');
break;
default:
origin = btoa(url.split('/').splice(0, 3).join('/'));
path = '/' + url.split('/').splice(3).join('/');
break;
}
return origin + path;
}
// Rewriting response buffers to send to client.
body = (buffer, config) => {
proxified_body = buffer.toString()
.replace(/integrity="(.*?)"/gi, '')
.replace(/nonce="(.*?)"/gi, '')
.replace(/(href|src|poster|data|action|srcset|data-src|data-href)="\/\/(.*?)"/gi, `$1` + `="http://` + `$2` + `"`)
.replace(/(href|src|poster|data|action|srcset|data-src|data-href)='\/\/(.*?)'/gi, `$1` + `='http://` + `$2` + `'`)
.replace(/(href|src|poster|data|action|srcset|data-src|data-href)="\/(.*?)"/gi, `$1` + `="${config.prefix}${btoa(config.url.origin)}/` + `$2` + `"`)
.replace(/(href|src|poster|data|action|srcset|data-src|data-href)='\/(.*?)'/gi, `$1` + `='${config.prefix}${btoa(config.url.origin)}/` + `$2` + `'`)
.replace(/(href|src|poster|data|action|srcset|data-src|data-href)="(https:\/\/|http:\/\/)(.*?)"/gi, str => {
attribute = str.split('=').splice(0, 1).join('');
href = str.replace(`${attribute}=`, '').slice(1).slice(0, -1);
return `${attribute}="${config.prefix}${url(href)}"`;
})
.replace(/(href|src|poster|data|action|srcset|data-src|data-href)='(https:\/\/|http:\/\/)(.*?)'/gi, str => {
attribute = str.split('=').splice(0, 1).join('');
href = str.replace(`${attribute}=`, '').slice(1).slice(0, -1);
return `${attribute}='${config.prefix}${url(href)}'`;
})
.replace(/(window|document).location.href/gi, `"${config.url.href}"`)
.replace(/(window|document).location.hostname/gi, `"${config.url.hostname}"`)
.replace(/(window|document).location.pathname/gi, `"${config.url.path}"`)
.replace(/location.href/gi, `"${config.url.href}"`)
.replace(/location.hostname/gi, `"${config.url.hostname}"`)
.replace(/location.pathname/gi, `"${config.url.path}"`)
.replace(/url\("\/\/(.*?)"\)/gi, `url("http://` + `$1` + `")`)
.replace(/url\('\/\/(.*?)'\)/gi, `url('http://` + `$1` + `')`)
.replace(/url\(\/\/(.*?)\)/gi, `url(http://` + `$1` + `)`)
.replace(/url\("\/(.*?)"\)/gi, `url("${config.prefix}${btoa(config.url.origin)}/` + `$1` + `")`)
.replace(/url\('\/(.*?)'\)/gi, `url('${config.prefix}${btoa(config.url.origin)}/` + `$1` + `')`)
.replace(/url\(\/(.*?)\)/gi, `url(${config.prefix}${btoa(config.url.origin)}/` + `$1` + `)`);
if (config.injection == true) {
proxified_body = proxified_body.replace(/<head(.*?)>/gi, `<head` + `$1` + `> \n <script src="${config.prefix}static/inject.js" id="_alloy_data" prefix="${config.prefix}" url="${btoa(config.url.href)}"></script>`);
if (!proxified_body.match(/<head(.*?)>/gi)) proxified_body = proxified_body.replace(/<html(.*?)>/gi, `<html` + `$1` + `> \n <script src="${config.prefix}static/inject.js" id="_alloy_data" prefix="${config.prefix}" url="${btoa(config.url.href)}"></script>`);
};
return proxified_body;
};
// Rewriting the "Origin" request header.
origin = (origin, config) => {
origin = '/' + String(origin).split('/').splice(3).join('/');
origin = url(origin.replace(config.prefix, ''), 'decode');
if (origin.startsWith('https://') || origin.startsWith('http://')) {
origin = origin.split('/').splice(0, 3).join('/');
} else origin = config.url.origin;
return origin;
};
// Rewriting the "Referer" request header.
referer = (referer, config) => {
referer = '/' + String(referer).split('/').splice(3).join('/');
referer = url(referer.replace(config.prefix, ''), 'decode');
if (referer.startsWith('https://') || referer.startsWith('http://')) {
referer = referer;
} else referer = config.url.href;
return referer;
};
headers = (proxy) => {
Object.entries(proxy.response.headers).forEach(([header_name, header_value]) => {
if (header_name == 'location') {
proxy.response.statusCode = 308;
proxy.response.headers[header_name] = proxy.prefix + url(header_value);
};
if (header_name == 'set-cookie') {
var array = [];
header_value.forEach(cookie => {
cookie = cookie.replace(/Domain=(.*?);/gi, `Domain=` + proxy.req.headers['host'] + ';').replace(/(.*?)=(.*?);/, '$1' + '@' + proxy.url.hostname + `=` + '$2' + ';');
array.push(cookie);
});
proxy.response.headers[header_name] = array;
};
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') || header_name.startsWith('content-length')) {
delete proxy.response.headers[header_name];
};
});
};
// Setting all our functions to be used in "proxy.js"
module.exports = {
url: url,
body: body,
origin: origin,
referer: referer,
headers: headers
}

View file

@ -0,0 +1,109 @@
var alloy_data = document.querySelector('#_alloy_data');
var prefix = alloy_data.getAttribute('prefix');
var url = new URL(atob(alloy_data.getAttribute('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)
}
// 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);

View file

@ -0,0 +1,110 @@
const WebSocket = require('ws');
// Setting Base64 encoding and decoding functions.
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, config) => {
// Using the HTTP server as the WS server.
const wss = new WebSocket.Server({
server: server
});
wss.on('connection', (cli, req) => {
try {
const svr = new WebSocket(atob(req.url.replace(config.prefix + 'ws/', '')));
svr.on('message', (data) => {
try {
cli.send(data)
} catch (err) {}
});
// Getting response from WS client to send to the user from the server.
svr.on('open', () => {
cli.on('message', (data) => {
svr.send(data)
});
});
// Closes server when WS client closes.
cli.on('close', (code) => {
try {
svr.close(code);
} catch (err) {
svr.close(1006)
};
});
// Closes client when WS server closes.
svr.on('close', (code) => {
try {
cli.close(code);
} catch (err) {
cli.close(1006)
};
});
// Closes server when WS client errors.
cli.on('error', (err) => {
try {
svr.close(1001);
} catch (err) {
svr.close(1006)
};
});
// Closes client when WS server errors.
svr.on('error', (err) => {
try {
cli.close(1001);
} catch (err) {
cli.close(1006)
};
});
} catch (err) {
console.log(err);
cli.close(1001);
}
});
}

View file

@ -0,0 +1,56 @@
{
"_from": "alloyproxy@^1.1.0",
"_id": "alloyproxy@1.1.0",
"_inBundle": false,
"_integrity": "sha512-AlLoWex3qx2dWRO+3HovFjUWoRx4Lq9hEeyH5soIvJ0Y18VP2kgd8nuGirLJgJiVkoZyZJ31qzYK5q+vRsAebA==",
"_location": "/alloyproxy",
"_phantomChildren": {},
"_requested": {
"type": "range",
"registry": true,
"raw": "alloyproxy@^1.1.0",
"name": "alloyproxy",
"escapedName": "alloyproxy",
"rawSpec": "^1.1.0",
"saveSpec": null,
"fetchSpec": "^1.1.0"
},
"_requiredBy": [
"#USER",
"/"
],
"_resolved": "https://registry.npmjs.org/alloyproxy/-/alloyproxy-1.1.0.tgz",
"_shasum": "95d4064bd691a0f949e1a66de9bd966e1c0fff7f",
"_spec": "alloyproxy@^1.1.0",
"_where": "C:\\Users\\Not A Porxy\\Documents\\HolyUnblockerWorkspace\\HolyUB",
"author": {
"name": "Titanium Network"
},
"bugs": {
"url": "https://github.com/titaniumnetwork-dev/alloyproxy/issues"
},
"bundleDependencies": false,
"dependencies": {
"ws": "^7.4.0"
},
"deprecated": false,
"description": "Proxy library to unblock the web!",
"homepage": "https://github.com/titaniumnetwork-dev/alloyproxy#readme",
"keywords": [
"proxy",
"unblocker",
"web",
"proxy"
],
"license": "ISC",
"main": "index.js",
"name": "alloyproxy",
"repository": {
"type": "git",
"url": "git+https://github.com/titaniumnetwork-dev/alloyproxy.git"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"version": "1.1.0"
}

View file

@ -48,7 +48,7 @@ $('al').onclick = function() {
url = btoa('http://' + url[0] + '/' + url.slice(1).join('/'));
console.log(url);
} else url = btoa(url)
frame.src = "https://" + domain + "/fetch/" + url;
frame.src = "https://" + domain + "/session/?url=" + url;
frame.style['visibility'] = "visible";
frame.setAttribute('allow', 'fullscreen');
frame.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups allow-forms');
@ -65,7 +65,7 @@ $('albp').onclick = function() {
url = btoa('http://' + url[0] + '/' + url.slice(1).join('/'));
console.log(url);
} else url = btoa(url)
window.location.href = "https://" + domain + "/fetch/" + url;
window.location.href = "https://" + domain + "/session/?url=" + url;
document.cookie = 'oldsmobile=badcar; expires=' + (Date.now() + 259200) + '; SameSite=Lax; domain=.' + auth + '; path=/; Secure;';
return false;
};