first commit

This commit is contained in:
MCHost 2024-03-29 02:43:46 -04:00
commit c51c98aacd
8 changed files with 742 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

221
404.txt Normal file
View File

@ -0,0 +1,221 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>My-MC.LINK - Peer Not Found! </title>
<link rel="canonical" href="https://codepen.io/ricardpriet/pen/zPqyvY">
<style>
@import url('https://fonts.googleapis.com/css?family=Montserrat:400,600,700');
@import url('https://fonts.googleapis.com/css?family=Catamaran:400,800');
.error-container {
text-align: center;
font-size: 180px;
font-family: 'Catamaran', sans-serif;
font-weight: 800;
margin: 20px 15px;
}
.error-container > span {
display: inline-block;
line-height: 0.7;
position: relative;
color: #FFB485;
}
.error-container > span {
display: inline-block;
position: relative;
vertical-align: middle;
}
.error-container > span:nth-of-type(1) {
color: #D1F2A5;
animation: colordancing 4s infinite;
}
.error-container > span:nth-of-type(3) {
color: #F56991;
animation: colordancing2 4s infinite;
}
.error-container > span:nth-of-type(2) {
width: 120px;
height: 120px;
border-radius: 999px;
}
.error-container > span:nth-of-type(2):before,
.error-container > span:nth-of-type(2):after {
border-radius: 0%;
content:"";
position: absolute;
top: 0; left: 0;
width: inherit; height: inherit;
border-radius: 999px;
box-shadow: inset 30px 0 0 rgba(209, 242, 165, 0.4),
inset 0 30px 0 rgba(239, 250, 180, 0.4),
inset -30px 0 0 rgba(255, 196, 140, 0.4),
inset 0 -30px 0 rgba(245, 105, 145, 0.4);
animation: shadowsdancing 4s infinite;
}
.error-container > span:nth-of-type(2):before {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.screen-reader-text {
position: absolute;
top: -9999em;
left: -9999em;
}
@keyframes shadowsdancing {
0% {
box-shadow: inset 30px 0 0 rgba(209, 242, 165, 0.4),
inset 0 30px 0 rgba(239, 250, 180, 0.4),
inset -30px 0 0 rgba(255, 196, 140, 0.4),
inset 0 -30px 0 rgba(245, 105, 145, 0.4);
}
25% {
box-shadow: inset 30px 0 0 rgba(245, 105, 145, 0.4),
inset 0 30px 0 rgba(209, 242, 165, 0.4),
inset -30px 0 0 rgba(239, 250, 180, 0.4),
inset 0 -30px 0 rgba(255, 196, 140, 0.4);
}
50% {
box-shadow: inset 30px 0 0 rgba(255, 196, 140, 0.4),
inset 0 30px 0 rgba(245, 105, 145, 0.4),
inset -30px 0 0 rgba(209, 242, 165, 0.4),
inset 0 -30px 0 rgba(239, 250, 180, 0.4);
}
75% {
box-shadow: inset 30px 0 0 rgba(239, 250, 180, 0.4),
inset 0 30px 0 rgba(255, 196, 140, 0.4),
inset -30px 0 0 rgba(245, 105, 145, 0.4),
inset 0 -30px 0 rgba(209, 242, 165, 0.4);
}
100% {
box-shadow: inset 30px 0 0 rgba(209, 242, 165, 0.4),
inset 0 30px 0 rgba(239, 250, 180, 0.4),
inset -30px 0 0 rgba(255, 196, 140, 0.4),
inset 0 -30px 0 rgba(245, 105, 145, 0.4);
}
}
@keyframes colordancing {
0% {
color: #D1F2A5;
}
25% {
color: #F56991;
}
50% {
color: #FFC48C;
}
75% {
color: #EFFAB4;
}
100% {
color: #D1F2A5;
}
}
@keyframes colordancing2 {
0% {
color: #FFC48C;
}
25% {
color: #EFFAB4;
}
50% {
color: #D1F2A5;
}
75% {
color: #F56991;
}
100% {
color: #FFC48C;
}
}
/* demo stuff */
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
background-color: #416475;
margin-bottom: 50px;
}
html, button, input, select, textarea {
font-family: 'Montserrat', Helvetica, sans-serif;
color: #92a4ad;
}
h1 {
text-align: center;
margin: 30px 15px;
}
.zoom-area {
max-width: 550px;
margin: 30px auto 30px;
font-size: 19px;
text-align: center;
}
.link-container {
text-align: center;
}
a.more-link {
text-transform: uppercase;
font-size: 13px;
background-color: #92a4ad;
padding: 10px 15px;
border-radius: 0;
color: #416475;
display: inline-block;
margin-right: 5px;
margin-bottom: 5px;
line-height: 1.5;
text-decoration: none;
margin-top: 50px;
letter-spacing: 1px;
}
</style>
<script>
window.console = window.console || function(t) {};
</script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const errorMessages = [
"Whoopsie daisy! Our code took a coffee break.",
"Houston, we have a problem...with our code.",
"Error 404: Sense of Direction Not Found.",
"Looks like our code is doing the electric slide...backward.",
"Oops! Did someone trip over the server cable again?",
"404 Error: Wit Not Found. Please try again later.",
"This wasn't in the developer manual!",
"Well, that's a funny way to say 'Hello, World!'",
"Looks like our code decided to go on a spontaneous vacation.",
"Hold on tight, we're experiencing technical turbulence.",
"Error 101: Gremlins in the System.",
"If at first you don't succeed, call IT support.",
"Congratulations! You've found the hidden feature...of bugs.",
"Looks like our code got lost in translation.",
"Abandon hope, all ye who debug here.",
"Error 418: I'm a teapot. But seriously, something's wrong.",
"Well, this is awkward...even for code.",
"Have you tried turning it off and on again? No, seriously.",
"Error 505: Brain.exe has stopped responding.",
"Looks like our code took a wrong turn at Albuquerque."];
let currentMessageIndex = 0;
const errorMessageElement = document.getElementById('error-message');
setInterval(() => {
currentMessageIndex = (currentMessageIndex + 1) % errorMessages.length;
errorMessageElement.textContent = errorMessages[currentMessageIndex];
}, 3000); // Change message every 5 seconds
});
</script>
</head>
<body translate="no">
<h1 id="error-message">Look's like we did not get that quite right... </h1>
<p class="zoom-area"><b>Routing Error: Invalid hash or connection timeout.</b><BR>Please reset your link and try again. </p>
<section class="error-container">
<span>4</span>
<span><span class="screen-reader-text">0</span></span>
<span>4</span>
</section>
</body>
</html>

132
README.md Normal file
View File

@ -0,0 +1,132 @@
# hyperMC-Web-Relay
This relays Hyper Relay connection hashes over wildcard DNS and wildcard virtualhost reverse proxy to allow for automatic URLs via connection topics.
Set up instructions:
This will require a server listening to a connection topic using our version of hyper-relay:
https://git.ssh.surf/hypermc/hyper-relay
`git clone git@git.ssh.surf:hypermc/hyper-relay.git`
`cd hyper-relay`
`npm i`
Now listen to a TCP port over the Hyper Network:
```
root@server:/hyper-relay# node server.js 80 hellothere
w7zpwusw6ljrgbffxtklak23rkhaxwhs2kskozteme6ofefevlia
```
The result above shows the connection hash for your hyper port.
This will be the hash used as your subdomain later in this process.
NOTE: The "hellothere" above is the connection "topic" this is used to generate the hash and it can be any string or key phrase you wish.
# The Reverse proxy
We will proxy all of the traffic to their specific peers using a reverse proxy method, in this example, we will utilize httpd/apache below you will find the standard configuration that will work for our purposes.
```
<VirtualHost *:443>
SSLProxyEngine On
ServerAlias *.your-tld.here
ServerAdmin webmaster@your-tld.here
DocumentRoot /var/www/html
ErrorLog /var/log/error.log
CustomLog /var/log/access.log combined
SSLCertificateFile /path/to/fullchain.pem
SSLCertificateKeyFile /path/to/privkey.pem
# Reverse Proxy for subdomains
<Proxy *>
Require all granted
</Proxy>
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto https
ProxyPass "/" "http://localhost:8081/"
ProxyPassReverse "/" "http://localhost:8081/"
</VirtualHost>
```
NOTE 1: This requires `mod_proxy` and `mod_ssl` to work properly.
NOTE 2: This requires the full use of the wildcard *.your-told.here you will not be able to use any subdomain within this scope unless it runs via a hyper-relay.
We highly reccomend using SSL only for this reverse connection, however, you may configure your proxy pass as desired.
# Wildcard DNS Entry
In order to serve your subdomain hashes without the need to generate an A record create a wildcard subdomain record.
Example:
`*.example.com. IN A 192.0.2.1`
This system does work well with cloudflare proxy, feel free to proxy your traffic!
# Running the Web Relay ServerAdmin
`git clone git@git.ssh.surf:hypermc/hyperMC-Web-Relay.git`
`cd hyperMC-Web-Relay`
`npm i`
There are two servers provided within this repo.
One will work without the use of workers, and it can work well for static content sites.
To deploy this server, run `node non-worker-server.js`
The relay will begin listening on port 8081, this port may be changed in the script.
```
[root@server hyperMC-Web-Relay]# node fullyworking_proxy.js
Creating HyperDHT server...
HyperDHT server created and ready.
HTTP server listening on port 8081
```
To deploy a multi worker server, run `node worker-server.js`
The server will start workers based off your CPU count and then start those workers listening for connections:
```
[root@server hyper-web-relay]# node worker-server.js
Master 703855 is running
Total Workers 4
Worker 703885 started
Worker 703878 started
Worker 703904 started
Worker 703929 started
Worker 703878 listening on port 8081
Worker 703965 listening on port 8081
Worker 704044 listening on port 8081
Worker 703885 listening on port 8081
```
You now can make a request from a hyper-relay connection hash:
```
~ curl -IL https://w7zpwusw6ljrgbffxtklak23rkhaxwhs2kskozteme6ofefevlia.your-tld.here/
HTTP/2 200
date: Fri, 29 Mar 2024 06:39:38 GMT
content-type: text/html; charset=UTF-8
last-modified: Tue, 19 Mar 2024 05:07:41 GMT
vary: Accept-Encoding
cf-cache-status: DYNAMIC
report-to: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=mGhuDrFp%2B2lMm9iQ45CshdOmN7Sbf%2Fs1dgWKD3PtcISbcBi6uB4YZIG2qTTmfRpL1C1f3vqF01IFERjjpDspEuQ98dRfgQpelyODFjd99aeUY5uGQcPxQoAusjb%2BBxwRWkI6ZQE0EPKy4m%2BeGbY0%2FGLVndHc%2F52vEvvAIIhzR%2FqMIweFqgyAwGAaELc7sUIDayE%3D"}],"group":"cf-nel","max_age":604800}
nel: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
server: cloudflare
cf-ray: 86bddd2349cf8bbb-ATL
alt-svc: h3=":443"; ma=86400
```

141
non-worker-server.js Normal file
View File

@ -0,0 +1,141 @@
const fs = require('fs');
const http = require('http');
const httpProxy = require('http-proxy');
const HyperDHTServer = require('hyperdht');
const libNet = require('hyper-cmd-lib-net');
const goodbye = require('graceful-goodbye');
const libKeys = require('hyper-cmd-lib-keys');
const b32 = require("hi-base32");
const net = require("net");
const pump = require("pump");
let invalid = false;
let mod = 0;
const tunnels = {};
const agent = new http.Agent({ maxSockets: Number.MAX_VALUE });
const content = fs.readFileSync('404.txt', 'utf8');
const DEBUG = 0; // Set DEBUG to 1 to enable debug mode
// Enabling DEBUG mode will slow down the code, please only enable this if you need
// Information about connections coming in because you need to validate connection hashes.
const startServer = async () => {
console.log("Creating HyperDHT server...");
const dhtServer = new HyperDHTServer();
await dhtServer.ready();
console.log("HyperDHT server created and ready.");
const proxy = httpProxy.createProxyServer({
ws: true,
agent: agent,
timeout: 360000
});
const server = http.createServer(async function (req, res) {
try {
console.log("Incoming HTTP request...");
const split = req.headers.host.split('.');
if (DEBUG === 1) console.log("Request Headers Host Split: ", split);
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
if (DEBUG === 1) {
console.log("Public Key Buffer: ", publicKey);
console.log("Length: " + publicKey.length);
}
if (!(publicKey.length >= 32)) {
console.log("Invalid Connection!")
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content);
invalid = true
} else {
invalid = false
}
if (invalid == true) return
if (!tunnels[publicKey]) {
console.log("No tunnel found for public key, creating new tunnel...");
const port = 1337 + ((mod++) % 1000);
const server = net.createServer(function (servsock) {
console.log('Incoming Connection, Connecting to:', publicKey.toString('hex'));
if (DEBUG === 1) console.log("Public Key Length: ", publicKey.toString('hex').length);
const socket = dhtServer.connect(publicKey);
const local = servsock;
let open = { local: true, remote: true };
local.on('data', (d) => {
if (DEBUG === 1) console.log("Local Data: ", d);
socket.write(d);
});
socket.on('data', (d) => {
if (DEBUG === 1) console.log("Socket Data: ", d);
local.write(d);
});
const remoteend = (type) => {
if (DEBUG === 1) console.log('Local Connection Ended, Ending Remote Connection');
if (open.remote) socket.end();
open.remote = false;
};
const localend = (type) => {
if (DEBUG === 1) console.log('Remote Connection Ended, Ending Local Connection');
if (open.local) local.end();
open.local = false;
};
local.on('error', remoteend);
local.on('finish', remoteend);
local.on('end', remoteend);
socket.on('finish', localend);
socket.on('error', localend);
socket.on('end', localend);
});
server.listen(port, "127.0.0.1");
tunnels[publicKey] = port;
console.log("New tunnel created. Public Key:", publicKey, "Port:", port);
proxy.web(req, res, {
target: 'http://127.0.0.1:' + port
}, function (e) {
console.log("Proxy Web Error: ", e);
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content);
});
return;
} else {
console.log('Tunnel exists for public key:', publicKey);
proxy.web(req, res, {
target: 'http://127.0.0.1:' + tunnels[publicKey]
}, function (e) {
console.log("Proxy Web Error: ", e);
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content);
});
}
} catch (e) {
console.error("Error Occurred: ", e);
}
});
server.on('upgrade', function (req, socket, head) {
console.log('Upgrade Request');
const split = req.headers.host.split('.');
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
proxy.ws(req, socket, {
target: 'http://127.0.0.1:' + tunnels[publicKey]
}, function (e) {
console.error("Proxy WS Error: ", e);
socket.end();
});
});
server.listen(8081);
console.log("HTTP server listening on port 8081");
process.on('SIGINT', function () {
console.log("Shutting down...");
server.close();
dhtServer.destroy();
console.log("Shutdown complete.");
process.exit();
});
};
startServer().catch(console.error);

24
package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "raven",
"version": "1.0.0",
"description": "",
"main": "proxy.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@hyperswarm/dht": "^6.5.1",
"bun": "^1.0.35",
"graceful-goodbye": "^1.3.0",
"hi-base32": "^0.5.1",
"http": "^0.0.1-security",
"http-proxy": "^1.18.1",
"http2-proxy": "^5.0.53",
"hyper-cmd-lib-keys": "^0.1.0",
"hyper-cmd-lib-net": "^0.1.0",
"hyperdht": "^6.13.1",
"pump": "^3.0.0"
}
}

35
relay.js Normal file
View File

@ -0,0 +1,35 @@
const DHT = require("@hyperswarm/dht");
const net = require("net");
const pump = require("pump");
const node = new DHT({});
module.exports = () => {
return {
serve: (keyPair, host, port) => {
const server = node.createServer();
server.on("connection", function (servsock) {
const socket = net.connect(port, host);
socket.on('serve error', console.error);
let open = { servsock: true, remote: true };
servsock.on('data', (d) => { socket.write(d) });
socket.on('data', (d) => { servsock.write(d) });
const remoteend = () => {
if (open.remote) socket.end();
open.remote = false;
}
const servsockend = () => {
if (open.servsock) servsock.end();
open.servsock = false;
}
servsock.on('error', remoteend)
servsock.on('finish', remoteend)
servsock.on('end', remoteend)
socket.on('finish', servsockend)
socket.on('error', servsockend)
socket.on('end', servsockend)
});
server.listen(keyPair);
return keyPair.publicKey;
}
};
};

34
server.js Normal file
View File

@ -0,0 +1,34 @@
const net = require('net');
const b32 = require("hi-base32");
const DHT = require("@hyperswarm/dht");
const node = new DHT({});
const pump = require("pump");
const { pipeline } = require('stream');
const server = net.createServer(clientSocket => {
clientSocket.on('end', () => {
console.log('Client disconnected');
});
clientSocket.on('error', err => {
console.error('Client socket error:', err);
});
clientSocket.once("data",(firstData) => {
const firstLine = firstData.toString()
if (firstLine !== '') {
console.log(firstLine)
const [hostname] = firstLine.split("\n").filter(a=>a.toLowerCase().startsWith('host:'));
const split = hostname.split(":")[1].trim().split('.');
console.log(split);
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()), 'hex');
console.log(publicKey.toString('hex'))
const socket = node.connect(publicKey);
socket.on('client error', console.error);
pump(socket,clientSocket,socket)
socket.write(firstLine);
}
});
});
server.listen(8081, () => {
console.log('Proxy server listening');
});

154
worker-server.js Normal file
View File

@ -0,0 +1,154 @@
const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
console.log(`Master ${process.pid} is running`);
console.log(`Total Workers ${numCPUs*8}`)
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
} else {
const fs = require('fs');
const http = require('http');
const httpProxy = require('http-proxy');
const HyperDHTServer = require('hyperdht');
const b32 = require("hi-base32");
const net = require("net");
let invalid = false;
const tunnels = {};
const agent = new http.Agent({ maxSockets: Number.MAX_VALUE });
const content = fs.readFileSync('404.txt.new', 'utf8');
const DEBUG = 0; // Set DEBUG to 1 to enable debug mode
const CONINFO = 0; // Set CONINFO to 1 for a smaller breakdown of connections.
const dhtServer = new HyperDHTServer();
const startServer = async () => {
console.log(`Worker ${process.pid} started`);
await dhtServer.ready();
const proxy = httpProxy.createProxyServer({
ws: true,
agent: agent,
timeout: 360000
});
const server = http.createServer(async function (req, res) {
try {
if (DEBUG === 1 || CONINFO === 1) console.log("Incoming HTTP request...");
const split = req.headers.host.split('.');
if (DEBUG === 1) console.log("Request Headers Host Split: ", split);
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
if (DEBUG === 1) {
console.log("Public Key Buffer: ", publicKey);
console.log("Length: " + publicKey.length);
}
if (!(publicKey.length >= 32)) {
console.log("Invalid Connection!")
res.writeHead(418, { 'Content-Type': 'text/html' });
res.end(content);
invalid = true
} else {
invalid = false
}
if (invalid == true) return
if (!tunnels[publicKey]) {
if (DEBUG === 1 || CONINFO === 1) console.log("No tunnel found for public key, creating new tunnel...");
const port = await getAvailablePort(); // Get an available port
const server = net.createServer(function (servsock) {
if (DEBUG === 1 || CONINFO === 1) console.log('Incoming Connection, Connecting to:', publicKey.toString('hex'));
if (DEBUG === 1) console.log("Public Key Length: ", publicKey.toString('hex').length);
const socket = dhtServer.connect(publicKey);
const local = servsock;
let open = { local: true, remote: true };
local.on('data', (d) => {
if (DEBUG === 1) console.log("Local Data: ", d);
socket.write(d);
});
socket.on('data', (d) => {
if (DEBUG === 1) console.log("Socket Data: ", d);
local.write(d);
});
const remoteend = (type) => {
if (DEBUG === 1) console.log('Local Connection Ended, Ending Remote Connection');
if (open.remote) socket.end();
open.remote = false;
};
const localend = (type) => {
if (DEBUG === 1) console.log('Remote Connection Ended, Ending Local Connection');
if (open.local) local.end();
open.local = false;
};
local.on('error', remoteend);
local.on('finish', remoteend);
local.on('end', remoteend);
socket.on('finish', localend);
socket.on('error', localend);
socket.on('end', localend);
});
// Check if the port is available
server.listen(port, "127.0.0.1", () => {
if (DEBUG === 1 | CONINFO === 1) console.log(`Tunnel server listening on port ${port}`);
tunnels[publicKey] = port;
if (DEBUG === 1 || CONINFO === 1) console.log("New tunnel created. Public Key:", publicKey, "Port:", port);
proxy.web(req, res, {
target: 'http://127.0.0.1:' + port
}, function (e) {
console.log("Proxy Web Error: ", e);
res.writeHead(404, { 'Content-Type': 'text/html' });
res.end(content);
});
});
return;
} else {
if (DEBUG === 1) console.log('Tunnel exists for public key:', publicKey);
proxy.web(req, res, {
target: 'http://127.0.0.1:' + tunnels[publicKey]
}, function (e) {
console.log("Proxy Web Error: ", e);
res.writeHead(418, { 'Content-Type': 'text/html' });
res.end(content);
});
}
} catch (e) {
console.error("Error Occurred: ", e);
}
});
server.on('upgrade', function (req, socket, head) {
if (DEBUG === 1) console.log('Upgrade Request');
const split = req.headers.host.split('.');
const publicKey = Buffer.from(b32.decode.asBytes(split[0].toUpperCase()));
proxy.ws(req, socket, {
target: 'http://127.0.0.1:' + tunnels[publicKey]
}, function (e) {
console.error("Proxy WS Error: ", e);
socket.end();
});
});
server.listen(8081, () => {
console.log(`Worker ${process.pid} listening on port 8081`);
});
};
startServer().catch(console.error);
async function getAvailablePort() {
let port;
do {
port = 1337 + Math.floor(Math.random() * 1000); // Generate a random port between 1337 and 2336
} while (Object.values(tunnels).includes(port)); // Check if the port is already used
return port;
}
}