UNPKG

pocket-messaging

Version:

A small cryptographic messaging library written in TypeScript both for browser and nodejs supporting TCP and WebSockets

143 lines (142 loc) 6.82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.HandshakeFactory = void 0; const pocket_sockets_1 = require("pocket-sockets"); const types_1 = require("./types"); const Handshake_1 = require("./Handshake"); const EncryptedClient_1 = require("./EncryptedClient"); /** * This class extends the SocketFactory with handshake capabilties. * The SocketFactory EVENTS objects is redeclared here and extended. */ class HandshakeFactory extends pocket_sockets_1.SocketFactory { constructor(handshakeFactoryConfig) { super(handshakeFactoryConfig.socketFactoryConfig, handshakeFactoryConfig.socketFactoryStats); this.handleOnConnect = async (client, isServer) => { try { let handshakeResult; let peerData; if (typeof this.handshakeFactoryConfig.peerData === "function") { peerData = this.handshakeFactoryConfig.peerData(isServer); } else { peerData = this.handshakeFactoryConfig.peerData; } let encryptedClient; if (isServer) { handshakeResult = await (0, Handshake_1.HandshakeAsServer)(client, this.handshakeFactoryConfig.keyPair.secretKey, this.handshakeFactoryConfig.keyPair.publicKey, this.handshakeFactoryConfig.discriminator, this.handshakeFactoryConfig.allowedClients, peerData); encryptedClient = new EncryptedClient_1.EncryptedClient(client, handshakeResult.serverToClientKey, handshakeResult.serverNonce, handshakeResult.clientToServerKey, handshakeResult.clientNonce, handshakeResult.peerLongtermPk); } else { if (!this.handshakeFactoryConfig.serverPublicKey) { client.close(); return; } handshakeResult = await (0, Handshake_1.HandshakeAsClient)(client, this.handshakeFactoryConfig.keyPair.secretKey, this.handshakeFactoryConfig.keyPair.publicKey, this.handshakeFactoryConfig.serverPublicKey, this.handshakeFactoryConfig.discriminator, peerData); encryptedClient = new EncryptedClient_1.EncryptedClient(client, handshakeResult.clientToServerKey, handshakeResult.clientNonce, handshakeResult.serverToClientKey, handshakeResult.serverNonce, handshakeResult.peerLongtermPk); } if (!handshakeResult || !encryptedClient) { return; } const publicKeyStr = handshakeResult.peerLongtermPk.toString("hex"); if (this.checkClientsOverflow(publicKeyStr)) { const publicKeyOverflowEvent = [handshakeResult.peerLongtermPk]; this.triggerEvent(types_1.EVENT_HANDSHAKEFACTORY_PUBLICKEY_OVERFLOW, ...publicKeyOverflowEvent); client.close(); return; } this.increaseClientsCounter(publicKeyStr); client.onClose(() => { this.decreaseClientsCounter(publicKeyStr); }); const handshakeEvent = [isServer, client, encryptedClient, handshakeResult]; this.triggerEvent(types_1.EVENT_HANDSHAKEFACTORY_HANDSHAKE, ...handshakeEvent); } catch (error) { const handshakeErrorEvent = [error]; this.triggerEvent(types_1.EVENT_HANDSHAKEFACTORY_HANDSHAKE_ERROR, ...handshakeErrorEvent); client.close(); } }; this.handshakeFactoryConfig = handshakeFactoryConfig; } /** Override from parent. */ checkConnectionsOverflow(address, isServer = false) { if (super.checkConnectionsOverflow(address, isServer)) { return true; } if (!isServer) { if (this.handshakeFactoryConfig.maxConnectionsPerClientPair !== undefined) { const pair = [this.handshakeFactoryConfig.serverPublicKey?.toString("hex"), this.handshakeFactoryConfig.keyPair.publicKey.toString("hex")]; pair.sort(); const pairKey = pair.join(":"); const clientPairCount = this.readCounter(pairKey); if (clientPairCount >= this.handshakeFactoryConfig.maxConnectionsPerClientPair) { return true; } } } return false; } init() { this.onConnect(this.handleOnConnect); super.init(); } getHandshakeFactoryConfig() { return this.handshakeFactoryConfig; } /** * Increase the counter connections per client public key. */ increaseClientsCounter(peerPublicKey) { this.increaseCounter(peerPublicKey); const pair = [peerPublicKey, this.handshakeFactoryConfig.keyPair.publicKey.toString("hex")]; pair.sort(); const pairKey = pair.join(":"); this.increaseCounter(pairKey); } decreaseClientsCounter(peerPublicKey) { this.decreaseCounter(peerPublicKey); const pair = [peerPublicKey, this.handshakeFactoryConfig.keyPair.publicKey.toString("hex")]; pair.sort(); const pairKey = pair.join(":"); this.decreaseCounter(pairKey); } /** * @params peerPublicKey * @returns true if any limit is reached. */ checkClientsOverflow(peerPublicKey) { if (this.handshakeFactoryConfig.maxConnectionsPerClient !== undefined) { const clientCount = this.readCounter(peerPublicKey); if (clientCount >= this.handshakeFactoryConfig.maxConnectionsPerClient) { return true; } } if (this.handshakeFactoryConfig.maxConnectionsPerClientPair !== undefined) { const pair = [peerPublicKey, this.handshakeFactoryConfig.keyPair.publicKey.toString("hex")]; pair.sort(); const pairKey = pair.join(":"); const clientPairCount = this.readCounter(pairKey); if (clientPairCount >= this.handshakeFactoryConfig.maxConnectionsPerClientPair) { return true; } } return false; } /** * Detect specific error in the handshake process. * This error is also emitted on the general onError event hook provided by SocketFactory. */ onHandshakeError(callback) { this.hookEvent(types_1.EVENT_HANDSHAKEFACTORY_HANDSHAKE_ERROR, callback); } onHandshake(callback) { this.hookEvent(types_1.EVENT_HANDSHAKEFACTORY_HANDSHAKE, callback); } onPublicKeyOverflow(callback) { this.hookEvent(types_1.EVENT_HANDSHAKEFACTORY_PUBLICKEY_OVERFLOW, callback); } } exports.HandshakeFactory = HandshakeFactory;