UNPKG

@libp2p/pubsub

Version:
129 lines 4.16 kB
import { randomBytes } from '@libp2p/crypto'; import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys'; import { InvalidMessageError } from '@libp2p/interface'; import { peerIdFromMultihash, peerIdFromPublicKey } from '@libp2p/peer-id'; import * as Digest from 'multiformats/hashes/digest'; import { sha256 } from 'multiformats/hashes/sha2'; import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'; import { toString as uint8ArrayToString } from 'uint8arrays/to-string'; /** * Generate a random sequence number */ export function randomSeqno() { return BigInt(`0x${uint8ArrayToString(randomBytes(8), 'base16')}`); } /** * Generate a message id, based on the `key` and `seqno` */ export const msgId = (key, seqno) => { const seqnoBytes = uint8ArrayFromString(seqno.toString(16).padStart(16, '0'), 'base16'); const keyBytes = publicKeyToProtobuf(key); const msgId = new Uint8Array(keyBytes.byteLength + seqnoBytes.length); msgId.set(keyBytes, 0); msgId.set(seqnoBytes, keyBytes.byteLength); return msgId; }; /** * Generate a message id, based on message `data` */ export const noSignMsgId = (data) => { return sha256.encode(data); }; /** * Check if any member of the first set is also a member * of the second set */ export const anyMatch = (a, b) => { let bHas; if (Array.isArray(b)) { bHas = (val) => b.includes(val); } else { bHas = (val) => b.has(val); } for (const val of a) { if (bHas(val)) { return true; } } return false; }; /** * Make everything an array */ export const ensureArray = function (maybeArray) { if (!Array.isArray(maybeArray)) { return [maybeArray]; } return maybeArray; }; const isSigned = async (message) => { if ((message.sequenceNumber == null) || (message.from == null) || (message.signature == null)) { return false; } // if a public key is present in the `from` field, the message should be signed const fromID = peerIdFromMultihash(Digest.decode(message.from)); if (fromID.publicKey != null) { return true; } if (message.key != null) { const signingKey = message.key; const signingID = peerIdFromPublicKey(publicKeyFromProtobuf(signingKey)); return signingID.equals(fromID); } return false; }; export const toMessage = async (message) => { if (message.from == null) { throw new InvalidMessageError('RPC message was missing from'); } if (!await isSigned(message)) { return { type: 'unsigned', topic: message.topic ?? '', data: message.data ?? new Uint8Array(0) }; } const from = peerIdFromMultihash(Digest.decode(message.from)); const key = message.key ?? from.publicKey; if (key == null) { throw new InvalidMessageError('RPC message was missing public key'); } const msg = { type: 'signed', from, topic: message.topic ?? '', sequenceNumber: bigIntFromBytes(message.sequenceNumber ?? new Uint8Array(0)), data: message.data ?? new Uint8Array(0), signature: message.signature ?? new Uint8Array(0), key: key instanceof Uint8Array ? publicKeyFromProtobuf(key) : key }; return msg; }; export const toRpcMessage = (message) => { if (message.type === 'signed') { return { from: message.from.toMultihash().bytes, data: message.data, sequenceNumber: bigIntToBytes(message.sequenceNumber), topic: message.topic, signature: message.signature, key: message.key ? publicKeyToProtobuf(message.key) : undefined }; } return { data: message.data, topic: message.topic }; }; export const bigIntToBytes = (num) => { let str = num.toString(16); if (str.length % 2 !== 0) { str = `0${str}`; } return uint8ArrayFromString(str, 'base16'); }; export const bigIntFromBytes = (num) => { return BigInt(`0x${uint8ArrayToString(num, 'base16')}`); }; //# sourceMappingURL=utils.js.map