mirror of
https://github.com/QuiteAFancyEmerald/Holy-Unblocker.git
synced 2025-05-15 21:00:00 -04:00
Fixed Rammerhead support. The speed issue is aparent accross both UV and RH and I'm not sure how to fix it
This commit is contained in:
parent
cacdf0de5e
commit
7a783f6fd1
9 changed files with 1616 additions and 75 deletions
|
@ -25,6 +25,7 @@
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
"wisp-server-node": "^1.1.0",
|
"wisp-server-node": "^1.1.0",
|
||||||
"ws": "^8.18.0"
|
"ws": "^8.18.0",
|
||||||
|
"rammerhead": "https://github.com/NebulaServices/rammerhead/releases/download/rammerhead-1.2.41-nebula.8/rammerhead-1.2.41-nebula.7.tgz"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1328
pnpm-lock.yaml
generated
1328
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,14 +1,15 @@
|
||||||
import wisp from "wisp-server-node";
|
import { paintSource, tryReadFile } from './randomization.mjs';
|
||||||
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
import pkg from './routes.mjs';
|
||||||
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
import { readFile } from 'fs/promises';
|
||||||
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
|
||||||
import http from 'http';
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import { readFile } from 'fs/promises';
|
import http from 'http';
|
||||||
import pkg from './routes.mjs';
|
import createRammerhead from 'rammerhead/src/server/index.js';
|
||||||
import { paintSource, tryReadFile } from './randomization.mjs';
|
import { createBareServer } from '@tomphttp/bare-server-node';
|
||||||
|
import wisp from "wisp-server-node";
|
||||||
|
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
|
||||||
|
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
|
||||||
|
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
|
||||||
|
|
||||||
const config = JSON.parse(await readFile(new URL('./config.json', import.meta.url)));
|
const config = JSON.parse(await readFile(new URL('./config.json', import.meta.url)));
|
||||||
const { pages, text404 } = pkg;
|
const { pages, text404 } = pkg;
|
||||||
|
@ -16,8 +17,64 @@ const __dirname = path.resolve();
|
||||||
const port = process.env.PORT || config.port;
|
const port = process.env.PORT || config.port;
|
||||||
const app = express();
|
const app = express();
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const server = http.createServer();
|
const bare = createBareServer('/bare/');
|
||||||
|
const rh = createRammerhead();
|
||||||
|
|
||||||
|
const rammerheadScopes = [
|
||||||
|
'/rammerhead.js',
|
||||||
|
'/hammerhead.js',
|
||||||
|
'/transport-worker.js',
|
||||||
|
'/task.js',
|
||||||
|
'/iframe-task.js',
|
||||||
|
'/worker-hammerhead.js',
|
||||||
|
'/messaging',
|
||||||
|
'/sessionexists',
|
||||||
|
'/deletesession',
|
||||||
|
'/newsession',
|
||||||
|
'/editsession',
|
||||||
|
'/needpassword',
|
||||||
|
'/syncLocalStorage',
|
||||||
|
'/api/shuffleDict',
|
||||||
|
'/mainport'
|
||||||
|
];
|
||||||
|
|
||||||
|
const rammerheadSession = /^\/[a-z0-9]{32}/;
|
||||||
|
|
||||||
|
function shouldRouteRh(req) {
|
||||||
|
const url = new URL(req.url, 'http://0.0.0.0');
|
||||||
|
return (
|
||||||
|
rammerheadScopes.includes(url.pathname) ||
|
||||||
|
rammerheadSession.test(url.pathname)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function routeRhRequest(req, res) {
|
||||||
|
rh.emit('request', req, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function routeRhUpgrade(req, socket, head) {
|
||||||
|
rh.emit('upgrade', req, socket, head);
|
||||||
|
}
|
||||||
|
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
|
if (bare.shouldRoute(req)) {
|
||||||
|
bare.routeRequest(req, res);
|
||||||
|
} else if (shouldRouteRh(req)) {
|
||||||
|
routeRhRequest(req, res);
|
||||||
|
} else {
|
||||||
|
app(req, res);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.on('upgrade', (req, socket, head) => {
|
||||||
|
if (bare.shouldRoute(req)) {
|
||||||
|
bare.routeUpgrade(req, socket, head);
|
||||||
|
} else if (shouldRouteRh(req)) {
|
||||||
|
routeRhUpgrade(req, socket, head);
|
||||||
|
} else if (req.url.endsWith('/wisp/')) {
|
||||||
|
wisp.routeRequest(req, socket, head);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
router.get('/', async (req, res) => res.send(paintSource(tryReadFile(path.join(__dirname, 'views', ['/', '/?'].includes(req.url) ? pages.index : pages[Object.keys(req.query)[0]])))));
|
router.get('/', async (req, res) => res.send(paintSource(tryReadFile(path.join(__dirname, 'views', ['/', '/?'].includes(req.url) ? pages.index : pages[Object.keys(req.query)[0]])))));
|
||||||
app.use(router);
|
app.use(router);
|
||||||
|
@ -25,23 +82,13 @@ app.use(express.static(path.join(__dirname, 'views')));
|
||||||
app.use("/uv/", express.static(uvPath));
|
app.use("/uv/", express.static(uvPath));
|
||||||
app.use("/epoxy/", express.static(epoxyPath));
|
app.use("/epoxy/", express.static(epoxyPath));
|
||||||
app.use("/baremux/", express.static(baremuxPath));
|
app.use("/baremux/", express.static(baremuxPath));
|
||||||
|
|
||||||
app.disable('x-powered-by');
|
app.disable('x-powered-by');
|
||||||
|
|
||||||
app.use((req, res) => {
|
app.use((req, res) => {
|
||||||
res.status(404).send(paintSource(text404));
|
res.status(404).send(paintSource(text404));
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("request", (req, res) => {
|
|
||||||
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
|
|
||||||
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
|
|
||||||
app(req, res);
|
|
||||||
});
|
|
||||||
server.on("upgrade", (req, socket, head) => {
|
|
||||||
if (req.url.endsWith("/wisp/"))
|
|
||||||
wisp.routeRequest(req, socket, head);
|
|
||||||
else
|
|
||||||
socket.end();
|
|
||||||
});
|
|
||||||
|
|
||||||
server.listen(port);
|
server.listen(port);
|
||||||
console.log('Holy Unblocker is listening on port ' + port + '.');
|
console.log('Holy Unblocker is listening on port ' + port + '.');
|
28
views/assets/js/proxy.js
Normal file
28
views/assets/js/proxy.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
const form = document.getElementById("pr-form");
|
||||||
|
const address = document.getElementById("pr-url");
|
||||||
|
|
||||||
|
const searchEngine = "https://google.com/search?q=%s";
|
||||||
|
|
||||||
|
const proxy = localStorage.getItem('proxy') || 'uv';
|
||||||
|
|
||||||
|
form.addEventListener("submit", async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
const url = search(address.value, searchEngine);
|
||||||
|
|
||||||
|
let frame = document.getElementById("hu-frame");
|
||||||
|
frame.style.display = "block";
|
||||||
|
|
||||||
|
if (proxy === "uv") {
|
||||||
|
try {
|
||||||
|
await registerSW();
|
||||||
|
} catch (err) {
|
||||||
|
window.location.href = "/pages/error/error.html";
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame.src = __uv$config.prefix + __uv$config.encodeUrl(url);
|
||||||
|
} else if (proxy === "rh") {
|
||||||
|
frame.src = await RammerheadEncode(url);
|
||||||
|
} // lmfao
|
||||||
|
});
|
|
@ -1,18 +1,7 @@
|
||||||
"use strict";
|
|
||||||
/**
|
|
||||||
* Distributed with Ultraviolet and compatible with most configurations.
|
|
||||||
*/
|
|
||||||
const stockSW = "/uv/sw.js";
|
const stockSW = "/uv/sw.js";
|
||||||
|
|
||||||
/**
|
|
||||||
* List of hostnames that are allowed to run serviceworkers on http://
|
|
||||||
*/
|
|
||||||
const swAllowedHostnames = ["localhost", "127.0.0.1"];
|
const swAllowedHostnames = ["localhost", "127.0.0.1"];
|
||||||
|
|
||||||
/**
|
|
||||||
* Global util
|
|
||||||
* Used in 404.html and index.html
|
|
||||||
*/
|
|
||||||
async function registerSW() {
|
async function registerSW() {
|
||||||
if (!navigator.serviceWorker) {
|
if (!navigator.serviceWorker) {
|
||||||
if (
|
if (
|
||||||
|
@ -26,7 +15,6 @@ async function registerSW() {
|
||||||
|
|
||||||
await navigator.serviceWorker.register(stockSW);
|
await navigator.serviceWorker.register(stockSW);
|
||||||
|
|
||||||
// Register the EpoxyClient transport to be used for network requests
|
|
||||||
let wispUrl = (location.protocol === "https:" ? "wss" : "ws") + "://" + location.host + "/wisp/";
|
let wispUrl = (location.protocol === "https:" ? "wss" : "ws") + "://" + location.host + "/wisp/";
|
||||||
await BareMux.SetTransport("EpxMod.EpoxyClient", { wisp: wispUrl });
|
await BareMux.SetTransport("EpxMod.EpoxyClient", { wisp: wispUrl, wisp_v2: false }); // ?????
|
||||||
}
|
}
|
|
@ -1,10 +1,3 @@
|
||||||
"use strict";
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} input
|
|
||||||
* @param {string} template Template for a search query.
|
|
||||||
* @returns {string} Fully qualified URL
|
|
||||||
*/
|
|
||||||
function search(input, template) {
|
function search(input, template) {
|
||||||
try {
|
try {
|
||||||
// input is a valid URL:
|
// input is a valid URL:
|
||||||
|
@ -24,9 +17,181 @@ function search(input, template) {
|
||||||
// input was not valid URL
|
// input was not valid URL
|
||||||
}
|
}
|
||||||
|
|
||||||
// input may have been a valid URL, however the hostname was invalid
|
|
||||||
|
|
||||||
// Attempts to convert the input to a fully qualified URL have failed
|
|
||||||
// Treat the input as a search query
|
|
||||||
return template.replace("%s", encodeURIComponent(input));
|
return template.replace("%s", encodeURIComponent(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function RammerheadEncode(baseUrl) {
|
||||||
|
// Hellhead
|
||||||
|
const mod = (n, m) => ((n % m) + m) % m;
|
||||||
|
const baseDictionary =
|
||||||
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~-";
|
||||||
|
const shuffledIndicator = "_rhs";
|
||||||
|
const generateDictionary = function () {
|
||||||
|
let str = "";
|
||||||
|
const split = baseDictionary.split("");
|
||||||
|
while (split.length > 0) {
|
||||||
|
str += split.splice(Math.floor(Math.random() * split.length), 1)[0];
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StrShuffler {
|
||||||
|
constructor(dictionary = generateDictionary()) {
|
||||||
|
this.dictionary = dictionary;
|
||||||
|
}
|
||||||
|
shuffle(str) {
|
||||||
|
if (str.startsWith(shuffledIndicator)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
let shuffledStr = "";
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
const char = str.charAt(i);
|
||||||
|
const idx = baseDictionary.indexOf(char);
|
||||||
|
if (char === "%" && str.length - i >= 3) {
|
||||||
|
shuffledStr += char;
|
||||||
|
shuffledStr += str.charAt(++i);
|
||||||
|
shuffledStr += str.charAt(++i);
|
||||||
|
} else if (idx === -1) {
|
||||||
|
shuffledStr += char;
|
||||||
|
} else {
|
||||||
|
shuffledStr += this.dictionary.charAt(
|
||||||
|
mod(idx + i, baseDictionary.length)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shuffledIndicator + shuffledStr;
|
||||||
|
}
|
||||||
|
unshuffle(str) {
|
||||||
|
if (!str.startsWith(shuffledIndicator)) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = str.slice(shuffledIndicator.length);
|
||||||
|
|
||||||
|
let unshuffledStr = "";
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
const char = str.charAt(i);
|
||||||
|
const idx = this.dictionary.indexOf(char);
|
||||||
|
if (char === "%" && str.length - i >= 3) {
|
||||||
|
unshuffledStr += char;
|
||||||
|
unshuffledStr += str.charAt(++i);
|
||||||
|
unshuffledStr += str.charAt(++i);
|
||||||
|
} else if (idx === -1) {
|
||||||
|
unshuffledStr += char;
|
||||||
|
} else {
|
||||||
|
unshuffledStr += baseDictionary.charAt(
|
||||||
|
mod(idx - i, baseDictionary.length)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return unshuffledStr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function get(url, callback, shush = false) {
|
||||||
|
var request = new XMLHttpRequest();
|
||||||
|
request.open("GET", url, true);
|
||||||
|
request.send();
|
||||||
|
|
||||||
|
request.onerror = function () {
|
||||||
|
if (!shush) console.log("Cannot communicate with the server");
|
||||||
|
};
|
||||||
|
request.onload = function () {
|
||||||
|
if (request.status === 200) {
|
||||||
|
callback(request.responseText);
|
||||||
|
} else {
|
||||||
|
if (!shush)
|
||||||
|
console.log(
|
||||||
|
'unexpected server response to not match "200". Server says "' +
|
||||||
|
request.responseText +
|
||||||
|
'"'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var api = {
|
||||||
|
newsession(callback) {
|
||||||
|
get("/newsession", callback);
|
||||||
|
},
|
||||||
|
sessionexists(id, callback) {
|
||||||
|
get("/sessionexists?id=" + encodeURIComponent(id), function (res) {
|
||||||
|
if (res === "exists") return callback(true);
|
||||||
|
if (res === "not found") return callback(false);
|
||||||
|
console.log("unexpected response from server. received" + res);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
shuffleDict(id, callback) {
|
||||||
|
console.log("Shuffling", id);
|
||||||
|
get("/api/shuffleDict?id=" + encodeURIComponent(id), function (res) {
|
||||||
|
callback(JSON.parse(res));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var localStorageKey = "rammerhead_sessionids";
|
||||||
|
var localStorageKeyDefault = "rammerhead_default_sessionid";
|
||||||
|
var sessionIdsStore = {
|
||||||
|
get() {
|
||||||
|
var rawData = localStorage.getItem(localStorageKey);
|
||||||
|
if (!rawData) return [];
|
||||||
|
try {
|
||||||
|
var data = JSON.parse(rawData);
|
||||||
|
if (!Array.isArray(data)) throw "getout";
|
||||||
|
return data;
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set(data) {
|
||||||
|
if (!data || !Array.isArray(data)) throw new TypeError("must be array");
|
||||||
|
localStorage.setItem(localStorageKey, JSON.stringify(data));
|
||||||
|
},
|
||||||
|
getDefault() {
|
||||||
|
var sessionId = localStorage.getItem(localStorageKeyDefault);
|
||||||
|
if (sessionId) {
|
||||||
|
var data = sessionIdsStore.get();
|
||||||
|
data.filter(function (e) {
|
||||||
|
return e.id === sessionId;
|
||||||
|
});
|
||||||
|
if (data.length) return data[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
setDefault(id) {
|
||||||
|
localStorage.setItem(localStorageKeyDefault, id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
function addSession(id) {
|
||||||
|
var data = sessionIdsStore.get();
|
||||||
|
data.unshift({ id: id, createdOn: new Date().toLocaleString() });
|
||||||
|
sessionIdsStore.set(data);
|
||||||
|
}
|
||||||
|
function getSessionId() {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
var id = localStorage.getItem("session-string");
|
||||||
|
api.sessionexists(id, function (value) {
|
||||||
|
if (!value) {
|
||||||
|
console.log("Session validation failed");
|
||||||
|
api.newsession(function (id) {
|
||||||
|
addSession(id);
|
||||||
|
localStorage.setItem("session-string", id);
|
||||||
|
console.log(id);
|
||||||
|
console.log("^ new id");
|
||||||
|
resolve(id);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
resolve(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var ProxyHref;
|
||||||
|
|
||||||
|
return getSessionId().then((id) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
api.shuffleDict(id, function (shuffleDict) {
|
||||||
|
var shuffler = new StrShuffler(shuffleDict);
|
||||||
|
ProxyHref = "/" + id + "/" + shuffler.shuffle(baseUrl);
|
||||||
|
resolve(ProxyHref);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,22 +0,0 @@
|
||||||
const form = document.getElementById("pr-form");
|
|
||||||
const address = document.getElementById("pr-url");
|
|
||||||
|
|
||||||
const searchEngine = "https://google.com/search?q=%s";
|
|
||||||
|
|
||||||
|
|
||||||
form.addEventListener("submit", async (event) => {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
try {
|
|
||||||
await registerSW();
|
|
||||||
} catch (err) {
|
|
||||||
alert(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
const url = search(address.value, searchEngine);
|
|
||||||
|
|
||||||
let frame = document.getElementById("hu-frame");
|
|
||||||
frame.style.display = "block";
|
|
||||||
frame.src = __uv$config.prefix + __uv$config.encodeUrl(url);
|
|
||||||
});
|
|
|
@ -11,6 +11,11 @@
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
|
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
|
||||||
<link rel="stylesheet" href="assets/css/styles.css">
|
<link rel="stylesheet" href="assets/css/styles.css">
|
||||||
|
<script src="/assets/js/proxy.js" defer></script>
|
||||||
|
<script src="/assets/js/search.js" defer></script>
|
||||||
|
<script defer>
|
||||||
|
localStorage.setItem('proxy', 'rh');
|
||||||
|
</script>
|
||||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/tsparticles@1.39.2/tsparticles.min.js" integrity="sha256-FCz5ToEA27payrGYaVGRidiIA+68Z31TBXFzcIT1/gU=" crossorigin="anonymous"></script>
|
<script defer="defer" src="https://cdn.jsdelivr.net/npm/tsparticles@1.39.2/tsparticles.min.js" integrity="sha256-FCz5ToEA27payrGYaVGRidiIA+68Z31TBXFzcIT1/gU=" crossorigin="anonymous"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -27,10 +32,9 @@
|
||||||
<img class="pr-logo" src="/assets/img/rhicon.webp" alt="Ramm­erh­ea­d P­ro­y Logo">
|
<img class="pr-logo" src="/assets/img/rhicon.webp" alt="Ramm­erh­ea­d P­ro­y Logo">
|
||||||
<p>Ram­merhe­ad is one of the mo­st adva­nced fr­ee se­cure w­eb prox­ies.</p>
|
<p>Ram­merhe­ad is one of the mo­st adva­nced fr­ee se­cure w­eb prox­ies.</p>
|
||||||
<p>Its ses­sion-ba­sed prox­ying con­cept enables much suppo­rt for web­ites like Dis­cord, Yo­uTu­be, and mor­e!</p>
|
<p>Its ses­sion-ba­sed prox­ying con­cept enables much suppo­rt for web­ites like Dis­cord, Yo­uTu­be, and mor­e!</p>
|
||||||
<div id="pr-form">
|
<form id="pr-form">
|
||||||
<a href="#" id="pr-go1" class="pr-button glowbutton" onclick="goProx.rnav();">Classic</a>
|
<input type="text" id="pr-url" spellcheck="false" autocomplete="off" placeholder="Search or enter in a target site!">
|
||||||
<a href="#" id="pr-go2" class="pr-button glowbutton" onclick="goProx.rnav(true);">Stealth</a>
|
</form>
|
||||||
</div>
|
|
||||||
<p>Import­ant: Ma­ke su­re you trea­t thi­s as a PR­IVA­TE sess­i­on. Do NO­T shar­e Ram­me­rh­ead li­nks.</p>
|
<p>Import­ant: Ma­ke su­re you trea­t thi­s as a PR­IVA­TE sess­i­on. Do NO­T shar­e Ram­me­rh­ead li­nks.</p>
|
||||||
<h3>More Information:</h3>
|
<h3>More Information:</h3>
|
||||||
<div class="font3">
|
<div class="font3">
|
||||||
|
@ -47,6 +51,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<iframe style="display: none;" id="hu-frame"></iframe>
|
||||||
<div id="footer" class="fullwidth"></div>
|
<div id="footer" class="fullwidth"></div>
|
||||||
<!-- IMPORTANT-HUCOOKINGINSERT-DONOTDELETE -->
|
<!-- IMPORTANT-HUCOOKINGINSERT-DONOTDELETE -->
|
||||||
<script src="assets/js/common.js"></script>
|
<script src="assets/js/common.js"></script>
|
||||||
|
|
|
@ -18,7 +18,10 @@
|
||||||
<script src="/uv/uv.config.js" defer></script>
|
<script src="/uv/uv.config.js" defer></script>
|
||||||
<script src="/assets/js/register-sw.js" defer></script>
|
<script src="/assets/js/register-sw.js" defer></script>
|
||||||
<script src="/assets/js/search.js" defer></script>
|
<script src="/assets/js/search.js" defer></script>
|
||||||
<script src="/assets/js/uvhuwork.js" defer></script>
|
<script src="/assets/js/proxy.js" defer></script>
|
||||||
|
<script defer>
|
||||||
|
localStorage.setItem('proxy', 'uv');
|
||||||
|
</script>
|
||||||
<script defer="defer" src="https://cdn.jsdelivr.net/npm/tsparticles@1.39.2/tsparticles.min.js" integrity="sha256-FCz5ToEA27payrGYaVGRidiIA+68Z31TBXFzcIT1/gU=" crossorigin="anonymous"></script>
|
<script defer="defer" src="https://cdn.jsdelivr.net/npm/tsparticles@1.39.2/tsparticles.min.js" integrity="sha256-FCz5ToEA27payrGYaVGRidiIA+68Z31TBXFzcIT1/gU=" crossorigin="anonymous"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
@ -37,8 +40,6 @@
|
||||||
CAPT­CHA suppor­t.</p>
|
CAPT­CHA suppor­t.</p>
|
||||||
<form id="pr-form">
|
<form id="pr-form">
|
||||||
<input type="text" id="pr-url" spellcheck="false" autocomplete="off" placeholder="Search or enter in a target site!">
|
<input type="text" id="pr-url" spellcheck="false" autocomplete="off" placeholder="Search or enter in a target site!">
|
||||||
<a href="#" id="pr-go1" class="pr-button glowbutton">Cl­assic</a>
|
|
||||||
<a href="#" id="pr-go2" class="pr-button glowbutton">Stea­lth</a>
|
|
||||||
</form>
|
</form>
|
||||||
<h3>More Information:</h3>
|
<h3>More Information:</h3>
|
||||||
<div class="font3">
|
<div class="font3">
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue