From dbf25771a178f804d21ff0d40f36ffa3a875476f Mon Sep 17 00:00:00 2001 From: vini <91087061+vinikjkkj@users.noreply.github.com> Date: Wed, 3 Jul 2024 04:29:16 -0300 Subject: [PATCH] refactor: Change Sync Functions to Promises to Prevent Blocking Event Loop (#896) * initial commit * lint * lint 2 --- src/Socket/messages-recv.ts | 6 +++--- src/Socket/socket.ts | 2 +- src/Utils/crypto.ts | 11 +++++++---- src/Utils/noise-handler.ts | 4 ++-- src/WABinary/decode.ts | 13 ++++++++----- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Socket/messages-recv.ts b/src/Socket/messages-recv.ts index 49985f4..b8dcfad 100644 --- a/src/Socket/messages-recv.ts +++ b/src/Socket/messages-recv.ts @@ -440,7 +440,7 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { const ref = toRequiredBuffer(getBinaryNodeChildBuffer(linkCodeCompanionReg, 'link_code_pairing_ref')) const primaryIdentityPublicKey = toRequiredBuffer(getBinaryNodeChildBuffer(linkCodeCompanionReg, 'primary_identity_pub')) const primaryEphemeralPublicKeyWrapped = toRequiredBuffer(getBinaryNodeChildBuffer(linkCodeCompanionReg, 'link_code_pairing_wrapped_primary_ephemeral_pub')) - const codePairingPublicKey = decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped) + const codePairingPublicKey = await decipherLinkPublicKey(primaryEphemeralPublicKeyWrapped) const companionSharedKey = Curve.sharedKey(authState.creds.pairingEphemeralKeyPair.private, codePairingPublicKey) const random = randomBytes(32) const linkCodeSalt = randomBytes(32) @@ -499,10 +499,10 @@ export const makeMessagesRecvSocket = (config: SocketConfig) => { } } - function decipherLinkPublicKey(data: Uint8Array | Buffer) { + async function decipherLinkPublicKey(data: Uint8Array | Buffer) { const buffer = toRequiredBuffer(data) const salt = buffer.slice(0, 32) - const secretKey = derivePairingCodeKey(authState.creds.pairingCode!, salt) + const secretKey = await derivePairingCodeKey(authState.creds.pairingCode!, salt) const iv = buffer.slice(32, 48) const payload = buffer.slice(48, 80) return aesDecryptCTR(payload, secretKey, iv) diff --git a/src/Socket/socket.ts b/src/Socket/socket.ts index a56ea06..bca4e19 100644 --- a/src/Socket/socket.ts +++ b/src/Socket/socket.ts @@ -548,7 +548,7 @@ export const makeSocket = (config: SocketConfig) => { async function generatePairingKey() { const salt = randomBytes(32) const randomIv = randomBytes(16) - const key = derivePairingCodeKey(authState.creds.pairingCode!, salt) + const key = await derivePairingCodeKey(authState.creds.pairingCode!, salt) const ciphered = aesEncryptCTR(authState.creds.pairingEphemeralKeyPair.public, key, randomIv) return Buffer.concat([salt, randomIv, ciphered]) } diff --git a/src/Utils/crypto.ts b/src/Utils/crypto.ts index 376bf46..6f2cb21 100644 --- a/src/Utils/crypto.ts +++ b/src/Utils/crypto.ts @@ -1,9 +1,12 @@ -import { createCipheriv, createDecipheriv, createHash, createHmac, pbkdf2Sync, randomBytes } from 'crypto' +import { createCipheriv, createDecipheriv, createHash, createHmac, pbkdf2, randomBytes } from 'crypto' import HKDF from 'futoin-hkdf' import * as libsignal from 'libsignal' +import { promisify } from 'util' import { KEY_BUNDLE_TYPE } from '../Defaults' import { KeyPair } from '../Types' +const pbkdf2Promise = promisify(pbkdf2) + /** prefix version byte to the pub keys, required for some curve crypto functions */ export const generateSignalPubKey = (pubKey: Uint8Array | Buffer) => ( pubKey.length === 33 @@ -126,6 +129,6 @@ export function hkdf(buffer: Uint8Array | Buffer, expandedLength: number, info: return HKDF(!Buffer.isBuffer(buffer) ? Buffer.from(buffer) : buffer, expandedLength, info) } -export function derivePairingCodeKey(pairingCode: string, salt: Buffer) { - return pbkdf2Sync(pairingCode, salt, 2 << 16, 32, 'sha256') -} \ No newline at end of file +export async function derivePairingCodeKey(pairingCode: string, salt: Buffer) { + return await pbkdf2Promise(pairingCode, salt, 2 << 16, 32, 'sha256') +} diff --git a/src/Utils/noise-handler.ts b/src/Utils/noise-handler.ts index 5e37ba3..84cbe73 100644 --- a/src/Utils/noise-handler.ts +++ b/src/Utils/noise-handler.ts @@ -163,7 +163,7 @@ export const makeNoiseHandler = ({ return frame }, - decodeFrame: (newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => { + decodeFrame: async(newData: Buffer | Uint8Array, onFrame: (buff: Uint8Array | BinaryNode) => void) => { // the binary protocol uses its own framing mechanism // on top of the WS frames // so we get this data and separate out the frames @@ -184,7 +184,7 @@ export const makeNoiseHandler = ({ if(isFinished) { const result = decrypt(frame as Uint8Array) - frame = decodeBinaryNode(result) + frame = await decodeBinaryNode(result) } logger.trace({ msg: (frame as any)?.attrs?.id }, 'recv frame') diff --git a/src/WABinary/decode.ts b/src/WABinary/decode.ts index b900bc4..23bb480 100644 --- a/src/WABinary/decode.ts +++ b/src/WABinary/decode.ts @@ -1,11 +1,14 @@ -import { inflateSync } from 'zlib' +import { promisify } from 'util' +import { inflate } from 'zlib' import * as constants from './constants' import { jidEncode } from './jid-utils' import type { BinaryNode, BinaryNodeCodingOptions } from './types' -export const decompressingIfRequired = (buffer: Buffer) => { +const inflatePromise = promisify(inflate) + +export const decompressingIfRequired = async(buffer: Buffer) => { if(2 & buffer.readUInt8()) { - buffer = inflateSync(buffer.slice(1)) + buffer = await inflatePromise(buffer.slice(1)) } else { // nodes with no compression have a 0x00 prefix, we remove that buffer = buffer.slice(1) } @@ -259,7 +262,7 @@ export const decodeDecompressedBinaryNode = ( } } -export const decodeBinaryNode = (buff: Buffer): BinaryNode => { - const decompBuff = decompressingIfRequired(buff) +export const decodeBinaryNode = async(buff: Buffer): Promise => { + const decompBuff = await decompressingIfRequired(buff) return decodeDecompressedBinaryNode(decompBuff, constants) }