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:
Entrpix 2024-07-06 22:11:30 -04:00
parent cacdf0de5e
commit 7a783f6fd1
9 changed files with 1616 additions and 75 deletions

View file

@ -25,6 +25,7 @@
"mime-types": "^2.1.35",
"node-fetch": "^3.3.2",
"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

File diff suppressed because it is too large Load diff

View file

@ -1,14 +1,15 @@
import wisp from "wisp-server-node";
import { uvPath } from "@titaniumnetwork-dev/ultraviolet";
import { epoxyPath } from "@mercuryworkshop/epoxy-transport";
import { baremuxPath } from "@mercuryworkshop/bare-mux/node";
import http from 'http';
import { paintSource, tryReadFile } from './randomization.mjs';
import pkg from './routes.mjs';
import { readFile } from 'fs/promises';
import path from 'path';
import express from 'express';
import { readFile } from 'fs/promises';
import pkg from './routes.mjs';
import { paintSource, tryReadFile } from './randomization.mjs';
import http from 'http';
import createRammerhead from 'rammerhead/src/server/index.js';
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 { pages, text404 } = pkg;
@ -16,8 +17,64 @@ const __dirname = path.resolve();
const port = process.env.PORT || config.port;
const app = express();
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]])))));
app.use(router);
@ -25,23 +82,13 @@ app.use(express.static(path.join(__dirname, 'views')));
app.use("/uv/", express.static(uvPath));
app.use("/epoxy/", express.static(epoxyPath));
app.use("/baremux/", express.static(baremuxPath));
app.disable('x-powered-by');
app.use((req, res) => {
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);
console.log('Holy Unblocker is listening on port ' + port + '.');

28
views/assets/js/proxy.js Normal file
View 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
});

View file

@ -1,18 +1,7 @@
"use strict";
/**
* Distributed with Ultraviolet and compatible with most configurations.
*/
const stockSW = "/uv/sw.js";
/**
* List of hostnames that are allowed to run serviceworkers on http://
*/
const swAllowedHostnames = ["localhost", "127.0.0.1"];
/**
* Global util
* Used in 404.html and index.html
*/
async function registerSW() {
if (!navigator.serviceWorker) {
if (
@ -26,7 +15,6 @@ async function registerSW() {
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/";
await BareMux.SetTransport("EpxMod.EpoxyClient", { wisp: wispUrl });
await BareMux.SetTransport("EpxMod.EpoxyClient", { wisp: wispUrl, wisp_v2: false }); // ?????
}

View file

@ -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) {
try {
// input is a valid URL:
@ -24,9 +17,181 @@ function search(input, template) {
// 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));
}
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);
});
});
});
}

View file

@ -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);
});

View file

@ -11,6 +11,11 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<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>
</head>
@ -27,10 +32,9 @@
<img class="pr-logo" src="/assets/img/rhicon.webp" alt="Ramm&#173;erh&#173;ea&#173;d P&#173;ro&#173;y Logo">
<p>Ram&#173;merhe&#173;ad is one of the mo&#173;st adva&#173;nced fr&#173;ee se&#173;cure w&#173;eb prox&#173;ies.</p>
<p>Its ses&#173;sion-ba&#173;sed prox&#173;ying con&#173;cept enables much suppo&#173;rt for web&#173;ites like Dis&#173;cord, Yo&#173;uTu&#173;be, and mor&#173;e!</p>
<div id="pr-form">
<a href="#" id="pr-go1" class="pr-button glowbutton" onclick="goProx.rnav();">Classic</a>
<a href="#" id="pr-go2" class="pr-button glowbutton" onclick="goProx.rnav(true);">Stealth</a>
</div>
<form id="pr-form">
<input type="text" id="pr-url" spellcheck="false" autocomplete="off" placeholder="Search or enter in a target site!">
</form>
<p>Import&#173;ant: Ma&#173;ke su&#173;re you trea&#173;t thi&#173;s as a PR&#173;IVA&#173;TE sess&#173;i&#173;on. Do NO&#173;T shar&#173;e Ram&#173;me&#173;rh&#173;ead li&#173;nks.</p>
<h3>More Information:</h3>
<div class="font3">
@ -47,6 +51,7 @@
</div>
</div>
</div>
<iframe style="display: none;" id="hu-frame"></iframe>
<div id="footer" class="fullwidth"></div>
<!-- IMPORTANT-HUCOOKINGINSERT-DONOTDELETE -->
<script src="assets/js/common.js"></script>

View file

@ -18,7 +18,10 @@
<script src="/uv/uv.config.js" defer></script>
<script src="/assets/js/register-sw.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>
</head>
@ -37,8 +40,6 @@
CAPT&#173;CHA suppor&#173;t.</p>
<form id="pr-form">
<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&#173;assic</a>
<a href="#" id="pr-go2" class="pr-button glowbutton">Stea&#173;lth</a>
</form>
<h3>More Information:</h3>
<div class="font3">