"use strict"; import net from 'net'; import { EventEmitter, once } from 'events'; import l from 'log'; import nexline from 'nexline'; import settings from '../../settings.mjs'; import rekey from './rekey.mjs'; import { write_safe } from '../io/StreamHelpers.mjs'; import { encrypt_bytes, decrypt_bytes } from '../crypto/secretbox.mjs'; /** * Represents a connection to a single endpoint. */ class Connection extends EventEmitter { constructor(secret_join) { super(); this.session_key = Buffer.from(secret_join, "base64"); } /** * Connects to a peer and initialises a secure TCP connection thereto. * @param {string} address The address to connect to. * @param {string} port The TCP port to connect to. * @return {net.Socket} A socket setup for secure communication. */ async connect(address, port) { this.address = address; this.port = port; this.socket = new new.Socket(); this.socket.connect({ address, port }); await once(this.socket, "connect"); this.socket.setKeepAlive(true); this.session_key = await rekey(this.socket, this.session_key); this.reader = nexline({ input: this.socket }); this.read_task = read_loop(); } destroy() { this.socket.destroy(); this.emit("destroy"); } async read_loop() { try { for await (let line of this.reader) { handle_message(line); } } catch(error) { l.warn(`Warning: Killing connection to ${this.address}:${this.port} after error: ${settings.cli.verbose ? error : error.message}`); } finally { this.destroy(); } } handle_message(text) { let message = JSON.parse(text); } async send(message) { // TODO: Implement a binary frame-based protocol here instead? It would be 33% more bandwidth efficient. // Perhaps ? If messages are too long, we'll have to do something about that though.... // TODO: Consider https://devdocs.io/node/crypto#crypto.createCipheriv() - which lets us use any openssl ciphers we like - e.g. ChaCha20-Poly1305 let payload = JSON.stringify(message); payload = encrypt_bytes(this.session_key, payload); await write_safe(this.socket, payload); } } export default Connection;