local server back

stable
Marcus 2021-02-13 23:56:20 -05:00
parent b7bfa79173
commit 906c2a2f9a
9 changed files with 297 additions and 231 deletions

View File

@ -20,8 +20,6 @@ const identity = yargs.profile ?
// title(identity.name.replace(/-/g, ' '));
// await profiles.create();
// log.debug(await profiles.all())
log.debug(await identity.name());

View File

@ -1,212 +0,0 @@
const net = require('net');
const EventEmitter = require('events');
const NodeRSA = require('node-rsa');
const log = require('signale').scope('stp');
const natUpnp = require('nat-upnp');
const client = natUpnp.createClient();
client.map = function(port) {
return new Promise((res, rej) => {
this.portMapping({
private: port,
public: port,
ttl: 10,
description: 'valnet'
}, (err) => {
if(err) rej(err);
res();
});
});
}
client.unmap = function(port) {
return new Promise((res, rej) => {
this.portUnmapping({
private: port,
public: port
}, (err) => {
if(err) rej(err);
res();
});
});
}
client.mappings = function() {
return new Promise((res, rej) => {
this.getMappings((err, mappings) => {
if(err) rej(err);
res(mappings);
});
});
}
const { config } = require('./../package.json');
module.exports.createServer = function(keys, port) {
const server = new Server(keys, port);
// server.on('connection');
return server;
// return 5;
}
module.exports.connect = function(identity, port, ip) {
const client = net.connect(port, ip);
return new STPSocket(client, identity);
}
class Server extends EventEmitter {
tcpServer;
identity;
port;
constructor(identity, port) {
super();
this.identity = identity;
this.port = port;
(async () => {
try {
log.debug('first upnp mapping attempt...');
await client.map(this.port);
this.openServer();
} catch (e) {
log.warn(`Could not open upnp port ${this.port}`);
log.warn('Check your router is configured to allow upnp.');
log.warn('Valnet will continue to operate, but incomming')
log.warn('peer connections will not be possible.')
}
})();
}
openServer() {
log.success(`opened upnp port ${this.port}`);
this.tcpServer = net.createServer(this.tcpConnectClient.bind(this));
this.tcpServer.listen(this.port);
}
tcpConnectClient(tcpSocket) {
log.debug('incomming TCP connection! ' + tcpSocket.remoteAddress);
const socket = new STPSocket(tcpSocket, this.identity);
socket.on('ready', () => {
this.emit('connection', socket);
})
}
}
class STPSocket extends EventEmitter {
tcpSocket;
readyState = 0;
buffer = '';
externalIdentity;
get remoteAddress() {
return this.tcpSocket.remoteAddress;
}
get remoteIdentity() {
return this.externalIdentity.exportKey('pkcs8-public-pem');
}
get open() {
return this.tcpSocket.readyState === 'open'
}
constructor(tcpSocket, identity) {
super();
this.tcpSocket = tcpSocket;
this.identity = identity;
if(this.open) this.handshake();
else this.tcpSocket.on('connect', this.handshake.bind(this));
this.tcpSocket.on('data', this.data.bind(this));
this.tcpSocket.on('error', (...args) => this.emit('error', ...args));
this.tcpSocket.on('close', (...args) => this.emit('close', ...args));
}
data(evt) {
// log.debug(evt.toString());
this.buffer += evt.toString();
this.processBuffer();
}
processBuffer() {
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
this.buffer = '';
for(const message of parts) {
if(message.endsWith('\x03')) {
const obj = JSON.parse(message.substr(1, message.length - 2));
this.processMessage(obj);
} else {
this.buffer += message;
}
}
}
processMessage(obj) {
switch(obj.cmd) {
case 'KEY': {
if(this.readyState === 0) {
// log.debug('registering external key');
this.externalIdentity = new NodeRSA();
this.externalIdentity.importKey(obj.data.key, 'pkcs8-public-pem');
this.tcpSocket.write(new AckPacket().toBuffer());
this.readyState = 1;
}
break;
}
case 'ACK': {
if(this.readyState === 1) {
this.readyState = 2;
// log.debug('socket ready!');
this.emit('ready');
}
break;
}
}
}
handshake() {
// log.debug('begin handshake on socket');
const pk = this.identity.publicKey;
const packet = new KeyExchangePacket(pk);
const buffer = packet.toBuffer();
this.tcpSocket.write(buffer);
}
}
class STPPacket {
cmd = 'NOOP';
data = {};
meta = {};
toBuffer() {
return Buffer.from(`\x02${JSON.stringify({
cmd: this.cmd,
data: this.data,
meta: this.meta
})}\x03`);
}
}
class KeyExchangePacket extends STPPacket {
constructor(key, type = 'pkcs8-pem') {
super();
this.cmd = 'KEY';
this.data.key = key;
this.meta.type = type;
}
}
class AckPacket extends STPPacket {
constructor() {
super();
this.cmd = 'ACK';
}
}
// client.getMappings(function(err, results) {
// });
// client.getMappings({ local: true }, function(err, results) {
// });
// client.externalIp(function(err, ip) {
// });

136
lib/STP/index.js 100644
View File

@ -0,0 +1,136 @@
const net = require('net');
const EventEmitter = require('events');
const NodeRSA = require('node-rsa');
const log = require('signale').scope('stp');
const {
KeyExchangePacket,
AckPacket
} = require('./packets');
const { rejects } = require('assert');
module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) {
const server = new Server(identity, port);
server.on('connection', connection => {
cb(connection);
});
// return 5;
}
module.exports.connect = function({
identity,
port,
ip
}) {
return new STPSocket(net.connect(port, ip), identity);
}
class Server extends EventEmitter {
tcpServer;
identity;
port;
constructor(identity, port) {
super();
this.identity = identity;
this.port = port;
this.openServer();
}
openServer() {
log.info(`opening STP server on ${this.port}`);
this.tcpServer = net.createServer(this.tcpConnectClient.bind(this));
this.tcpServer.listen(this.port);
}
tcpConnectClient(tcpSocket) {
const socket = new STPSocket(tcpSocket, this.identity);
socket.on('ready', () => {
this.emit('connection', socket);
})
}
}
class STPSocket extends EventEmitter {
tcpSocket;
readyState = 0;
buffer = '';
externalKey;
identity;
get loopback() {
return this.identity.publicKey ===
this.externalKey.exportKey('pkcs8-public-pem');
}
get remoteAddress() {
return this.tcpSocket.remoteAddress;
}
get remoteIdentity() {
return this.externalKey.exportKey('pkcs8-public-pem');
}
get open() {
return this.tcpSocket.readyState === 'open'
}
constructor(tcpSocket, identity) {
super();
this.tcpSocket = tcpSocket;
this.identity = identity;
if(this.open) this.handshake();
else this.tcpSocket.on('connect', this.handshake.bind(this));
this.tcpSocket.on('data', this.data.bind(this));
this.tcpSocket.on('error', (...args) => this.emit('error', ...args));
this.tcpSocket.on('close', (...args) => this.emit('close', ...args));
}
data(evt) {
this.buffer += evt.toString();
this.processBuffer();
}
processBuffer() {
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
this.buffer = '';
for(const message of parts) {
if(message.endsWith('\x03')) {
const obj = JSON.parse(message.substr(1, message.length - 2));
this.processMessage(obj);
} else {
this.buffer += message;
}
}
}
processMessage(obj) {
switch(obj.cmd) {
case 'KEY': {
if(this.readyState === 0) {
log.info('registering external key');
this.externalKey = new NodeRSA();
this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem');
this.tcpSocket.write(new AckPacket().toBuffer());
this.readyState = 1;
}
break;
}
case 'ACK': {
if(this.readyState === 1) {
this.readyState = 2;
log.success('internal key acknowledged');
this.emit('ready');
}
break;
}
}
}
handshake() {
const pk = this.identity.publicKey;
const packet = new KeyExchangePacket(pk);
const buffer = packet.toBuffer();
this.tcpSocket.write(buffer);
}
}

38
lib/STP/packets.js 100644
View File

