mirror of https://github.com/waku-org/js-waku.git
Merge pull request #221 from status-im/waku-msg-version-1
This commit is contained in:
commit
d0958c1c57
|
@ -9,6 +9,7 @@
|
|||
"bitauth",
|
||||
"bufbuild",
|
||||
"cimg",
|
||||
"ciphertext",
|
||||
"circleci",
|
||||
"codecov",
|
||||
"commitlint",
|
||||
|
@ -17,7 +18,9 @@
|
|||
"Dlazy",
|
||||
"Dout",
|
||||
"Dscore",
|
||||
"ecies",
|
||||
"editorconfig",
|
||||
"ephem",
|
||||
"esnext",
|
||||
"ethersproject",
|
||||
"execa",
|
||||
|
@ -55,9 +58,12 @@
|
|||
"protobuf",
|
||||
"protoc",
|
||||
"reactjs",
|
||||
"recid",
|
||||
"rlnrelay",
|
||||
"sandboxed",
|
||||
"secio",
|
||||
"seckey",
|
||||
"secp",
|
||||
"staticnode",
|
||||
"statusim",
|
||||
"submodule",
|
||||
|
|
|
@ -11,11 +11,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- `WakuRelay.deleteObserver` to allow removal of observers, useful when a React component add observers when mounting and needs to delete it when unmounting.
|
||||
- Keep alive feature that pings host regularly, reducing the chance of connections being dropped due to idle.
|
||||
Can be disabled or default frequency (10s) can be changed when calling `Waku.create`.
|
||||
- New `lib/utils` module for easy, dependency-less hex/bytes conversions.
|
||||
|
||||
### Changed
|
||||
- **Breaking**: Auto select peer if none provided for store and light push protocols.
|
||||
- Upgrade to `libp2p@0.31.7` and `libp2p-gossipsub@0.10.0` to avoid `TextEncoder` errors in ReactJS tests.
|
||||
- Disable keep alive by default as latest nim-waku release does not support ping protocol.
|
||||
- **Breaking**: Optional parameters for `WakuMessage.fromBytes` and `WakuMessage.fromUtf8String` are now passed in a single `Options` object.
|
||||
- **Breaking**: `WakuMessage` static functions are now async to allow for encryption and decryption.
|
||||
- **Breaking**: `WakuMessage` constructor is now private, `from*` and `decode*` function should be used.
|
||||
- `WakuMessage` version 1 is partially supported, enabling asymmetrical encryption and signature of messages;
|
||||
this can be done by passing keys to `WakuMessage.from*` and `WakuMessage.decode*` methods.
|
||||
Note: this is not yet compatible with nim-waku.
|
||||
|
||||
### Fixed
|
||||
- Disable `keepAlive` if set to `0`.
|
||||
|
|
|
@ -104,7 +104,10 @@ export default async function startChat(): Promise<void> {
|
|||
rl.prompt();
|
||||
const chatMessage = ChatMessage.fromUtf8String(new Date(), nick, line);
|
||||
|
||||
const msg = WakuMessage.fromBytes(chatMessage.encode(), ChatContentTopic);
|
||||
const msg = await WakuMessage.fromBytes(chatMessage.encode(), {
|
||||
contentTopic: ChatContentTopic,
|
||||
timestamp: new Date(),
|
||||
});
|
||||
if (opts.lightPush) {
|
||||
await waku.lightPush.push(msg);
|
||||
} else {
|
||||
|
|
|
@ -25,18 +25,30 @@ export default function BroadcastPublicKey({
|
|||
if (!waku) return;
|
||||
|
||||
if (publicKeyMsg) {
|
||||
const wakuMsg = encodePublicKeyWakuMessage(publicKeyMsg);
|
||||
waku.lightPush.push(wakuMsg).catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
});
|
||||
encodePublicKeyWakuMessage(publicKeyMsg)
|
||||
.then((wakuMsg) => {
|
||||
waku.lightPush.push(wakuMsg).catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log('Failed to encode Public Key Message in Waku Message');
|
||||
});
|
||||
} else {
|
||||
createPublicKeyMessage(signer, ethDmKeyPair.publicKey)
|
||||
.then((msg) => {
|
||||
setPublicKeyMsg(msg);
|
||||
const wakuMsg = encodePublicKeyWakuMessage(msg);
|
||||
waku.lightPush.push(wakuMsg).catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
});
|
||||
encodePublicKeyWakuMessage(msg)
|
||||
.then((wakuMsg) => {
|
||||
waku.lightPush.push(wakuMsg).catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(
|
||||
'Failed to encode Public Key Message in Waku Message'
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to create public key message', e);
|
||||
|
@ -56,9 +68,11 @@ export default function BroadcastPublicKey({
|
|||
);
|
||||
}
|
||||
|
||||
function encodePublicKeyWakuMessage(
|
||||
async function encodePublicKeyWakuMessage(
|
||||
publicKeyMessage: PublicKeyMessage
|
||||
): WakuMessage {
|
||||
): Promise<WakuMessage> {
|
||||
const payload = publicKeyMessage.encode();
|
||||
return WakuMessage.fromBytes(payload, PublicKeyContentTopic);
|
||||
return await WakuMessage.fromBytes(payload, {
|
||||
contentTopic: PublicKeyContentTopic,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import * as EthCrypto from 'eth-crypto';
|
|||
import { ethers } from 'ethers';
|
||||
import { Signer } from '@ethersproject/abstract-signer';
|
||||
import { DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||
import { byteArrayToHex, hexToBuf } from './utils';
|
||||
import { hexToBuf, equalByteArrays, bufToHex } from 'js-waku/lib/utils';
|
||||
|
||||
export interface KeyPair {
|
||||
privateKey: string;
|
||||
|
@ -49,15 +49,7 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
|||
const formattedMsg = formatPublicKeyForSignature(msg.ethDmPublicKey);
|
||||
try {
|
||||
const sigAddress = ethers.utils.verifyMessage(formattedMsg, msg.signature);
|
||||
const sigAddressBytes = hexToBuf(sigAddress);
|
||||
// Compare the actual byte arrays instead of strings that may differ in casing or prefixing.
|
||||
const cmp = sigAddressBytes.compare(new Buffer(msg.ethAddress));
|
||||
console.log(
|
||||
`Buffer comparison result: ${cmp} for (signature address, message address)`,
|
||||
sigAddressBytes,
|
||||
msg.ethAddress
|
||||
);
|
||||
return cmp === 0;
|
||||
return equalByteArrays(sigAddress, msg.ethAddress);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
'Failed to verify signature for Public Key Message',
|
||||
|
@ -77,7 +69,7 @@ export function validatePublicKeyMessage(msg: PublicKeyMessage): boolean {
|
|||
*/
|
||||
function formatPublicKeyForSignature(ethDmPublicKey: Uint8Array): string {
|
||||
return JSON.stringify({
|
||||
ethDmPublicKey: byteArrayToHex(ethDmPublicKey),
|
||||
ethDmPublicKey: bufToHex(ethDmPublicKey),
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { KeyPair } from '../crypto';
|
||||
import { bufToHex, hexToBuf } from 'js-waku/lib/utils';
|
||||
|
||||
/**
|
||||
* Save keypair to storage, encrypted with password
|
||||
|
@ -10,9 +11,9 @@ export async function saveKeyPairToStorage(
|
|||
const { salt, iv, cipher } = await encryptKey(ethDmKeyPair, password);
|
||||
|
||||
const data = {
|
||||
salt: new Buffer(salt).toString('hex'),
|
||||
iv: new Buffer(iv).toString('hex'),
|
||||
cipher: new Buffer(cipher).toString('hex'),
|
||||
salt: bufToHex(salt),
|
||||
iv: bufToHex(iv),
|
||||
cipher: bufToHex(cipher),
|
||||
};
|
||||
|
||||
localStorage.setItem('cipherEthDmKeyPair', JSON.stringify(data));
|
||||
|
@ -28,9 +29,9 @@ export async function loadKeyPairFromStorage(
|
|||
if (!str) return;
|
||||
const data = JSON.parse(str);
|
||||
|
||||
const salt = new Buffer(data.salt, 'hex');
|
||||
const iv = new Buffer(data.iv, 'hex');
|
||||
const cipher = new Buffer(data.cipher, 'hex');
|
||||
const salt = hexToBuf(data.salt);
|
||||
const iv = hexToBuf(data.iv);
|
||||
const cipher = hexToBuf(data.cipher);
|
||||
|
||||
return await decryptKey(salt, iv, cipher, password);
|
||||
}
|
||||
|
|
|
@ -117,7 +117,9 @@ async function encodeEncryptedWakuMessage(
|
|||
};
|
||||
|
||||
const payload = encode(directMsg);
|
||||
return WakuMessage.fromBytes(payload, DirectMessageContentTopic);
|
||||
return WakuMessage.fromBytes(payload, {
|
||||
contentTopic: DirectMessageContentTopic,
|
||||
});
|
||||
}
|
||||
|
||||
function sendMessage(
|
||||
|
|
|
@ -3,7 +3,7 @@ import { getStatusFleetNodes, Waku, WakuMessage } from 'js-waku';
|
|||
import { decode, DirectMessage, PublicKeyMessage } from './messaging/wire';
|
||||
import { decryptMessage, validatePublicKeyMessage } from './crypto';
|
||||
import { Message } from './messaging/Messages';
|
||||
import { byteArrayToHex, equalByteArrays } from './utils';
|
||||
import { bufToHex, equalByteArrays } from 'js-waku/lib/utils';
|
||||
|
||||
export const PublicKeyContentTopic = '/eth-dm/1/public-key/proto';
|
||||
export const DirectMessageContentTopic = '/eth-dm/1/direct-message/json';
|
||||
|
@ -41,7 +41,7 @@ export function handlePublicKeyMessage(
|
|||
if (!msg.payload) return;
|
||||
const publicKeyMsg = PublicKeyMessage.decode(msg.payload);
|
||||
if (!publicKeyMsg) return;
|
||||
const ethDmPublicKey = byteArrayToHex(publicKeyMsg.ethDmPublicKey);
|
||||
const ethDmPublicKey = bufToHex(publicKeyMsg.ethDmPublicKey);
|
||||
console.log(ethDmPublicKey, myAddress);
|
||||
if (myAddress && equalByteArrays(publicKeyMsg.ethAddress, myAddress)) return;
|
||||
|
||||
|
@ -50,7 +50,7 @@ export function handlePublicKeyMessage(
|
|||
|
||||
if (res) {
|
||||
setter((prevPks: Map<string, string>) => {
|
||||
prevPks.set(byteArrayToHex(publicKeyMsg.ethAddress), ethDmPublicKey);
|
||||
prevPks.set(bufToHex(publicKeyMsg.ethAddress), ethDmPublicKey);
|
||||
return new Map(prevPks);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -55,11 +55,10 @@ async function handleMessage(
|
|||
} else {
|
||||
const timestamp = new Date();
|
||||
const chatMessage = ChatMessage.fromUtf8String(timestamp, nick, message);
|
||||
const wakuMsg = WakuMessage.fromBytes(
|
||||
chatMessage.encode(),
|
||||
ChatContentTopic,
|
||||
timestamp
|
||||
);
|
||||
const wakuMsg = await WakuMessage.fromBytes(chatMessage.encode(), {
|
||||
contentTopic: ChatContentTopic,
|
||||
timestamp,
|
||||
});
|
||||
return messageSender(wakuMsg);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"debug": "^4.3.1",
|
||||
"ecies-parity": "^0.1.1",
|
||||
"it-concat": "^2.0.0",
|
||||
"it-length-prefixed": "^5.0.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"libp2p": "^0.31.7",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-mplex": "^0.10.3",
|
||||
|
@ -19,6 +21,7 @@
|
|||
"libp2p-tcp": "^0.15.4",
|
||||
"libp2p-websockets": "^0.15.6",
|
||||
"multiaddr": "^9.0.1",
|
||||
"secp256k1": "^4.0.2",
|
||||
"ts-proto": "^1.79.7",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
|
@ -30,6 +33,7 @@
|
|||
"@types/google-protobuf": "^3.7.4",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"@types/node": "^14.14.31",
|
||||
"@types/secp256k1": "^4.0.2",
|
||||
"@types/tail": "^2.0.0",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
||||
|
@ -3586,6 +3590,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
|
||||
},
|
||||
"node_modules/@types/secp256k1": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.2.tgz",
|
||||
"integrity": "sha512-QMg+9v0bbNJ2peLuHRWxzmy0HRJIG6gFZNhaRSp7S3ggSbCCxiqQB2/ybvhXyhHOCequpNkrx7OavNhrWOsW0A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/tail": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tail/-/tail-2.2.0.tgz",
|
||||
|
@ -4545,6 +4558,15 @@
|
|||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bip66": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz",
|
||||
"integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/bl": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
|
||||
|
@ -4617,6 +4639,20 @@
|
|||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/browserify-aes": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"buffer-xor": "^1.0.3",
|
||||
"cipher-base": "^1.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"evp_bytestokey": "^1.0.3",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.16.6",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
|
||||
|
@ -4676,6 +4712,12 @@
|
|||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"node_modules/buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
|
||||
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/bufio": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bufio/-/bufio-1.0.7.tgz",
|
||||
|
@ -4934,6 +4976,16 @@
|
|||
"npm": ">=3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/class-is": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz",
|
||||
|
@ -6544,6 +6596,33 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/create-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"cipher-base": "^1.0.1",
|
||||
"inherits": "^2.0.1",
|
||||
"md5.js": "^1.3.4",
|
||||
"ripemd160": "^2.0.1",
|
||||
"sha.js": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/create-hmac": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"cipher-base": "^1.0.3",
|
||||
"create-hash": "^1.1.0",
|
||||
"inherits": "^2.0.1",
|
||||
"ripemd160": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"node_modules/create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
|
@ -7191,6 +7270,20 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/drbg.js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz",
|
||||
"integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"browserify-aes": "^1.0.6",
|
||||
"create-hash": "^1.1.2",
|
||||
"create-hmac": "^1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
|
@ -7205,6 +7298,71 @@
|
|||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
|
||||
},
|
||||
"node_modules/ecies-parity": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ecies-parity/-/ecies-parity-0.1.1.tgz",
|
||||
"integrity": "sha512-eq95uTiNkQYr9orLJZVD/aGfcvRiC6tORZvB2JiieEYX4OwbJV74ahDhDm9d/4NkO7lPoi19DWcEQ8SKh+kQ6A==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"acorn": "7.1.0",
|
||||
"elliptic": "6.5.1",
|
||||
"es6-promise": "^4.2.4",
|
||||
"nan": "2.14.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"secp256k1": "3.7.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ecies-parity/node_modules/acorn": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
|
||||
"integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ecies-parity/node_modules/elliptic": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz",
|
||||
"integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.4.0",
|
||||
"brorand": "^1.0.1",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ecies-parity/node_modules/nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
|
||||
},
|
||||
"node_modules/ecies-parity/node_modules/secp256k1": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz",
|
||||
"integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bindings": "^1.5.0",
|
||||
"bip66": "^1.1.5",
|
||||
"bn.js": "^4.11.8",
|
||||
"create-hash": "^1.2.0",
|
||||
"drbg.js": "^1.0.1",
|
||||
"elliptic": "^6.4.1",
|
||||
"nan": "^2.14.0",
|
||||
"safe-buffer": "^5.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
@ -7390,6 +7548,11 @@
|
|||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"node_modules/es6-promisify": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
|
||||
|
@ -7866,6 +8029,16 @@
|
|||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"md5.js": "^1.3.4",
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/exec-sh": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
|
||||
|
@ -9928,6 +10101,40 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/hash-base": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
|
||||
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.6.0",
|
||||
"safe-buffer": "^5.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/hash-base/node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
|
@ -12400,6 +12607,17 @@
|
|||
"node": ">= 8.16.2"
|
||||
}
|
||||
},
|
||||
"node_modules/md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"hash-base": "^3.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/memorystream": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
||||
|
@ -16227,6 +16445,16 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"hash-base": "^3.0.0",
|
||||
"inherits": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/rsvp": {
|
||||
"version": "4.8.5",
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||
|
@ -16792,6 +17020,19 @@
|
|||
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/sha.js": {
|
||||
"version": "2.4.11",
|
||||
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"sha.js": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/shallow-clone": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||
|
@ -22021,6 +22262,15 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
|
||||
},
|
||||
"@types/secp256k1": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.2.tgz",
|
||||
"integrity": "sha512-QMg+9v0bbNJ2peLuHRWxzmy0HRJIG6gFZNhaRSp7S3ggSbCCxiqQB2/ybvhXyhHOCequpNkrx7OavNhrWOsW0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/tail": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/tail/-/tail-2.2.0.tgz",
|
||||
|
@ -22736,6 +22986,15 @@
|
|||
"file-uri-to-path": "1.0.0"
|
||||
}
|
||||
},
|
||||
"bip66": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz",
|
||||
"integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"bl": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/bl/-/bl-5.0.0.tgz",
|
||||
|
@ -22802,6 +23061,20 @@
|
|||
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
|
||||
"dev": true
|
||||
},
|
||||
"browserify-aes": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"buffer-xor": "^1.0.3",
|
||||
"cipher-base": "^1.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"evp_bytestokey": "^1.0.3",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"browserslist": {
|
||||
"version": "4.16.6",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz",
|
||||
|
@ -22837,6 +23110,12 @@
|
|||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
|
||||
},
|
||||
"buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
|
||||
"integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
|
||||
"optional": true
|
||||
},
|
||||
"bufio": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bufio/-/bufio-1.0.7.tgz",
|
||||
|
@ -23030,6 +23309,16 @@
|
|||
"uint8arrays": "^2.1.3"
|
||||
}
|
||||
},
|
||||
"cipher-base": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
|
||||
"integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"class-is": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/class-is/-/class-is-1.1.0.tgz",
|
||||
|
@ -24307,6 +24596,33 @@
|
|||
"yaml": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"create-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"cipher-base": "^1.0.1",
|
||||
"inherits": "^2.0.1",
|
||||
"md5.js": "^1.3.4",
|
||||
"ripemd160": "^2.0.1",
|
||||
"sha.js": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"create-hmac": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"cipher-base": "^1.0.3",
|
||||
"create-hash": "^1.1.0",
|
||||
"inherits": "^2.0.1",
|
||||
"ripemd160": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"create-require": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
|
||||
|
@ -24807,6 +25123,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"drbg.js": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz",
|
||||
"integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"browserify-aes": "^1.0.6",
|
||||
"create-hash": "^1.1.2",
|
||||
"create-hmac": "^1.1.4"
|
||||
}
|
||||
},
|
||||
"ecc-jsbn": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
|
||||
|
@ -24823,6 +25150,60 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"ecies-parity": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ecies-parity/-/ecies-parity-0.1.1.tgz",
|
||||
"integrity": "sha512-eq95uTiNkQYr9orLJZVD/aGfcvRiC6tORZvB2JiieEYX4OwbJV74ahDhDm9d/4NkO7lPoi19DWcEQ8SKh+kQ6A==",
|
||||
"requires": {
|
||||
"acorn": "7.1.0",
|
||||
"elliptic": "6.5.1",
|
||||
"es6-promise": "^4.2.4",
|
||||
"nan": "2.14.0",
|
||||
"secp256k1": "3.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"acorn": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
|
||||
"integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ=="
|
||||
},
|
||||
"elliptic": {
|
||||
"version": "6.5.1",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.1.tgz",
|
||||
"integrity": "sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg==",
|
||||
"requires": {
|
||||
"bn.js": "^4.4.0",
|
||||
"brorand": "^1.0.1",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"nan": {
|
||||
"version": "2.14.0",
|
||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
|
||||
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
|
||||
},
|
||||
"secp256k1": {
|
||||
"version": "3.7.1",
|
||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz",
|
||||
"integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"bindings": "^1.5.0",
|
||||
"bip66": "^1.1.5",
|
||||
"bn.js": "^4.11.8",
|
||||
"create-hash": "^1.2.0",
|
||||
"drbg.js": "^1.0.1",
|
||||
"elliptic": "^6.4.1",
|
||||
"nan": "^2.14.0",
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
|
@ -24978,6 +25359,11 @@
|
|||
"integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
|
||||
"dev": true
|
||||
},
|
||||
"es6-promise": {
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||
},
|
||||
"es6-promisify": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-6.1.1.tgz",
|
||||
|
@ -25338,6 +25724,16 @@
|
|||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
|
||||
},
|
||||
"evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"md5.js": "^1.3.4",
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"exec-sh": {
|
||||
"version": "0.3.6",
|
||||
"resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz",
|
||||
|
@ -26899,6 +27295,25 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"hash-base": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
|
||||
"integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.4",
|
||||
"readable-stream": "^3.6.0",
|
||||
"safe-buffer": "^5.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
|
@ -28899,6 +29314,17 @@
|
|||
"integrity": "sha512-BJXxkuIfJchcXOJWTT2DOL+yFWifFv2yGYOUzvXg8Qz610QKw+sHCvTMYwA+qWGhlA2uivBezChZ/pBy1tWdkQ==",
|
||||
"dev": true
|
||||
},
|
||||
"md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"hash-base": "^3.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"memorystream": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
|
||||
|
@ -31889,6 +32315,16 @@
|
|||
"glob": "^7.1.3"
|
||||
}
|
||||
},
|
||||
"ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"hash-base": "^3.0.0",
|
||||
"inherits": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"rsvp": {
|
||||
"version": "4.8.5",
|
||||
"resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz",
|
||||
|
@ -32347,6 +32783,16 @@
|
|||
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
|
||||
"peer": true
|
||||
},
|
||||
"sha.js": {
|
||||
"version": "2.4.11",
|
||||
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"shallow-clone": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||
|
|
|
@ -57,8 +57,10 @@
|
|||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"debug": "^4.3.1",
|
||||
"ecies-parity": "^0.1.1",
|
||||
"it-concat": "^2.0.0",
|
||||
"it-length-prefixed": "^5.0.2",
|
||||
"js-sha3": "^0.8.0",
|
||||
"libp2p": "^0.31.7",
|
||||
"libp2p-gossipsub": "^0.10.0",
|
||||
"libp2p-mplex": "^0.10.3",
|
||||
|
@ -66,6 +68,7 @@
|
|||
"libp2p-tcp": "^0.15.4",
|
||||
"libp2p-websockets": "^0.15.6",
|
||||
"multiaddr": "^9.0.1",
|
||||
"secp256k1": "^4.0.2",
|
||||
"ts-proto": "^1.79.7",
|
||||
"uuid": "^8.3.2"
|
||||
},
|
||||
|
@ -77,6 +80,7 @@
|
|||
"@types/google-protobuf": "^3.7.4",
|
||||
"@types/mocha": "^8.2.2",
|
||||
"@types/node": "^14.14.31",
|
||||
"@types/secp256k1": "^4.0.2",
|
||||
"@types/tail": "^2.0.0",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^4.0.1",
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
export { getStatusFleetNodes, Environment, Protocol } from './lib/discover';
|
||||
|
||||
export * as utils from './lib/utils';
|
||||
|
||||
export { Waku } from './lib/waku';
|
||||
export { WakuMessage } from './lib/waku_message';
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
export function byteArrayToHex(bytes: Uint8Array): string {
|
||||
const buf = new Buffer(bytes);
|
||||
return buf.toString('hex');
|
||||
export function hexToBuf(str: string): Buffer {
|
||||
return Buffer.from(str.replace(/^0x/i, ''), 'hex');
|
||||
}
|
||||
|
||||
export function hexToBuf(str: string): Buffer {
|
||||
return Buffer.from(str.replace(/0x/, ''), 'hex');
|
||||
export function bufToHex(buf: Uint8Array | Buffer | ArrayBuffer): string {
|
||||
const _buf = Buffer.from(buf);
|
||||
return _buf.toString('hex');
|
||||
}
|
||||
|
||||
export function equalByteArrays(
|
|
@ -76,7 +76,7 @@ export class Waku {
|
|||
this.lightPush = lightPush;
|
||||
this.keepAliveTimers = {};
|
||||
|
||||
const keepAlive = options.keepAlive !== undefined ? options.keepAlive : 0;
|
||||
const keepAlive = options.keepAlive || 0;
|
||||
|
||||
if (keepAlive !== 0) {
|
||||
libp2p.connectionManager.on('peer:connect', (connection: Connection) => {
|
||||
|
|
|
@ -33,7 +33,7 @@ describe('Waku Light Push', () => {
|
|||
});
|
||||
|
||||
const messageText = 'Light Push works!';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
|
||||
const pushResponse = await waku.lightPush.push(message);
|
||||
expect(pushResponse?.isSuccess).to.be.true;
|
||||
|
@ -73,7 +73,7 @@ describe('Waku Light Push', () => {
|
|||
const nimPeerId = await nimWaku.getPeerId();
|
||||
|
||||
const messageText = 'Light Push works!';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
|
||||
const pushResponse = await waku.lightPush.push(message, {
|
||||
peerId: nimPeerId,
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
import { expect } from 'chai';
|
||||
import fc from 'fast-check';
|
||||
|
||||
import { WakuMessage } from './waku_message';
|
||||
|
||||
describe('Waku Message', function () {
|
||||
it('Waku message round trip binary serialization', function () {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), (s) => {
|
||||
const msg = WakuMessage.fromUtf8String(s);
|
||||
const binary = msg.encode();
|
||||
const actual = WakuMessage.decode(binary);
|
||||
|
||||
expect(actual).to.deep.equal(msg);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('Payload to utf-8', function () {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), (s) => {
|
||||
const msg = WakuMessage.fromUtf8String(s);
|
||||
const utf8 = msg.payloadAsUtf8;
|
||||
|
||||
return utf8 === s;
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,85 +0,0 @@
|
|||
// Ensure that this class matches the proto interface while
|
||||
import { Reader } from 'protobufjs/minimal';
|
||||
|
||||
// Protecting the user from protobuf oddities
|
||||
import * as proto from '../proto/waku/v2/message';
|
||||
|
||||
export const DefaultContentTopic = '/waku/2/default-content/proto';
|
||||
const DefaultVersion = 0;
|
||||
|
||||
export class WakuMessage {
|
||||
public constructor(public proto: proto.WakuMessage) {}
|
||||
|
||||
/**
|
||||
* Create Message with a utf-8 string as payload.
|
||||
*/
|
||||
static fromUtf8String(
|
||||
utf8: string,
|
||||
contentTopic: string = DefaultContentTopic,
|
||||
timestamp: Date = new Date()
|
||||
): WakuMessage {
|
||||
const payload = Buffer.from(utf8, 'utf-8');
|
||||
return new WakuMessage({
|
||||
payload,
|
||||
version: DefaultVersion,
|
||||
contentTopic,
|
||||
timestamp: timestamp.valueOf() / 1000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create Message with a byte array as payload.
|
||||
*/
|
||||
static fromBytes(
|
||||
payload: Uint8Array,
|
||||
contentTopic: string = DefaultContentTopic,
|
||||
timestamp: Date = new Date()
|
||||
): WakuMessage {
|
||||
return new WakuMessage({
|
||||
payload,
|
||||
timestamp: timestamp.valueOf() / 1000,
|
||||
version: DefaultVersion,
|
||||
contentTopic,
|
||||
});
|
||||
}
|
||||
|
||||
static decode(bytes: Uint8Array): WakuMessage {
|
||||
const wakuMsg = proto.WakuMessage.decode(Reader.create(bytes));
|
||||
return new WakuMessage(wakuMsg);
|
||||
}
|
||||
|
||||
encode(): Uint8Array {
|
||||
return proto.WakuMessage.encode(this.proto).finish();
|
||||
}
|
||||
|
||||
get payloadAsUtf8(): string {
|
||||
if (!this.proto.payload) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Array.from(this.proto.payload)
|
||||
.map((char) => {
|
||||
return String.fromCharCode(char);
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
|
||||
get payload(): Uint8Array | undefined {
|
||||
return this.proto.payload;
|
||||
}
|
||||
|
||||
get contentTopic(): string | undefined {
|
||||
return this.proto.contentTopic;
|
||||
}
|
||||
|
||||
get version(): number | undefined {
|
||||
return this.proto.version;
|
||||
}
|
||||
|
||||
get timestamp(): Date | undefined {
|
||||
if (this.proto.timestamp) {
|
||||
return new Date(this.proto.timestamp * 1000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
import { expect } from 'chai';
|
||||
import debug from 'debug';
|
||||
import fc from 'fast-check';
|
||||
import TCP from 'libp2p-tcp';
|
||||
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
WakuRelayMessage,
|
||||
} from '../../test_utils';
|
||||
import { delay } from '../delay';
|
||||
import { hexToBuf } from '../utils';
|
||||
import { Waku } from '../waku';
|
||||
|
||||
import { generatePrivateKey, getPublicKey } from './version_1';
|
||||
|
||||
import { DefaultContentTopic, WakuMessage } from './index';
|
||||
|
||||
const dbg = debug('waku:test:message');
|
||||
|
||||
describe('Waku Message', function () {
|
||||
it('Waku message round trip binary serialization [clear]', async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(fc.string(), async (s) => {
|
||||
const msg = await WakuMessage.fromUtf8String(s);
|
||||
const binary = msg.encode();
|
||||
const actual = await WakuMessage.decode(binary);
|
||||
|
||||
expect(actual).to.deep.equal(msg);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('Payload to utf-8', async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(fc.string(), async (s) => {
|
||||
const msg = await WakuMessage.fromUtf8String(s);
|
||||
const utf8 = msg.payloadAsUtf8;
|
||||
|
||||
return utf8 === s;
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip binary encryption [asymmetric, no signature]', async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
||||
async (payload, privKey) => {
|
||||
const publicKey = getPublicKey(privKey);
|
||||
|
||||
const msg = await WakuMessage.fromBytes(payload, {
|
||||
encPublicKey: publicKey,
|
||||
});
|
||||
|
||||
const wireBytes = msg.encode();
|
||||
const actual = await WakuMessage.decode(wireBytes, [privKey]);
|
||||
|
||||
expect(actual?.payload).to.deep.equal(payload);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip binary encryption [asymmetric, signature]', async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
||||
async (payload, sigPrivKey, encPrivKey) => {
|
||||
const sigPubKey = getPublicKey(sigPrivKey);
|
||||
const encPubKey = getPublicKey(encPrivKey);
|
||||
|
||||
const msg = await WakuMessage.fromBytes(payload, {
|
||||
encPublicKey: encPubKey,
|
||||
sigPrivKey: sigPrivKey,
|
||||
});
|
||||
|
||||
const wireBytes = msg.encode();
|
||||
const actual = await WakuMessage.decode(wireBytes, [encPrivKey]);
|
||||
|
||||
expect(actual?.payload).to.deep.equal(payload);
|
||||
expect(actual?.signaturePublicKey).to.deep.equal(sigPubKey);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('Interop: Nim', function () {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
beforeEach(async function () {
|
||||
this.timeout(30_000);
|
||||
|
||||
waku = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
libp2p: {
|
||||
addresses: { listen: ['/ip4/0.0.0.0/tcp/0'] },
|
||||
modules: { transport: [TCP] },
|
||||
},
|
||||
});
|
||||
|
||||
const multiAddrWithId = waku.getLocalMultiaddrWithID();
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ staticnode: multiAddrWithId, rpcPrivate: true });
|
||||
|
||||
await new Promise((resolve) =>
|
||||
waku.libp2p.pubsub.once('gossipsub:heartbeat', resolve)
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
nimWaku ? nimWaku.stop() : null;
|
||||
waku ? await waku.stop() : null;
|
||||
});
|
||||
|
||||
it('JS decrypts nim message [asymmetric, no signature]', async function () {
|
||||
this.timeout(10000);
|
||||
await delay(200);
|
||||
|
||||
const messageText = 'Here is an encrypted message.';
|
||||
const message: WakuRelayMessage = {
|
||||
contentTopic: DefaultContentTopic,
|
||||
payload: Buffer.from(messageText, 'utf-8').toString('hex'),
|
||||
};
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
|
||||
waku.relay.addDecryptionPrivateKey(privateKey);
|
||||
|
||||
const receivedMsgPromise: Promise<WakuMessage> = new Promise((resolve) => {
|
||||
waku.relay.addObserver(resolve);
|
||||
});
|
||||
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
dbg('Post message');
|
||||
await nimWaku.postAsymmetricMessage(message, publicKey);
|
||||
|
||||
const receivedMsg = await receivedMsgPromise;
|
||||
|
||||
expect(receivedMsg.contentTopic).to.eq(message.contentTopic);
|
||||
expect(receivedMsg.version).to.eq(1);
|
||||
expect(receivedMsg.payloadAsUtf8).to.eq(messageText);
|
||||
});
|
||||
|
||||
it('Js encrypts message for nim [asymmetric, no signature]', async function () {
|
||||
this.timeout(5000);
|
||||
|
||||
const keyPair = await nimWaku.getAsymmetricKeyPair();
|
||||
const privateKey = hexToBuf(keyPair.privateKey);
|
||||
const publicKey = hexToBuf(keyPair.publicKey);
|
||||
|
||||
const messageText = 'This is a message I am going to encrypt';
|
||||
const message = await WakuMessage.fromUtf8String(messageText, {
|
||||
encPublicKey: publicKey,
|
||||
});
|
||||
|
||||
await waku.relay.send(message);
|
||||
|
||||
let msgs: WakuRelayMessage[] = [];
|
||||
|
||||
while (msgs.length === 0) {
|
||||
await delay(200);
|
||||
msgs = await nimWaku.getAsymmetricMessages(privateKey);
|
||||
}
|
||||
|
||||
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
||||
expect(hexToBuf(msgs[0].payload).toString('utf-8')).to.equal(messageText);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,209 @@
|
|||
// Ensure that this class matches the proto interface while
|
||||
import { Buffer } from 'buffer';
|
||||
|
||||
import debug from 'debug';
|
||||
import { Reader } from 'protobufjs/minimal';
|
||||
|
||||
// Protecting the user from protobuf oddities
|
||||
import * as proto from '../../proto/waku/v2/message';
|
||||
|
||||
import * as version_1 from './version_1';
|
||||
|
||||
export const DefaultContentTopic = '/waku/2/default-content/proto';
|
||||
const DefaultVersion = 0;
|
||||
const dbg = debug('waku:message');
|
||||
|
||||
export interface Options {
|
||||
contentTopic?: string;
|
||||
timestamp?: Date;
|
||||
encPublicKey?: Uint8Array;
|
||||
sigPrivKey?: Uint8Array;
|
||||
}
|
||||
|
||||
export class WakuMessage {
|
||||
private constructor(
|
||||
public proto: proto.WakuMessage,
|
||||
private _signaturePublicKey?: Uint8Array,
|
||||
private _signature?: Uint8Array
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Create Message with a utf-8 string as payload.
|
||||
*/
|
||||
static async fromUtf8String(
|
||||
utf8: string,
|
||||
opts?: Options
|
||||
): Promise<WakuMessage> {
|
||||
const payload = Buffer.from(utf8, 'utf-8');
|
||||
return WakuMessage.fromBytes(payload, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Waku Message with the given payload.
|
||||
*
|
||||
* By default, the payload is kept clear (version 0).
|
||||
* If `opts.encPublicKey` is passed, the payload is encrypted using
|
||||
* asymmetric encryption (version 1).
|
||||
*
|
||||
* If `opts.sigPrivKey` is passed and version 1 is used, the payload is signed
|
||||
* before encryption.
|
||||
*/
|
||||
static async fromBytes(
|
||||
payload: Uint8Array,
|
||||
opts?: Options
|
||||
): Promise<WakuMessage> {
|
||||
const { timestamp, contentTopic, encPublicKey, sigPrivKey } = Object.assign(
|
||||
{ timestamp: new Date(), contentTopic: DefaultContentTopic },
|
||||
opts ? opts : {}
|
||||
);
|
||||
|
||||
let _payload = payload;
|
||||
let version = DefaultVersion;
|
||||
let sig;
|
||||
if (encPublicKey) {
|
||||
const enc = version_1.clearEncode(_payload, sigPrivKey);
|
||||
_payload = await version_1.encryptAsymmetric(enc.payload, encPublicKey);
|
||||
sig = enc.sig;
|
||||
version = 1;
|
||||
}
|
||||
|
||||
return new WakuMessage(
|
||||
{
|
||||
payload: _payload,
|
||||
timestamp: timestamp.valueOf() / 1000,
|
||||
version,
|
||||
contentTopic,
|
||||
},
|
||||
sig?.publicKey,
|
||||
sig?.signature
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a byte array into Waku Message.
|
||||
*
|
||||
* If the payload is encrypted, then `decPrivateKey` is used for decryption.
|
||||
*/
|
||||
static async decode(
|
||||
bytes: Uint8Array,
|
||||
decPrivateKeys?: Uint8Array[]
|
||||
): Promise<WakuMessage | undefined> {
|
||||
const protoBuf = proto.WakuMessage.decode(Reader.create(bytes));
|
||||
|
||||
return WakuMessage.decodeProto(protoBuf, decPrivateKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a Waku Message Protobuf Object into Waku Message.
|
||||
*
|
||||
* If the payload is encrypted, then `decPrivateKey` is used for decryption.
|
||||
*/
|
||||
static async decodeProto(
|
||||
protoBuf: proto.WakuMessage,
|
||||
decPrivateKeys?: Uint8Array[]
|
||||
): Promise<WakuMessage | undefined> {
|
||||
if (protoBuf.payload === undefined) {
|
||||
dbg('Payload is undefined');
|
||||
return;
|
||||
}
|
||||
const payload = protoBuf.payload;
|
||||
|
||||
let signaturePublicKey;
|
||||
let signature;
|
||||
if (protoBuf.version === 1 && protoBuf.payload) {
|
||||
if (decPrivateKeys === undefined) {
|
||||
dbg('Payload is encrypted but no private keys have been provided.');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Returns a bunch of `undefined` and hopefully one decrypted result
|
||||
const allResults = await Promise.all(
|
||||
decPrivateKeys.map(async (privateKey) => {
|
||||
try {
|
||||
return await version_1.decryptAsymmetric(payload, privateKey);
|
||||
} catch (e) {
|
||||
dbg('Failed to decrypt asymmetric message', e);
|
||||
return;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const isDefined = (dec: Uint8Array | undefined): dec is Uint8Array => {
|
||||
return !!dec;
|
||||
};
|
||||
|
||||
const decodedResults = allResults.filter(isDefined);
|
||||
|
||||
if (decodedResults.length === 0) {
|
||||
dbg('Failed to decrypt payload.');
|
||||
return;
|
||||
}
|
||||
const dec = decodedResults[0];
|
||||
|
||||
const res = await version_1.clearDecode(dec);
|
||||
if (!res) {
|
||||
dbg('Failed to decode payload.');
|
||||
return;
|
||||
}
|
||||
Object.assign(protoBuf, { payload: res.payload });
|
||||
signaturePublicKey = res.sig?.publicKey;
|
||||
signature = res.sig?.signature;
|
||||
}
|
||||
|
||||
return new WakuMessage(protoBuf, signaturePublicKey, signature);
|
||||
}
|
||||
|
||||
encode(): Uint8Array {
|
||||
return proto.WakuMessage.encode(this.proto).finish();
|
||||
}
|
||||
|
||||
get payloadAsUtf8(): string {
|
||||
if (!this.proto.payload) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return Array.from(this.proto.payload)
|
||||
.map((char) => {
|
||||
return String.fromCharCode(char);
|
||||
})
|
||||
.join('');
|
||||
}
|
||||
|
||||
get payload(): Uint8Array | undefined {
|
||||
return this.proto.payload;
|
||||
}
|
||||
|
||||
get contentTopic(): string | undefined {
|
||||
return this.proto.contentTopic;
|
||||
}
|
||||
|
||||
get version(): number | undefined {
|
||||
return this.proto.version;
|
||||
}
|
||||
|
||||
get timestamp(): Date | undefined {
|
||||
if (this.proto.timestamp) {
|
||||
return new Date(this.proto.timestamp * 1000);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The public key used to sign the message.
|
||||
*
|
||||
* MAY be present if the message is version 1.
|
||||
*/
|
||||
get signaturePublicKey(): Uint8Array | undefined {
|
||||
return this._signaturePublicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* The signature of the message.
|
||||
*
|
||||
* MAY be present if the message is version 1.
|
||||
*/
|
||||
get signature(): Uint8Array | undefined {
|
||||
return this._signature;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
import { expect } from 'chai';
|
||||
import fc from 'fast-check';
|
||||
|
||||
import {
|
||||
clearDecode,
|
||||
clearEncode,
|
||||
decryptAsymmetric,
|
||||
encryptAsymmetric,
|
||||
getPublicKey,
|
||||
} from './version_1';
|
||||
|
||||
describe('Waku Message Version 1', function () {
|
||||
it('Sign & Recover', function () {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.uint8Array(),
|
||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
||||
(message, privKey) => {
|
||||
const enc = clearEncode(message, privKey);
|
||||
const res = clearDecode(enc.payload);
|
||||
|
||||
const pubKey = getPublicKey(privKey);
|
||||
|
||||
expect(res?.payload).deep.equal(
|
||||
message,
|
||||
'Payload was not encrypted then decrypted correctly'
|
||||
);
|
||||
expect(res?.sig?.publicKey).deep.equal(
|
||||
pubKey,
|
||||
'signature Public key was not recovered from encrypted then decrypted signature'
|
||||
);
|
||||
expect(enc?.sig?.publicKey).deep.equal(
|
||||
pubKey,
|
||||
'Incorrect signature public key was returned when signing the payload'
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('Asymmetric encrypt & Decrypt', async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
fc.uint8Array({ minLength: 32, maxLength: 32 }),
|
||||
async (message, privKey) => {
|
||||
const publicKey = getPublicKey(privKey);
|
||||
|
||||
const enc = await encryptAsymmetric(message, publicKey);
|
||||
const res = await decryptAsymmetric(enc, privKey);
|
||||
|
||||
expect(res).deep.equal(message);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,210 @@
|
|||
import { Buffer } from 'buffer';
|
||||
import * as crypto from 'crypto';
|
||||
|
||||
import ecies from 'ecies-parity';
|
||||
import { keccak256 } from 'js-sha3';
|
||||
import * as secp256k1 from 'secp256k1';
|
||||
|
||||
import { hexToBuf } from '../utils';
|
||||
|
||||
const FlagsLength = 1;
|
||||
const FlagMask = 3; // 0011
|
||||
const IsSignedMask = 4; // 0100
|
||||
const PaddingTarget = 256;
|
||||
const SignatureLength = 65;
|
||||
|
||||
/**
|
||||
* Encode the payload pre-encryption.
|
||||
*
|
||||
* @internal
|
||||
* @param messagePayload: The payload to include in the message
|
||||
* @param sigPrivKey: If set, a signature using this private key is added.
|
||||
* @returns The encoded payload, ready for encryption using {@link encryptAsymmetric}
|
||||
* or {@link encryptSymmetric}.
|
||||
*/
|
||||
export function clearEncode(
|
||||
messagePayload: Uint8Array,
|
||||
sigPrivKey?: Uint8Array
|
||||
): { payload: Uint8Array; sig?: Signature } {
|
||||
let envelope = Buffer.from([0]); // No flags
|
||||
envelope = addPayloadSizeField(envelope, messagePayload);
|
||||
envelope = Buffer.concat([envelope, messagePayload]);
|
||||
|
||||
// Calculate padding:
|
||||
let rawSize =
|
||||
FlagsLength +
|
||||
getSizeOfPayloadSizeField(messagePayload) +
|
||||
messagePayload.length;
|
||||
|
||||
if (sigPrivKey) {
|
||||
rawSize += SignatureLength;
|
||||
}
|
||||
|
||||
const remainder = rawSize % PaddingTarget;
|
||||
const paddingSize = PaddingTarget - remainder;
|
||||
const pad = randomBytes(paddingSize);
|
||||
|
||||
if (!validateDataIntegrity(pad, paddingSize)) {
|
||||
throw new Error('failed to generate random padding of size ' + paddingSize);
|
||||
}
|
||||
|
||||
envelope = Buffer.concat([envelope, pad]);
|
||||
|
||||
let sig;
|
||||
if (sigPrivKey) {
|
||||
envelope[0] |= IsSignedMask;
|
||||
const hash = keccak256(envelope);
|
||||
const s = secp256k1.ecdsaSign(hexToBuf(hash), sigPrivKey);
|
||||
envelope = Buffer.concat([envelope, s.signature, Buffer.from([s.recid])]);
|
||||
sig = {
|
||||
signature: Buffer.from(s.signature),
|
||||
publicKey: getPublicKey(sigPrivKey),
|
||||
};
|
||||
}
|
||||
|
||||
return { payload: envelope, sig };
|
||||
}
|
||||
|
||||
export type Signature = {
|
||||
signature: Uint8Array;
|
||||
publicKey: Uint8Array;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode a decrypted payload.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function clearDecode(
|
||||
message: Uint8Array | Buffer
|
||||
): { payload: Uint8Array; sig?: Signature } | undefined {
|
||||
const buf = Buffer.from(message);
|
||||
let start = 1;
|
||||
let sig;
|
||||
|
||||
const sizeOfPayloadSizeField = buf.readUIntLE(0, 1) & FlagMask;
|
||||
|
||||
if (sizeOfPayloadSizeField === 0) return;
|
||||
|
||||
const payloadSize = buf.readUIntLE(start, sizeOfPayloadSizeField);
|
||||
start += sizeOfPayloadSizeField;
|
||||
const payload = buf.slice(start, start + payloadSize);
|
||||
|
||||
const isSigned = (buf.readUIntLE(0, 1) & IsSignedMask) == IsSignedMask;
|
||||
if (isSigned) {
|
||||
const signature = getSignature(buf);
|
||||
const hash = getHash(buf, isSigned);
|
||||
const publicKey = ecRecoverPubKey(hash, signature);
|
||||
sig = { signature, publicKey };
|
||||
}
|
||||
|
||||
return { payload, sig };
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceed with Asymmetric encryption of the data as per [26/WAKU-PAYLOAD](rfc.vac.dev/spec/26/).
|
||||
* The data MUST be flags | payload-length | payload | [signature].
|
||||
* The returned result can be set to `WakuMessage.payload`.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export async function encryptAsymmetric(
|
||||
data: Uint8Array | Buffer,
|
||||
publicKey: Uint8Array | Buffer
|
||||
): Promise<Uint8Array> {
|
||||
return ecies.encrypt(Buffer.from(publicKey), Buffer.from(data));
|
||||
}
|
||||
|
||||
export async function decryptAsymmetric(
|
||||
payload: Uint8Array | Buffer,
|
||||
privKey: Uint8Array | Buffer
|
||||
): Promise<Uint8Array> {
|
||||
return ecies.decrypt(Buffer.from(privKey), Buffer.from(payload));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new private key
|
||||
*/
|
||||
export function generatePrivateKey(): Uint8Array {
|
||||
return randomBytes(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the public key for the given private key
|
||||
*/
|
||||
export function getPublicKey(privateKey: Uint8Array | Buffer): Uint8Array {
|
||||
return secp256k1.publicKeyCreate(privateKey, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the flags & auxiliary-field as per [26/WAKU-PAYLOAD](rfc.vac.dev/spec/26/).
|
||||
*/
|
||||
function addPayloadSizeField(msg: Buffer, payload: Uint8Array): Buffer {
|
||||
const fieldSize = getSizeOfPayloadSizeField(payload);
|
||||
let field = Buffer.alloc(4);
|
||||
field.writeUInt32LE(payload.length, 0);
|
||||
field = field.slice(0, fieldSize);
|
||||
msg = Buffer.concat([msg, field]);
|
||||
msg[0] |= fieldSize;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the auxiliary-field which in turns contains the payload size
|
||||
*/
|
||||
function getSizeOfPayloadSizeField(payload: Uint8Array): number {
|
||||
let s = 1;
|
||||
for (let i = payload.length; i >= 256; i /= 256) {
|
||||
s++;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
function validateDataIntegrity(
|
||||
value: Uint8Array,
|
||||
expectedSize: number
|
||||
): boolean {
|
||||
if (value.length !== expectedSize) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
expectedSize > 3 &&
|
||||
Buffer.from(value).equals(Buffer.alloc(value.length))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getSignature(message: Buffer): Buffer {
|
||||
return message.slice(message.length - SignatureLength, message.length);
|
||||
}
|
||||
|
||||
function getHash(message: Buffer, isSigned: boolean): string {
|
||||
if (isSigned) {
|
||||
return keccak256(message.slice(0, message.length - SignatureLength));
|
||||
}
|
||||
return keccak256(message);
|
||||
}
|
||||
|
||||
function ecRecoverPubKey(messageHash: string, signature: Buffer): Uint8Array {
|
||||
const recovery = signature.slice(64).readIntBE(0, 1);
|
||||
return secp256k1.ecdsaRecover(
|
||||
signature.slice(0, 64),
|
||||
recovery,
|
||||
hexToBuf(messageHash),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
function randomBytes(length: number): Uint8Array {
|
||||
if (typeof window !== 'undefined' && window && window.crypto) {
|
||||
const array = new Uint8Array(length);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array;
|
||||
} else {
|
||||
return crypto.randomBytes(length);
|
||||
}
|
||||
}
|
|
@ -79,11 +79,9 @@ describe('Waku Relay', () => {
|
|||
|
||||
const messageText = 'JS to JS communication works';
|
||||
const messageTimestamp = new Date('1995-12-17T03:24:00');
|
||||
const message = WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
undefined,
|
||||
messageTimestamp
|
||||
);
|
||||
const message = await WakuMessage.fromUtf8String(messageText, {
|
||||
timestamp: messageTimestamp,
|
||||
});
|
||||
|
||||
const receivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
|
@ -108,8 +106,12 @@ describe('Waku Relay', () => {
|
|||
|
||||
const fooMessageText = 'Published on content topic foo';
|
||||
const barMessageText = 'Published on content topic bar';
|
||||
const fooMessage = WakuMessage.fromUtf8String(fooMessageText, 'foo');
|
||||
const barMessage = WakuMessage.fromUtf8String(barMessageText, 'bar');
|
||||
const fooMessage = await WakuMessage.fromUtf8String(fooMessageText, {
|
||||
contentTopic: 'foo',
|
||||
});
|
||||
const barMessage = await WakuMessage.fromUtf8String(barMessageText, {
|
||||
contentTopic: 'bar',
|
||||
});
|
||||
|
||||
const receivedBarMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
|
@ -144,10 +146,9 @@ describe('Waku Relay', () => {
|
|||
|
||||
const messageText =
|
||||
'Published on content topic with added then deleted observer';
|
||||
const message = WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
'added-then-deleted-observer'
|
||||
);
|
||||
const message = await WakuMessage.fromUtf8String(messageText, {
|
||||
contentTopic: 'added-then-deleted-observer',
|
||||
});
|
||||
|
||||
// The promise **fails** if we receive a message on this observer.
|
||||
const receivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
|
@ -204,7 +205,7 @@ describe('Waku Relay', () => {
|
|||
]);
|
||||
|
||||
const messageText = 'Communicating using a custom pubsub topic';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
|
||||
const waku2ReceivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
|
@ -275,7 +276,7 @@ describe('Waku Relay', () => {
|
|||
this.timeout(5000);
|
||||
|
||||
const messageText = 'This is a message';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
|
||||
await waku.relay.send(message);
|
||||
|
||||
|
@ -294,7 +295,7 @@ describe('Waku Relay', () => {
|
|||
it('Nim publishes to js', async function () {
|
||||
this.timeout(5000);
|
||||
const messageText = 'Here is another message.';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
|
||||
const receivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
|
@ -360,7 +361,7 @@ describe('Waku Relay', () => {
|
|||
this.timeout(30000);
|
||||
|
||||
const messageText = 'This is a message';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
await delay(1000);
|
||||
await waku.relay.send(message);
|
||||
|
||||
|
@ -381,7 +382,7 @@ describe('Waku Relay', () => {
|
|||
await delay(200);
|
||||
|
||||
const messageText = 'Here is another message.';
|
||||
const message = WakuMessage.fromUtf8String(messageText);
|
||||
const message = await WakuMessage.fromUtf8String(messageText);
|
||||
|
||||
const receivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
|
@ -463,7 +464,7 @@ describe('Waku Relay', () => {
|
|||
).to.be.false;
|
||||
|
||||
const msgStr = 'Hello there!';
|
||||
const message = WakuMessage.fromUtf8String(msgStr);
|
||||
const message = await WakuMessage.fromUtf8String(msgStr);
|
||||
|
||||
const waku2ReceivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import debug from 'debug';
|
||||
import Libp2p from 'libp2p';
|
||||
import Gossipsub from 'libp2p-gossipsub';
|
||||
import { AddrInfo, MessageIdFunction } from 'libp2p-gossipsub/src/interfaces';
|
||||
|
@ -24,6 +25,8 @@ import { DefaultPubsubTopic, RelayCodec } from './constants';
|
|||
import { getRelayPeers } from './get_relay_peers';
|
||||
import { RelayHeartbeat } from './relay_heartbeat';
|
||||
|
||||
const dbg = debug('waku:relay');
|
||||
|
||||
export { RelayCodec, DefaultPubsubTopic };
|
||||
|
||||
/**
|
||||
|
@ -60,9 +63,15 @@ export interface GossipOptions {
|
|||
export class WakuRelay extends Gossipsub {
|
||||
heartbeat: RelayHeartbeat;
|
||||
pubsubTopic: string;
|
||||
|
||||
/**
|
||||
* Decryption private keys to use to attempt decryption of incoming messages.
|
||||
*/
|
||||
public decPrivateKeys: Set<Uint8Array>;
|
||||
|
||||
/**
|
||||
* observers called when receiving new message.
|
||||
* Observers under key "" are always called.
|
||||
* Observers under key `""` are always called.
|
||||
*/
|
||||
public observers: {
|
||||
[contentTopic: string]: Set<(message: WakuMessage) => void>;
|
||||
|
@ -82,16 +91,13 @@ export class WakuRelay extends Gossipsub {
|
|||
|
||||
this.heartbeat = new RelayHeartbeat(this);
|
||||
this.observers = {};
|
||||
this.decPrivateKeys = new Set();
|
||||
|
||||
const multicodecs = [constants.RelayCodec];
|
||||
|
||||
Object.assign(this, { multicodecs });
|
||||
|
||||
if (options?.pubsubTopic) {
|
||||
this.pubsubTopic = options.pubsubTopic;
|
||||
} else {
|
||||
this.pubsubTopic = constants.DefaultPubsubTopic;
|
||||
}
|
||||
this.pubsubTopic = options?.pubsubTopic || constants.DefaultPubsubTopic;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -114,7 +120,23 @@ export class WakuRelay extends Gossipsub {
|
|||
*/
|
||||
public async send(message: WakuMessage): Promise<void> {
|
||||
const msg = message.encode();
|
||||
await super.publish(this.pubsubTopic, new Buffer(msg));
|
||||
await super.publish(this.pubsubTopic, Buffer.from(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a decryption private key to attempt decryption of messages of
|
||||
* the given content topic.
|
||||
*/
|
||||
addDecryptionPrivateKey(privateKey: Uint8Array): void {
|
||||
this.decPrivateKeys.add(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a decryption private key to attempt decryption of messages of
|
||||
* the given content topic.
|
||||
*/
|
||||
deleteDecryptionPrivateKey(privateKey: Uint8Array): void {
|
||||
this.decPrivateKeys.delete(privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,6 +145,7 @@ export class WakuRelay extends Gossipsub {
|
|||
* @param callback called when a new message is received via waku relay
|
||||
* @param contentTopics Content Topics for which the callback with be called,
|
||||
* all of them if undefined, [] or ["",..] is passed.
|
||||
* @param decPrivateKeys Private keys used to decrypt incoming Waku Messages.
|
||||
* @returns {void}
|
||||
*/
|
||||
addObserver(
|
||||
|
@ -185,19 +208,30 @@ export class WakuRelay extends Gossipsub {
|
|||
*/
|
||||
subscribe(pubsubTopic: string): void {
|
||||
this.on(pubsubTopic, (event) => {
|
||||
const wakuMsg = WakuMessage.decode(event.data);
|
||||
if (this.observers['']) {
|
||||
this.observers[''].forEach((callbackFn) => {
|
||||
callbackFn(wakuMsg);
|
||||
dbg(`Message received on ${pubsubTopic}`);
|
||||
WakuMessage.decode(event.data, Array.from(this.decPrivateKeys))
|
||||
.then((wakuMsg) => {
|
||||
if (!wakuMsg) {
|
||||
dbg('Failed to decode Waku Message');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.observers['']) {
|
||||
this.observers[''].forEach((callbackFn) => {
|
||||
callbackFn(wakuMsg);
|
||||
});
|
||||
}
|
||||
if (wakuMsg.contentTopic) {
|
||||
if (this.observers[wakuMsg.contentTopic]) {
|
||||
this.observers[wakuMsg.contentTopic].forEach((callbackFn) => {
|
||||
callbackFn(wakuMsg);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
dbg('Failed to decode Waku Message', e);
|
||||
});
|
||||
}
|
||||
if (wakuMsg.contentTopic) {
|
||||
if (this.observers[wakuMsg.contentTopic]) {
|
||||
this.observers[wakuMsg.contentTopic].forEach((callbackFn) => {
|
||||
callbackFn(wakuMsg);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
super.subscribe(pubsubTopic);
|
||||
|
|
|
@ -24,7 +24,9 @@ describe('Waku Store', () => {
|
|||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
expect(
|
||||
await nimWaku.sendMessage(WakuMessage.fromUtf8String(`Message ${i}`))
|
||||
await nimWaku.sendMessage(
|
||||
await WakuMessage.fromUtf8String(`Message ${i}`)
|
||||
)
|
||||
).to.be.true;
|
||||
}
|
||||
|
||||
|
@ -58,7 +60,9 @@ describe('Waku Store', () => {
|
|||
|
||||
for (let i = 0; i < 15; i++) {
|
||||
expect(
|
||||
await nimWaku.sendMessage(WakuMessage.fromUtf8String(`Message ${i}`))
|
||||
await nimWaku.sendMessage(
|
||||
await WakuMessage.fromUtf8String(`Message ${i}`)
|
||||
)
|
||||
).to.be.true;
|
||||
}
|
||||
|
||||
|
@ -98,7 +102,7 @@ describe('Waku Store', () => {
|
|||
for (let i = 0; i < 2; i++) {
|
||||
expect(
|
||||
await nimWaku.sendMessage(
|
||||
WakuMessage.fromUtf8String(`Message ${i}`),
|
||||
await WakuMessage.fromUtf8String(`Message ${i}`),
|
||||
customPubSubTopic
|
||||
)
|
||||
).to.be.true;
|
||||
|
|
|
@ -114,19 +114,24 @@ export class WakuStore {
|
|||
return messages;
|
||||
}
|
||||
|
||||
const pageMessages = response.messages.map((protoMsg) => {
|
||||
return new WakuMessage(protoMsg);
|
||||
});
|
||||
const pageMessages: WakuMessage[] = [];
|
||||
await Promise.all(
|
||||
response.messages.map(async (protoMsg) => {
|
||||
const msg = await WakuMessage.decodeProto(protoMsg);
|
||||
|
||||
if (msg) {
|
||||
messages.push(msg);
|
||||
pageMessages.push(msg);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
if (opts.callback) {
|
||||
// TODO: Test the callback feature
|
||||
// TODO: Change callback to take individual messages
|
||||
opts.callback(pageMessages);
|
||||
}
|
||||
|
||||
pageMessages.forEach((wakuMessage) => {
|
||||
messages.push(wakuMessage);
|
||||
});
|
||||
|
||||
const responsePageSize = response.pagingInfo?.pageSize;
|
||||
const queryPageSize = historyRpcQuery.query?.pagingInfo?.pageSize;
|
||||
if (
|
||||
|
|
|
@ -41,6 +41,7 @@ export interface Args {
|
|||
persistMessages?: boolean;
|
||||
lightpush?: boolean;
|
||||
topics?: string;
|
||||
rpcPrivate?: boolean;
|
||||
}
|
||||
|
||||
export enum LogLevel {
|
||||
|
@ -53,6 +54,16 @@ export enum LogLevel {
|
|||
Fatal = 'fatal',
|
||||
}
|
||||
|
||||
export interface KeyPair {
|
||||
privateKey: string;
|
||||
publicKey: string;
|
||||
}
|
||||
|
||||
export interface WakuRelayMessage {
|
||||
payload: string;
|
||||
contentTopic?: string;
|
||||
}
|
||||
|
||||
export class NimWaku {
|
||||
private process?: ChildProcess;
|
||||
private pid?: number;
|
||||
|
@ -180,9 +191,64 @@ export class NimWaku {
|
|||
async messages(): Promise<WakuMessage[]> {
|
||||
this.checkProcess();
|
||||
|
||||
return this.rpcCall<proto.WakuMessage[]>('get_waku_v2_relay_v1_messages', [
|
||||
DefaultPubsubTopic,
|
||||
]).then((msgs) => msgs.map((protoMsg) => new WakuMessage(protoMsg)));
|
||||
const isDefined = (msg: WakuMessage | undefined): msg is WakuMessage => {
|
||||
return !!msg;
|
||||
};
|
||||
|
||||
const protoMsgs = await this.rpcCall<proto.WakuMessage[]>(
|
||||
'get_waku_v2_relay_v1_messages',
|
||||
[DefaultPubsubTopic]
|
||||
);
|
||||
|
||||
const msgs = await Promise.all(
|
||||
protoMsgs.map(async (protoMsg) => await WakuMessage.decodeProto(protoMsg))
|
||||
);
|
||||
|
||||
return msgs.filter(isDefined);
|
||||
}
|
||||
|
||||
async getAsymmetricKeyPair(): Promise<KeyPair> {
|
||||
this.checkProcess();
|
||||
|
||||
const { seckey, pubkey } = await this.rpcCall<{
|
||||
seckey: string;
|
||||
pubkey: string;
|
||||
}>('get_waku_v2_private_v1_asymmetric_keypair', []);
|
||||
|
||||
return { privateKey: seckey, publicKey: pubkey };
|
||||
}
|
||||
|
||||
async postAsymmetricMessage(
|
||||
message: WakuRelayMessage,
|
||||
publicKey: Uint8Array,
|
||||
pubsubTopic?: string
|
||||
): Promise<boolean> {
|
||||
this.checkProcess();
|
||||
|
||||
if (!message.payload) {
|
||||
throw 'Attempting to send empty message';
|
||||
}
|
||||
|
||||
return this.rpcCall<boolean>('post_waku_v2_private_v1_asymmetric_message', [
|
||||
pubsubTopic ? pubsubTopic : DefaultPubsubTopic,
|
||||
message,
|
||||
'0x' + bufToHex(publicKey),
|
||||
]);
|
||||
}
|
||||
|
||||
async getAsymmetricMessages(
|
||||
privateKey: Uint8Array,
|
||||
pubsubTopic?: string
|
||||
): Promise<WakuRelayMessage[]> {
|
||||
this.checkProcess();
|
||||
|
||||
return await this.rpcCall<WakuRelayMessage[]>(
|
||||
'get_waku_v2_private_v1_asymmetric_messages',
|
||||
[
|
||||
pubsubTopic ? pubsubTopic : DefaultPubsubTopic,
|
||||
'0x' + bufToHex(privateKey),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
async getPeerId(): Promise<PeerId> {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// TypeScript Version: 2.1
|
||||
/// <reference types="node" />
|
||||
declare module 'ecies-parity' {
|
||||
// Compute the public key for a given private key.
|
||||
export function getPublic(privateKey: Buffer): Buffer;
|
||||
|
||||
// Compute the compressed public key for a given private key.
|
||||
export function getPublicCompressed(privateKey: Buffer): Buffer;
|
||||
|
||||
// Create an ECDSA signature.
|
||||
export function sign(key: Buffer, msg: Buffer): Promise<Buffer>;
|
||||
|
||||
// Verify an ECDSA signature.
|
||||
export function verify(
|
||||
publicKey: Buffer,
|
||||
msg: Buffer,
|
||||
sig: Buffer
|
||||
): Promise<null>;
|
||||
|
||||
// Derive shared secret for given private and public keys.
|
||||
export function derive(
|
||||
privateKeyA: Buffer,
|
||||
publicKeyB: Buffer
|
||||
): Promise<Buffer>;
|
||||
|
||||
// Input/output structure for ECIES operations.
|
||||
export interface Ecies {
|
||||
iv: Buffer;
|
||||
ephemPublicKey: Buffer;
|
||||
ciphertext: Buffer;
|
||||
mac: Buffer;
|
||||
}
|
||||
|
||||
// Encrypt message for given recipient's public key.
|
||||
export function encrypt(
|
||||
publicKeyTo: Buffer,
|
||||
msg: Buffer,
|
||||
opts?: { iv?: Buffer; ephemPrivateKey?: Buffer }
|
||||
): Promise<Buffer>;
|
||||
|
||||
// Decrypt message using given private key.
|
||||
export function decrypt(privateKey: Buffer, payload: Buffer): Promise<Buffer>;
|
||||
}
|
|
@ -41,7 +41,7 @@
|
|||
// "experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
|
||||
// "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
|
||||
|
||||
"lib": ["es2017"],
|
||||
"lib": ["es2017", "dom"],
|
||||
"types": ["node", "mocha"],
|
||||
"typeRoots": ["node_modules/@types", "src/types"]
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue