local server back
parent
b7bfa79173
commit
906c2a2f9a
|
|
@ -20,8 +20,6 @@ const identity = yargs.profile ?
|
||||||
// title(identity.name.replace(/-/g, ' '));
|
// title(identity.name.replace(/-/g, ' '));
|
||||||
|
|
||||||
// await profiles.create();
|
// 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",
|
"license": "MIT",
|
||||||
"config": {
|
"config": {
|
||||||
"ports": {
|
"ports": {
|
||||||
"ns": 5500,
|
|
||||||
"relay": 5600,
|
"relay": 5600,
|
||||||
"http": 5700
|
"http": 5700,
|
||||||
|
"service": 5800
|
||||||
},
|
},
|
||||||
"addresses": {
|
"addresses": {
|
||||||
"relay": "valnet.xyz"
|
"relay": "valnet.xyz"
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,22 @@ const clients = [];
|
||||||
// const client = stp.connect(identity, config.ports.relay, '127.0.0.1');
|
// const client = stp.connect(identity, config.ports.relay, '127.0.0.1');
|
||||||
|
|
||||||
// ==================================== [STP SERVER]
|
// ==================================== [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]
|
// ==================================== [EXPRESS]
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
|
@ -21,11 +36,36 @@ const app = express();
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
app.get('/', (req, res) => {
|
||||||
res.end(`
|
res.end(`
|
||||||
<table style="width: 100%">
|
<style>
|
||||||
${clients.map(client => `
|
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>
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<th>Address</th>
|
||||||
|
<th>loopback</th>
|
||||||
|
</tr>
|
||||||
|
${clients.map((client, index) => `
|
||||||
|
<tr>
|
||||||
|
<td><pre>${index}</pre></td>
|
||||||
<td><pre>${client.remoteAddress}</pre></td>
|
<td><pre>${client.remoteAddress}</pre></td>
|
||||||
<td><pre>${client.remoteIdentity}</pre></td>
|
<td><pre>${client.loopback}</pre></td>
|
||||||
</tr>
|
</tr>
|
||||||
`).join('')}
|
`).join('')}
|
||||||
</table>
|
</table>
|
||||||
|
|
@ -34,7 +74,7 @@ app.get('/', (req, res) => {
|
||||||
|
|
||||||
// app.post
|
// app.post
|
||||||
|
|
||||||
app.listen(9999);
|
app.listen(8080);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Reference in New Issue