ringnet
v2.0.2
Published
A secure peer-to-peer networking NodeJS module based on WebSockets using RSA and AES.
Downloads
116
Maintainers
Readme
ringnet
A secure peer-to-peer networking NodeJS module based on HTTPS WebSockets using RSA and AES.
This package aims to create a secure, trusted network among decentralized peers, and make the aforementioned easy to setup and use right out-of-the-box.
This package is (still) in development and, while unit testing exists for a fair bit of the code base, the coverage of said tests varies. Please ensure your project's usecase takes the status of this package into account before including this package into a "production" environment.
Install
npm install ringnet
Usage
Include ringnet
const { Peer, Message } = require('ringnet');
Creating a new peer
// See 'Constructor Options' below.
var peer = new Peer(options);
Constructor Options
credentials (object)
- Optional, defaults to
{'key: "https.key.pem", 'cert': "https.cert.pem"}
. - If provided, the peer will use the key (
credentials.key
) and cert (credentials.cert
) properties for creation of the https server in which to listen for incommingwss
(secure) connections. Previously an insecure http server was used for peer-to-peer communcation and has since been deprecated. The peer must have valid https key and certificate in order to run. Self-signed certificates are acceptable for use. - NOTE: If the
httpsServer
is provided, and is a valid HTTPS server instance, this option,credentials
, will be ignored.
debug (boolean)
- Optional, defaults to
false
- If set to true, the peer will output useful diagnostic information to
stdout
while running
discoveryAddresses (array)
- Optional, defaults to empty array
[]
- The addresses with or without accompanying ports of peers that the created peer will try to connect to after intialization
discoveryRange (array, length=2)
- Optional, defaults to
[26780, 26790]
- If a member of
discoveryAddresses
does not contain a port, the peer will sequentially try connect to said entry using this range of ports (inclusive). The first index of this array should be the starting port and the second and last index of this array should be the ending port
httpsServer (object)
- Optional, defaults to
false
. - If provided, the peer will use the given HTTPS Server for creation of the underyling WebSocket server.
httpsServerMode (enum)
- Optional, defaults to
HTTPS_SERVER_MODES.CREATE
, - See all available HTTPS server modes in
./lib/src/httpsServerModes.js
port (integer)
- Optional, defaults to
DSCVRY_LISTEN
environment variable with a fallback of26780
- The port that the created peer will listen on, accepting new requests via HTTP server and WebSocket connections
privateKey (string)
- Required, defaults to
peer.pem
- This is the path/location of the peer private key file. This is necessary in order to communicate securely with other peers in the decentralized network
publicAddress (array)
- Optional, defaults to
false
. - The addresses that will be used to tell other peers where they can find us when new peers connect to them. This address should be a publicly accessible FQDN or IP address that will resolve to this instantiated peer.
publicKey (string)
- Optional, defaults to
peer.pub
- This is the path/location of the peer public key file. This is necessary in order to communicate securely with other peers in the decentralized network. If missing, the publicKey will attempt to be derrived from privateKey, if privateKey is given and valid.
ringPublicKey (string)
- Required, defaults to
ring.pub
- This is the path/location of the ring public key file. This is necessary in order to establish trust amongst the decentralized peers
signature (string)
- Required, defaults to
peer.signature
- This is the path/location of the peer signature file which is the signature of the peer's public key as signed by a ring private key. This is necessady in order to establish trust amongst the decentralized peers.
wsServerOptions (object)
- Optional, defaults to empty object
{}
- If given, the peer will use the provided object to create the
ws
(WebSockets) server. See https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback for more options and additional information.
Peer Constructor Example
/*
Create a peer, `peer`, using `myRingPulicKey.pub`, `myPeerPublicKey.pub`,
`myPeerPublicKey.pem`, and `myPeerSignature` files, that listens on port
`26780` and will attempt to discover the address `127.0.0.1:26781` when
discovering. This peer will, if given an IP to discover with no port, scan
ports 26780-26790 (inclusive) against the IP in order to attempt to
establish a secure connection with said IP. This peer will report that
it's public IP address is "127.0.0.1" and it will also output diagnostics
(`debug`).
*/
var peer = new Peer({
'credentials': {
'key': "myHttpsServer.key.pem",
'cert': "myHttpsServer.cert.pem"
},
'ringPublicKey': "myRingPulicKey.pub",
'publicKey': "myPeerPublicKey.pub",
'privateKey': "myPeerPrivateKey.pem",
'signature': "myPeerSignature.signature",
'port': 26780,
'discoveryAddresses': [ "127.0.0.1:26781" ],
'discoveryRange': [ 26780, 27900 ],
'publicAddress': "127.0.0.1",
'debug': true,
});
Setting up the event handlers
peer.on('ready', () => {
/* Indicates the underyling HTTP Server is ready. */
});
peer.on('request', ({connection, request }) => {
/* A new request has been received by the WebSocket server */
});
peer.on('connection', ({connection }) => {
/* A new VERIFIED AND TRUSTED connection has been made */
});
peer.on('message', () => ({ message, connection }) => {
/*
A message has been received by the WebSocket server.
NOTE:
This event is only emitted if the message header's 'type' property is not
set or is not of type string. See custom message header type example below.
*/
});
peer.on('discovering', () => {
/* The peer is discovering based on it's list of known or potential peers */
});
peer.on('discovered', () => {
/* The peer is done discovering */
});
peer.on('your_custom_message_header_type', () => {
/*
The peer has received a message of "unknown" (custom) type and emits the
message header's 'type' property.
NOTE:
These "unknown" (custom) events are only emitted if the message header's 'type'
property is a string.
*/
});
Using async
/ await
Clients can also leverage async / await to detemine peer readiness or the completion of the discovery operation.
async function createPeer() {
const peer = new Peer({ /* ... */ });
// Wait for peer to initialize...
await peer.init();
// Wait for Peer to finish discover operation...
await peer.discover();
}
Creating and Sending Messages
/**
* Creates and sends a new 'MySuperCoolMessage' Message with arbitrary body (object).
*/
async function sendMySuperCoolMessage() {
var message = new Message({
type: "MySuperCoolMessage",
body: {
someProperty: "Some Value!"
}
});
try {
// Broadcast the message to all connected, verified peers
const broadcastResults = await peer.broadcast({ message });
} catch(e) {
console.error(e.stack);
}
}
Listening for Messages
peer.on("MySuperCoolMessage", ({ message, connection }) => {
// Do something here
});
Testing On Local Machine
Generate or bring-your-own HTTPS server key and certificate:
$ npm run setup
In a terminal window, start the first peer (peer1):
$ npm run peer1
In a second terminal window, start the second peer (peer2):
$ npm run peer2
Once the peer-to-peer network has been established (post-HELO handshake), messages from one peer can be sent out to all other peers in the network securely, just as in a typical client-server scenario, but in a decentralized fashion. Every peer is a server and every peer is a client. There is no central management.
Type some text into terminal/prompt while the second peer (peer2) is running and hit enter. The second peer will send the message securely to the first peer (peer1), as the peers have established trust in the decentralized network.
Quit (
Ctrl^C
or typeexit
and hit enter) on the second terminal window to quit the second peer.Verify the encrypted message sent by the second peer made it to the first peer (peer1) by returning to the first terminal window. The last few lines of output will now reflect the message sent by the second peer to the first peer and received by the first peer from the second peer.
Quit (
Ctrl^C
or typeexit
and hit enter) on the first terminal window to quit the first peer.