Skip to content

Commit

Permalink
refactor: handle error
Browse files Browse the repository at this point in the history
  • Loading branch information
DIY0R committed Nov 24, 2024
1 parent 3dc9a6f commit e495238
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 69 deletions.
1 change: 0 additions & 1 deletion lib/common/createData.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable max-params */
const createData = (typeMessage, message) => ({ typeMessage, message });
const createMessage = (
typeMessage,
Expand Down
11 changes: 11 additions & 0 deletions lib/common/errorWrapper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class WrappedError extends Error {
constructor(message, originalError) {
super(message);
this.name = 'Error';
this.timestamp = new Date().toISOString();
if (originalError instanceof Error) {
this.originalError = originalError;
}
}
}
module.exports = WrappedError;
3 changes: 2 additions & 1 deletion lib/common/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const serdes = require('./serdes');
const uuid = require('./uuid');
const createData = require('./createData');
module.exports = { ...serdes, ...uuid, ...createData };
const WrappedError = require('./errorWrapper');
module.exports = { ...serdes, uuid, ...createData, WrappedError };
2 changes: 1 addition & 1 deletion lib/common/uuid.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ const crypto = require('crypto');
const uuid = () =>
crypto.randomUUID({ disableEntropyCache: false }).replace(/-/gi, '');

module.exports = { uuid };
module.exports = uuid;
12 changes: 10 additions & 2 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,30 @@ const TTL = 300;
const HANDSHAKE = 'HANDSHAKE';
const DM = 'MESSAGE';
const CRYPTO_DM = 'CRYPTO_DM';
const ERROR = 'ERROR';
const PUBLIC_KEY_REQUEST = 'PUBLIC_KEY_REQUEST';
const PUBLIC_KEY_RESPONSE = 'PUBLIC_KEY_RESPONSE';
const TIMEOUT_ERROR_MESSAGE = `Neighbor check timed out after ${TIMEOUT_DURATION / 1000} seconds`;
const TIMEOUT_ERROR = 'TIMEOUT_ERROR';
const TIMEOUT_ERROR_REQUEST = 'RSA key retrieval timed out.';
const DECRYPT_ERROR = 'Unable to decrypt the message.';
const SEND_ERROR = 'Failed to send the data.';
const PUBLISH_ERROR = 'Failed to publish the data.';
const DEFAULT_TIMEOUT = 10000;
module.exports = {
PUBLIC_KEY_REQUEST,
PUBLIC_KEY_RESPONSE,
HANDSHAKE,
DEFAULT_TIMEOUT,
TIMEOUT_ERROR,
TIMEOUT_ERROR_REQUEST,
TIME_CLEAN_MSG,
CHECK_INTERVAL,
TIMEOUT_DURATION,
TIMEOUT_ERROR_MESSAGE,
TTL,
CRYPTO_DM,
DM,
ERROR,
SEND_ERROR,
DECRYPT_ERROR,
PUBLISH_ERROR,
};
94 changes: 54 additions & 40 deletions lib/cryptoRsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,36 @@
const crypto = require('crypto');
const EventEmitter = require('events');
const Connection = require('./connection');
const { createMessage, uuid } = require('./common');
const { createMessage, uuid, WrappedError } = require('./common');
const {
PUBLIC_KEY_RESPONSE,
TTL,
PUBLIC_KEY_REQUEST,
DEFAULT_TIMEOUT,
TIMEOUT_ERROR,
CRYPTO_DM,
ERROR,
TIMEOUT_ERROR_REQUEST,
DECRYPT_ERROR,
} = require('./constants');

class CryptoRSA extends Connection {
publicKey = '';
#privateKey = '';
_nodePublicKeys = new Map();
#responseEmitter = new EventEmitter();
_nodePublicKeys = new Map();

constructor(port, targetNode) {
super(port, targetNode);
this.#generateKeys();
}

#generateKeys() {
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
},
});
this.publicKey = publicKey;
this.#privateKey = privateKey;
}

