mirror of
https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
synced 2025-05-16 05:00:02 -04:00
Merge branch 'master' of https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic
This commit is contained in:
commit
ecdd1986ad
20 changed files with 16967 additions and 46 deletions
44
README.md
44
README.md
|
@ -2,7 +2,7 @@
|
|||
|
||||
#### Titanium Network is sponsored by:
|
||||
|
||||
<img src="https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic/blob/master/views/assets/img/nodeclusters.png?raw" width="500px"></img>
|
||||
<img src="https://raw.githubusercontent.com/QuiteAFancyEmerald/HolyUnblockerPublic/fa858c0e429d73324bffc045bd2a3217064fb1e5/views/assets/img/nodeclusters.png?raw" width="500px"></img>
|
||||
|
||||
Holy Unblocker, a website that can be used to bypass web filters; both extension and firewall. This is the public source code for Holy Unblocker, a rather fancy website with some cool dynamic backgrounds while also focusing with detail put into the design, mechanics and features overall like custom Tab Cloaks with more to come in the future.
|
||||
|
||||
|
@ -62,15 +62,17 @@ Site Documentation: <a href="https://www.holyubofficial.net/?in">Documentation</
|
|||
Either use the button above to deploy to Heroku or do the below:
|
||||
|
||||
```
|
||||
git clone https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic.git
|
||||
|
||||
cd HolyUnblockerPublic
|
||||
|
||||
npm install
|
||||
|
||||
npm start
|
||||
$ git clone https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic.git
|
||||
$ cd HolyUnblockerPublic
|
||||
$ npm install
|
||||
```
|
||||
|
||||
Afterwards run:
|
||||
```
|
||||
$ npm start
|
||||
```
|
||||
For more detailed documentation on workspace setup please view <a href="#workspace-configurations">this</a>.
|
||||
|
||||
The default place for the proxy when its started is `http://localhost:8080` but you can change it if needed in config.json
|
||||
|
||||
This website has been hosted locally on Alloy Proxy. More more information go to the Alloy Proxy repository below.
|
||||
|
@ -200,13 +202,29 @@ Preferably if you have your own device use Visual Studio Code. Pretty much the b
|
|||
Not going to go too in depth with this part but first fork this repository. Then clone it locally through a terminal of some sort depending on what OS you are on. Make sure you navigate to the folder you want to set this up in.
|
||||
|
||||
```
|
||||
git clone https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic.git
|
||||
|
||||
cd HolyUnblockerPublic
|
||||
|
||||
npm install
|
||||
$ git clone https://github.com/QuiteAFancyEmerald/HolyUnblockerPublic.git
|
||||
$ cd HolyUnblockerPublic
|
||||
$ npm install
|
||||
```
|
||||
|
||||
##### Setup pm2 (Optional - Node.js Process Manager)
|
||||
```
|
||||
$ npm install pm2@latest -g
|
||||
$ pm2 start app.js
|
||||
```
|
||||
**Useful pm2 Flags**
|
||||
```
|
||||
# Specify an app name
|
||||
--name <app_name>
|
||||
|
||||
# Watch and Restart app when files change
|
||||
--watch
|
||||
|
||||
# Set memory threshold for app reload
|
||||
--max-memory-restart <200MB>
|
||||
```
|
||||
For more information view the official pm2 documentation <a href="https://pm2.keymetrics.io/docs/usage/pm2-doc-single-page/">here</a>.
|
||||
##### Workspace Setup (continued)
|
||||
Now simply add the folder you cloned in VSC. Then run `npm install`. I recommend that if you are releasing this publically on GitHub that you add a `.gitignore` in your root directory with the following exclusions:
|
||||
|
||||
`node_modules`
|
||||
|
|
4
app.js
4
app.js
|
@ -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, '<‌').replace(/>/gi, '>‌'))); }, // Doing replace functions on "<" and ">" to prevent XSS.
|
||||
request: [],
|
||||
|
@ -237,4 +237,4 @@ atob = (str) => {
|
|||
return str;
|
||||
};
|
||||
|
||||
*/
|
||||
*/
|
|
@ -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
156
src/alloyproxy/README.md
Normal 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.
|
||||
|
29
src/alloyproxy/examples/app.js
Normal file
29
src/alloyproxy/examples/app.js
Normal 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
33
src/alloyproxy/index.js
Normal 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);
|
||||
|
||||
}
|
||||
|
||||
}
|
275
src/alloyproxy/libs/proxy.js
Normal file
275
src/alloyproxy/libs/proxy.js
Normal 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, '<‌').replace(/>/gi, '>‌'));
|
||||
|
||||
};
|
||||
|
||||
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, '<‌').replace(/>/gi, '>‌'));
|
||||
|
||||
}
|
||||
// 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, '<‌').replace(/>/gi, '>‌'));
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
};
|
||||
|
||||
}
|
142
src/alloyproxy/libs/requests.js
Normal file
142
src/alloyproxy/libs/requests.js
Normal 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();
|
||||
|
||||
|
||||
});
|
||||
|
||||
}
|
187
src/alloyproxy/libs/rewriting.js
Normal file
187
src/alloyproxy/libs/rewriting.js
Normal 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
|
||||
|
||||
}
|
109
src/alloyproxy/libs/static/inject.js
Normal file
109
src/alloyproxy/libs/static/inject.js
Normal 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);
|
110
src/alloyproxy/libs/websocket.js
Normal file
110
src/alloyproxy/libs/websocket.js
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
56
src/alloyproxy/package.json
Normal file
56
src/alloyproxy/package.json
Normal 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"
|
||||
}
|
File diff suppressed because one or more lines are too long
2
views/assets/css/styles.min.css
vendored
2
views/assets/css/styles.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -488,6 +488,56 @@ $('faball').onclick = function() {
|
|||
return false;
|
||||
};
|
||||
|
||||
//Emulators
|
||||
$('gba').onclick = function() {
|
||||
var frame = document.getElementById("frame");
|
||||
var background = document.getElementById("particles-js");
|
||||
var url = $('url').value;
|
||||
var det = document.domain;
|
||||
var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
frame.src = "https://" + domain + "/gba/index.html";
|
||||
frame.style['visibility'] = "visible";
|
||||
frame.setAttribute('allow', 'fullscreen');
|
||||
frame.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups allow-forms');
|
||||
//performance fix
|
||||
background.style['visibility'] = "hidden";
|
||||
document.getElementById('frame').contentWindow.focus();
|
||||
return false;
|
||||
};
|
||||
|
||||
$('nes').onclick = function() {
|
||||
var frame = document.getElementById("frame");
|
||||
var background = document.getElementById("particles-js");
|
||||
var url = $('url').value;
|
||||
var det = document.domain;
|
||||
var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
frame.src = "https://" + domain + "/nes/index.html";
|
||||
frame.style['visibility'] = "visible";
|
||||
frame.setAttribute('allow', 'fullscreen');
|
||||
frame.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups allow-forms');
|
||||
//performance fix
|
||||
background.style['visibility'] = "hidden";
|
||||
document.getElementById('frame').contentWindow.focus();
|
||||
return false;
|
||||
};
|
||||
|
||||
$('snes').onclick = function() {
|
||||
var frame = document.getElementById("frame");
|
||||
var background = document.getElementById("particles-js");
|
||||
var url = $('url').value;
|
||||
var det = document.domain;
|
||||
var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
frame.src = "https://" + domain + "/nes/index.html";
|
||||
frame.style['visibility'] = "visible";
|
||||
frame.setAttribute('allow', 'fullscreen');
|
||||
frame.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups allow-forms');
|
||||
//performance fix
|
||||
background.style['visibility'] = "hidden";
|
||||
document.getElementById('frame').contentWindow.focus();
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
// Cookie Auth
|
||||
var host = location.hostname.split('.');
|
||||
var auth = location.hostname;
|
||||
|
@ -497,4 +547,4 @@ if (host.length == 3) {
|
|||
|
||||
window.onload = function() {
|
||||
$('url').focus();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,12 +43,10 @@ $('al').onclick = function() {
|
|||
var url = $('url').value;
|
||||
var det = document.domain;
|
||||
var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
if (!url.startsWith('http') || !url.startsWith('https://')) {
|
||||
url = url.split('/');
|
||||
url = btoa('http://' + url[0] + '/' + url.slice(1).join('/'));
|
||||
console.log(url);
|
||||
} else url = btoa(url)
|
||||
frame.src = "https://" + domain + "/fetch/" + url;
|
||||
if (url.startsWith('https://') || url.startsWith('http://')) url = url;
|
||||
else if (url.startsWith('//')) url = 'http:' + url;
|
||||
else url = 'http://' + url;
|
||||
frame.src = "https://" + domain + "/fetch/" + btoa(url);
|
||||
frame.style['visibility'] = "visible";
|
||||
frame.setAttribute('allow', 'fullscreen');
|
||||
frame.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-popups allow-forms');
|
||||
|
@ -60,12 +58,10 @@ $('albp').onclick = function() {
|
|||
var url = $('url').value;
|
||||
var det = document.domain;
|
||||
var domain = det.replace('www.', '').split(/[/?#]/)[0];
|
||||
if (!url.startsWith('http') || !url.startsWith('https://')) {
|
||||
url = url.split('/');
|
||||
url = btoa('http://' + url[0] + '/' + url.slice(1).join('/'));
|
||||
console.log(url);
|
||||
} else url = btoa(url)
|
||||
window.location.href = "https://" + domain + "/fetch/" + url;
|
||||
if (url.startsWith('https://') || url.startsWith('http://')) url = url;
|
||||
else if (url.startsWith('//')) url = 'http:' + url;
|
||||
else url = 'http://' + url;
|
||||
window.location.href = "https://" + domain + "/fetch/" + btoa(url);
|
||||
document.cookie = 'oldsmobile=badcar; expires=' + (Date.now() + 259200) + '; SameSite=Lax; domain=.' + auth + '; path=/; Secure;';
|
||||
return false;
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -7,8 +7,6 @@
|
|||
<!-- Important: Use ​ to mess with keywords.. -->
|
||||
<title>H​oly Unb​loc​ke​r</title>
|
||||
<meta name="description" content= "Get past internet cen​sorsh​ip today! Enjoy safer, private internet access bypa​ssi​ng filters such as Securly or iboss. Supports Di​sc​or​d and more! :D" />
|
||||
<meta name="robots" content= "none">
|
||||
<meta name="googlebot" content= "all">
|
||||
<meta name="keywords" content="S​ecurly, ib​os​s, Re​la​y, Li​gh​tspe​ed, Ho​ly​Unb​l​oc​k​er, U​nbl​oc​ke​r, By​p​a​ss, Ch​r​o​meb​ook​s, Al​lo​y Pr​ox​y, N​od​e Un​bl​ock​er, Vi​a ​Unbl​oc​ke​r, Q​uit​e A F​ancy Em​era𔁳ld, T​i​ta​ni​um Ne​t​wo​rk">
|
||||
<meta name="theme-color" content="#00ff00">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="assets/img/i.png">
|
||||
|
@ -106,7 +104,7 @@
|
|||
.d-popupbg p {height: 5px; font-size: 14px; font-family: 'Montserrat Alternates', sans-serif; padding: 15px; padding-inline: 10px;}
|
||||
</style>
|
||||
<div class="d-popupbg" id="popup">
|
||||
<p class="text-center">Jo<wbr>in the <a id="tnlink">T<wbr>N Disc<wbr>ord</a> for mo<wbr>re privat​e site lin<wbr>ks. Simply type "%pr<wbr>ox<wbr>y h<wbr>u" and the bot will D<wbr>M you another li<wbr>n<wbr>k.</p>
|
||||
<p class="text-center">Jo<wbr>in the <a id="tnlink">T<wbr>N Disc<wbr>ord</a> for mo<wbr>re privat​e site lin<wbr>ks. Simply type %pr<wbr>ox<wbr>y h<wbr>u and the bot will D<wbr>M you another li<wbr>n<wbr>k.</p>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center align-items-center in-flex">
|
||||
<script src="particles.js"></script>
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
<div style="padding: 5%;">
|
||||
<div class="responsive">
|
||||
<div class="gallery">
|
||||
<a target="_blank" href="./archive/gba/index.html">
|
||||
<a id="gba" href="#">
|
||||
<img src="/assets/img/gba.png" alt="GBA Em​ulator">
|
||||
</a>
|
||||
<div class="desc"><p style="font-weight: bold;">G​BA Emu​lat​or</p><br>Emul<wbr>ate G<wbr>BA ga<wbr>mes! Click to upload a R<wbr>OM.</div>
|
||||
|
@ -105,7 +105,7 @@
|
|||
</div>
|
||||
<div class="responsive">
|
||||
<div class="gallery">
|
||||
<a target="_blank" href="/m.html">
|
||||
<a id="gba" href="#">
|
||||
<img src="/assets/img/gb.png" alt="GB Emu​lator">
|
||||
</a>
|
||||
<div class="desc"><p style="font-weight: bold;">G​B Emul​ato​r</p><br>Emul<wbr>ate G<wbr>B ga<wbr>mes! Click to upload a R<wbr>OM.</div>
|
||||
|
@ -113,7 +113,7 @@
|
|||
</div>
|
||||
<div class="responsive">
|
||||
<div class="gallery">
|
||||
<a target="_blank" href="./archive/nes/index.html">
|
||||
<a id="nes" href="#">
|
||||
<img src="/assets/img/nes.png" alt="NE​S Emul​ator">
|
||||
</a>
|
||||
<div class="desc"><p style="font-weight: bold;">NE​S Em​ulat​or</p><br>Emu<wbr>late N<wbr>ES ga<wbr>mes! Click to upl<wbr>oad a RO<wbr>M.</div>
|
||||
|
@ -121,7 +121,7 @@
|
|||
</div>
|
||||
<div class="responsive">
|
||||
<div class="gallery">
|
||||
<a target="_blank" href="./archive/snes/index.html">
|
||||
<a id="snes" href="#">
|
||||
<img src="/assets/img/snes.png" alt="SN​ES Emu​lator">
|
||||
</a>
|
||||
<div class="desc"><p style="font-weight: bold;">S​NE​S Em​ula​to​r</p><br>Emul<wbr>ate S<wbr>NES ga<wbr>mes! Click to upload a R<wbr>OM.</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
User-agent: *
|
||||
Allow: /
|
||||
Disallow: /
|
||||
|
||||
User-agent: Googlebot
|
||||
Allow: /
|
||||
|
@ -10,6 +10,55 @@ Allow: /?g
|
|||
Allow: /?c
|
||||
Allow: /?in
|
||||
Allow: /?faq
|
||||
Disallow: /archive/
|
||||
|
||||
Sitemap: https://quiteafancyemerald.com
|
||||
User-agent: Bingbot
|
||||
Allow: /
|
||||
Allow: /?z
|
||||
Allow: /?y
|
||||
Allow: /?d
|
||||
Allow: /?g
|
||||
Allow: /?c
|
||||
Allow: /?in
|
||||
Allow: /?faq
|
||||
|
||||
User-agent: Slurp
|
||||
Allow: /
|
||||
Allow: /?z
|
||||
Allow: /?y
|
||||
Allow: /?d
|
||||
Allow: /?g
|
||||
Allow: /?c
|
||||
Allow: /?in
|
||||
Allow: /?faq
|
||||
|
||||
User-agent: DuckDuckBot
|
||||
Allow: /
|
||||
Allow: /?z
|
||||
Allow: /?y
|
||||
Allow: /?d
|
||||
Allow: /?g
|
||||
Allow: /?c
|
||||
Allow: /?in
|
||||
Allow: /?faq
|
||||
|
||||
User-agent: Baiduspider
|
||||
Allow: /
|
||||
Allow: /?z
|
||||
Allow: /?y
|
||||
Allow: /?d
|
||||
Allow: /?g
|
||||
Allow: /?c
|
||||
Allow: /?in
|
||||
Allow: /?faq
|
||||
|
||||
User-agent: YandexBot
|
||||
Allow: /
|
||||
Allow: /?z
|
||||
Allow: /?y
|
||||
Allow: /?d
|
||||
Allow: /?g
|
||||
Allow: /?c
|
||||
Allow: /?in
|
||||
Allow: /?faq
|
||||
|
||||
Sitemap: https://holyuboffical.net
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue