diff --git a/CHANGELOG.md b/CHANGELOG.md index 0df8703eef..e48fc42054 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - docs: Various improvements. - Ran `npm audit fix`. - `Waku.dial` accepts protocols expected from the peer. Defaults to Waku Relay only. +- Deprecated `hexToBuf` & `bufToHex` in favour of `hexToBytes` & `bytesToHex` to move towards removing the `buffer` polyfill. ### Removed diff --git a/examples/eth-pm-wallet-encryption/src/crypto.ts b/examples/eth-pm-wallet-encryption/src/crypto.ts index fbb03c0d49..1dd44f93aa 100644 --- a/examples/eth-pm-wallet-encryption/src/crypto.ts +++ b/examples/eth-pm-wallet-encryption/src/crypto.ts @@ -1,7 +1,7 @@ import "@ethersproject/shims"; import { PublicKeyMessage } from "./messaging/wire"; -import { hexToBuf, equalByteArrays, bufToHex } from "js-waku/lib/utils"; +import { hexToBytes, equalByteArrays, bytesToHex } from "js-waku/lib/utils"; import * as sigUtil from "eth-sig-util"; /** @@ -28,8 +28,8 @@ export async function createPublicKeyMessage( return new PublicKeyMessage({ encryptionPublicKey: encryptionPublicKey, - ethAddress: hexToBuf(address), - signature: hexToBuf(signature), + ethAddress: hexToBytes(address), + signature: hexToBytes(signature), }); } @@ -41,7 +41,7 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) { version: "1", }, message: { - encryptionPublicKey: bufToHex(encryptionPublicKey), + encryptionPublicKey: bytesToHex(encryptionPublicKey), ownerAddress: fromAddress, }, // Refers to the keys of the *types* object below. @@ -79,7 +79,7 @@ export async function signEncryptionKey( console.log("TYPED SIGNED:" + JSON.stringify(result)); - return hexToBuf(result); + return hexToBytes(result); } /** @@ -88,13 +88,13 @@ export async function signEncryptionKey( export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { const recovered = sigUtil.recoverTypedSignature_v4({ data: JSON.parse( - buildMsgParams(msg.encryptionPublicKey, "0x" + bufToHex(msg.ethAddress)) + buildMsgParams(msg.encryptionPublicKey, "0x" + bytesToHex(msg.ethAddress)) ), - sig: "0x" + bufToHex(msg.signature), + sig: "0x" + bytesToHex(msg.signature), }); console.log("Recovered", recovered); - console.log("ethAddress", "0x" + bufToHex(msg.ethAddress)); + console.log("ethAddress", "0x" + bytesToHex(msg.ethAddress)); return equalByteArrays(recovered, msg.ethAddress); } diff --git a/examples/eth-pm-wallet-encryption/src/messaging/SendMessage.tsx b/examples/eth-pm-wallet-encryption/src/messaging/SendMessage.tsx index f5547802f0..71ec73bc36 100644 --- a/examples/eth-pm-wallet-encryption/src/messaging/SendMessage.tsx +++ b/examples/eth-pm-wallet-encryption/src/messaging/SendMessage.tsx @@ -8,7 +8,7 @@ import { } from "@material-ui/core"; import React, { ChangeEvent, useState, KeyboardEvent } from "react"; import { Waku, WakuMessage } from "js-waku"; -import { bufToHex, hexToBuf } from "js-waku/lib/utils"; +import { bytesToHex, hexToBytes } from "js-waku/lib/utils"; import { PrivateMessage } from "./wire"; import { PrivateMessageContentTopic } from "../waku"; import * as sigUtil from "eth-sig-util"; @@ -111,7 +111,7 @@ async function encodeEncryptedWakuMessage( address: string ): Promise { const privateMessage = new PrivateMessage({ - toAddress: hexToBuf(address), + toAddress: hexToBytes(address), message: message, }); @@ -119,7 +119,7 @@ async function encodeEncryptedWakuMessage( const encObj = sigUtil.encrypt( Buffer.from(publicKey).toString("base64"), - { data: bufToHex(payload) }, + { data: bytesToHex(payload) }, "x25519-xsalsa20-poly1305" ); diff --git a/examples/eth-pm-wallet-encryption/src/waku.ts b/examples/eth-pm-wallet-encryption/src/waku.ts index 72f4202e93..7297ab27f2 100644 --- a/examples/eth-pm-wallet-encryption/src/waku.ts +++ b/examples/eth-pm-wallet-encryption/src/waku.ts @@ -3,7 +3,7 @@ import { Waku, WakuMessage } from "js-waku"; import { PrivateMessage, PublicKeyMessage } from "./messaging/wire"; import { validatePublicKeyMessage } from "./crypto"; import { Message } from "./messaging/Messages"; -import { bufToHex, equalByteArrays } from "js-waku/lib/utils"; +import { bytesToHex, equalByteArrays } from "js-waku/lib/utils"; export const PublicKeyContentTopic = "/eth-pm-wallet/1/encryption-public-key/proto"; @@ -44,7 +44,7 @@ export function handlePublicKeyMessage( if (res) { setPublicKeys((prevPks: Map) => { prevPks.set( - bufToHex(publicKeyMsg.ethAddress), + bytesToHex(publicKeyMsg.ethAddress), publicKeyMsg.encryptionPublicKey ); return new Map(prevPks); diff --git a/examples/eth-pm/src/crypto.ts b/examples/eth-pm/src/crypto.ts index b087709639..a854c74a9e 100644 --- a/examples/eth-pm/src/crypto.ts +++ b/examples/eth-pm/src/crypto.ts @@ -1,13 +1,13 @@ import "@ethersproject/shims"; import { PublicKeyMessage } from "./messaging/wire"; -import { hexToBuf, equalByteArrays, bufToHex } from "js-waku/lib/utils"; +import { hexToBytes, equalByteArrays, bytesToHex } from "js-waku/lib/utils"; import { generatePrivateKey, getPublicKey } from "js-waku"; import * as sigUtil from "eth-sig-util"; import { PublicKeyContentTopic } from "./waku"; import { keccak256 } from "ethers/lib/utils"; -export const PublicKeyMessageEncryptionKey = hexToBuf( +export const PublicKeyMessageEncryptionKey = hexToBytes( keccak256(Buffer.from(PublicKeyContentTopic, "utf-8")) ); @@ -49,8 +49,8 @@ export async function createPublicKeyMessage( return new PublicKeyMessage({ encryptionPublicKey: encryptionPublicKey, - ethAddress: hexToBuf(address), - signature: hexToBuf(signature), + ethAddress: hexToBytes(address), + signature: hexToBytes(signature), }); } @@ -62,7 +62,7 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) { version: "1", }, message: { - encryptionPublicKey: bufToHex(encryptionPublicKey), + encryptionPublicKey: bytesToHex(encryptionPublicKey), ownerAddress: fromAddress, }, // Refers to the keys of the *types* object below. @@ -100,7 +100,7 @@ export async function signEncryptionKey( console.log("TYPED SIGNED:" + JSON.stringify(result)); - return hexToBuf(result); + return hexToBytes(result); } /** @@ -109,13 +109,13 @@ export async function signEncryptionKey( export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean { const recovered = sigUtil.recoverTypedSignature_v4({ data: JSON.parse( - buildMsgParams(msg.encryptionPublicKey, "0x" + bufToHex(msg.ethAddress)) + buildMsgParams(msg.encryptionPublicKey, "0x" + bytesToHex(msg.ethAddress)) ), - sig: "0x" + bufToHex(msg.signature), + sig: "0x" + bytesToHex(msg.signature), }); console.log("Recovered", recovered); - console.log("ethAddress", "0x" + bufToHex(msg.ethAddress)); + console.log("ethAddress", "0x" + bytesToHex(msg.ethAddress)); return equalByteArrays(recovered, msg.ethAddress); } diff --git a/examples/eth-pm/src/key_pair_handling/key_pair_storage.ts b/examples/eth-pm/src/key_pair_handling/key_pair_storage.ts index 7673b497f7..7dac244e39 100644 --- a/examples/eth-pm/src/key_pair_handling/key_pair_storage.ts +++ b/examples/eth-pm/src/key_pair_handling/key_pair_storage.ts @@ -1,5 +1,5 @@ import { KeyPair } from "../crypto"; -import { bufToHex, hexToBuf } from "js-waku/lib/utils"; +import { bytesToHex, hexToBytes } from "js-waku/lib/utils"; /** * Save keypair to storage, encrypted with password @@ -11,9 +11,9 @@ export async function saveKeyPairToStorage( const { salt, iv, cipher } = await encryptKey(EncryptionKeyPair, password); const data = { - salt: bufToHex(salt), - iv: bufToHex(iv), - cipher: bufToHex(cipher), + salt: bytesToHex(salt), + iv: bytesToHex(iv), + cipher: bytesToHex(cipher), }; localStorage.setItem("cipherEncryptionKeyPair", JSON.stringify(data)); @@ -29,9 +29,9 @@ export async function loadKeyPairFromStorage( if (!str) return; const data = JSON.parse(str); - const salt = hexToBuf(data.salt); - const iv = hexToBuf(data.iv); - const cipher = hexToBuf(data.cipher); + const salt = hexToBytes(data.salt); + const iv = hexToBytes(data.iv); + const cipher = hexToBytes(data.cipher); return await decryptKey(salt, iv, cipher, password); } @@ -96,9 +96,9 @@ async function encryptKey(encryptionKeyPair: KeyPair, password: string) { * Derive a key from a password, and use the key to decrypt the cipher key pair. */ async function decryptKey( - salt: Buffer, - iv: Buffer, - cipherKeyPair: Buffer, + salt: Uint8Array, + iv: Uint8Array, + cipherKeyPair: Uint8Array, password: string ): Promise { const keyMaterial = await getKeyMaterial(password); diff --git a/examples/eth-pm/src/messaging/SendMessage.tsx b/examples/eth-pm/src/messaging/SendMessage.tsx index b0cd0be95a..3ccf0c5b67 100644 --- a/examples/eth-pm/src/messaging/SendMessage.tsx +++ b/examples/eth-pm/src/messaging/SendMessage.tsx @@ -8,7 +8,7 @@ import { } from "@material-ui/core"; import React, { ChangeEvent, useState, KeyboardEvent } from "react"; import { Waku, WakuMessage } from "js-waku"; -import { hexToBuf } from "js-waku/lib/utils"; +import { hexToBytes } from "js-waku/lib/utils"; import { PrivateMessage } from "./wire"; import { PrivateMessageContentTopic } from "../waku"; @@ -110,7 +110,7 @@ async function encodeEncryptedWakuMessage( address: string ): Promise { const privateMessage = new PrivateMessage({ - toAddress: hexToBuf(address), + toAddress: hexToBytes(address), message: message, }); diff --git a/examples/eth-pm/src/waku.ts b/examples/eth-pm/src/waku.ts index 08aa1b8027..b602f19900 100644 --- a/examples/eth-pm/src/waku.ts +++ b/examples/eth-pm/src/waku.ts @@ -3,7 +3,7 @@ import { Waku, WakuMessage } from "js-waku"; import { PrivateMessage, PublicKeyMessage } from "./messaging/wire"; import { validatePublicKeyMessage } from "./crypto"; import { Message } from "./messaging/Messages"; -import { bufToHex, equalByteArrays } from "js-waku/lib/utils"; +import { bytesToHex, equalByteArrays } from "js-waku/lib/utils"; export const PublicKeyContentTopic = "/eth-pm/1/public-key/proto"; export const PrivateMessageContentTopic = "/eth-pm/1/private-message/proto"; @@ -42,7 +42,7 @@ export function handlePublicKeyMessage( if (res) { setter((prevPks: Map) => { prevPks.set( - bufToHex(publicKeyMsg.ethAddress), + bytesToHex(publicKeyMsg.ethAddress), publicKeyMsg.encryptionPublicKey ); return new Map(prevPks); diff --git a/src/lib/enr/create.ts b/src/lib/enr/create.ts index 3f6431ab64..b7c4c6bdae 100644 --- a/src/lib/enr/create.ts +++ b/src/lib/enr/create.ts @@ -1,4 +1,4 @@ -import { bufToHex } from "../utils"; +import { bytesToHex } from "../utils"; import { NodeId } from "./types"; @@ -6,5 +6,5 @@ export function createNodeId(buffer: Buffer): NodeId { if (buffer.length !== 32) { throw new Error("NodeId must be 32 bytes in length"); } - return bufToHex(buffer); + return bytesToHex(buffer); } diff --git a/src/lib/enr/enr.spec.ts b/src/lib/enr/enr.spec.ts index 45310f3a51..4251ee1ecd 100644 --- a/src/lib/enr/enr.spec.ts +++ b/src/lib/enr/enr.spec.ts @@ -2,7 +2,7 @@ import { assert, expect } from "chai"; import { Multiaddr } from "multiaddr"; import PeerId from "peer-id"; -import { bufToHex } from "../utils"; +import { bytesToHex } from "../utils"; import { ERR_INVALID_ID } from "./constants"; import { ENR } from "./enr"; @@ -31,8 +31,8 @@ describe("ENR", function () { const txt = enr.encodeTxt(keypair.privateKey); expect(txt.slice(0, 4)).to.be.equal("enr:"); const enr2 = ENR.decodeTxt(txt); - expect(bufToHex(enr2.signature as Buffer)).to.be.equal( - bufToHex(enr.signature as Buffer) + expect(bytesToHex(enr2.signature as Buffer)).to.be.equal( + bytesToHex(enr.signature as Buffer) ); const multiaddr = enr2.getLocationMultiaddr("udp")!; expect(multiaddr.toString()).to.be.equal("/ip4/18.223.219.100/udp/9000"); @@ -56,7 +56,7 @@ describe("ENR", function () { const enr = ENR.decodeTxt(txt); const eth2 = enr.get("eth2") as Buffer; expect(eth2).to.not.be.undefined; - expect(bufToHex(eth2)).to.be.equal("f6775d0700000113ffffffffffff1f00"); + expect(bytesToHex(eth2)).to.be.equal("f6775d0700000113ffffffffffff1f00"); }); it("should decode valid ENR with multiaddrs successfully [shared test vector]", () => { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 8817873ca4..b3674060f4 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -2,6 +2,8 @@ import { keccak256, Message } from "js-sha3"; /** * Convert input to a Buffer. + * + * @deprecated Use `hexToBytes` instead. */ export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer { if (typeof hex === "string") { @@ -11,36 +13,66 @@ export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer { } } +/** + * Convert input to a byte array. + */ +export function hexToBytes(hex: string | Uint8Array): Uint8Array { + if (typeof hex === "string") { + const _hex = hex.replace(/^0x/i, ""); + const bytes = []; + for (let c = 0; c < _hex.length; c += 2) + bytes.push(parseInt(_hex.substring(c, c + 2), 16)); + + return new Uint8Array(bytes); + } + return hex; +} + /** * Convert input to hex string (no `0x` prefix). + * + * @deprecated Use `bytesToHex` instead. */ export function bufToHex(buf: Uint8Array | Buffer | ArrayBuffer): string { const _buf = Buffer.from(buf); return _buf.toString("hex"); } +/** + * Convert byte array to hex string (no `0x` prefix). + */ +export function bytesToHex(bytes: Uint8Array): string { + const hex = []; + for (let i = 0; i < bytes.length; i++) { + const current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i]; + hex.push((current >>> 4).toString(16)); + hex.push((current & 0xf).toString(16)); + } + return hex.join(""); +} + /** * Compare both inputs, return true if they represent the same byte array. */ export function equalByteArrays( - a: Uint8Array | Buffer | string, - b: Uint8Array | Buffer | string + a: Uint8Array | string, + b: Uint8Array | string ): boolean { - let aBuf: Buffer; - let bBuf: Buffer; + let _a: string; + let _b: string; if (typeof a === "string") { - aBuf = hexToBuf(a); + _a = a.replace(/^0x/i, "").toLowerCase(); } else { - aBuf = Buffer.from(a); + _a = bytesToHex(a); } if (typeof b === "string") { - bBuf = hexToBuf(b); + _b = b.replace(/^0x/i, "").toLowerCase(); } else { - bBuf = Buffer.from(b); + _b = bytesToHex(b); } - return aBuf.compare(bBuf) === 0; + return _a === _b; } /** diff --git a/src/lib/waku_message/index.node.spec.ts b/src/lib/waku_message/index.node.spec.ts index 7dff20663c..ec3e1cae37 100644 --- a/src/lib/waku_message/index.node.spec.ts +++ b/src/lib/waku_message/index.node.spec.ts @@ -2,13 +2,14 @@ import { expect } from "chai"; import debug from "debug"; import { + bytesToUtf8, makeLogFileName, NimWaku, NOISE_KEY_1, WakuRelayMessage, } from "../../test_utils"; import { delay } from "../../test_utils/delay"; -import { hexToBuf } from "../utils"; +import { hexToBytes } from "../utils"; import { Protocols, Waku } from "../waku"; import { @@ -90,8 +91,8 @@ describe("Waku Message [node only]", function () { dbg("Ask nim-waku to generate asymmetric key pair"); const keyPair = await nimWaku.getAsymmetricKeyPair(); - const privateKey = hexToBuf(keyPair.privateKey); - const publicKey = hexToBuf(keyPair.publicKey); + const privateKey = hexToBytes(keyPair.privateKey); + const publicKey = hexToBytes(keyPair.publicKey); const messageText = "This is a message I am going to encrypt"; dbg("Encrypt message"); @@ -116,7 +117,7 @@ describe("Waku Message [node only]", function () { dbg("Check message content"); expect(msgs[0].contentTopic).to.equal(message.contentTopic); - expect(hexToBuf(msgs[0].payload).toString("utf-8")).to.equal(messageText); + expect(bytesToUtf8(hexToBytes(msgs[0].payload))).to.equal(messageText); }); it("JS decrypts nim message [symmetric, no signature]", async function () { @@ -177,7 +178,7 @@ describe("Waku Message [node only]", function () { } expect(msgs[0].contentTopic).to.equal(message.contentTopic); - expect(hexToBuf(msgs[0].payload).toString("utf-8")).to.equal(messageText); + expect(bytesToUtf8(hexToBytes(msgs[0].payload))).to.equal(messageText); }); }); }); diff --git a/src/lib/waku_message/version_1.ts b/src/lib/waku_message/version_1.ts index cea2928eb9..9e7339923b 100644 --- a/src/lib/waku_message/version_1.ts +++ b/src/lib/waku_message/version_1.ts @@ -5,7 +5,7 @@ import * as ecies from "ecies-geth"; import { keccak256 } from "js-sha3"; import * as secp256k1 from "secp256k1"; -import { hexToBuf } from "../utils"; +import { hexToBytes } from "../utils"; import { IvSize, symmetric, SymmetricKeySize } from "./symmetric"; @@ -58,7 +58,7 @@ export function clearEncode( if (sigPrivKey) { envelope[0] |= IsSignedMask; const hash = keccak256(envelope); - const s = secp256k1.ecdsaSign(hexToBuf(hash), sigPrivKey); + const s = secp256k1.ecdsaSign(hexToBytes(hash), sigPrivKey); envelope = Buffer.concat([envelope, s.signature, Buffer.from([s.recid])]); sig = { signature: Buffer.from(s.signature), @@ -116,7 +116,7 @@ export async function encryptAsymmetric( data: Uint8Array | Buffer, publicKey: Uint8Array | Buffer | string ): Promise { - return ecies.encrypt(hexToBuf(publicKey), Buffer.from(data)); + return ecies.encrypt(Buffer.from(hexToBytes(publicKey)), Buffer.from(data)); } /** @@ -148,7 +148,11 @@ export async function encryptSymmetric( const iv = symmetric.generateIv(); // Returns `cipher | tag` - const cipher = await symmetric.encrypt(iv, hexToBuf(key), Buffer.from(data)); + const cipher = await symmetric.encrypt( + iv, + Buffer.from(hexToBytes(key)), + Buffer.from(data) + ); return Buffer.concat([cipher, Buffer.from(iv)]); } @@ -170,7 +174,7 @@ export async function decryptSymmetric( const cipher = data.slice(0, ivStart); const iv = data.slice(ivStart); - return symmetric.decrypt(iv, hexToBuf(key), cipher); + return symmetric.decrypt(iv, Buffer.from(hexToBytes(key)), cipher); } /** @@ -250,7 +254,7 @@ function ecRecoverPubKey(messageHash: string, signature: Buffer): Uint8Array { return secp256k1.ecdsaRecover( signature.slice(0, 64), recovery, - hexToBuf(messageHash), + hexToBytes(messageHash), false ); } diff --git a/src/lib/waku_relay/index.ts b/src/lib/waku_relay/index.ts index 313fdf047c..4f4b59108b 100644 --- a/src/lib/waku_relay/index.ts +++ b/src/lib/waku_relay/index.ts @@ -13,7 +13,7 @@ import { InMessage } from "libp2p-interfaces/src/pubsub"; import { SignaturePolicy } from "libp2p-interfaces/src/pubsub/signature-policy"; import PeerId from "peer-id"; -import { hexToBuf } from "../utils"; +import { hexToBytes } from "../utils"; import { CreateOptions, DefaultPubSubTopic } from "../waku"; import { DecryptionMethod, WakuMessage } from "../waku_message"; @@ -135,7 +135,7 @@ export class WakuRelay extends Gossipsub { key: Uint8Array | string, options?: { method?: DecryptionMethod; contentTopics?: string[] } ): void { - this.decryptionKeys.set(hexToBuf(key), options ?? {}); + this.decryptionKeys.set(hexToBytes(key), options ?? {}); } /** @@ -145,7 +145,7 @@ export class WakuRelay extends Gossipsub { * Strings must be in hex format. */ deleteDecryptionKey(key: Uint8Array | string): void { - this.decryptionKeys.delete(hexToBuf(key)); + this.decryptionKeys.delete(hexToBytes(key)); } /** diff --git a/src/lib/waku_store/index.ts b/src/lib/waku_store/index.ts index a9222a9cdf..fa0435b4b8 100644 --- a/src/lib/waku_store/index.ts +++ b/src/lib/waku_store/index.ts @@ -8,7 +8,7 @@ import PeerId from "peer-id"; import { HistoryResponse_Error } from "../../proto"; import { getPeersForProtocol, selectRandomPeer } from "../select_peer"; -import { hexToBuf } from "../utils"; +import { hexToBytes } from "../utils"; import { DefaultPubSubTopic } from "../waku"; import { DecryptionMethod, WakuMessage } from "../waku_message"; @@ -181,7 +181,7 @@ export class WakuStore { if (opts.decryptionKeys) { opts.decryptionKeys.forEach((key) => { decryptionKeys.push({ - key: hexToBuf(key), + key: hexToBytes(key), contentTopics: contentTopics.length ? contentTopics : undefined, method: undefined, }); @@ -276,7 +276,7 @@ export class WakuStore { key: Uint8Array | string, options?: { method?: DecryptionMethod; contentTopics?: string[] } ): void { - this.decryptionKeys.set(hexToBuf(key), options ?? {}); + this.decryptionKeys.set(hexToBytes(key), options ?? {}); } /** @@ -286,7 +286,7 @@ export class WakuStore { * Strings must be in hex format. */ deleteDecryptionKey(key: Uint8Array | string): void { - this.decryptionKeys.delete(hexToBuf(key)); + this.decryptionKeys.delete(hexToBytes(key)); } /** diff --git a/src/test_utils/index.ts b/src/test_utils/index.ts index a01035af71..1a5bf83131 100644 --- a/src/test_utils/index.ts +++ b/src/test_utils/index.ts @@ -9,3 +9,4 @@ export * from "./async_fs"; export * from "./constants"; export * from "./log_file"; export * from "./nim_waku"; +export * from "./utf8"; diff --git a/src/test_utils/nim_waku.node.spec.ts b/src/test_utils/nim_waku.node.spec.ts index 6bd3bfacfa..02b0e91b53 100644 --- a/src/test_utils/nim_waku.node.spec.ts +++ b/src/test_utils/nim_waku.node.spec.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; -import { argsToArray, bufToHex, defaultArgs, strToHex } from "./nim_waku"; +import { argsToArray, bytesToHex, defaultArgs, strToHex } from "./nim_waku"; describe("nim_waku", () => { it("Correctly serialized arguments", function () { @@ -37,7 +37,7 @@ describe("nim_waku", () => { ]); const expected = "5468697320697320616e207574662d3820737472696e672e"; - const actual = bufToHex(buf); + const actual = bytesToHex(buf); expect(actual).to.deep.equal(expected); }); }); diff --git a/src/test_utils/nim_waku.ts b/src/test_utils/nim_waku.ts index 6f42007dd4..a0b90ae7b8 100644 --- a/src/test_utils/nim_waku.ts +++ b/src/test_utils/nim_waku.ts @@ -11,7 +11,7 @@ import { Multiaddr, multiaddr } from "multiaddr"; import PeerId from "peer-id"; import portfinder from "portfinder"; -import { hexToBuf } from "../lib/utils"; +import { hexToBytes } from "../lib/utils"; import { DefaultPubSubTopic } from "../lib/waku"; import { WakuMessage } from "../lib/waku_message"; import * as proto from "../proto/waku/v2/message"; @@ -203,7 +203,7 @@ export class NimWaku { } const rpcMessage = { - payload: bufToHex(message.payload), + payload: bytesToHex(message.payload), contentTopic: message.contentTopic, timestamp, }; @@ -258,7 +258,7 @@ export class NimWaku { return this.rpcCall("post_waku_v2_private_v1_asymmetric_message", [ pubSubTopic ? pubSubTopic : DefaultPubSubTopic, message, - "0x" + bufToHex(publicKey), + "0x" + bytesToHex(publicKey), ]); } @@ -272,18 +272,18 @@ export class NimWaku { "get_waku_v2_private_v1_asymmetric_messages", [ pubSubTopic ? pubSubTopic : DefaultPubSubTopic, - "0x" + bufToHex(privateKey), + "0x" + bytesToHex(privateKey), ] ); } - async getSymmetricKey(): Promise { + async getSymmetricKey(): Promise { this.checkProcess(); return this.rpcCall( "get_waku_v2_private_v1_symmetric_key", [] - ).then(hexToBuf); + ).then(hexToBytes); } async postSymmetricMessage( @@ -300,7 +300,7 @@ export class NimWaku { return this.rpcCall("post_waku_v2_private_v1_symmetric_message", [ pubSubTopic ? pubSubTopic : DefaultPubSubTopic, message, - "0x" + bufToHex(symKey), + "0x" + bytesToHex(symKey), ]); } @@ -312,7 +312,10 @@ export class NimWaku { return await this.rpcCall( "get_waku_v2_private_v1_symmetric_messages", - [pubSubTopic ? pubSubTopic : DefaultPubSubTopic, "0x" + bufToHex(symKey)] + [ + pubSubTopic ? pubSubTopic : DefaultPubSubTopic, + "0x" + bytesToHex(symKey), + ] ); } @@ -416,7 +419,7 @@ export function strToHex(str: string): string { return hex; } -export function bufToHex(buffer: Uint8Array): string { +export function bytesToHex(buffer: Uint8Array): string { return Array.prototype.map .call(buffer, (x) => ("00" + x.toString(16)).slice(-2)) .join(""); diff --git a/src/test_utils/utf8.ts b/src/test_utils/utf8.ts new file mode 100644 index 0000000000..a70b7b8417 --- /dev/null +++ b/src/test_utils/utf8.ts @@ -0,0 +1,43 @@ +// Thanks https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330 +export function bytesToUtf8(bytes: Uint8Array): string { + let i = 0, + s = ""; + while (i < bytes.length) { + let c = bytes[i++]; + if (c > 127) { + if (c > 191 && c < 224) { + if (i >= bytes.length) + throw new Error("UTF-8 decode: incomplete 2-byte sequence"); + c = ((c & 31) << 6) | (bytes[i++] & 63); + } else if (c > 223 && c < 240) { + if (i + 1 >= bytes.length) + throw new Error("UTF-8 decode: incomplete 3-byte sequence"); + c = ((c & 15) << 12) | ((bytes[i++] & 63) << 6) | (bytes[i++] & 63); + } else if (c > 239 && c < 248) { + if (i + 2 >= bytes.length) + throw new Error("UTF-8 decode: incomplete 4-byte sequence"); + c = + ((c & 7) << 18) | + ((bytes[i++] & 63) << 12) | + ((bytes[i++] & 63) << 6) | + (bytes[i++] & 63); + } else + throw new Error( + "UTF-8 decode: unknown multi byte start 0x" + + c.toString(16) + + " at index " + + (i - 1) + ); + } + if (c <= 0xffff) s += String.fromCharCode(c); + else if (c <= 0x10ffff) { + c -= 0x10000; + s += String.fromCharCode((c >> 10) | 0xd800); + s += String.fromCharCode((c & 0x3ff) | 0xdc00); + } else + throw new Error( + "UTF-8 decode: code point 0x" + c.toString(16) + " exceeds UTF-16 reach" + ); + } + return s; +}