Skip to content
Bidirectional networking over RSA and AES.
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.


This is a utility package which helps simplify secure communication between a client and a server over TCP. It transmits values over channels, similar to event emitters, and offers a connection guard on the server.


When a connection is first established, the client sends an identity (such as a username) to the server. The server's guard will receive the connection and identity, and may accept or reject the connection.

Approved connections become active and can actively transmit values back and forth between the client and server. These transactions are automatically encrypted with RSA public keys which are exchanged when the connection is accepted.

Each transaction is also encrypted with AES256. For this to work, both the server and client must already know the password. The server's guard can set a different password for each client, but a connection will not establish unless both sides agree on a password.


The server binds to a port and uses the connection event as a guard. You can accept incoming connections by calling connection.accept() with a 32-character password for AES256 encryption.

const server = new Server(12345);

server.on('connection', async connection => {
    let ip = connection.getAddress();
    let identity = connection.getIdentity();

    if (identity == 'baileyherbert') {
        await connection.accept('00a3ac30ef0b23da56f09fc5b68f40fa');
        await connection.send('notification', 'Welcome back!');



The client connects directly to the server given the port, host, and an identity string. When starting the client with start(), a 32-character password must be supplied which must match the password provided by the server with accept().

const client = new Client(12345, '', 'baileyherbert');

client.start('00a3ac30ef0b23da56f09fc5b68f40fa').then(async () => {
    client.listen('notification', message => {
        console.log('The server said:', message);

    await client.send('event', 'signed_in');


Many different types of data can be sent. They are encoded to JSON while transmitting over encryption, and are decoded before triggering listeners. For instance, all of the following are supported:

client.send('channel', true);
client.send('channel', 'some text');
client.send('channel', 125.3);
client.send('channel', { name: 'John Doe' });


The internal socket is configured to send data without delay on both sides of a connection. However, Node will sometimes emit data in chunks. To address this, the package implements a newline buffer. It is important to note that this is managed internally, and you do not need to manually append a new line character to the end of your data payloads.


This package supports a call method which works similarly to send, but gives us the return value of the remote function which listened to it.

// Server can return immediately or through a promise:
connection.listen('updateProfile', changes => {
    return { id: 42 };
    return new Promise(resolve => {
        resolve({ id: 42 });

// The client gets it back when using call():'updateProfile', { name: 'John Smith' }).then(profile => {
    console.log('Profile updated for user',; // 42


When working with TypeScript, you can use generics to constrain data types.

client.send<boolean>('channel', true); // valid
client.send<boolean>('channel', 'string'); // error

client.listen<{ name: string }>('channel', info => {
    let { name } = info; // valid, recognizes as string
    let { age } = info; // error, age not found
});<boolean>('channel').then(bool => ...);<boolean, string>('channel', str).then(bool => ...);
You can’t perform that action at this time.