@ -0,0 +1,38 @@
class STPPacket {
cmd = 'NOOP';
data = {};
meta = {};
toBuffer() {
return Buffer.from(`\x02${JSON.stringify({
cmd: this.cmd,
data: this.data,
meta: this.meta
})}\x03`);
}
}
class KeyExchangePacket extends STPPacket {
constructor(key, type = 'pkcs8-pem') {
super();
this.cmd = 'KEY';
this.data.key = key;
this.meta.type = type;
}
}
function basicPacket(commandName) {
return class extends STPPacket {
constructor() {
super();
this.cmd = commandName;
}
}
}
module.exports.STPPacket = STPPacket;
module.exports.KeyExchangePacket = KeyExchangePacket;
module.exports.AckPacket = basicPacket('ACK')
module.exports.GetClientsPacket = basicPacket('NODES')

11
lib/node.js 100644
View File

@ -0,0 +1,11 @@
const EventEmitter = require('events')
class Node extends EventEmitter {
constructor() {
}
}
module.exports.Node = Node;

63
lib/upnp.js 100644
View File

@ -0,0 +1,63 @@
const natUpnp = require('nat-upnp');
const client = natUpnp.createClient();
module.exports.map = function(port) {
return new Promise((res, rej) => {
client.portMapping({
private: port,
public: port,
ttl: 10,
description: 'valnet'
}, (err) => {
if(err) rej(err);
res();
});
});
}
module.exports.mapIndefinite = function(port) {
return new Promise((res, rej) => {
client.portMapping({
private: port,
public: port,
ttl: 0,
description: 'valnet'
}, (err) => {
if(err) rej(err);
res();
});
});
}
module.exports.unmap = function(port) {
return new Promise((res, rej) => {
client.portUnmapping({
private: port,
public: port
}, (err) => {
if(err) rej(err);
res();
});
});
}
module.exports.mappings = function() {
return new Promise((res, rej) => {
client.getMappings((err, mappings) => {
if(err) rej(err);
res(mappings);
});
});
}
/*
(async () => {
try {
log.debug('first upnp mapping attempt...');
await client.map(this.port);
this.openServer();
} catch (e) {
log.warn(`Could not open upnp port ${this.port}`);
log.warn('Check your router is configured to allow upnp.');
log.warn('Valnet will continue to operate, but incomming')
log.warn('peer connections will not be possible.')
}
})();
*/

View File

@ -23,13 +23,5 @@ const identity = new Identity('name-server', 'default');
// async function connectClient (client) {
// log.info(`connected client ${client.remoteAddress}`);
// client.on('error', () => {
// log.debug('who cares')
// })
// }
})();

View File

@ -5,9 +5,9 @@
"license": "MIT",
"config": {
"ports": {
"ns": 5500,
"relay": 5600,
"http": 5700
"http": 5700,
"service": 5800
},
"addresses": {
"relay": "valnet.xyz"

View File

@ -13,7 +13,22 @@ const clients = [];
// const client = stp.connect(identity, config.ports.relay, '127.0.0.1');
// ==================================== [STP SERVER]
const server = stp.createServer(identity, config.ports.relay);
stp.createServer({
identity: identity,
port: config.ports.relay
}, socket => {
log.debug('loopback ' + socket.loopback)
clients.push(socket);
});
const client = stp.connect({
identity,
port: config.ports.relay,
ip: 'valnet.xyz'
});
client.on('error', e => {
log.error(e)
})
// ==================================== [EXPRESS]
const express = require('express');
@ -21,20 +36,45 @@ const app = express();
app.get('/', (req, res) => {
res.end(`
<table style="width: 100%">
${clients.map(client => `
<style>
td:not(:last-child), th:not(:last-child) {
border-right: 1px solid black;
}
td, th {
padding-left: 8px;
}
th {
border-bottom: 3px solid black;
}
table {
border-spacing: 0px;
font-family: sans-serif;
font-size: 13px;
}
tr:nth-child(2n) {
background: #ccc;
}
</style>
<table style="min-width: 300px">
<tr>
<td><pre>${client.remoteAddress}</pre></td>
<td><pre>${client.remoteIdentity}</pre></td>
<th>Id</th>
<th>Address</th>
<th>loopback</th>
</tr>
`).join('')}
${clients.map((client, index) => `
<tr>
<td><pre>${index}</pre></td>
<td><pre>${client.remoteAddress}</pre></td>
<td><pre>${client.loopback}</pre></td>
</tr>
`).join('')}
</table>
`);
});
// app.post
app.listen(9999);
app.listen(8080);