_requestPublicKey(targetNode) {
const publicKey = this.getTargetNodeKey(targetNode);
const publicKey = this.#getTargetNodeKey(targetNode);
return new Promise((resolve, reject) => {
if (publicKey) return resolve(publicKey);
const messageId = uuid();
const timerId = setTimeout(
() => reject(new Error(TIMEOUT_ERROR)),
() => reject(new Error(TIMEOUT_ERROR_REQUEST)),
DEFAULT_TIMEOUT,
);
this.#responseEmitter.once(messageId, key => {
Expand Down Expand Up @@ -74,6 +60,34 @@ class CryptoRSA extends Connection {
return { encryptedMessage, encryptedSymKey, iv };
}

_deleteNodeKey(nodeId) {
return this._nodePublicKeys.delete(nodeId);
}

[CRYPTO_DM](_, messageData) {
const processedMessage = this._processMessage(messageData, CRYPTO_DM);
if (processedMessage) {
try {
const message = this.#decryptMessage(processedMessage.message);
this.emit(CRYPTO_DM, {
...processedMessage,
message: JSON.parse(message),
});
} catch (error) {
this.emit(
ERROR,
new WrappedError(DECRYPT_ERROR, error),
processedMessage,
);
}
}
}

#getTargetNodeKey(nodeId) {
const publicKey = this._nodePublicKeys.get(nodeId);
if (publicKey) return publicKey;
}

#decryptMessage(message) {
const { encryptedMessage, encryptedSymKey, iv } = message;
const decryptedSymKey = crypto.privateDecrypt(
Expand All @@ -91,21 +105,20 @@ class CryptoRSA extends Connection {
return decryptedMessage;
}

getTargetNodeKey(nodeId) {
const publicKey = this._nodePublicKeys.get(nodeId);
if (publicKey) return publicKey;
}

deleteNodeKey(nodeId) {
return this._nodePublicKeys.delete(nodeId);
}

[CRYPTO_DM](_, messageData) {
const processedMessage = this._processMessage(messageData, CRYPTO_DM);
if (processedMessage) {
const message = this.#decryptMessage(processedMessage.message);
this.emit(CRYPTO_DM, { ...processedMessage, message });
}
#generateKeys() {
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
},
});
this.publicKey = publicKey;
this.#privateKey = privateKey;
}

[PUBLIC_KEY_REQUEST](_, messageData) {
Expand Down Expand Up @@ -136,10 +149,11 @@ class CryptoRSA extends Connection {
messageData,
PUBLIC_KEY_RESPONSE,
);
if (!processedMessage) return;
const { messageId, publicKey } = messageData.message;
this._nodePublicKeys.set(messageData.fromNode, publicKey);
this.#responseEmitter.emit(messageId, publicKey);
if (!processedMessage) {
const { messageId, publicKey } = messageData.message;
this._nodePublicKeys.set(messageData.fromNode, publicKey);
this.#responseEmitter.emit(messageId, publicKey);
}
}
}

Expand Down
64 changes: 40 additions & 24 deletions lib/messaging.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ const {
TTL,
TIME_CLEAN_MSG,
CRYPTO_DM,
ERROR,
SEND_ERROR,
PUBLISH_ERROR,
} = require('./constants');
const WrappedError = require('./common/errorWrapper');

class Messaging extends CryptoRSA {
#NODE_ID = uuid();
Expand All @@ -23,31 +27,43 @@ class Messaging extends CryptoRSA {
}

async publish(targetNode, message) {
await this.#neighborCheck();
const messageForm = createMessage(
DM,
targetNode,
this.#NODE_ID,
uuid(),
TTL,
message,
);
this._broadcast(messageForm);
try {
await this.#neighborCheck();
const messageForm = createMessage(
DM,
targetNode,
this.#NODE_ID,
uuid(),
TTL,
message,
);
this._broadcast(messageForm);
} catch (error) {
const wrappedError = new WrappedError(PUBLISH_ERROR, error);
this.emit(ERROR, wrappedError);
throw wrappedError;
}
}

async send(targetNode, message) {
await this.#neighborCheck();
const publicKey = await this._requestPublicKey(targetNode);
const cryptMessage = this._generateCryptoMessage(message, publicKey);
const messageForm = createMessage(
CRYPTO_DM,
targetNode,
this.#NODE_ID,
uuid(),
TTL,
cryptMessage,
);
this._broadcast(messageForm);
try {
await this.#neighborCheck();
const publicKey = await this._requestPublicKey(targetNode);
const cryptMessage = this._generateCryptoMessage(message, publicKey);
const messageForm = createMessage(
CRYPTO_DM,
targetNode,
this.#NODE_ID,
uuid(),
TTL,
cryptMessage,
);
this._broadcast(messageForm);
} catch (error) {
const wrappedError = new WrappedError(SEND_ERROR, error);
this.emit(ERROR, wrappedError);
throw wrappedError;
}
}

get nodeId() {
Expand Down Expand Up @@ -75,7 +91,7 @@ class Messaging extends CryptoRSA {
const nodeId = this.#findNodeId(connectionId);
if (!nodeId) return;
this.neighbors.delete(nodeId);
this.deleteNodeKey(nodeId);
this._deleteNodeKey(nodeId);
}

_processMessage(message, typeMessage) {
Expand Down Expand Up @@ -103,7 +119,7 @@ class Messaging extends CryptoRSA {
return new Promise((resolve, reject) => {
if (this.neighbors.size > 0) return resolve();
const timer = setTimeout(
() => reject(Error(TIMEOUT_ERROR_MESSAGE)),
() => reject(new Error(TIMEOUT_ERROR_MESSAGE)),
TIMEOUT_DURATION,
);
const interval = setInterval(() => {
Expand Down

0 comments on commit e495238

Please sign in to comment.