Home Reference Source Repository

src/lib/network/secure-client-connection.js

import io from 'socket.io-client';
import EventEmitter from 'events';
import ecdh from 'crypto-ecdh';
import { exists, write } from 'crypto-io-fs';
import { seed, netKeyPath } from './../../params';
// TODO: hardcoded swarm key?
// TODO: replace with websocket

export const initConnection = new Promise((resolve, reject) => {
  const socket = io(seed);

  socket.on('handshake', pubKey => {
    const pair = ecdh('hex');
    pair.derive(pubKey);

    // start a new secure connection using ECDH
    new SecureClientConnection(socket, pair).on('connected', connection => resolve(connection));
  });
});

class SecureClientConnection extends EventEmitter {
  constructor(socket, pair) {
    super();
    // declare properties
    this.id = socket.id;
    this.pair = pair;
    this.socket = socket;
    // bind methods
    this.handshake = this.handshake.bind(this);
    // init listeners & emitters
    this.shake();
  }

  requestKey() {
    return new Promise((resolve, reject) => {
      this.socket.on('_request-key', key => {
        resolve(key);
      });
      this.socket.emit('request-key');
    });
  }

  async shake() {
    this.socket.on('secure-connection', this.handshake);
    this.socket.emit('_handshake', this.pair.public);
  }

  async handshake(cipher) {
    const key = await this.pair.decrypt(cipher);
    // get a new pair
    const pair = ecdh('hex');
    // encrypt our new key
    cipher = await this.pair.encrypt(pair.public);
    this.pair = pair;
    this.pair.derive(key);

    this.socket.on('network', async cipher => {
      const address = await this.pair.decrypt(cipher);
      if (!exists(netKeyPath)) {
        cipher = await this.requestKey();
        const key = await this.pair.decrypt(cipher);
        await write(netKeyPath, key);
      }
      this.emit('connected', {address});
    });
    this.socket.on('address', data => console.log(data));
    this.socket.emit('_secure-connection', cipher.toString());
  }
}