local server back
parent
b7bfa79173
commit
906c2a2f9a
|
|
@ -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());
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
212
lib/STP.js
212
lib/STP.js
|
|
@ -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) {
|
||||
// });
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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')
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
const EventEmitter = require('events')
|
||||
|
||||
|
||||
class Node extends EventEmitter {
|
||||
constructor() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports.Node = Node;
|
||||
|
|
@ -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.')
|
||||
}
|
||||
})();
|
||||
*/
|
||||
|
|
@ -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')
|
||||
// })
|
||||
// }
|
||||
|
||||
|
||||
|
||||
})();
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
"license": "MIT",
|
||||
"config": {
|
||||
"ports": {
|
||||
"ns": 5500,
|
||||
"relay": 5600,
|
||||
"http": 5700
|
||||
"http": 5700,
|
||||
"service": 5800
|
||||
},
|
||||
"addresses": {
|
||||
"relay": "valnet.xyz"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Reference in New Issue