pocket-messaging
Version:
A small cryptographic messaging library written in TypeScript both for browser and nodejs supporting TCP and WebSockets
94 lines (93 loc) • 3.16 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.EncryptedClient = void 0;
const Crypto_1 = require("./Crypto");
const pocket_sockets_1 = require("pocket-sockets");
/**
* Wrap an already connected and handshooked socket client as encrypted.
*
*/
class EncryptedClient extends pocket_sockets_1.WrappedClient {
constructor(client, outgoingKey, outgoingNonce, incomingKey, incomingNonce, peerPublicKey) {
super(client);
this.outgoingKey = outgoingKey;
this.outgoingNonce = outgoingNonce;
this.incomingKey = incomingKey;
this.incomingNonce = incomingNonce;
this.peerPublicKey = peerPublicKey;
this.handlers = {};
this.handleOnData = async (data) => {
if (Buffer.isBuffer(data)) {
this.incomingData = Buffer.concat([this.incomingData, data]);
this.decryptData();
}
else {
throw new Error("EncryptedClient does not work with text data");
}
};
this.incomingData = Buffer.alloc(0);
}
async init() {
await super.init();
await (0, Crypto_1.init)(); // Init sodium
}
unRead(data) {
throw new Error("unRead function not available in EncryptedClient");
}
getPeerPublicKey() {
return this.peerPublicKey;
}
decryptData() {
const ret = (0, Crypto_1.unbox)(this.incomingData, this.incomingNonce, this.incomingKey);
if (!ret) {
// Not enough data in chunk
return;
}
const [decrypted, nextNonce, bytesConsumed] = ret;
this.incomingNonce = nextNonce;
this.incomingData = this.incomingData.slice(bytesConsumed);
this.triggerEvent("data", decrypted);
if (this.incomingData.length > 0) {
this.decryptData();
}
}
send(data) {
if (Buffer.isBuffer(data)) {
// encrypt data
const [encryptedData, nextNonce] = (0, Crypto_1.box)(data, this.outgoingNonce, this.outgoingKey);
this.outgoingNonce = nextNonce;
this.client.send(encryptedData);
}
else {
throw new Error("EncryptedClient does not work with text data");
}
}
onData(fn) {
this.hookEvent("data", fn);
if ((this.handlers["data"] ?? []).length === 1) {
this.client.onData(this.handleOnData);
}
}
offData(fn) {
this.unhookEvent("data", fn);
if ((this.handlers["data"] ?? []).length === 0) {
this.client.offData(this.handleOnData);
}
}
hookEvent(type, callback) {
const cbs = this.handlers[type] || [];
this.handlers[type] = cbs;
cbs.push(callback);
}
unhookEvent(type, callback) {
const cbs = (this.handlers[type] || []).filter((cb) => callback !== cb);
this.handlers[type] = cbs;
}
triggerEvent(type, ...args) {
const cbs = this.handlers[type] || [];
cbs.forEach(callback => {
callback(...args);
});
}
}
exports.EncryptedClient = EncryptedClient;