mirror of
https://github.com/logos-messaging/js-waku.git
synced 2026-01-05 07:13:11 +00:00
Remove odd prettier config (#500)
This commit is contained in:
parent
4874bf134d
commit
4c80f7f0df
@ -1,30 +1,30 @@
|
||||
import '@ethersproject/shims';
|
||||
import "@ethersproject/shims";
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import './App.css';
|
||||
import { Waku } from 'js-waku';
|
||||
import { Message } from './messaging/Messages';
|
||||
import 'fontsource-roboto';
|
||||
import { AppBar, IconButton, Toolbar, Typography } from '@material-ui/core';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import "./App.css";
|
||||
import { Waku } from "js-waku";
|
||||
import { Message } from "./messaging/Messages";
|
||||
import "fontsource-roboto";
|
||||
import { AppBar, IconButton, Toolbar, Typography } from "@material-ui/core";
|
||||
import {
|
||||
createMuiTheme,
|
||||
ThemeProvider,
|
||||
makeStyles,
|
||||
} from '@material-ui/core/styles';
|
||||
import { lightBlue, orange, teal } from '@material-ui/core/colors';
|
||||
import WifiIcon from '@material-ui/icons/Wifi';
|
||||
import BroadcastPublicKey from './BroadcastPublicKey';
|
||||
import Messaging from './messaging/Messaging';
|
||||
} from "@material-ui/core/styles";
|
||||
import { lightBlue, orange, teal } from "@material-ui/core/colors";
|
||||
import WifiIcon from "@material-ui/icons/Wifi";
|
||||
import BroadcastPublicKey from "./BroadcastPublicKey";
|
||||
import Messaging from "./messaging/Messaging";
|
||||
import {
|
||||
PrivateMessageContentTopic,
|
||||
handlePrivateMessage,
|
||||
handlePublicKeyMessage,
|
||||
initWaku,
|
||||
PublicKeyContentTopic,
|
||||
} from './waku';
|
||||
import { Web3Provider } from '@ethersproject/providers/src.ts/web3-provider';
|
||||
import GetEncryptionPublicKey from './GetEncryptionPublicKey';
|
||||
import ConnectWallet from './ConnectWallet';
|
||||
} from "./waku";
|
||||
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
||||
import GetEncryptionPublicKey from "./GetEncryptionPublicKey";
|
||||
import ConnectWallet from "./ConnectWallet";
|
||||
|
||||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
@ -39,21 +39,21 @@ const theme = createMuiTheme({
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: '100vh',
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minHeight: "100vh",
|
||||
},
|
||||
appBar: {
|
||||
// height: '200p',
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
},
|
||||
main: {
|
||||
flex: 1,
|
||||
margin: '10px',
|
||||
margin: "10px",
|
||||
},
|
||||
wakuStatus: {
|
||||
marginRight: theme.spacing(2),
|
||||
@ -88,11 +88,11 @@ function App() {
|
||||
if (waku) return;
|
||||
initWaku()
|
||||
.then((_waku) => {
|
||||
console.log('waku: ready');
|
||||
console.log("waku: ready");
|
||||
setWaku(_waku);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to initiate Waku', e);
|
||||
console.error("Failed to initiate Waku", e);
|
||||
});
|
||||
}, [waku]);
|
||||
|
||||
@ -158,10 +158,10 @@ function App() {
|
||||
return () => clearInterval(interval);
|
||||
}, [waku]);
|
||||
|
||||
let addressDisplay = '';
|
||||
let addressDisplay = "";
|
||||
if (address) {
|
||||
addressDisplay =
|
||||
address.substr(0, 6) + '...' + address.substr(address.length - 4, 4);
|
||||
address.substr(0, 6) + "..." + address.substr(address.length - 4, 4);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -175,12 +175,12 @@ function App() {
|
||||
aria-label="waku-status"
|
||||
>
|
||||
<WifiIcon
|
||||
color={waku ? undefined : 'disabled'}
|
||||
color={waku ? undefined : "disabled"}
|
||||
style={waku ? { color: teal[500] } : {}}
|
||||
/>
|
||||
</IconButton>
|
||||
<Typography className={classes.peers} aria-label="connected-peers">
|
||||
Peers: {peerStats.relayPeers} relay, {peerStats.lightPushPeers}{' '}
|
||||
Peers: {peerStats.relayPeers} relay, {peerStats.lightPushPeers}{" "}
|
||||
light push
|
||||
</Typography>
|
||||
<Typography variant="h6" className={classes.title}>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { createPublicKeyMessage } from './crypto';
|
||||
import { PublicKeyMessage } from './messaging/wire';
|
||||
import { WakuMessage, Waku } from 'js-waku';
|
||||
import { PublicKeyContentTopic } from './waku';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import { createPublicKeyMessage } from "./crypto";
|
||||
import { PublicKeyMessage } from "./messaging/wire";
|
||||
import { WakuMessage, Waku } from "js-waku";
|
||||
import { PublicKeyContentTopic } from "./waku";
|
||||
|
||||
interface Props {
|
||||
encryptionPublicKey: Uint8Array | undefined;
|
||||
@ -26,26 +26,26 @@ export default function BroadcastPublicKey({
|
||||
if (!waku) return;
|
||||
if (!providerRequest) return;
|
||||
|
||||
console.log('Creating Public Key Message');
|
||||
console.log("Creating Public Key Message");
|
||||
createPublicKeyMessage(address, encryptionPublicKey, providerRequest)
|
||||
.then((msg) => {
|
||||
console.log('Public Key Message created');
|
||||
console.log("Public Key Message created");
|
||||
encodePublicKeyWakuMessage(msg)
|
||||
.then((wakuMsg) => {
|
||||
console.log('Public Key Message encoded');
|
||||
console.log("Public Key Message encoded");
|
||||
waku.lightPush
|
||||
.push(wakuMsg)
|
||||
.then((res) => console.log('Public Key Message pushed', res))
|
||||
.then((res) => console.log("Public Key Message pushed", res))
|
||||
.catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
console.error("Failed to send Public Key Message", e);
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
console.log('Failed to encode Public Key Message in Waku Message');
|
||||
console.log("Failed to encode Public Key Message in Waku Message");
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to create public key message', e);
|
||||
console.error("Failed to create public key message", e);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { ethers } from 'ethers';
|
||||
import { Web3Provider } from '@ethersproject/providers/src.ts/web3-provider';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import { ethers } from "ethers";
|
||||
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
||||
|
||||
declare let window: any;
|
||||
|
||||
@ -14,14 +14,14 @@ export default function ConnectWallet({ setAddress, setProvider }: Props) {
|
||||
const connectWallet = () => {
|
||||
try {
|
||||
window.ethereum
|
||||
.request({ method: 'eth_requestAccounts' })
|
||||
.request({ method: "eth_requestAccounts" })
|
||||
.then((accounts: string[]) => {
|
||||
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||
setAddress(accounts[0]);
|
||||
setProvider(_provider);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('No web3 provider available');
|
||||
console.error("No web3 provider available");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React from "react";
|
||||
|
||||
interface Props {
|
||||
setEncPublicKey: (key: Uint8Array) => void;
|
||||
@ -18,20 +18,20 @@ export default function GetEncryptionPublicKey({
|
||||
if (!providerRequest) return;
|
||||
if (!address) return;
|
||||
|
||||
console.log('Getting Encryption Public Key from Wallet');
|
||||
console.log("Getting Encryption Public Key from Wallet");
|
||||
providerRequest({
|
||||
method: 'eth_getEncryptionPublicKey',
|
||||
method: "eth_getEncryptionPublicKey",
|
||||
params: [address],
|
||||
})
|
||||
.then((key: string | undefined) => {
|
||||
console.log('Encryption Public key:', key);
|
||||
console.log("Encryption Public key:", key);
|
||||
|
||||
if (typeof key !== 'string') {
|
||||
console.error('Could not get encryption key');
|
||||
if (typeof key !== "string") {
|
||||
console.error("Could not get encryption key");
|
||||
return;
|
||||
}
|
||||
|
||||
setEncPublicKey(Buffer.from(key, 'base64'));
|
||||
setEncPublicKey(Buffer.from(key, "base64"));
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.code === 4001) {
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import '@ethersproject/shims';
|
||||
import "@ethersproject/shims";
|
||||
|
||||
import { PublicKeyMessage } from './messaging/wire';
|
||||
import { hexToBuf, equalByteArrays, bufToHex } from 'js-waku/lib/utils';
|
||||
import * as sigUtil from 'eth-sig-util';
|
||||
import { PublicKeyMessage } from "./messaging/wire";
|
||||
import { hexToBuf, equalByteArrays, bufToHex } from "js-waku/lib/utils";
|
||||
import * as sigUtil from "eth-sig-util";
|
||||
|
||||
/**
|
||||
* Sign the encryption public key with Web3. This can then be published to let other
|
||||
@ -23,8 +23,8 @@ export async function createPublicKeyMessage(
|
||||
providerRequest
|
||||
);
|
||||
|
||||
console.log('Asking wallet to sign Public Key Message');
|
||||
console.log('Public Key Message signed');
|
||||
console.log("Asking wallet to sign Public Key Message");
|
||||
console.log("Public Key Message signed");
|
||||
|
||||
return new PublicKeyMessage({
|
||||
encryptionPublicKey: encryptionPublicKey,
|
||||
@ -37,24 +37,24 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
||||
return JSON.stringify({
|
||||
domain: {
|
||||
chainId: 1,
|
||||
name: 'Ethereum Private Message over Waku',
|
||||
version: '1',
|
||||
name: "Ethereum Private Message over Waku",
|
||||
version: "1",
|
||||
},
|
||||
message: {
|
||||
encryptionPublicKey: bufToHex(encryptionPublicKey),
|
||||
ownerAddress: fromAddress,
|
||||
},
|
||||
// Refers to the keys of the *types* object below.
|
||||
primaryType: 'PublishEncryptionPublicKey',
|
||||
primaryType: "PublishEncryptionPublicKey",
|
||||
types: {
|
||||
EIP712Domain: [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'version', type: 'string' },
|
||||
{ name: 'chainId', type: 'uint256' },
|
||||
{ name: "name", type: "string" },
|
||||
{ name: "version", type: "string" },
|
||||
{ name: "chainId", type: "uint256" },
|
||||
],
|
||||
PublishEncryptionPublicKey: [
|
||||
{ name: 'encryptionPublicKey', type: 'string' },
|
||||
{ name: 'ownerAddress', type: 'string' },
|
||||
{ name: "encryptionPublicKey", type: "string" },
|
||||
{ name: "ownerAddress", type: "string" },
|
||||
],
|
||||
},
|
||||
});
|
||||
@ -72,12 +72,12 @@ export async function signEncryptionKey(
|
||||
const msgParams = buildMsgParams(encryptionPublicKey, fromAddress);
|
||||
|
||||
const result = await providerRequest({
|
||||
method: 'eth_signTypedData_v3',
|
||||
method: "eth_signTypedData_v3",
|
||||
params: [fromAddress, msgParams],
|
||||
from: fromAddress,
|
||||
});
|
||||
|
||||
console.log('TYPED SIGNED:' + JSON.stringify(result));
|
||||
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
||||
|
||||
return hexToBuf(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" + bufToHex(msg.ethAddress))
|
||||
),
|
||||
sig: '0x' + bufToHex(msg.signature),
|
||||
sig: "0x" + bufToHex(msg.signature),
|
||||
});
|
||||
|
||||
console.log('Recovered', recovered);
|
||||
console.log('ethAddress', '0x' + bufToHex(msg.ethAddress));
|
||||
console.log("Recovered", recovered);
|
||||
console.log("ethAddress", "0x" + bufToHex(msg.ethAddress));
|
||||
|
||||
return equalByteArrays(recovered, msg.ethAddress);
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { List, ListItem, ListItemText } from '@material-ui/core';
|
||||
import React from "react";
|
||||
import { List, ListItem, ListItemText } from "@material-ui/core";
|
||||
|
||||
/**
|
||||
* Clear text message
|
||||
@ -31,10 +31,10 @@ function generate(messages: Message[]) {
|
||||
|
||||
function formatDisplayDate(timestamp: Date): string {
|
||||
return timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import Messages, { Message } from './Messages';
|
||||
import { Waku } from 'js-waku';
|
||||
import SendMessage from './SendMessage';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import Messages, { Message } from "./Messages";
|
||||
import { Waku } from "js-waku";
|
||||
import SendMessage from "./SendMessage";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'left',
|
||||
flexDirection: 'column',
|
||||
margin: '5px',
|
||||
display: "flex",
|
||||
alignItems: "left",
|
||||
flexDirection: "column",
|
||||
margin: "5px",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -5,13 +5,13 @@ import {
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} 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 { PrivateMessage } from './wire';
|
||||
import { PrivateMessageContentTopic } from '../waku';
|
||||
import * as sigUtil from 'eth-sig-util';
|
||||
} 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 { PrivateMessage } from "./wire";
|
||||
import { PrivateMessageContentTopic } from "../waku";
|
||||
import * as sigUtil from "eth-sig-util";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
formControl: {
|
||||
@ -31,7 +31,7 @@ export interface Props {
|
||||
|
||||
export default function SendMessage({ waku, recipients }: Props) {
|
||||
const classes = useStyles();
|
||||
const [recipient, setRecipient] = useState<string>('');
|
||||
const [recipient, setRecipient] = useState<string>("");
|
||||
const [message, setMessage] = useState<string>();
|
||||
|
||||
const handleRecipientChange = (
|
||||
@ -54,7 +54,7 @@ export default function SendMessage({ waku, recipients }: Props) {
|
||||
|
||||
const keyDownHandler = async (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
event.key === 'Enter' &&
|
||||
event.key === "Enter" &&
|
||||
!event.altKey &&
|
||||
!event.ctrlKey &&
|
||||
!event.shiftKey
|
||||
@ -67,8 +67,8 @@ export default function SendMessage({ waku, recipients }: Props) {
|
||||
|
||||
sendMessage(waku, recipient, publicKey, message, (res) => {
|
||||
if (res) {
|
||||
console.log('callback called with', res);
|
||||
setMessage('');
|
||||
console.log("callback called with", res);
|
||||
setMessage("");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -77,9 +77,9 @@ export default function SendMessage({ waku, recipients }: Props) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
<FormControl className={classes.formControl}>
|
||||
@ -118,12 +118,12 @@ async function encodeEncryptedWakuMessage(
|
||||
const payload = privateMessage.encode();
|
||||
|
||||
const encObj = sigUtil.encrypt(
|
||||
Buffer.from(publicKey).toString('base64'),
|
||||
Buffer.from(publicKey).toString("base64"),
|
||||
{ data: bufToHex(payload) },
|
||||
'x25519-xsalsa20-poly1305'
|
||||
"x25519-xsalsa20-poly1305"
|
||||
);
|
||||
|
||||
const encryptedPayload = Buffer.from(JSON.stringify(encObj), 'utf8');
|
||||
const encryptedPayload = Buffer.from(JSON.stringify(encObj), "utf8");
|
||||
return WakuMessage.fromBytes(encryptedPayload, PrivateMessageContentTopic);
|
||||
}
|
||||
|
||||
@ -136,20 +136,20 @@ function sendMessage(
|
||||
) {
|
||||
encodeEncryptedWakuMessage(message, recipientPublicKey, recipientAddress)
|
||||
.then((msg) => {
|
||||
console.log('pushing');
|
||||
console.log("pushing");
|
||||
waku.lightPush
|
||||
.push(msg)
|
||||
.then((res) => {
|
||||
console.log('Message sent', res);
|
||||
console.log("Message sent", res);
|
||||
callback(res ? res.isSuccess : false);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to send message', e);
|
||||
console.error("Failed to send message", e);
|
||||
callback(false);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Cannot encode & encrypt message', e);
|
||||
console.error("Cannot encode & encrypt message", e);
|
||||
callback(false);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as protobuf from 'protobufjs/light';
|
||||
import * as protobuf from "protobufjs/light";
|
||||
|
||||
export interface PublicKeyMessagePayload {
|
||||
encryptionPublicKey: Uint8Array;
|
||||
@ -14,12 +14,12 @@ const Root = protobuf.Root,
|
||||
* Message used to communicate the encryption public key linked to a given Ethereum account
|
||||
*/
|
||||
export class PublicKeyMessage {
|
||||
private static Type = new Type('PublicKeyMessage')
|
||||
.add(new Field('encryptionPublicKey', 1, 'bytes'))
|
||||
.add(new Field('ethAddress', 2, 'bytes'))
|
||||
.add(new Field('signature', 3, 'bytes'));
|
||||
private static Type = new Type("PublicKeyMessage")
|
||||
.add(new Field("encryptionPublicKey", 1, "bytes"))
|
||||
.add(new Field("ethAddress", 2, "bytes"))
|
||||
.add(new Field("signature", 3, "bytes"));
|
||||
private static Root = new Root()
|
||||
.define('messages')
|
||||
.define("messages")
|
||||
.add(PublicKeyMessage.Type);
|
||||
|
||||
constructor(public payload: PublicKeyMessagePayload) {}
|
||||
@ -40,7 +40,7 @@ export class PublicKeyMessage {
|
||||
!payload.encryptionPublicKey ||
|
||||
!payload.ethAddress
|
||||
) {
|
||||
console.log('Field missing on decoded Public Key Message', payload);
|
||||
console.log("Field missing on decoded Public Key Message", payload);
|
||||
return;
|
||||
}
|
||||
return new PublicKeyMessage(payload);
|
||||
@ -68,10 +68,10 @@ export interface PrivateMessagePayload {
|
||||
* Encrypted Message used for private communication over the Waku network.
|
||||
*/
|
||||
export class PrivateMessage {
|
||||
private static Type = new Type('PrivateMessage')
|
||||
.add(new Field('toAddress', 1, 'bytes'))
|
||||
.add(new Field('message', 2, 'string'));
|
||||
private static Root = new Root().define('messages').add(PrivateMessage.Type);
|
||||
private static Type = new Type("PrivateMessage")
|
||||
.add(new Field("toAddress", 1, "bytes"))
|
||||
.add(new Field("message", 2, "string"));
|
||||
private static Root = new Root().define("messages").add(PrivateMessage.Type);
|
||||
|
||||
constructor(public payload: PrivateMessagePayload) {}
|
||||
|
||||
@ -85,7 +85,7 @@ export class PrivateMessage {
|
||||
bytes
|
||||
) as unknown as PrivateMessagePayload;
|
||||
if (!payload.toAddress || !payload.message) {
|
||||
console.log('Field missing on decoded PrivateMessage', payload);
|
||||
console.log("Field missing on decoded PrivateMessage", payload);
|
||||
return;
|
||||
}
|
||||
return new PrivateMessage(payload);
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
import "@testing-library/jest-dom";
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
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 { Dispatch, SetStateAction } from "react";
|
||||
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";
|
||||
|
||||
export const PublicKeyContentTopic =
|
||||
'/eth-pm-wallet/1/encryption-public-key/proto';
|
||||
"/eth-pm-wallet/1/encryption-public-key/proto";
|
||||
export const PrivateMessageContentTopic =
|
||||
'/eth-pm-wallet/1/private-message/proto';
|
||||
"/eth-pm-wallet/1/private-message/proto";
|
||||
|
||||
export async function initWaku(): Promise<Waku> {
|
||||
const waku = await Waku.create({ bootstrap: { default: true } });
|
||||
@ -19,7 +19,7 @@ export async function initWaku(): Promise<Waku> {
|
||||
// As we are not implementing connection management in this example
|
||||
|
||||
setTimeout(reject, 10000);
|
||||
waku.libp2p.connectionManager.on('peer:connect', () => {
|
||||
waku.libp2p.connectionManager.on("peer:connect", () => {
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
@ -32,14 +32,14 @@ export function handlePublicKeyMessage(
|
||||
setPublicKeys: Dispatch<SetStateAction<Map<string, Uint8Array>>>,
|
||||
msg: WakuMessage
|
||||
) {
|
||||
console.log('Public Key Message received:', msg);
|
||||
console.log("Public Key Message received:", msg);
|
||||
if (!msg.payload) return;
|
||||
const publicKeyMsg = PublicKeyMessage.decode(msg.payload);
|
||||
if (!publicKeyMsg) return;
|
||||
if (myAddress && equalByteArrays(publicKeyMsg.ethAddress, myAddress)) return;
|
||||
|
||||
const res = validatePublicKeyMessage(publicKeyMsg);
|
||||
console.log('Is Public Key Message valid?', res);
|
||||
console.log("Is Public Key Message valid?", res);
|
||||
|
||||
if (res) {
|
||||
setPublicKeys((prevPks: Map<string, Uint8Array>) => {
|
||||
@ -61,27 +61,27 @@ export async function handlePrivateMessage(
|
||||
}) => Promise<any>,
|
||||
wakuMsg: WakuMessage
|
||||
) {
|
||||
console.log('Private Message received:', wakuMsg);
|
||||
console.log("Private Message received:", wakuMsg);
|
||||
if (!wakuMsg.payload) return;
|
||||
|
||||
const decryptedPayload = await providerRequest({
|
||||
method: 'eth_decrypt',
|
||||
method: "eth_decrypt",
|
||||
params: [wakuMsg.payloadAsUtf8, address],
|
||||
}).catch((error) => console.log(error.message));
|
||||
|
||||
console.log('Decrypted Payload:', decryptedPayload);
|
||||
console.log("Decrypted Payload:", decryptedPayload);
|
||||
const privateMessage = PrivateMessage.decode(
|
||||
Buffer.from(decryptedPayload, 'hex')
|
||||
Buffer.from(decryptedPayload, "hex")
|
||||
);
|
||||
if (!privateMessage) {
|
||||
console.log('Failed to decode Private Message');
|
||||
console.log("Failed to decode Private Message");
|
||||
return;
|
||||
}
|
||||
if (!equalByteArrays(privateMessage.toAddress, address)) return;
|
||||
|
||||
const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date();
|
||||
|
||||
console.log('Message decrypted:', privateMessage.message);
|
||||
console.log("Message decrypted:", privateMessage.message);
|
||||
setter((prevMsgs: Message[]) => {
|
||||
const copy = prevMsgs.slice();
|
||||
copy.push({
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import '@ethersproject/shims';
|
||||
import "@ethersproject/shims";
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import './App.css';
|
||||
import { Waku } from 'js-waku';
|
||||
import { KeyPair, PublicKeyMessageEncryptionKey } from './crypto';
|
||||
import { Message } from './messaging/Messages';
|
||||
import 'fontsource-roboto';
|
||||
import { AppBar, IconButton, Toolbar, Typography } from '@material-ui/core';
|
||||
import KeyPairHandling from './key_pair_handling/KeyPairHandling';
|
||||
import React, { useEffect, useState } from "react";
|
||||
import "./App.css";
|
||||
import { Waku } from "js-waku";
|
||||
import { KeyPair, PublicKeyMessageEncryptionKey } from "./crypto";
|
||||
import { Message } from "./messaging/Messages";
|
||||
import "fontsource-roboto";
|
||||
import { AppBar, IconButton, Toolbar, Typography } from "@material-ui/core";
|
||||
import KeyPairHandling from "./key_pair_handling/KeyPairHandling";
|
||||
import {
|
||||
createMuiTheme,
|
||||
ThemeProvider,
|
||||
makeStyles,
|
||||
} from '@material-ui/core/styles';
|
||||
import { teal, purple, green } from '@material-ui/core/colors';
|
||||
import WifiIcon from '@material-ui/icons/Wifi';
|
||||
import BroadcastPublicKey from './BroadcastPublicKey';
|
||||
import Messaging from './messaging/Messaging';
|
||||
} from "@material-ui/core/styles";
|
||||
import { teal, purple, green } from "@material-ui/core/colors";
|
||||
import WifiIcon from "@material-ui/icons/Wifi";
|
||||
import BroadcastPublicKey from "./BroadcastPublicKey";
|
||||
import Messaging from "./messaging/Messaging";
|
||||
import {
|
||||
PrivateMessageContentTopic,
|
||||
handlePrivateMessage,
|
||||
handlePublicKeyMessage,
|
||||
initWaku,
|
||||
PublicKeyContentTopic,
|
||||
} from './waku';
|
||||
import { Web3Provider } from '@ethersproject/providers/src.ts/web3-provider';
|
||||
import ConnectWallet from './ConnectWallet';
|
||||
} from "./waku";
|
||||
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
||||
import ConnectWallet from "./ConnectWallet";
|
||||
|
||||
const theme = createMuiTheme({
|
||||
palette: {
|
||||
@ -40,21 +40,21 @@ const theme = createMuiTheme({
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
minHeight: '100vh',
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
minHeight: "100vh",
|
||||
},
|
||||
appBar: {
|
||||
// height: '200p',
|
||||
},
|
||||
container: {
|
||||
display: 'flex',
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
},
|
||||
main: {
|
||||
flex: 1,
|
||||
margin: '10px',
|
||||
margin: "10px",
|
||||
},
|
||||
wakuStatus: {
|
||||
marginRight: theme.spacing(2),
|
||||
@ -91,11 +91,11 @@ function App() {
|
||||
if (waku) return;
|
||||
initWaku()
|
||||
.then((_waku) => {
|
||||
console.log('waku: ready');
|
||||
console.log("waku: ready");
|
||||
setWaku(_waku);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to initiate Waku', e);
|
||||
console.error("Failed to initiate Waku", e);
|
||||
});
|
||||
}, [waku]);
|
||||
|
||||
@ -177,10 +177,10 @@ function App() {
|
||||
return () => clearInterval(interval);
|
||||
}, [waku]);
|
||||
|
||||
let addressDisplay = '';
|
||||
let addressDisplay = "";
|
||||
if (address) {
|
||||
addressDisplay =
|
||||
address.substr(0, 6) + '...' + address.substr(address.length - 4, 4);
|
||||
address.substr(0, 6) + "..." + address.substr(address.length - 4, 4);
|
||||
}
|
||||
|
||||
return (
|
||||
@ -194,12 +194,12 @@ function App() {
|
||||
aria-label="waku-status"
|
||||
>
|
||||
<WifiIcon
|
||||
color={waku ? undefined : 'disabled'}
|
||||
color={waku ? undefined : "disabled"}
|
||||
style={waku ? { color: green[500] } : {}}
|
||||
/>
|
||||
</IconButton>
|
||||
<Typography className={classes.peers} aria-label="connected-peers">
|
||||
Peers: {peerStats.relayPeers} relay, {peerStats.lightPushPeers}{' '}
|
||||
Peers: {peerStats.relayPeers} relay, {peerStats.lightPushPeers}{" "}
|
||||
light push
|
||||
</Typography>
|
||||
<Typography variant="h6" className={classes.title}>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React, { useState } from 'react';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
createPublicKeyMessage,
|
||||
KeyPair,
|
||||
PublicKeyMessageEncryptionKey,
|
||||
} from './crypto';
|
||||
import { PublicKeyMessage } from './messaging/wire';
|
||||
import { WakuMessage, Waku } from 'js-waku';
|
||||
import { PublicKeyContentTopic } from './waku';
|
||||
} from "./crypto";
|
||||
import { PublicKeyMessage } from "./messaging/wire";
|
||||
import { WakuMessage, Waku } from "js-waku";
|
||||
import { PublicKeyContentTopic } from "./waku";
|
||||
|
||||
interface Props {
|
||||
EncryptionKeyPair: KeyPair | undefined;
|
||||
@ -36,11 +36,11 @@ export default function BroadcastPublicKey({
|
||||
encodePublicKeyWakuMessage(publicKeyMsg)
|
||||
.then((wakuMsg) => {
|
||||
waku.lightPush.push(wakuMsg).catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
console.error("Failed to send Public Key Message", e);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log('Failed to encode Public Key Message in Waku Message', e);
|
||||
console.log("Failed to encode Public Key Message in Waku Message", e);
|
||||
});
|
||||
} else {
|
||||
createPublicKeyMessage(
|
||||
@ -54,20 +54,20 @@ export default function BroadcastPublicKey({
|
||||
.then((wakuMsg) => {
|
||||
waku.lightPush
|
||||
.push(wakuMsg)
|
||||
.then((res) => console.log('Public Key Message pushed', res))
|
||||
.then((res) => console.log("Public Key Message pushed", res))
|
||||
.catch((e) => {
|
||||
console.error('Failed to send Public Key Message', e);
|
||||
console.error("Failed to send Public Key Message", e);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log(
|
||||
'Failed to encode Public Key Message in Waku Message',
|
||||
"Failed to encode Public Key Message in Waku Message",
|
||||
e
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to create public key message', e);
|
||||
console.error("Failed to create public key message", e);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { ethers } from 'ethers';
|
||||
import { Web3Provider } from '@ethersproject/providers/src.ts/web3-provider';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import { ethers } from "ethers";
|
||||
import { Web3Provider } from "@ethersproject/providers/src.ts/web3-provider";
|
||||
|
||||
declare let window: any;
|
||||
|
||||
@ -14,14 +14,14 @@ export default function ConnectWallet({ setAddress, setProvider }: Props) {
|
||||
const connectWallet = () => {
|
||||
try {
|
||||
window.ethereum
|
||||
.request({ method: 'eth_requestAccounts' })
|
||||
.request({ method: "eth_requestAccounts" })
|
||||
.then((accounts: string[]) => {
|
||||
const _provider = new ethers.providers.Web3Provider(window.ethereum);
|
||||
setAddress(accounts[0]);
|
||||
setProvider(_provider);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('No web3 provider available');
|
||||
console.error("No web3 provider available");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import '@ethersproject/shims';
|
||||
import "@ethersproject/shims";
|
||||
|
||||
import { PublicKeyMessage } from './messaging/wire';
|
||||
import { hexToBuf, equalByteArrays, bufToHex } 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';
|
||||
import { PublicKeyMessage } from "./messaging/wire";
|
||||
import { hexToBuf, equalByteArrays, bufToHex } 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(
|
||||
keccak256(Buffer.from(PublicKeyContentTopic, 'utf-8'))
|
||||
keccak256(Buffer.from(PublicKeyContentTopic, "utf-8"))
|
||||
);
|
||||
|
||||
export interface KeyPair {
|
||||
@ -44,8 +44,8 @@ export async function createPublicKeyMessage(
|
||||
providerRequest
|
||||
);
|
||||
|
||||
console.log('Asking wallet to sign Public Key Message');
|
||||
console.log('Public Key Message signed');
|
||||
console.log("Asking wallet to sign Public Key Message");
|
||||
console.log("Public Key Message signed");
|
||||
|
||||
return new PublicKeyMessage({
|
||||
encryptionPublicKey: encryptionPublicKey,
|
||||
@ -58,24 +58,24 @@ function buildMsgParams(encryptionPublicKey: Uint8Array, fromAddress: string) {
|
||||
return JSON.stringify({
|
||||
domain: {
|
||||
chainId: 1,
|
||||
name: 'Ethereum Private Message over Waku',
|
||||
version: '1',
|
||||
name: "Ethereum Private Message over Waku",
|
||||
version: "1",
|
||||
},
|
||||
message: {
|
||||
encryptionPublicKey: bufToHex(encryptionPublicKey),
|
||||
ownerAddress: fromAddress,
|
||||
},
|
||||
// Refers to the keys of the *types* object below.
|
||||
primaryType: 'PublishEncryptionPublicKey',
|
||||
primaryType: "PublishEncryptionPublicKey",
|
||||
types: {
|
||||
EIP712Domain: [
|
||||
{ name: 'name', type: 'string' },
|
||||
{ name: 'version', type: 'string' },
|
||||
{ name: 'chainId', type: 'uint256' },
|
||||
{ name: "name", type: "string" },
|
||||
{ name: "version", type: "string" },
|
||||
{ name: "chainId", type: "uint256" },
|
||||
],
|
||||
PublishEncryptionPublicKey: [
|
||||
{ name: 'encryptionPublicKey', type: 'string' },
|
||||
{ name: 'ownerAddress', type: 'string' },
|
||||
{ name: "encryptionPublicKey", type: "string" },
|
||||
{ name: "ownerAddress", type: "string" },
|
||||
],
|
||||
},
|
||||
});
|
||||
@ -93,12 +93,12 @@ export async function signEncryptionKey(
|
||||
const msgParams = buildMsgParams(encryptionPublicKey, fromAddress);
|
||||
|
||||
const result = await providerRequest({
|
||||
method: 'eth_signTypedData_v3',
|
||||
method: "eth_signTypedData_v3",
|
||||
params: [fromAddress, msgParams],
|
||||
from: fromAddress,
|
||||
});
|
||||
|
||||
console.log('TYPED SIGNED:' + JSON.stringify(result));
|
||||
console.log("TYPED SIGNED:" + JSON.stringify(result));
|
||||
|
||||
return hexToBuf(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" + bufToHex(msg.ethAddress))
|
||||
),
|
||||
sig: '0x' + bufToHex(msg.signature),
|
||||
sig: "0x" + bufToHex(msg.signature),
|
||||
});
|
||||
|
||||
console.log('Recovered', recovered);
|
||||
console.log('ethAddress', '0x' + bufToHex(msg.ethAddress));
|
||||
console.log("Recovered", recovered);
|
||||
console.log("ethAddress", "0x" + bufToHex(msg.ethAddress));
|
||||
|
||||
return equalByteArrays(recovered, msg.ethAddress);
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import { LoadKeyPair } from './LoadKeyPair';
|
||||
import { SaveKeyPair } from './SaveKeyPair';
|
||||
import React, { useState } from 'react';
|
||||
import { generateEncryptionKeyPair, KeyPair } from '../crypto';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import PasswordInput from './PasswordInput';
|
||||
import { Button } from "@material-ui/core";
|
||||
import { LoadKeyPair } from "./LoadKeyPair";
|
||||
import { SaveKeyPair } from "./SaveKeyPair";
|
||||
import React, { useState } from "react";
|
||||
import { generateEncryptionKeyPair, KeyPair } from "../crypto";
|
||||
import { makeStyles } from "@material-ui/core/styles";
|
||||
import PasswordInput from "./PasswordInput";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
textAlign: 'center',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexDirection: 'column',
|
||||
margin: '5px',
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexDirection: "column",
|
||||
margin: "5px",
|
||||
},
|
||||
generate: { margin: '5px' },
|
||||
generate: { margin: "5px" },
|
||||
storage: {
|
||||
margin: '5px',
|
||||
margin: "5px",
|
||||
},
|
||||
loadSave: {
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
margin: '5px',
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
margin: "5px",
|
||||
},
|
||||
loadSaveButton: {
|
||||
margin: '5px',
|
||||
margin: "5px",
|
||||
},
|
||||
});
|
||||
|
||||
@ -49,7 +49,7 @@ export default function KeyPairHandling({
|
||||
setEncryptionKeyPair(keyPair);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to generate Key Pair', e);
|
||||
console.error("Failed to generate Key Pair", e);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { loadKeyPairFromStorage } from './key_pair_storage';
|
||||
import { KeyPair } from '../crypto';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import { loadKeyPairFromStorage } from "./key_pair_storage";
|
||||
import { KeyPair } from "../crypto";
|
||||
|
||||
export interface Props {
|
||||
setEncryptionKeyPair: (keyPair: KeyPair) => void;
|
||||
@ -19,7 +19,7 @@ export function LoadKeyPair({
|
||||
if (!password) return;
|
||||
loadKeyPairFromStorage(password).then((keyPair: KeyPair | undefined) => {
|
||||
if (!keyPair) return;
|
||||
console.log('Encryption KeyPair loaded from storage');
|
||||
console.log("Encryption KeyPair loaded from storage");
|
||||
setEncryptionKeyPair(keyPair);
|
||||
});
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { TextField } from '@material-ui/core';
|
||||
import React, { ChangeEvent } from 'react';
|
||||
import { TextField } from "@material-ui/core";
|
||||
import React, { ChangeEvent } from "react";
|
||||
|
||||
interface Props {
|
||||
password: string | undefined;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Button } from '@material-ui/core';
|
||||
import React from 'react';
|
||||
import { KeyPair } from '../crypto';
|
||||
import { saveKeyPairToStorage } from './key_pair_storage';
|
||||
import { Button } from "@material-ui/core";
|
||||
import React from "react";
|
||||
import { KeyPair } from "../crypto";
|
||||
import { saveKeyPairToStorage } from "./key_pair_storage";
|
||||
|
||||
export interface Props {
|
||||
EncryptionKeyPair: KeyPair | undefined;
|
||||
@ -13,7 +13,7 @@ export function SaveKeyPair({ password, EncryptionKeyPair }: Props) {
|
||||
if (!EncryptionKeyPair) return;
|
||||
if (!password) return;
|
||||
saveKeyPairToStorage(EncryptionKeyPair, password).then(() => {
|
||||
console.log('Encryption KeyPair saved to storage');
|
||||
console.log("Encryption KeyPair saved to storage");
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { KeyPair } from '../crypto';
|
||||
import { bufToHex, hexToBuf } from 'js-waku/lib/utils';
|
||||
import { KeyPair } from "../crypto";
|
||||
import { bufToHex, hexToBuf } from "js-waku/lib/utils";
|
||||
|
||||
/**
|
||||
* Save keypair to storage, encrypted with password
|
||||
@ -16,7 +16,7 @@ export async function saveKeyPairToStorage(
|
||||
cipher: bufToHex(cipher),
|
||||
};
|
||||
|
||||
localStorage.setItem('cipherEncryptionKeyPair', JSON.stringify(data));
|
||||
localStorage.setItem("cipherEncryptionKeyPair", JSON.stringify(data));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -25,7 +25,7 @@ export async function saveKeyPairToStorage(
|
||||
export async function loadKeyPairFromStorage(
|
||||
password: string
|
||||
): Promise<KeyPair | undefined> {
|
||||
const str = localStorage.getItem('cipherEncryptionKeyPair');
|
||||
const str = localStorage.getItem("cipherEncryptionKeyPair");
|
||||
if (!str) return;
|
||||
const data = JSON.parse(str);
|
||||
|
||||
@ -42,11 +42,11 @@ export async function loadKeyPairFromStorage(
|
||||
function getKeyMaterial(password: string): Promise<CryptoKey> {
|
||||
const enc = new TextEncoder();
|
||||
return window.crypto.subtle.importKey(
|
||||
'raw',
|
||||
"raw",
|
||||
enc.encode(password),
|
||||
{ name: 'PBKDF2' },
|
||||
{ name: "PBKDF2" },
|
||||
false,
|
||||
['deriveBits', 'deriveKey']
|
||||
["deriveBits", "deriveKey"]
|
||||
);
|
||||
}
|
||||
|
||||
@ -56,15 +56,15 @@ function getKeyMaterial(password: string): Promise<CryptoKey> {
|
||||
function getWrapKey(keyMaterial: CryptoKey, salt: Uint8Array) {
|
||||
return window.crypto.subtle.deriveKey(
|
||||
{
|
||||
name: 'PBKDF2',
|
||||
name: "PBKDF2",
|
||||
salt: salt,
|
||||
iterations: 100000,
|
||||
hash: 'SHA-256',
|
||||
hash: "SHA-256",
|
||||
},
|
||||
keyMaterial,
|
||||
{ name: 'AES-GCM', length: 256 },
|
||||
{ name: "AES-GCM", length: 256 },
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
["encrypt", "decrypt"]
|
||||
);
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ async function encryptKey(encryptionKeyPair: KeyPair, password: string) {
|
||||
const iv = window.crypto.getRandomValues(new Uint8Array(12));
|
||||
const cipher = await window.crypto.subtle.encrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
name: "AES-GCM",
|
||||
iv: iv,
|
||||
},
|
||||
wrappingKey,
|
||||
@ -107,7 +107,7 @@ async function decryptKey(
|
||||
try {
|
||||
let decrypted = await window.crypto.subtle.decrypt(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
name: "AES-GCM",
|
||||
iv: iv,
|
||||
},
|
||||
key,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { List, ListItem, ListItemText } from '@material-ui/core';
|
||||
import React from "react";
|
||||
import { List, ListItem, ListItemText } from "@material-ui/core";
|
||||
|
||||
/**
|
||||
* Clear text message
|
||||
@ -31,10 +31,10 @@ function generate(messages: Message[]) {
|
||||
|
||||
function formatDisplayDate(timestamp: Date): string {
|
||||
return timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import Messages, { Message } from './Messages';
|
||||
import { Waku } from 'js-waku';
|
||||
import SendMessage from './SendMessage';
|
||||
import { makeStyles } from '@material-ui/core';
|
||||
import Messages, { Message } from "./Messages";
|
||||
import { Waku } from "js-waku";
|
||||
import SendMessage from "./SendMessage";
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'left',
|
||||
flexDirection: 'column',
|
||||
margin: '5px',
|
||||
display: "flex",
|
||||
alignItems: "left",
|
||||
flexDirection: "column",
|
||||
margin: "5px",
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@ -5,12 +5,12 @@ import {
|
||||
MenuItem,
|
||||
Select,
|
||||
TextField,
|
||||
} 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 { PrivateMessage } from './wire';
|
||||
import { PrivateMessageContentTopic } from '../waku';
|
||||
} 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 { PrivateMessage } from "./wire";
|
||||
import { PrivateMessageContentTopic } from "../waku";
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
formControl: {
|
||||
@ -30,7 +30,7 @@ export interface Props {
|
||||
|
||||
export default function SendMessage({ waku, recipients }: Props) {
|
||||
const classes = useStyles();
|
||||
const [recipient, setRecipient] = useState<string>('');
|
||||
const [recipient, setRecipient] = useState<string>("");
|
||||
const [message, setMessage] = useState<string>();
|
||||
|
||||
const handleRecipientChange = (
|
||||
@ -53,7 +53,7 @@ export default function SendMessage({ waku, recipients }: Props) {
|
||||
|
||||
const keyDownHandler = async (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
event.key === 'Enter' &&
|
||||
event.key === "Enter" &&
|
||||
!event.altKey &&
|
||||
!event.ctrlKey &&
|
||||
!event.shiftKey
|
||||
@ -66,8 +66,8 @@ export default function SendMessage({ waku, recipients }: Props) {
|
||||
|
||||
sendMessage(waku, recipient, publicKey, message, (res) => {
|
||||
if (res) {
|
||||
console.log('callback called with', res);
|
||||
setMessage('');
|
||||
console.log("callback called with", res);
|
||||
setMessage("");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -76,9 +76,9 @@ export default function SendMessage({ waku, recipients }: Props) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
flexWrap: 'wrap',
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
<FormControl className={classes.formControl}>
|
||||
@ -129,20 +129,20 @@ function sendMessage(
|
||||
) {
|
||||
encodeEncryptedWakuMessage(message, recipientPublicKey, recipientAddress)
|
||||
.then((msg) => {
|
||||
console.log('pushing');
|
||||
console.log("pushing");
|
||||
waku.lightPush
|
||||
.push(msg)
|
||||
.then((res) => {
|
||||
console.log('Message sent', res);
|
||||
console.log("Message sent", res);
|
||||
callback(res ? res.isSuccess : false);
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed to send message', e);
|
||||
console.error("Failed to send message", e);
|
||||
callback(false);
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Cannot encode & encrypt message', e);
|
||||
console.error("Cannot encode & encrypt message", e);
|
||||
callback(false);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as protobuf from 'protobufjs/light';
|
||||
import * as protobuf from "protobufjs/light";
|
||||
|
||||
export interface PublicKeyMessagePayload {
|
||||
encryptionPublicKey: Uint8Array;
|
||||
@ -14,12 +14,12 @@ const Root = protobuf.Root,
|
||||
* Message used to communicate the encryption public key linked to a given Ethereum account
|
||||
*/
|
||||
export class PublicKeyMessage {
|
||||
private static Type = new Type('PublicKeyMessage')
|
||||
.add(new Field('encryptionPublicKey', 1, 'bytes'))
|
||||
.add(new Field('ethAddress', 2, 'bytes'))
|
||||
.add(new Field('signature', 3, 'bytes'));
|
||||
private static Type = new Type("PublicKeyMessage")
|
||||
.add(new Field("encryptionPublicKey", 1, "bytes"))
|
||||
.add(new Field("ethAddress", 2, "bytes"))
|
||||
.add(new Field("signature", 3, "bytes"));
|
||||
private static Root = new Root()
|
||||
.define('messages')
|
||||
.define("messages")
|
||||
.add(PublicKeyMessage.Type);
|
||||
|
||||
constructor(public payload: PublicKeyMessagePayload) {}
|
||||
@ -40,7 +40,7 @@ export class PublicKeyMessage {
|
||||
!payload.encryptionPublicKey ||
|
||||
!payload.ethAddress
|
||||
) {
|
||||
console.log('Field missing on decoded Public Key Message', payload);
|
||||
console.log("Field missing on decoded Public Key Message", payload);
|
||||
return;
|
||||
}
|
||||
return new PublicKeyMessage(payload);
|
||||
@ -68,10 +68,10 @@ export interface PrivateMessagePayload {
|
||||
* Encrypted Message used for private communication over the Waku network.
|
||||
*/
|
||||
export class PrivateMessage {
|
||||
private static Type = new Type('PrivateMessage')
|
||||
.add(new Field('toAddress', 1, 'bytes'))
|
||||
.add(new Field('message', 2, 'string'));
|
||||
private static Root = new Root().define('messages').add(PrivateMessage.Type);
|
||||
private static Type = new Type("PrivateMessage")
|
||||
.add(new Field("toAddress", 1, "bytes"))
|
||||
.add(new Field("message", 2, "string"));
|
||||
private static Root = new Root().define("messages").add(PrivateMessage.Type);
|
||||
|
||||
constructor(public payload: PrivateMessagePayload) {}
|
||||
|
||||
@ -85,7 +85,7 @@ export class PrivateMessage {
|
||||
bytes
|
||||
) as unknown as PrivateMessagePayload;
|
||||
if (!payload.toAddress || !payload.message) {
|
||||
console.log('Field missing on decoded Private Message', payload);
|
||||
console.log("Field missing on decoded Private Message", payload);
|
||||
return;
|
||||
}
|
||||
return new PrivateMessage(payload);
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
import "@testing-library/jest-dom";
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
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 { Dispatch, SetStateAction } from "react";
|
||||
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";
|
||||
|
||||
export const PublicKeyContentTopic = '/eth-pm/1/public-key/proto';
|
||||
export const PrivateMessageContentTopic = '/eth-pm/1/private-message/proto';
|
||||
export const PublicKeyContentTopic = "/eth-pm/1/public-key/proto";
|
||||
export const PrivateMessageContentTopic = "/eth-pm/1/private-message/proto";
|
||||
|
||||
export async function initWaku(): Promise<Waku> {
|
||||
const waku = await Waku.create({ bootstrap: { default: true } });
|
||||
@ -17,7 +17,7 @@ export async function initWaku(): Promise<Waku> {
|
||||
// As we are not implementing connection management in this example
|
||||
|
||||
setTimeout(reject, 10000);
|
||||
waku.libp2p.connectionManager.on('peer:connect', () => {
|
||||
waku.libp2p.connectionManager.on("peer:connect", () => {
|
||||
resolve(null);
|
||||
});
|
||||
});
|
||||
@ -30,14 +30,14 @@ export function handlePublicKeyMessage(
|
||||
setter: Dispatch<SetStateAction<Map<string, Uint8Array>>>,
|
||||
msg: WakuMessage
|
||||
) {
|
||||
console.log('Public Key Message received:', msg);
|
||||
console.log("Public Key Message received:", msg);
|
||||
if (!msg.payload) return;
|
||||
const publicKeyMsg = PublicKeyMessage.decode(msg.payload);
|
||||
if (!publicKeyMsg) return;
|
||||
if (myAddress && equalByteArrays(publicKeyMsg.ethAddress, myAddress)) return;
|
||||
|
||||
const res = validatePublicKeyMessage(publicKeyMsg);
|
||||
console.log('Is Public Key Message valid?', res);
|
||||
console.log("Is Public Key Message valid?", res);
|
||||
|
||||
if (res) {
|
||||
setter((prevPks: Map<string, Uint8Array>) => {
|
||||
@ -55,18 +55,18 @@ export async function handlePrivateMessage(
|
||||
address: string,
|
||||
wakuMsg: WakuMessage
|
||||
) {
|
||||
console.log('Private Message received:', wakuMsg);
|
||||
console.log("Private Message received:", wakuMsg);
|
||||
if (!wakuMsg.payload) return;
|
||||
const privateMessage = PrivateMessage.decode(wakuMsg.payload);
|
||||
if (!privateMessage) {
|
||||
console.log('Failed to decode Private Message');
|
||||
console.log("Failed to decode Private Message");
|
||||
return;
|
||||
}
|
||||
if (!equalByteArrays(privateMessage.toAddress, address)) return;
|
||||
|
||||
const timestamp = wakuMsg.timestamp ? wakuMsg.timestamp : new Date();
|
||||
|
||||
console.log('Message decrypted:', privateMessage.message);
|
||||
console.log("Message decrypted:", privateMessage.message);
|
||||
setter((prevMsgs: Message[]) => {
|
||||
const copy = prevMsgs.slice();
|
||||
copy.push({
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
const webpack = require('webpack');
|
||||
const webpack = require("webpack");
|
||||
|
||||
module.exports = {
|
||||
dev: (config) => {
|
||||
@ -6,21 +6,21 @@ module.exports = {
|
||||
if (!config.resolve) config.resolve = {};
|
||||
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||
Object.assign(config.resolve.fallback, {
|
||||
buffer: require.resolve('buffer'),
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
buffer: require.resolve("buffer"),
|
||||
crypto: require.resolve("crypto-browserify"),
|
||||
stream: require.resolve("stream-browserify"),
|
||||
});
|
||||
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.ENV': JSON.stringify('dev'),
|
||||
"process.env.ENV": JSON.stringify("dev"),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser.js',
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
process: "process/browser.js",
|
||||
Buffer: ["buffer", "Buffer"],
|
||||
})
|
||||
);
|
||||
|
||||
@ -34,21 +34,21 @@ module.exports = {
|
||||
if (!config.resolve) config.resolve = {};
|
||||
if (!config.resolve.fallback) config.resolve.fallback = {};
|
||||
Object.assign(config.resolve.fallback, {
|
||||
buffer: require.resolve('buffer'),
|
||||
crypto: require.resolve('crypto-browserify'),
|
||||
stream: require.resolve('stream-browserify'),
|
||||
buffer: require.resolve("buffer"),
|
||||
crypto: require.resolve("crypto-browserify"),
|
||||
stream: require.resolve("stream-browserify"),
|
||||
});
|
||||
|
||||
if (!config.plugins) config.plugins = [];
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.ENV': JSON.stringify('prod'),
|
||||
"process.env.ENV": JSON.stringify("prod"),
|
||||
})
|
||||
);
|
||||
config.plugins.push(
|
||||
new webpack.ProvidePlugin({
|
||||
process: 'process/browser.js',
|
||||
Buffer: ['buffer', 'Buffer'],
|
||||
process: "process/browser.js",
|
||||
Buffer: ["buffer", "Buffer"],
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@ -1,48 +1,48 @@
|
||||
import { useEffect, useReducer, useState } from 'react';
|
||||
import './App.css';
|
||||
import { useEffect, useReducer, useState } from "react";
|
||||
import "./App.css";
|
||||
import {
|
||||
PageDirection,
|
||||
getNodesFromHostedJson,
|
||||
Waku,
|
||||
WakuMessage,
|
||||
} from 'js-waku';
|
||||
import handleCommand from './command';
|
||||
import Room from './Room';
|
||||
import { WakuContext } from './WakuContext';
|
||||
import { ThemeProvider } from '@livechat/ui-kit';
|
||||
import { generate } from 'server-name-generator';
|
||||
import { Message } from './Message';
|
||||
} from "js-waku";
|
||||
import handleCommand from "./command";
|
||||
import Room from "./Room";
|
||||
import { WakuContext } from "./WakuContext";
|
||||
import { ThemeProvider } from "@livechat/ui-kit";
|
||||
import { generate } from "server-name-generator";
|
||||
import { Message } from "./Message";
|
||||
|
||||
const themes = {
|
||||
AuthorName: {
|
||||
css: {
|
||||
fontSize: '1.1em',
|
||||
fontSize: "1.1em",
|
||||
},
|
||||
},
|
||||
Message: {
|
||||
css: {
|
||||
margin: '0em',
|
||||
padding: '0em',
|
||||
fontSize: '0.83em',
|
||||
margin: "0em",
|
||||
padding: "0em",
|
||||
fontSize: "0.83em",
|
||||
},
|
||||
},
|
||||
MessageText: {
|
||||
css: {
|
||||
margin: '0em',
|
||||
padding: '0.1em',
|
||||
paddingLeft: '1em',
|
||||
fontSize: '1.1em',
|
||||
margin: "0em",
|
||||
padding: "0.1em",
|
||||
paddingLeft: "1em",
|
||||
fontSize: "1.1em",
|
||||
},
|
||||
},
|
||||
MessageGroup: {
|
||||
css: {
|
||||
margin: '0em',
|
||||
padding: '0.2em',
|
||||
margin: "0em",
|
||||
padding: "0.2em",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ChatContentTopic = '/toy-chat/2/huilong/proto';
|
||||
export const ChatContentTopic = "/toy-chat/2/huilong/proto";
|
||||
|
||||
async function retrieveStoreMessages(
|
||||
waku: Waku,
|
||||
@ -79,7 +79,7 @@ async function retrieveStoreMessages(
|
||||
|
||||
return res.length;
|
||||
} catch (e) {
|
||||
console.log('Failed to retrieve messages', e);
|
||||
console.log("Failed to retrieve messages", e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -88,20 +88,20 @@ export default function App() {
|
||||
const [messages, dispatchMessages] = useReducer(reduceMessages, []);
|
||||
const [waku, setWaku] = useState<Waku | undefined>(undefined);
|
||||
const [nick, setNick] = useState<string>(() => {
|
||||
const persistedNick = window.localStorage.getItem('nick');
|
||||
const persistedNick = window.localStorage.getItem("nick");
|
||||
return persistedNick !== null ? persistedNick : generate();
|
||||
});
|
||||
const [historicalMessagesRetrieved, setHistoricalMessagesRetrieved] =
|
||||
useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
localStorage.setItem('nick', nick);
|
||||
localStorage.setItem("nick", nick);
|
||||
}, [nick]);
|
||||
|
||||
useEffect(() => {
|
||||
initWaku(setWaku)
|
||||
.then(() => console.log('Waku init done'))
|
||||
.catch((e) => console.log('Waku init failed ', e));
|
||||
.then(() => console.log("Waku init done"))
|
||||
.catch((e) => console.log("Waku init failed ", e));
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
@ -110,7 +110,7 @@ export default function App() {
|
||||
if (!historicalMessagesRetrieved) return;
|
||||
|
||||
const handleRelayMessage = (wakuMsg: WakuMessage) => {
|
||||
console.log('Message received: ', wakuMsg);
|
||||
console.log("Message received: ", wakuMsg);
|
||||
const msg = Message.fromWakuMessage(wakuMsg);
|
||||
if (msg) {
|
||||
dispatchMessages([msg]);
|
||||
@ -148,7 +148,7 @@ export default function App() {
|
||||
return (
|
||||
<div
|
||||
className="chat-app"
|
||||
style={{ height: '100vh', width: '100vw', overflow: 'hidden' }}
|
||||
style={{ height: "100vh", width: "100vw", overflow: "hidden" }}
|
||||
>
|
||||
<WakuContext.Provider value={{ waku: waku }}>
|
||||
<ThemeProvider theme={themes}>
|
||||
@ -190,16 +190,16 @@ async function initWaku(setter: (waku: Waku) => void) {
|
||||
|
||||
setter(waku);
|
||||
} catch (e) {
|
||||
console.log('Issue starting waku ', e);
|
||||
console.log("Issue starting waku ", e);
|
||||
}
|
||||
}
|
||||
|
||||
function selectFleetEnv() {
|
||||
// Works with react-scripts
|
||||
if (process?.env?.NODE_ENV === 'development') {
|
||||
return ['fleets', 'wakuv2.test', 'waku-websocket'];
|
||||
if (process?.env?.NODE_ENV === "development") {
|
||||
return ["fleets", "wakuv2.test", "waku-websocket"];
|
||||
} else {
|
||||
return ['fleets', 'wakuv2.prod', 'waku-websocket'];
|
||||
return ["fleets", "wakuv2.prod", "waku-websocket"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { memo, useEffect, useRef } from 'react';
|
||||
import { memo, useEffect, useRef } from "react";
|
||||
import {
|
||||
Message as LiveMessage,
|
||||
MessageText,
|
||||
MessageList,
|
||||
} from '@livechat/ui-kit';
|
||||
import { Message } from './Message';
|
||||
} from "@livechat/ui-kit";
|
||||
import { Message } from "./Message";
|
||||
|
||||
interface Props {
|
||||
messages: Message[];
|
||||
@ -18,7 +18,7 @@ export default function ChatList(props: Props) {
|
||||
key={
|
||||
message.sentTimestamp
|
||||
? message.sentTimestamp.valueOf()
|
||||
: '' +
|
||||
: "" +
|
||||
message.timestamp.valueOf() +
|
||||
message.nick +
|
||||
message.payloadAsUtf8
|
||||
@ -40,10 +40,10 @@ export default function ChatList(props: Props) {
|
||||
|
||||
function formatDisplayDate(message: Message): string {
|
||||
return message.timestamp.toLocaleString([], {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: '2-digit',
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { ChatMessage } from './chat_message';
|
||||
import { WakuMessage } from "js-waku";
|
||||
import { ChatMessage } from "./chat_message";
|
||||
|
||||
export class Message {
|
||||
public chatMessage: ChatMessage;
|
||||
@ -20,7 +20,7 @@ export class Message {
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(
|
||||
'Failed to decode chat message',
|
||||
"Failed to decode chat message",
|
||||
wakuMsg.payloadAsUtf8,
|
||||
e
|
||||
);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { ChangeEvent, KeyboardEvent, useState } from 'react';
|
||||
import { useWaku } from './WakuContext';
|
||||
import { ChangeEvent, KeyboardEvent, useState } from "react";
|
||||
import { useWaku } from "./WakuContext";
|
||||
import {
|
||||
TextInput,
|
||||
TextComposer,
|
||||
@ -7,20 +7,20 @@ import {
|
||||
Fill,
|
||||
Fit,
|
||||
SendButton,
|
||||
} from '@livechat/ui-kit';
|
||||
} from "@livechat/ui-kit";
|
||||
|
||||
interface Props {
|
||||
sendMessage: ((msg: string) => Promise<void>) | undefined;
|
||||
}
|
||||
|
||||
export default function MessageInput(props: Props) {
|
||||
const [inputText, setInputText] = useState<string>('');
|
||||
const [inputText, setInputText] = useState<string>("");
|
||||
const { waku } = useWaku();
|
||||
|
||||
const sendMessage = async () => {
|
||||
if (props.sendMessage) {
|
||||
await props.sendMessage(inputText);
|
||||
setInputText('');
|
||||
setInputText("");
|
||||
}
|
||||
};
|
||||
|
||||
@ -30,7 +30,7 @@ export default function MessageInput(props: Props) {
|
||||
|
||||
const keyPressHandler = async (event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
event.key === 'Enter' &&
|
||||
event.key === "Enter" &&
|
||||
!event.altKey &&
|
||||
!event.ctrlKey &&
|
||||
!event.shiftKey
|
||||
@ -41,7 +41,7 @@ export default function MessageInput(props: Props) {
|
||||
|
||||
// Enable the button if there are relay peers available or the user is sending a command
|
||||
const activeButton =
|
||||
(waku && waku.relay.getPeers().size !== 0) || inputText.startsWith('/');
|
||||
(waku && waku.relay.getPeers().size !== 0) || inputText.startsWith("/");
|
||||
|
||||
return (
|
||||
<TextComposer
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { WakuMessage } from 'js-waku';
|
||||
import { ChatContentTopic } from './App';
|
||||
import ChatList from './ChatList';
|
||||
import MessageInput from './MessageInput';
|
||||
import { useWaku } from './WakuContext';
|
||||
import { TitleBar } from '@livechat/ui-kit';
|
||||
import { Message } from './Message';
|
||||
import { ChatMessage } from './chat_message';
|
||||
import { useEffect, useState } from 'react';
|
||||
import PeerId from 'peer-id';
|
||||
import { WakuMessage } from "js-waku";
|
||||
import { ChatContentTopic } from "./App";
|
||||
import ChatList from "./ChatList";
|
||||
import MessageInput from "./MessageInput";
|
||||
import { useWaku } from "./WakuContext";
|
||||
import { TitleBar } from "@livechat/ui-kit";
|
||||
import { Message } from "./Message";
|
||||
import { ChatMessage } from "./chat_message";
|
||||
import { useEffect, useState } from "react";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
interface Props {
|
||||
messages: Message[];
|
||||
@ -32,10 +32,10 @@ export default function Room(props: Props) {
|
||||
});
|
||||
};
|
||||
|
||||
waku.libp2p.peerStore.on('change:protocols', addPeer);
|
||||
waku.libp2p.peerStore.on("change:protocols", addPeer);
|
||||
|
||||
return () => {
|
||||
waku.libp2p.connectionManager.removeListener('change:protocols', addPeer);
|
||||
waku.libp2p.connectionManager.removeListener("change:protocols", addPeer);
|
||||
};
|
||||
}, [waku]);
|
||||
|
||||
@ -57,7 +57,7 @@ export default function Room(props: Props) {
|
||||
return (
|
||||
<div
|
||||
className="chat-container"
|
||||
style={{ height: '98vh', display: 'flex', flexDirection: 'column' }}
|
||||
style={{ height: "98vh", display: "flex", flexDirection: "column" }}
|
||||
>
|
||||
<TitleBar
|
||||
leftIcons={[`Peers: ${relayPeers} relay ${storePeers} store.`]}
|
||||
@ -88,7 +88,7 @@ async function handleMessage(
|
||||
commandHandler: (cmd: string) => void,
|
||||
messageSender: (msg: WakuMessage) => Promise<void>
|
||||
) {
|
||||
if (message.startsWith('/')) {
|
||||
if (message.startsWith("/")) {
|
||||
commandHandler(message);
|
||||
} else {
|
||||
const timestamp = new Date();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
import { Waku } from 'js-waku';
|
||||
import { createContext, useContext } from "react";
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
export type WakuContextType = {
|
||||
waku?: Waku;
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import WakuMock, { Message } from './WakuMock';
|
||||
import WakuMock, { Message } from "./WakuMock";
|
||||
|
||||
test('Messages are emitted', async () => {
|
||||
test("Messages are emitted", async () => {
|
||||
const wakuMock = await WakuMock.create();
|
||||
|
||||
let message: Message;
|
||||
wakuMock.on('message', (msg) => {
|
||||
wakuMock.on("message", (msg) => {
|
||||
message = msg;
|
||||
});
|
||||
|
||||
@ -13,13 +13,13 @@ test('Messages are emitted', async () => {
|
||||
expect(message.message).toBeDefined();
|
||||
});
|
||||
|
||||
test('Messages are sent', async () => {
|
||||
test("Messages are sent", async () => {
|
||||
const wakuMock = await WakuMock.create();
|
||||
|
||||
const text = 'This is a message.';
|
||||
const text = "This is a message.";
|
||||
|
||||
let message: Message;
|
||||
wakuMock.on('message', (msg) => {
|
||||
wakuMock.on("message", (msg) => {
|
||||
message = msg;
|
||||
});
|
||||
|
||||
|
||||
@ -43,8 +43,8 @@ export default class WakuMock extends EventEmitter<Message> {
|
||||
|
||||
public async send(message: string): Promise<void> {
|
||||
const timestamp = new Date();
|
||||
const handle = 'me';
|
||||
this.emit('message', {
|
||||
const handle = "me";
|
||||
this.emit("message", {
|
||||
timestamp,
|
||||
handle,
|
||||
message,
|
||||
@ -58,9 +58,9 @@ export default class WakuMock extends EventEmitter<Message> {
|
||||
}
|
||||
|
||||
private emitMessage() {
|
||||
const handle = 'you';
|
||||
const handle = "you";
|
||||
const timestamp = new Date();
|
||||
this.emit('message', {
|
||||
this.emit("message", {
|
||||
timestamp,
|
||||
handle,
|
||||
message: `This is message #${this.index++}.`,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Reader } from 'protobufjs/minimal';
|
||||
import { Reader } from "protobufjs/minimal";
|
||||
|
||||
import * as proto from './proto/chat_message';
|
||||
import * as proto from "./proto/chat_message";
|
||||
|
||||
/**
|
||||
* ChatMessage is used by the various show case waku apps that demonstrates
|
||||
@ -21,7 +21,7 @@ export class ChatMessage {
|
||||
text: string
|
||||
): ChatMessage {
|
||||
const timestampNumber = Math.floor(timestamp.valueOf() / 1000);
|
||||
const payload = Buffer.from(text, 'utf-8');
|
||||
const payload = Buffer.from(text, "utf-8");
|
||||
|
||||
return new ChatMessage({
|
||||
timestamp: timestampNumber,
|
||||
@ -57,9 +57,9 @@ export class ChatMessage {
|
||||
|
||||
get payloadAsUtf8(): string {
|
||||
if (!this.proto.payload) {
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
|
||||
return Buffer.from(this.proto.payload).toString('utf-8');
|
||||
return Buffer.from(this.proto.payload).toString("utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { multiaddr } from 'multiaddr';
|
||||
import PeerId from 'peer-id';
|
||||
import { Waku } from 'js-waku';
|
||||
import { multiaddr } from "multiaddr";
|
||||
import PeerId from "peer-id";
|
||||
import { Waku } from "js-waku";
|
||||
|
||||
function help(): string[] {
|
||||
return [
|
||||
'/nick <nickname>: set a new nickname',
|
||||
'/info: some information about the node',
|
||||
'/connect <Multiaddr>: connect to the given peer',
|
||||
'/help: Display this help',
|
||||
"/nick <nickname>: set a new nickname",
|
||||
"/info: some information about the node",
|
||||
"/connect <Multiaddr>: connect to the given peer",
|
||||
"/help: Display this help",
|
||||
];
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ function nick(
|
||||
setNick: (nick: string) => void
|
||||
): string[] {
|
||||
if (!nick) {
|
||||
return ['No nick provided'];
|
||||
return ["No nick provided"];
|
||||
}
|
||||
setNick(nick);
|
||||
return [`New nick: ${nick}`];
|
||||
@ -24,23 +24,23 @@ function nick(
|
||||
|
||||
function info(waku: Waku | undefined): string[] {
|
||||
if (!waku) {
|
||||
return ['Waku node is starting'];
|
||||
return ["Waku node is starting"];
|
||||
}
|
||||
return [`PeerId: ${waku.libp2p.peerId.toB58String()}`];
|
||||
}
|
||||
|
||||
function connect(peer: string | undefined, waku: Waku | undefined): string[] {
|
||||
if (!waku) {
|
||||
return ['Waku node is starting'];
|
||||
return ["Waku node is starting"];
|
||||
}
|
||||
if (!peer) {
|
||||
return ['No peer provided'];
|
||||
return ["No peer provided"];
|
||||
}
|
||||
try {
|
||||
const peerMultiaddr = multiaddr(peer);
|
||||
const peerId = peerMultiaddr.getPeerId();
|
||||
if (!peerId) {
|
||||
return ['Peer Id needed to dial'];
|
||||
return ["Peer Id needed to dial"];
|
||||
}
|
||||
waku.addPeerToAddressBook(PeerId.createFromB58String(peerId), [
|
||||
peerMultiaddr,
|
||||
@ -49,13 +49,13 @@ function connect(peer: string | undefined, waku: Waku | undefined): string[] {
|
||||
`${peerId}: ${peerMultiaddr.toString()} added to address book, autodial in progress`,
|
||||
];
|
||||
} catch (e) {
|
||||
return ['Invalid multiaddr: ' + e];
|
||||
return ["Invalid multiaddr: " + e];
|
||||
}
|
||||
}
|
||||
|
||||
async function peers(waku: Waku | undefined): Promise<string[]> {
|
||||
if (!waku) {
|
||||
return ['Waku node is starting'];
|
||||
return ["Waku node is starting"];
|
||||
}
|
||||
let response: string[] = [];
|
||||
const peers = [];
|
||||
@ -64,47 +64,47 @@ async function peers(waku: Waku | undefined): Promise<string[]> {
|
||||
peers.push(peer);
|
||||
}
|
||||
Array.from(peers).forEach((peer) => {
|
||||
response.push(peer.id.toB58String() + ':');
|
||||
let addresses = ' addresses: [';
|
||||
response.push(peer.id.toB58String() + ":");
|
||||
let addresses = " addresses: [";
|
||||
peer.addresses.forEach(({ multiaddr }) => {
|
||||
addresses += ' ' + multiaddr.toString() + ',';
|
||||
addresses += " " + multiaddr.toString() + ",";
|
||||
});
|
||||
addresses = addresses.replace(/,$/, '');
|
||||
addresses += ']';
|
||||
addresses = addresses.replace(/,$/, "");
|
||||
addresses += "]";
|
||||
response.push(addresses);
|
||||
let protocols = ' protocols: [';
|
||||
let protocols = " protocols: [";
|
||||
protocols += peer.protocols;
|
||||
protocols += ']';
|
||||
protocols += "]";
|
||||
response.push(protocols);
|
||||
});
|
||||
if (response.length === 0) {
|
||||
response.push('Not connected to any peer.');
|
||||
response.push("Not connected to any peer.");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
function connections(waku: Waku | undefined): string[] {
|
||||
if (!waku) {
|
||||
return ['Waku node is starting'];
|
||||
return ["Waku node is starting"];
|
||||
}
|
||||
let response: string[] = [];
|
||||
waku.libp2p.connections.forEach(
|
||||
(
|
||||
connections: import('libp2p-interfaces/src/connection/connection')[],
|
||||
connections: import("libp2p-interfaces/src/connection/connection")[],
|
||||
peerId
|
||||
) => {
|
||||
response.push(peerId + ':');
|
||||
let strConnections = ' connections: [';
|
||||
response.push(peerId + ":");
|
||||
let strConnections = " connections: [";
|
||||
connections.forEach((connection) => {
|
||||
strConnections += JSON.stringify(connection.stat);
|
||||
strConnections += '; ' + JSON.stringify(connection.streams);
|
||||
strConnections += "; " + JSON.stringify(connection.streams);
|
||||
});
|
||||
strConnections += ']';
|
||||
strConnections += "]";
|
||||
response.push(strConnections);
|
||||
}
|
||||
);
|
||||
if (response.length === 0) {
|
||||
response.push('Not connected to any peer.');
|
||||
response.push("Not connected to any peer.");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
@ -118,22 +118,22 @@ export default async function handleCommand(
|
||||
const args = parseInput(input);
|
||||
const command = args.shift()!;
|
||||
switch (command) {
|
||||
case '/help':
|
||||
case "/help":
|
||||
help().map((str) => response.push(str));
|
||||
break;
|
||||
case '/nick':
|
||||
case "/nick":
|
||||
nick(args.shift(), setNick).map((str) => response.push(str));
|
||||
break;
|
||||
case '/info':
|
||||
case "/info":
|
||||
info(waku).map((str) => response.push(str));
|
||||
break;
|
||||
case '/connect':
|
||||
case "/connect":
|
||||
connect(args.shift(), waku).map((str) => response.push(str));
|
||||
break;
|
||||
case '/peers':
|
||||
case "/peers":
|
||||
(await peers(waku)).map((str) => response.push(str));
|
||||
break;
|
||||
case '/connections':
|
||||
case "/connections":
|
||||
connections(waku).map((str) => response.push(str));
|
||||
break;
|
||||
default:
|
||||
@ -143,6 +143,6 @@ export default async function handleCommand(
|
||||
}
|
||||
|
||||
export function parseInput(input: string): string[] {
|
||||
const clean = input.trim().replaceAll(/\s\s+/g, ' ');
|
||||
return clean.split(' ');
|
||||
const clean = input.trim().replaceAll(/\s\s+/g, " ");
|
||||
return clean.split(" ");
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import "./index.css";
|
||||
import App from "./App";
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
/* eslint-disable */
|
||||
import Long from 'long';
|
||||
import _m0 from 'protobufjs/minimal';
|
||||
import Long from "long";
|
||||
import _m0 from "protobufjs/minimal";
|
||||
|
||||
export const protobufPackage = '';
|
||||
export const protobufPackage = "";
|
||||
|
||||
export interface ChatMessage {
|
||||
timestamp: number;
|
||||
@ -11,7 +11,7 @@ export interface ChatMessage {
|
||||
}
|
||||
|
||||
function createBaseChatMessage(): ChatMessage {
|
||||
return { timestamp: 0, nick: '', payload: new Uint8Array() };
|
||||
return { timestamp: 0, nick: "", payload: new Uint8Array() };
|
||||
}
|
||||
|
||||
export const ChatMessage = {
|
||||
@ -22,7 +22,7 @@ export const ChatMessage = {
|
||||
if (message.timestamp !== 0) {
|
||||
writer.uint32(8).uint64(message.timestamp);
|
||||
}
|
||||
if (message.nick !== '') {
|
||||
if (message.nick !== "") {
|
||||
writer.uint32(18).string(message.nick);
|
||||
}
|
||||
if (message.payload.length !== 0) {
|
||||
@ -64,7 +64,7 @@ export const ChatMessage = {
|
||||
message.nick =
|
||||
object.nick !== undefined && object.nick !== null
|
||||
? String(object.nick)
|
||||
: '';
|
||||
: "";
|
||||
message.payload =
|
||||
object.payload !== undefined && object.payload !== null
|
||||
? bytesFromBase64(object.payload)
|
||||
@ -89,7 +89,7 @@ export const ChatMessage = {
|
||||
): ChatMessage {
|
||||
const message = createBaseChatMessage();
|
||||
message.timestamp = object.timestamp ?? 0;
|
||||
message.nick = object.nick ?? '';
|
||||
message.nick = object.nick ?? "";
|
||||
message.payload = object.payload ?? new Uint8Array();
|
||||
return message;
|
||||
},
|
||||
@ -99,16 +99,16 @@ declare var self: any | undefined;
|
||||
declare var window: any | undefined;
|
||||
declare var global: any | undefined;
|
||||
var globalThis: any = (() => {
|
||||
if (typeof globalThis !== 'undefined') return globalThis;
|
||||
if (typeof self !== 'undefined') return self;
|
||||
if (typeof window !== 'undefined') return window;
|
||||
if (typeof global !== 'undefined') return global;
|
||||
throw 'Unable to locate global object';
|
||||
if (typeof globalThis !== "undefined") return globalThis;
|
||||
if (typeof self !== "undefined") return self;
|
||||
if (typeof window !== "undefined") return window;
|
||||
if (typeof global !== "undefined") return global;
|
||||
throw "Unable to locate global object";
|
||||
})();
|
||||
|
||||
const atob: (b64: string) => string =
|
||||
globalThis.atob ||
|
||||
((b64) => globalThis.Buffer.from(b64, 'base64').toString('binary'));
|
||||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
|
||||
function bytesFromBase64(b64: string): Uint8Array {
|
||||
const bin = atob(b64);
|
||||
const arr = new Uint8Array(bin.length);
|
||||
@ -120,13 +120,13 @@ function bytesFromBase64(b64: string): Uint8Array {
|
||||
|
||||
const btoa: (bin: string) => string =
|
||||
globalThis.btoa ||
|
||||
((bin) => globalThis.Buffer.from(bin, 'binary').toString('base64'));
|
||||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
|
||||
function base64FromBytes(arr: Uint8Array): string {
|
||||
const bin: string[] = [];
|
||||
for (const byte of arr) {
|
||||
bin.push(String.fromCharCode(byte));
|
||||
}
|
||||
return btoa(bin.join(''));
|
||||
return btoa(bin.join(""));
|
||||
}
|
||||
|
||||
type Builtin =
|
||||
@ -158,7 +158,7 @@ export type Exact<P, I extends P> = P extends Builtin
|
||||
|
||||
function longToNumber(long: Long): number {
|
||||
if (long.gt(Number.MAX_SAFE_INTEGER)) {
|
||||
throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER');
|
||||
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
|
||||
}
|
||||
return long.toNumber();
|
||||
}
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||
import "@testing-library/jest-dom";
|
||||
|
||||
2
examples/web-chat/src/types/types.d.ts
vendored
2
examples/web-chat/src/types/types.d.ts
vendored
@ -1 +1 @@
|
||||
declare module '@livechat/ui-kit';
|
||||
declare module "@livechat/ui-kit";
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// import settings from default config file
|
||||
let properties = null;
|
||||
const originalConfigFn = require('./karma.conf.js');
|
||||
const originalConfigFn = require("./karma.conf.js");
|
||||
originalConfigFn({
|
||||
set: function (arg) {
|
||||
properties = arg;
|
||||
@ -8,7 +8,7 @@ originalConfigFn({
|
||||
});
|
||||
|
||||
// pass `--grep '[live data]'` to mocha to only run live data tests
|
||||
properties.client.args = ['--grep', '[live data]]'];
|
||||
properties.client.args = ["--grep", "[live data]]"];
|
||||
|
||||
// export settings
|
||||
module.exports = function (config) {
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
process.env.CHROME_BIN = require('puppeteer').executablePath();
|
||||
process.env.CHROME_BIN = require("puppeteer").executablePath();
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
frameworks: ['mocha', 'karma-typescript'],
|
||||
files: ['src/lib/**/*.ts', 'src/proto/**/*.ts'],
|
||||
frameworks: ["mocha", "karma-typescript"],
|
||||
files: ["src/lib/**/*.ts", "src/proto/**/*.ts"],
|
||||
preprocessors: {
|
||||
'**/*.ts': ['karma-typescript', 'env'],
|
||||
"**/*.ts": ["karma-typescript", "env"],
|
||||
},
|
||||
envPreprocessor: ['CI'],
|
||||
envPreprocessor: ["CI"],
|
||||
plugins: [
|
||||
require('karma-mocha'),
|
||||
require('karma-typescript'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-env-preprocessor'),
|
||||
require("karma-mocha"),
|
||||
require("karma-typescript"),
|
||||
require("karma-chrome-launcher"),
|
||||
require("karma-env-preprocessor"),
|
||||
],
|
||||
reporters: ['progress', 'karma-typescript'],
|
||||
browsers: ['ChromeHeadless'],
|
||||
reporters: ["progress", "karma-typescript"],
|
||||
browsers: ["ChromeHeadless"],
|
||||
singleRun: true,
|
||||
client: {
|
||||
mocha: {
|
||||
@ -29,17 +29,17 @@ module.exports = function (config) {
|
||||
coverageOptions: {
|
||||
instrumentation: false,
|
||||
},
|
||||
tsconfig: './tsconfig.json',
|
||||
tsconfig: "./tsconfig.json",
|
||||
compilerOptions: {
|
||||
noEmit: false,
|
||||
},
|
||||
include: {
|
||||
mode: 'replace',
|
||||
values: ['src/lib/**/*.ts', 'src/proto/**/*.ts'],
|
||||
mode: "replace",
|
||||
values: ["src/lib/**/*.ts", "src/proto/**/*.ts"],
|
||||
},
|
||||
exclude: {
|
||||
mode: 'replace',
|
||||
values: ['node_modules/**'],
|
||||
mode: "replace",
|
||||
values: ["node_modules/**"],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -140,9 +140,6 @@
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"prettier": {
|
||||
"singleQuote": true
|
||||
},
|
||||
"nyc": {
|
||||
"extends": "@istanbuljs/nyc-config-typescript",
|
||||
"exclude": [
|
||||
|
||||
32
src/index.ts
32
src/index.ts
@ -1,33 +1,33 @@
|
||||
export { getNodesFromHostedJson } from './lib/discovery';
|
||||
export * as discovery from './lib/discovery';
|
||||
export { getNodesFromHostedJson } from "./lib/discovery";
|
||||
export * as discovery from "./lib/discovery";
|
||||
|
||||
export * as enr from './lib/enr';
|
||||
export * as enr from "./lib/enr";
|
||||
|
||||
export * as utils from './lib/utils';
|
||||
export * as utils from "./lib/utils";
|
||||
|
||||
export * as waku from './lib/waku';
|
||||
export { Waku, DefaultPubSubTopic } from './lib/waku';
|
||||
export * as waku from "./lib/waku";
|
||||
export { Waku, DefaultPubSubTopic } from "./lib/waku";
|
||||
|
||||
export * as waku_message from './lib/waku_message';
|
||||
export { WakuMessage } from './lib/waku_message';
|
||||
export * as waku_message from "./lib/waku_message";
|
||||
export { WakuMessage } from "./lib/waku_message";
|
||||
|
||||
export {
|
||||
generatePrivateKey,
|
||||
generateSymmetricKey,
|
||||
getPublicKey,
|
||||
} from './lib/waku_message/version_1';
|
||||
} from "./lib/waku_message/version_1";
|
||||
|
||||
export * as waku_light_push from './lib/waku_light_push';
|
||||
export * as waku_light_push from "./lib/waku_light_push";
|
||||
export {
|
||||
WakuLightPush,
|
||||
LightPushCodec,
|
||||
PushResponse,
|
||||
} from './lib/waku_light_push';
|
||||
} from "./lib/waku_light_push";
|
||||
|
||||
export * as waku_relay from './lib/waku_relay';
|
||||
export { WakuRelay, RelayCodecs } from './lib/waku_relay';
|
||||
export * as waku_relay from "./lib/waku_relay";
|
||||
export { WakuRelay, RelayCodecs } from "./lib/waku_relay";
|
||||
|
||||
export * as waku_store from './lib/waku_store';
|
||||
export { PageDirection, WakuStore, StoreCodec } from './lib/waku_store';
|
||||
export * as waku_store from "./lib/waku_store";
|
||||
export { PageDirection, WakuStore, StoreCodec } from "./lib/waku_store";
|
||||
|
||||
export * as proto from './proto';
|
||||
export * as proto from "./proto";
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import debug from 'debug';
|
||||
import { Multiaddr } from 'multiaddr';
|
||||
import debug from "debug";
|
||||
import { Multiaddr } from "multiaddr";
|
||||
|
||||
import { DnsNodeDiscovery } from './dns';
|
||||
import { DnsNodeDiscovery } from "./dns";
|
||||
|
||||
import { getNodesFromHostedJson, getPseudoRandomSubset } from './index';
|
||||
import { getNodesFromHostedJson, getPseudoRandomSubset } from "./index";
|
||||
|
||||
const dbg = debug('waku:discovery:bootstrap');
|
||||
const dbg = debug("waku:discovery:bootstrap");
|
||||
|
||||
/**
|
||||
* Setup discovery method used to bootstrap.
|
||||
@ -55,7 +55,7 @@ export class Bootstrap {
|
||||
const maxPeers = opts.maxPeers ?? Bootstrap.DefaultMaxPeers;
|
||||
|
||||
if (opts.default) {
|
||||
dbg('Use hosted list of peers.');
|
||||
dbg("Use hosted list of peers.");
|
||||
|
||||
this.getBootstrapPeers = getNodesFromHostedJson.bind(
|
||||
{},
|
||||
@ -69,13 +69,13 @@ export class Bootstrap {
|
||||
);
|
||||
const peers = getPseudoRandomSubset(allPeers, maxPeers);
|
||||
dbg(
|
||||
'Use provided list of peers (reduced to maxPeers)',
|
||||
"Use provided list of peers (reduced to maxPeers)",
|
||||
allPeers.map((ma) => ma.toString())
|
||||
);
|
||||
this.getBootstrapPeers = (): Promise<Multiaddr[]> =>
|
||||
Promise.resolve(peers);
|
||||
} else if (typeof opts.getPeers === 'function') {
|
||||
dbg('Bootstrap: Use provided getPeers function.');
|
||||
} else if (typeof opts.getPeers === "function") {
|
||||
dbg("Bootstrap: Use provided getPeers function.");
|
||||
const getPeers = opts.getPeers;
|
||||
|
||||
this.getBootstrapPeers = async (): Promise<Multiaddr[]> => {
|
||||
@ -87,7 +87,7 @@ export class Bootstrap {
|
||||
};
|
||||
} else if (opts.enrUrl) {
|
||||
const enrUrl = opts.enrUrl;
|
||||
dbg('Use provided EIP-1459 ENR Tree URL.');
|
||||
dbg("Use provided EIP-1459 ENR Tree URL.");
|
||||
|
||||
const dns = DnsNodeDiscovery.dnsOverHttp();
|
||||
|
||||
@ -97,7 +97,7 @@ export class Bootstrap {
|
||||
return enrs.map((enr) => enr.getFullMultiaddrs()).flat();
|
||||
};
|
||||
} else {
|
||||
dbg('No bootstrap method specified, no peer will be returned');
|
||||
dbg("No bootstrap method specified, no peer will be returned");
|
||||
this.getBootstrapPeers = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { expect } from 'chai';
|
||||
import { expect } from "chai";
|
||||
|
||||
import { DnsClient, DnsNodeDiscovery } from './dns';
|
||||
import testData from './testdata.json';
|
||||
import { DnsClient, DnsNodeDiscovery } from "./dns";
|
||||
import testData from "./testdata.json";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -11,14 +11,14 @@ declare global {
|
||||
|
||||
const mockData = testData.dns;
|
||||
|
||||
const host = 'nodes.example.org';
|
||||
const rootDomain = 'JORXBYVVM7AEKETX5DGXW44EAY';
|
||||
const branchDomainA = 'D2SNLTAGWNQ34NTQTPHNZDECFU';
|
||||
const branchDomainB = 'D3SNLTAGWNQ34NTQTPHNZDECFU';
|
||||
const branchDomainC = 'D4SNLTAGWNQ34NTQTPHNZDECFU';
|
||||
const branchDomainD = 'D5SNLTAGWNQ34NTQTPHNZDECFU';
|
||||
const partialBranchA = 'AAAA';
|
||||
const partialBranchB = 'BBBB';
|
||||
const host = "nodes.example.org";
|
||||
const rootDomain = "JORXBYVVM7AEKETX5DGXW44EAY";
|
||||
const branchDomainA = "D2SNLTAGWNQ34NTQTPHNZDECFU";
|
||||
const branchDomainB = "D3SNLTAGWNQ34NTQTPHNZDECFU";
|
||||
const branchDomainC = "D4SNLTAGWNQ34NTQTPHNZDECFU";
|
||||
const branchDomainD = "D5SNLTAGWNQ34NTQTPHNZDECFU";
|
||||
const partialBranchA = "AAAA";
|
||||
const partialBranchB = "BBBB";
|
||||
const singleBranch = `enrtree-branch:${branchDomainA}`;
|
||||
const doubleBranch = `enrtree-branch:${branchDomainA},${branchDomainB}`;
|
||||
const multiComponentBranch = [
|
||||
@ -52,7 +52,7 @@ class MockDNS implements DnsClient {
|
||||
}
|
||||
|
||||
resolveTXT(fqdn: string): Promise<string[]> {
|
||||
if (this.fqdnThrows.includes(fqdn)) throw 'Mock DNS throws.';
|
||||
if (this.fqdnThrows.includes(fqdn)) throw "Mock DNS throws.";
|
||||
|
||||
const res = this.fqdnRes.get(fqdn);
|
||||
|
||||
@ -62,7 +62,7 @@ class MockDNS implements DnsClient {
|
||||
}
|
||||
}
|
||||
|
||||
describe('DNS Node Discovery', () => {
|
||||
describe("DNS Node Discovery", () => {
|
||||
let mockDns: MockDNS;
|
||||
|
||||
beforeEach(() => {
|
||||
@ -70,7 +70,7 @@ describe('DNS Node Discovery', () => {
|
||||
mockDns.addRes(host, [mockData.enrRoot]);
|
||||
});
|
||||
|
||||
it('retrieves a single peer', async function () {
|
||||
it("retrieves a single peer", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [singleBranch]);
|
||||
mockDns.addRes(`${branchDomainA}.${host}`, [mockData.enrA]);
|
||||
|
||||
@ -78,11 +78,11 @@ describe('DNS Node Discovery', () => {
|
||||
const peers = await dnsNodeDiscovery.getPeers(1, [mockData.enrTree]);
|
||||
|
||||
expect(peers.length).to.eq(1);
|
||||
expect(peers[0].ip).to.eq('45.77.40.127');
|
||||
expect(peers[0].ip).to.eq("45.77.40.127");
|
||||
expect(peers[0].tcp).to.eq(30303);
|
||||
});
|
||||
|
||||
it('retrieves all peers (2) when maxQuantity larger than DNS tree size', async function () {
|
||||
it("retrieves all peers (2) when maxQuantity larger than DNS tree size", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [doubleBranch]);
|
||||
mockDns.addRes(`${branchDomainA}.${host}`, [mockData.enrA]);
|
||||
mockDns.addRes(`${branchDomainB}.${host}`, [mockData.enrB]);
|
||||
@ -94,7 +94,7 @@ describe('DNS Node Discovery', () => {
|
||||
expect(peers[0].ip).to.not.eq(peers[1].ip);
|
||||
});
|
||||
|
||||
it('retrieves all peers (3) when branch entries are composed of multiple strings', async function () {
|
||||
it("retrieves all peers (3) when branch entries are composed of multiple strings", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, multiComponentBranch);
|
||||
mockDns.addRes(`${branchDomainA}.${host}`, [mockData.enr]);
|
||||
mockDns.addRes(`${branchDomainB}.${host}`, [mockData.enrA]);
|
||||
@ -111,7 +111,7 @@ describe('DNS Node Discovery', () => {
|
||||
expect(peers[1].ip).to.not.eq(peers[2].ip);
|
||||
});
|
||||
|
||||
it('it tolerates circular branch references', async function () {
|
||||
it("it tolerates circular branch references", async function () {
|
||||
// root --> branchA
|
||||
// branchA --> branchA
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [singleBranch]);
|
||||
@ -123,7 +123,7 @@ describe('DNS Node Discovery', () => {
|
||||
expect(peers.length).to.eq(0);
|
||||
});
|
||||
|
||||
it('recovers when dns.resolve returns empty', async function () {
|
||||
it("recovers when dns.resolve returns empty", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [singleBranch]);
|
||||
|
||||
// Empty response case
|
||||
@ -141,7 +141,7 @@ describe('DNS Node Discovery', () => {
|
||||
expect(peers.length).to.eq(0);
|
||||
});
|
||||
|
||||
it('ignores domain fetching errors', async function () {
|
||||
it("ignores domain fetching errors", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [errorBranchA]);
|
||||
mockDns.addThrow(`${branchDomainC}.${host}`);
|
||||
|
||||
@ -150,14 +150,14 @@ describe('DNS Node Discovery', () => {
|
||||
expect(peers.length).to.eq(0);
|
||||
});
|
||||
|
||||
it('ignores unrecognized TXT record formats', async function () {
|
||||
it("ignores unrecognized TXT record formats", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [mockData.enrBranchBadPrefix]);
|
||||
const dnsNodeDiscovery = new DnsNodeDiscovery(mockDns);
|
||||
const peers = await dnsNodeDiscovery.getPeers(1, [mockData.enrTree]);
|
||||
expect(peers.length).to.eq(0);
|
||||
});
|
||||
|
||||
it('caches peers it previously fetched', async function () {
|
||||
it("caches peers it previously fetched", async function () {
|
||||
mockDns.addRes(`${rootDomain}.${host}`, [errorBranchB]);
|
||||
mockDns.addRes(`${branchDomainD}.${host}`, [mockData.enrA]);
|
||||
|
||||
@ -175,9 +175,9 @@ describe('DNS Node Discovery', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('DNS Node Discovery [live data]', function () {
|
||||
const publicKey = 'AOFTICU2XWDULNLZGRMQS4RIZPAZEHYMV4FYHAPW563HNRAOERP7C';
|
||||
const fqdn = 'test.waku.nodes.status.im';
|
||||
describe("DNS Node Discovery [live data]", function () {
|
||||
const publicKey = "AOFTICU2XWDULNLZGRMQS4RIZPAZEHYMV4FYHAPW563HNRAOERP7C";
|
||||
const fqdn = "test.waku.nodes.status.im";
|
||||
const enrTree = `enrtree://${publicKey}@${fqdn}`;
|
||||
const maxQuantity = 3;
|
||||
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import assert from 'assert';
|
||||
import assert from "assert";
|
||||
|
||||
import { debug } from 'debug';
|
||||
import { debug } from "debug";
|
||||
|
||||
import { ENR } from '../enr';
|
||||
import { ENR } from "../enr";
|
||||
|
||||
import { DnsOverHttps, Endpoints } from './dns_over_https';
|
||||
import { ENRTree } from './enrtree';
|
||||
import { DnsOverHttps, Endpoints } from "./dns_over_https";
|
||||
import { ENRTree } from "./enrtree";
|
||||
|
||||
const dbg = debug('waku:discovery:dns');
|
||||
const dbg = debug("waku:discovery:dns");
|
||||
|
||||
export type SearchContext = {
|
||||
domain: string;
|
||||
@ -130,13 +130,13 @@ export class DnsNodeDiscovery {
|
||||
|
||||
assert(
|
||||
response.length,
|
||||
'Received empty result array while fetching TXT record'
|
||||
"Received empty result array while fetching TXT record"
|
||||
);
|
||||
assert(response[0].length, 'Received empty TXT record');
|
||||
assert(response[0].length, "Received empty TXT record");
|
||||
|
||||
// Branch entries can be an array of strings of comma delimited subdomains, with
|
||||
// some subdomain strings split across the array elements
|
||||
const result = response.join('');
|
||||
const result = response.join("");
|
||||
|
||||
this._DNSTreeCache[subdomain] = result;
|
||||
return result;
|
||||
@ -148,7 +148,7 @@ function getEntryType(entry: string): string {
|
||||
if (entry.startsWith(ENRTree.BRANCH_PREFIX)) return ENRTree.BRANCH_PREFIX;
|
||||
if (entry.startsWith(ENRTree.RECORD_PREFIX)) return ENRTree.RECORD_PREFIX;
|
||||
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
@ -171,7 +171,7 @@ function selectRandomPath(branches: string[], context: SearchContext): string {
|
||||
}
|
||||
// If all possible paths are circular...
|
||||
if (Object.keys(circularRefs).length === branches.length) {
|
||||
throw new Error('Unresolvable circular path detected');
|
||||
throw new Error("Unresolvable circular path detected");
|
||||
}
|
||||
|
||||
// Randomly select a viable path
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { TxtAnswer } from 'dns-packet';
|
||||
import { TxtAnswer } from "dns-packet";
|
||||
import {
|
||||
endpoints as defaultEndpoints,
|
||||
Endpoint,
|
||||
EndpointProps,
|
||||
query,
|
||||
} from 'dns-query';
|
||||
} from "dns-query";
|
||||
|
||||
import { DnsClient } from './dns';
|
||||
import { DnsClient } from "./dns";
|
||||
|
||||
const { cloudflare, google, opendns } = defaultEndpoints;
|
||||
|
||||
export type Endpoints =
|
||||
| 'doh'
|
||||
| 'dns'
|
||||
| "doh"
|
||||
| "dns"
|
||||
| Iterable<Endpoint | EndpointProps | string>;
|
||||
|
||||
export class DnsOverHttps implements DnsClient {
|
||||
@ -31,7 +31,7 @@ export class DnsOverHttps implements DnsClient {
|
||||
|
||||
async resolveTXT(domain: string): Promise<string[]> {
|
||||
const response = await query({
|
||||
questions: [{ type: 'TXT', name: domain }],
|
||||
questions: [{ type: "TXT", name: domain }],
|
||||
});
|
||||
|
||||
const answers = response.answers as TxtAnswer[];
|
||||
@ -41,18 +41,18 @@ export class DnsOverHttps implements DnsClient {
|
||||
const result: string[] = [];
|
||||
|
||||
data.forEach((d) => {
|
||||
if (typeof d === 'string') {
|
||||
if (typeof d === "string") {
|
||||
result.push(d);
|
||||
} else if (Array.isArray(d)) {
|
||||
d.forEach((sd) => {
|
||||
if (typeof sd === 'string') {
|
||||
if (typeof sd === "string") {
|
||||
result.push(sd);
|
||||
} else {
|
||||
result.push(Buffer.from(sd).toString('utf-8'));
|
||||
result.push(Buffer.from(sd).toString("utf-8"));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result.push(Buffer.from(d).toString('utf-8'));
|
||||
result.push(Buffer.from(d).toString("utf-8"));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
import { expect } from 'chai';
|
||||
import { expect } from "chai";
|
||||
|
||||
import { ENRTree } from './enrtree';
|
||||
import testData from './testdata.json';
|
||||
import { ENRTree } from "./enrtree";
|
||||
import testData from "./testdata.json";
|
||||
|
||||
const dns = testData.dns;
|
||||
|
||||
describe('ENRTree', () => {
|
||||
describe("ENRTree", () => {
|
||||
// Root DNS entries
|
||||
it('ENRTree (root): should parse and verify and DNS root entry', () => {
|
||||
it("ENRTree (root): should parse and verify and DNS root entry", () => {
|
||||
const subdomain = ENRTree.parseAndVerifyRoot(dns.enrRoot, dns.publicKey);
|
||||
|
||||
expect(subdomain).to.eq('JORXBYVVM7AEKETX5DGXW44EAY');
|
||||
expect(subdomain).to.eq("JORXBYVVM7AEKETX5DGXW44EAY");
|
||||
});
|
||||
|
||||
it('ENRTree (root): should error if DNS root entry is mis-prefixed', () => {
|
||||
it("ENRTree (root): should error if DNS root entry is mis-prefixed", () => {
|
||||
try {
|
||||
ENRTree.parseAndVerifyRoot(dns.enrRootBadPrefix, dns.publicKey);
|
||||
} catch (err: unknown) {
|
||||
@ -24,33 +24,33 @@ describe('ENRTree', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('ENRTree (root): should error if DNS root entry signature is invalid', () => {
|
||||
it("ENRTree (root): should error if DNS root entry signature is invalid", () => {
|
||||
try {
|
||||
ENRTree.parseAndVerifyRoot(dns.enrRootBadSig, dns.publicKey);
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.toString()).includes('Unable to verify ENRTree root signature');
|
||||
expect(e.toString()).includes("Unable to verify ENRTree root signature");
|
||||
}
|
||||
});
|
||||
|
||||
it('ENRTree (root): should error if DNS root entry is malformed', () => {
|
||||
it("ENRTree (root): should error if DNS root entry is malformed", () => {
|
||||
try {
|
||||
ENRTree.parseAndVerifyRoot(dns.enrRootMalformed, dns.publicKey);
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.toString()).includes('Could not parse ENRTree root entry');
|
||||
expect(e.toString()).includes("Could not parse ENRTree root entry");
|
||||
}
|
||||
});
|
||||
|
||||
// Tree DNS entries
|
||||
it('ENRTree (tree): should parse a DNS tree entry', () => {
|
||||
it("ENRTree (tree): should parse a DNS tree entry", () => {
|
||||
const { publicKey, domain } = ENRTree.parseTree(dns.enrTree);
|
||||
|
||||
expect(publicKey).to.eq(dns.publicKey);
|
||||
expect(domain).to.eq('nodes.example.org');
|
||||
expect(domain).to.eq("nodes.example.org");
|
||||
});
|
||||
|
||||
it('ENRTree (tree): should error if DNS tree entry is mis-prefixed', () => {
|
||||
it("ENRTree (tree): should error if DNS tree entry is mis-prefixed", () => {
|
||||
try {
|
||||
ENRTree.parseTree(dns.enrTreeBadPrefix);
|
||||
} catch (err: unknown) {
|
||||
@ -61,28 +61,28 @@ describe('ENRTree', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('ENRTree (tree): should error if DNS tree entry is misformatted', () => {
|
||||
it("ENRTree (tree): should error if DNS tree entry is misformatted", () => {
|
||||
try {
|
||||
ENRTree.parseTree(dns.enrTreeMalformed);
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.toString()).includes('Could not parse ENRTree tree entry');
|
||||
expect(e.toString()).includes("Could not parse ENRTree tree entry");
|
||||
}
|
||||
});
|
||||
|
||||
// Branch entries
|
||||
it('ENRTree (branch): should parse and verify a single component DNS branch entry', () => {
|
||||
it("ENRTree (branch): should parse and verify a single component DNS branch entry", () => {
|
||||
const expected = [
|
||||
'D2SNLTAGWNQ34NTQTPHNZDECFU',
|
||||
'67BLTJEU5R2D5S3B4QKJSBRFCY',
|
||||
'A2HDMZBB4JIU53VTEGC4TG6P4A',
|
||||
"D2SNLTAGWNQ34NTQTPHNZDECFU",
|
||||
"67BLTJEU5R2D5S3B4QKJSBRFCY",
|
||||
"A2HDMZBB4JIU53VTEGC4TG6P4A",
|
||||
];
|
||||
|
||||
const branches = ENRTree.parseBranch(dns.enrBranch);
|
||||
expect(branches).to.deep.eq(expected);
|
||||
});
|
||||
|
||||
it('ENRTree (branch): should error if DNS branch entry is mis-prefixed', () => {
|
||||
it("ENRTree (branch): should error if DNS branch entry is mis-prefixed", () => {
|
||||
try {
|
||||
ENRTree.parseBranch(dns.enrBranchBadPrefix);
|
||||
} catch (err: unknown) {
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import assert from 'assert';
|
||||
import assert from "assert";
|
||||
|
||||
import base64url from 'base64url';
|
||||
import * as base32 from 'hi-base32';
|
||||
import { ecdsaVerify } from 'secp256k1';
|
||||
import base64url from "base64url";
|
||||
import * as base32 from "hi-base32";
|
||||
import { ecdsaVerify } from "secp256k1";
|
||||
|
||||
import { ENR } from '../enr';
|
||||
import { keccak256Buf } from '../utils';
|
||||
import { ENR } from "../enr";
|
||||
import { keccak256Buf } from "../utils";
|
||||
|
||||
export type ENRRootValues = {
|
||||
eRoot: string;
|
||||
@ -21,9 +21,9 @@ export type ENRTreeValues = {
|
||||
|
||||
export class ENRTree {
|
||||
public static readonly RECORD_PREFIX = ENR.RECORD_PREFIX;
|
||||
public static readonly TREE_PREFIX = 'enrtree:';
|
||||
public static readonly BRANCH_PREFIX = 'enrtree-branch:';
|
||||
public static readonly ROOT_PREFIX = 'enrtree-root:';
|
||||
public static readonly TREE_PREFIX = "enrtree:";
|
||||
public static readonly BRANCH_PREFIX = "enrtree-branch:";
|
||||
public static readonly ROOT_PREFIX = "enrtree-root:";
|
||||
|
||||
/**
|
||||
* Extracts the branch subdomain referenced by a DNS tree root string after verifying
|
||||
@ -41,7 +41,7 @@ export class ENRTree {
|
||||
// The signature is a 65-byte secp256k1 over the keccak256 hash
|
||||
// of the record content, excluding the `sig=` part, encoded as URL-safe base64 string
|
||||
// (Trailing recovery bit must be trimmed to pass `ecdsaVerify` method)
|
||||
const signedComponent = root.split(' sig')[0];
|
||||
const signedComponent = root.split(" sig")[0];
|
||||
const signedComponentBuffer = Buffer.from(signedComponent);
|
||||
const signatureBuffer = base64url
|
||||
.toBuffer(rootValues.signature)
|
||||
@ -54,7 +54,7 @@ export class ENRTree {
|
||||
keyBuffer
|
||||
);
|
||||
|
||||
assert(isVerified, 'Unable to verify ENRTree root signature');
|
||||
assert(isVerified, "Unable to verify ENRTree root signature");
|
||||
|
||||
return rootValues.eRoot;
|
||||
}
|
||||
@ -64,7 +64,7 @@ export class ENRTree {
|
||||
/^enrtree-root:v1 e=([^ ]+) l=([^ ]+) seq=(\d+) sig=([^ ]+)$/
|
||||
);
|
||||
|
||||
assert.ok(Array.isArray(matches), 'Could not parse ENRTree root entry');
|
||||
assert.ok(Array.isArray(matches), "Could not parse ENRTree root entry");
|
||||
|
||||
matches.shift(); // The first entry is the full match
|
||||
const [eRoot, lRoot, seq, signature] = matches;
|
||||
@ -90,13 +90,13 @@ export class ENRTree {
|
||||
|
||||
const matches = tree.match(/^enrtree:\/\/([^@]+)@(.+)$/);
|
||||
|
||||
assert.ok(Array.isArray(matches), 'Could not parse ENRTree tree entry');
|
||||
assert.ok(Array.isArray(matches), "Could not parse ENRTree tree entry");
|
||||
|
||||
matches.shift(); // The first entry is the full match
|
||||
const [publicKey, domain] = matches;
|
||||
|
||||
assert.ok(publicKey, 'Could not parse public key from ENRTree tree entry');
|
||||
assert.ok(domain, 'Could not parse domain from ENRTree tree entry');
|
||||
assert.ok(publicKey, "Could not parse public key from ENRTree tree entry");
|
||||
assert.ok(domain, "Could not parse domain from ENRTree tree entry");
|
||||
|
||||
return { publicKey, domain };
|
||||
}
|
||||
@ -111,6 +111,6 @@ export class ENRTree {
|
||||
`ENRTree branch entry must start with '${this.BRANCH_PREFIX}'`
|
||||
);
|
||||
|
||||
return branch.split(this.BRANCH_PREFIX)[1].split(',');
|
||||
return branch.split(this.BRANCH_PREFIX)[1].split(",");
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,18 +15,18 @@
|
||||
* @throws If the remote host is unreachable or the response cannot be parsed
|
||||
* according to the passed _path_.
|
||||
*/
|
||||
import axios from 'axios';
|
||||
import debug from 'debug';
|
||||
import { Multiaddr } from 'multiaddr';
|
||||
import axios from "axios";
|
||||
import debug from "debug";
|
||||
import { Multiaddr } from "multiaddr";
|
||||
|
||||
import { getPseudoRandomSubset } from './index';
|
||||
const dbg = debug('waku:discovery');
|
||||
import { getPseudoRandomSubset } from "./index";
|
||||
const dbg = debug("waku:discovery");
|
||||
|
||||
const DefaultWantedNumber = 1;
|
||||
|
||||
export async function getNodesFromHostedJson(
|
||||
path: string[] = ['fleets', 'wakuv2.prod', 'waku-websocket'],
|
||||
url = 'https://fleets.status.im/',
|
||||
path: string[] = ["fleets", "wakuv2.prod", "waku-websocket"],
|
||||
url = "https://fleets.status.im/",
|
||||
wantedNumber: number = DefaultWantedNumber
|
||||
): Promise<Multiaddr[]> {
|
||||
if (wantedNumber <= 0) {
|
||||
@ -34,7 +34,7 @@ export async function getNodesFromHostedJson(
|
||||
}
|
||||
|
||||
const res = await axios.get(url, {
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
|
||||
let nodes = res.data;
|
||||
@ -58,11 +58,11 @@ export async function getNodesFromHostedJson(
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof nodes === 'string') {
|
||||
if (typeof nodes === "string") {
|
||||
return [new Multiaddr(nodes)];
|
||||
}
|
||||
|
||||
if (typeof nodes === 'object') {
|
||||
if (typeof nodes === "object") {
|
||||
nodes = Object.values(nodes) as string[];
|
||||
nodes = nodes.map((node: string) => new Multiaddr(node));
|
||||
return getPseudoRandomSubset(nodes, wantedNumber);
|
||||
|
||||
@ -1,32 +1,32 @@
|
||||
import { expect } from 'chai';
|
||||
import { expect } from "chai";
|
||||
|
||||
import { getPseudoRandomSubset } from './index';
|
||||
import { getPseudoRandomSubset } from "./index";
|
||||
|
||||
describe('Discovery', () => {
|
||||
it('returns all values when wanted number matches available values', function () {
|
||||
const values = ['a', 'b', 'c'];
|
||||
describe("Discovery", () => {
|
||||
it("returns all values when wanted number matches available values", function () {
|
||||
const values = ["a", "b", "c"];
|
||||
|
||||
const res = getPseudoRandomSubset(values, 3);
|
||||
|
||||
expect(res.length).to.eq(3);
|
||||
expect(res.includes('a')).to.be.true;
|
||||
expect(res.includes('b')).to.be.true;
|
||||
expect(res.includes('c')).to.be.true;
|
||||
expect(res.includes("a")).to.be.true;
|
||||
expect(res.includes("b")).to.be.true;
|
||||
expect(res.includes("c")).to.be.true;
|
||||
});
|
||||
|
||||
it('returns all values when wanted number is greater than available values', function () {
|
||||
const values = ['a', 'b', 'c'];
|
||||
it("returns all values when wanted number is greater than available values", function () {
|
||||
const values = ["a", "b", "c"];
|
||||
|
||||
const res = getPseudoRandomSubset(values, 5);
|
||||
|
||||
expect(res.length).to.eq(3);
|
||||
expect(res.includes('a')).to.be.true;
|
||||
expect(res.includes('b')).to.be.true;
|
||||
expect(res.includes('c')).to.be.true;
|
||||
expect(res.includes("a")).to.be.true;
|
||||
expect(res.includes("b")).to.be.true;
|
||||
expect(res.includes("c")).to.be.true;
|
||||
});
|
||||
|
||||
it('returns a subset of values when wanted number is lesser than available values', function () {
|
||||
const values = ['a', 'b', 'c'];
|
||||
it("returns a subset of values when wanted number is lesser than available values", function () {
|
||||
const values = ["a", "b", "c"];
|
||||
|
||||
const res = getPseudoRandomSubset(values, 2);
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { shuffle } from 'libp2p-gossipsub/src/utils';
|
||||
import { shuffle } from "libp2p-gossipsub/src/utils";
|
||||
|
||||
export { getNodesFromHostedJson } from './hosted_json';
|
||||
export { Bootstrap, BootstrapOptions } from './bootstrap';
|
||||
export { DnsClient, DnsNodeDiscovery, SearchContext } from './dns';
|
||||
export { Endpoints, DnsOverHttps } from './dns_over_https';
|
||||
export { ENRTree, ENRTreeValues, ENRRootValues } from './enrtree';
|
||||
export { getNodesFromHostedJson } from "./hosted_json";
|
||||
export { Bootstrap, BootstrapOptions } from "./bootstrap";
|
||||
export { DnsClient, DnsNodeDiscovery, SearchContext } from "./dns";
|
||||
export { Endpoints, DnsOverHttps } from "./dns_over_https";
|
||||
export { ENRTree, ENRTreeValues, ENRRootValues } from "./enrtree";
|
||||
|
||||
export function getPseudoRandomSubset<T>(
|
||||
values: T[],
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
// Maximum encoded size of an ENR
|
||||
export const MAX_RECORD_SIZE = 300;
|
||||
|
||||
export const ERR_INVALID_ID = 'Invalid record id';
|
||||
export const ERR_INVALID_ID = "Invalid record id";
|
||||
|
||||
export const ERR_NO_SIGNATURE = 'No valid signature found';
|
||||
export const ERR_NO_SIGNATURE = "No valid signature found";
|
||||
|
||||
// The maximum length of byte size of a multiaddr to encode in the `multiaddr` field
|
||||
// The size is a big endian 16-bit unsigned integer
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { bufToHex } from '../utils';
|
||||
import { bufToHex } from "../utils";
|
||||
|
||||
import { NodeId } from './types';
|
||||
import { NodeId } from "./types";
|
||||
|
||||
export function createNodeId(buffer: Buffer): NodeId {
|
||||
if (buffer.length !== 32) {
|
||||
throw new Error('NodeId must be 32 bytes in length');
|
||||
throw new Error("NodeId must be 32 bytes in length");
|
||||
}
|
||||
return bufToHex(buffer);
|
||||
}
|
||||
|
||||
@ -1,323 +1,323 @@
|
||||
import { assert, expect } from 'chai';
|
||||
import { Multiaddr } from 'multiaddr';
|
||||
import PeerId from 'peer-id';
|
||||
import { assert, expect } from "chai";
|
||||
import { Multiaddr } from "multiaddr";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import { bufToHex } from '../utils';
|
||||
import { bufToHex } from "../utils";
|
||||
|
||||
import { ERR_INVALID_ID } from './constants';
|
||||
import { ENR } from './enr';
|
||||
import { createKeypairFromPeerId } from './keypair';
|
||||
import { ERR_INVALID_ID } from "./constants";
|
||||
import { ENR } from "./enr";
|
||||
import { createKeypairFromPeerId } from "./keypair";
|
||||
|
||||
import { v4 } from './index';
|
||||
import { v4 } from "./index";
|
||||
|
||||
describe('ENR', function () {
|
||||
describe('Txt codec', () => {
|
||||
it('should encodeTxt and decodeTxt', async () => {
|
||||
const peerId = await PeerId.create({ keyType: 'secp256k1' });
|
||||
describe("ENR", function () {
|
||||
describe("Txt codec", () => {
|
||||
it("should encodeTxt and decodeTxt", async () => {
|
||||
const peerId = await PeerId.create({ keyType: "secp256k1" });
|
||||
const enr = ENR.createFromPeerId(peerId);
|
||||
const keypair = createKeypairFromPeerId(peerId);
|
||||
enr.setLocationMultiaddr(new Multiaddr('/ip4/18.223.219.100/udp/9000'));
|
||||
enr.setLocationMultiaddr(new Multiaddr("/ip4/18.223.219.100/udp/9000"));
|
||||
enr.multiaddrs = [
|
||||
new Multiaddr(
|
||||
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss'
|
||||
"/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss"
|
||||
),
|
||||
new Multiaddr(
|
||||
'/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss'
|
||||
"/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss"
|
||||
),
|
||||
new Multiaddr(
|
||||
'/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss'
|
||||
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss"
|
||||
),
|
||||
];
|
||||
const txt = enr.encodeTxt(keypair.privateKey);
|
||||
expect(txt.slice(0, 4)).to.be.equal('enr:');
|
||||
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)
|
||||
);
|
||||
const multiaddr = enr2.getLocationMultiaddr('udp')!;
|
||||
expect(multiaddr.toString()).to.be.equal('/ip4/18.223.219.100/udp/9000');
|
||||
const multiaddr = enr2.getLocationMultiaddr("udp")!;
|
||||
expect(multiaddr.toString()).to.be.equal("/ip4/18.223.219.100/udp/9000");
|
||||
expect(enr2.multiaddrs).to.not.be.undefined;
|
||||
expect(enr2.multiaddrs!.length).to.be.equal(3);
|
||||
const multiaddrsAsStr = enr2.multiaddrs!.map((ma) => ma.toString());
|
||||
expect(multiaddrsAsStr).to.include(
|
||||
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss'
|
||||
"/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss"
|
||||
);
|
||||
expect(multiaddrsAsStr).to.include(
|
||||
'/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss'
|
||||
"/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss"
|
||||
);
|
||||
expect(multiaddrsAsStr).to.include(
|
||||
'/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss'
|
||||
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss"
|
||||
);
|
||||
});
|
||||
|
||||
it('should decode valid enr successfully', () => {
|
||||
it("should decode valid enr successfully", () => {
|
||||
const txt =
|
||||
'enr:-Ku4QMh15cIjmnq-co5S3tYaNXxDzKTgj0ufusA-QfZ66EWHNsULt2kb0eTHoo1Dkjvvf6CAHDS1Di-htjiPFZzaIPcLh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD2d10HAAABE________x8AgmlkgnY0gmlwhHZFkMSJc2VjcDI1NmsxoQIWSDEWdHwdEA3Lw2B_byeFQOINTZ0GdtF9DBjes6JqtIN1ZHCCIyg';
|
||||
"enr:-Ku4QMh15cIjmnq-co5S3tYaNXxDzKTgj0ufusA-QfZ66EWHNsULt2kb0eTHoo1Dkjvvf6CAHDS1Di-htjiPFZzaIPcLh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD2d10HAAABE________x8AgmlkgnY0gmlwhHZFkMSJc2VjcDI1NmsxoQIWSDEWdHwdEA3Lw2B_byeFQOINTZ0GdtF9DBjes6JqtIN1ZHCCIyg";
|
||||
const enr = ENR.decodeTxt(txt);
|
||||
const eth2 = enr.get('eth2') as Buffer;
|
||||
const eth2 = enr.get("eth2") as Buffer;
|
||||
expect(eth2).to.not.be.undefined;
|
||||
expect(bufToHex(eth2)).to.be.equal('f6775d0700000113ffffffffffff1f00');
|
||||
expect(bufToHex(eth2)).to.be.equal("f6775d0700000113ffffffffffff1f00");
|
||||
});
|
||||
|
||||
it('should decode valid ENR with multiaddrs successfully [shared test vector]', () => {
|
||||
it("should decode valid ENR with multiaddrs successfully [shared test vector]", () => {
|
||||
const txt =
|
||||
'enr:-QEnuEBEAyErHEfhiQxAVQoWowGTCuEF9fKZtXSd7H_PymHFhGJA3rGAYDVSHKCyJDGRLBGsloNbS8AZF33IVuefjOO6BIJpZIJ2NIJpcIQS39tkim11bHRpYWRkcnO4lgAvNihub2RlLTAxLmRvLWFtczMud2FrdXYyLnRlc3Quc3RhdHVzaW0ubmV0BgG73gMAODcxbm9kZS0wMS5hYy1jbi1ob25na29uZy1jLndha3V2Mi50ZXN0LnN0YXR1c2ltLm5ldAYBu94DACm9A62t7AQL4Ef5ZYZosRpQTzFVAB8jGjf1TER2wH-0zBOe1-MDBNLeA4lzZWNwMjU2azGhAzfsxbxyCkgCqq8WwYsVWH7YkpMLnU2Bw5xJSimxKav-g3VkcIIjKA';
|
||||
"enr:-QEnuEBEAyErHEfhiQxAVQoWowGTCuEF9fKZtXSd7H_PymHFhGJA3rGAYDVSHKCyJDGRLBGsloNbS8AZF33IVuefjOO6BIJpZIJ2NIJpcIQS39tkim11bHRpYWRkcnO4lgAvNihub2RlLTAxLmRvLWFtczMud2FrdXYyLnRlc3Quc3RhdHVzaW0ubmV0BgG73gMAODcxbm9kZS0wMS5hYy1jbi1ob25na29uZy1jLndha3V2Mi50ZXN0LnN0YXR1c2ltLm5ldAYBu94DACm9A62t7AQL4Ef5ZYZosRpQTzFVAB8jGjf1TER2wH-0zBOe1-MDBNLeA4lzZWNwMjU2azGhAzfsxbxyCkgCqq8WwYsVWH7YkpMLnU2Bw5xJSimxKav-g3VkcIIjKA";
|
||||
const enr = ENR.decodeTxt(txt);
|
||||
|
||||
expect(enr.multiaddrs).to.not.be.undefined;
|
||||
expect(enr.multiaddrs!.length).to.be.equal(3);
|
||||
const multiaddrsAsStr = enr.multiaddrs!.map((ma) => ma.toString());
|
||||
expect(multiaddrsAsStr).to.include(
|
||||
'/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss'
|
||||
"/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss"
|
||||
);
|
||||
expect(multiaddrsAsStr).to.include(
|
||||
'/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss'
|
||||
"/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss"
|
||||
);
|
||||
expect(multiaddrsAsStr).to.include(
|
||||
'/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss'
|
||||
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss"
|
||||
);
|
||||
});
|
||||
|
||||
it('should decode valid enr with tcp successfully', async () => {
|
||||
it("should decode valid enr with tcp successfully", async () => {
|
||||
const txt =
|
||||
'enr:-IS4QAmC_o1PMi5DbR4Bh4oHVyQunZblg4bTaottPtBodAhJZvxVlWW-4rXITPNg4mwJ8cW__D9FBDc9N4mdhyMqB-EBgmlkgnY0gmlwhIbRi9KJc2VjcDI1NmsxoQOevTdO6jvv3fRruxguKR-3Ge4bcFsLeAIWEDjrfaigNoN0Y3CCdl8';
|
||||
"enr:-IS4QAmC_o1PMi5DbR4Bh4oHVyQunZblg4bTaottPtBodAhJZvxVlWW-4rXITPNg4mwJ8cW__D9FBDc9N4mdhyMqB-EBgmlkgnY0gmlwhIbRi9KJc2VjcDI1NmsxoQOevTdO6jvv3fRruxguKR-3Ge4bcFsLeAIWEDjrfaigNoN0Y3CCdl8";
|
||||
const enr = ENR.decodeTxt(txt);
|
||||
expect(enr.tcp).to.not.be.undefined;
|
||||
expect(enr.tcp).to.be.equal(30303);
|
||||
expect(enr.ip).to.not.be.undefined;
|
||||
expect(enr.ip).to.be.equal('134.209.139.210');
|
||||
expect(enr.ip).to.be.equal("134.209.139.210");
|
||||
expect(enr.publicKey).to.not.be.undefined;
|
||||
expect(enr.peerId.toB58String()).to.be.equal(
|
||||
'16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ'
|
||||
"16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ"
|
||||
);
|
||||
});
|
||||
|
||||
it('should throw error - no id', () => {
|
||||
it("should throw error - no id", () => {
|
||||
try {
|
||||
const txt = Buffer.from(
|
||||
'656e723a2d435972595a62404b574342526c4179357a7a61445a584a42476b636e68344d486342465a6e75584e467264764a6a5830346a527a6a7a',
|
||||
'hex'
|
||||
"656e723a2d435972595a62404b574342526c4179357a7a61445a584a42476b636e68344d486342465a6e75584e467264764a6a5830346a527a6a7a",
|
||||
"hex"
|
||||
).toString();
|
||||
ENR.decodeTxt(txt);
|
||||
assert.fail('Expect error here');
|
||||
assert.fail("Expect error here");
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.be.equal(ERR_INVALID_ID);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw error - no public key', () => {
|
||||
it("should throw error - no public key", () => {
|
||||
try {
|
||||
const txt =
|
||||
'enr:-IS4QJ2d11eu6dC7E7LoXeLMgMP3kom1u3SE8esFSWvaHoo0dP1jg8O3-nx9ht-EO3CmG7L6OkHcMmoIh00IYWB92QABgmlkgnY0gmlwhH8AAAGJc2d11eu6dCsxoQIB_c-jQMOXsbjWkbN-kj99H57gfId5pfb4wa1qxwV4CIN1ZHCCIyk';
|
||||
"enr:-IS4QJ2d11eu6dC7E7LoXeLMgMP3kom1u3SE8esFSWvaHoo0dP1jg8O3-nx9ht-EO3CmG7L6OkHcMmoIh00IYWB92QABgmlkgnY0gmlwhH8AAAGJc2d11eu6dCsxoQIB_c-jQMOXsbjWkbN-kj99H57gfId5pfb4wa1qxwV4CIN1ZHCCIyk";
|
||||
ENR.decodeTxt(txt);
|
||||
assert.fail('Expect error here');
|
||||
assert.fail("Expect error here");
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.be.equal('Failed to verify ENR: No public key');
|
||||
expect(e.message).to.be.equal("Failed to verify ENR: No public key");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Verify', () => {
|
||||
it('should throw error - no id', () => {
|
||||
describe("Verify", () => {
|
||||
it("should throw error - no id", () => {
|
||||
try {
|
||||
const enr = new ENR({}, BigInt(0), Buffer.alloc(0));
|
||||
enr.verify(Buffer.alloc(0), Buffer.alloc(0));
|
||||
assert.fail('Expect error here');
|
||||
assert.fail("Expect error here");
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.be.equal(ERR_INVALID_ID);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw error - invalid id', () => {
|
||||
it("should throw error - invalid id", () => {
|
||||
try {
|
||||
const enr = new ENR(
|
||||
{ id: Buffer.from('v3') },
|
||||
{ id: Buffer.from("v3") },
|
||||
BigInt(0),
|
||||
Buffer.alloc(0)
|
||||
);
|
||||
enr.verify(Buffer.alloc(0), Buffer.alloc(0));
|
||||
assert.fail('Expect error here');
|
||||
assert.fail("Expect error here");
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.be.equal(ERR_INVALID_ID);
|
||||
}
|
||||
});
|
||||
|
||||
it('should throw error - no public key', () => {
|
||||
it("should throw error - no public key", () => {
|
||||
try {
|
||||
const enr = new ENR(
|
||||
{ id: Buffer.from('v4') },
|
||||
{ id: Buffer.from("v4") },
|
||||
BigInt(0),
|
||||
Buffer.alloc(0)
|
||||
);
|
||||
enr.verify(Buffer.alloc(0), Buffer.alloc(0));
|
||||
assert.fail('Expect error here');
|
||||
assert.fail("Expect error here");
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.be.equal('Failed to verify ENR: No public key');
|
||||
expect(e.message).to.be.equal("Failed to verify ENR: No public key");
|
||||
}
|
||||
});
|
||||
|
||||
it('should return false', () => {
|
||||
it("should return false", () => {
|
||||
const txt =
|
||||
'enr:-Ku4QMh15cIjmnq-co5S3tYaNXxDzKTgj0ufusA-QfZ66EWHNsULt2kb0eTHoo1Dkjvvf6CAHDS1Di-htjiPFZzaIPcLh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD2d10HAAABE________x8AgmlkgnY0gmlwhHZFkMSJc2VjcDI1NmsxoQIWSDEWdHwdEA3Lw2B_byeFQOINTZ0GdtF9DBjes6JqtIN1ZHCCIyg';
|
||||
"enr:-Ku4QMh15cIjmnq-co5S3tYaNXxDzKTgj0ufusA-QfZ66EWHNsULt2kb0eTHoo1Dkjvvf6CAHDS1Di-htjiPFZzaIPcLh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD2d10HAAABE________x8AgmlkgnY0gmlwhHZFkMSJc2VjcDI1NmsxoQIWSDEWdHwdEA3Lw2B_byeFQOINTZ0GdtF9DBjes6JqtIN1ZHCCIyg";
|
||||
const enr = ENR.decodeTxt(txt);
|
||||
// should have id and public key inside ENR
|
||||
expect(enr.verify(Buffer.alloc(32), Buffer.alloc(64))).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('Fuzzing testcases', () => {
|
||||
it('should throw error in invalid signature', () => {
|
||||
describe("Fuzzing testcases", () => {
|
||||
it("should throw error in invalid signature", () => {
|
||||
const buf = Buffer.from(
|
||||
'656e723a2d4b7634514147774f54385374716d7749354c486149796d494f346f6f464b664e6b456a576130663150384f73456c67426832496a622d4772445f2d623957346b6350466377796e354845516d526371584e716470566f3168656f42683246306447356c64484f494141414141414141414143455a58526f4d704141414141414141414141505f5f5f5f5f5f5f5f5f5f676d6c6b676e5930676d6c7768424c663232534a6332566a634449314e6d73786f514a78436e4536765f7832656b67595f756f45317274777a76477934306d7139654436365866485042576749494e315a48437f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f434436410d0a',
|
||||
'hex'
|
||||
"656e723a2d4b7634514147774f54385374716d7749354c486149796d494f346f6f464b664e6b456a576130663150384f73456c67426832496a622d4772445f2d623957346b6350466377796e354845516d526371584e716470566f3168656f42683246306447356c64484f494141414141414141414143455a58526f4d704141414141414141414141505f5f5f5f5f5f5f5f5f5f676d6c6b676e5930676d6c7768424c663232534a6332566a634449314e6d73786f514a78436e4536765f7832656b67595f756f45317274777a76477934306d7139654436365866485042576749494e315a48437f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f434436410d0a",
|
||||
"hex"
|
||||
).toString();
|
||||
try {
|
||||
ENR.decodeTxt(buf);
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.equal(
|
||||
'Decoded ENR invalid signature: must be a byte array'
|
||||
"Decoded ENR invalid signature: must be a byte array"
|
||||
);
|
||||
}
|
||||
});
|
||||
it('should throw error in invalid sequence number', () => {
|
||||
it("should throw error in invalid sequence number", () => {
|
||||
const buf = Buffer.from(
|
||||
'656e723a2d495334514b6b33ff583945717841337838334162436979416e537550444d764b353264433530486d31584744643574457951684d3356634a4c2d5062446b44673541507a5f706f76763022d48dcf992d5379716b306e616e636f4e572d656e7263713042676d6c6b676e5930676d6c77684838414141474a6332566a634449314e6d73786f514d31453579557370397638516a397476335a575843766146427672504e647a384b5049314e68576651577a494e315a4843434239410a',
|
||||
'hex'
|
||||
"656e723a2d495334514b6b33ff583945717841337838334162436979416e537550444d764b353264433530486d31584744643574457951684d3356634a4c2d5062446b44673541507a5f706f76763022d48dcf992d5379716b306e616e636f4e572d656e7263713042676d6c6b676e5930676d6c77684838414141474a6332566a634449314e6d73786f514d31453579557370397638516a397476335a575843766146427672504e647a384b5049314e68576651577a494e315a4843434239410a",
|
||||
"hex"
|
||||
).toString();
|
||||
try {
|
||||
ENR.decodeTxt(buf);
|
||||
} catch (err: unknown) {
|
||||
const e = err as Error;
|
||||
expect(e.message).to.equal(
|
||||
'Decoded ENR invalid sequence number: must be a byte array'
|
||||
"Decoded ENR invalid sequence number: must be a byte array"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('Static tests', () => {
|
||||
describe("Static tests", () => {
|
||||
let privateKey: Buffer;
|
||||
let record: ENR;
|
||||
|
||||
beforeEach(() => {
|
||||
const seq = 1n;
|
||||
privateKey = Buffer.from(
|
||||
'b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291',
|
||||
'hex'
|
||||
"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291",
|
||||
"hex"
|
||||
);
|
||||
record = ENR.createV4(v4.publicKey(privateKey));
|
||||
record.set('ip', Buffer.from('7f000001', 'hex'));
|
||||
record.set('udp', Buffer.from((30303).toString(16), 'hex'));
|
||||
record.set("ip", Buffer.from("7f000001", "hex"));
|
||||
record.set("udp", Buffer.from((30303).toString(16), "hex"));
|
||||
record.seq = seq;
|
||||
});
|
||||
|
||||
it('should properly compute the node id', () => {
|
||||
it("should properly compute the node id", () => {
|
||||
expect(record.nodeId).to.equal(
|
||||
'a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7'
|
||||
"a448f24c6d18e575453db13171562b71999873db5b286df957af199ec94617f7"
|
||||
);
|
||||
});
|
||||
|
||||
it('should encode/decode to RLP encoding', () => {
|
||||
it("should encode/decode to RLP encoding", () => {
|
||||
const decoded = ENR.decode(record.encode(privateKey));
|
||||
expect(decoded).to.deep.equal(record);
|
||||
});
|
||||
|
||||
it('should encode/decode to text encoding', () => {
|
||||
it("should encode/decode to text encoding", () => {
|
||||
// spec enr https://eips.ethereum.org/EIPS/eip-778
|
||||
const testTxt =
|
||||
'enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8';
|
||||
"enr:-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04jRzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0xOIN1ZHCCdl8";
|
||||
const decoded = ENR.decodeTxt(testTxt);
|
||||
expect(decoded.udp).to.be.equal(30303);
|
||||
expect(decoded.ip).to.be.equal('127.0.0.1');
|
||||
expect(decoded.ip).to.be.equal("127.0.0.1");
|
||||
expect(decoded).to.deep.equal(record);
|
||||
expect(record.encodeTxt(privateKey)).to.equal(testTxt);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiaddr getters and setters', () => {
|
||||
describe("Multiaddr getters and setters", () => {
|
||||
let privateKey: Buffer;
|
||||
let record: ENR;
|
||||
|
||||
beforeEach(() => {
|
||||
privateKey = Buffer.from(
|
||||
'b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291',
|
||||
'hex'
|
||||
"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291",
|
||||
"hex"
|
||||
);
|
||||
record = ENR.createV4(v4.publicKey(privateKey));
|
||||
});
|
||||
|
||||
it('should get / set UDP multiaddr', () => {
|
||||
const multi0 = new Multiaddr('/ip4/127.0.0.1/udp/30303');
|
||||
it("should get / set UDP multiaddr", () => {
|
||||
const multi0 = new Multiaddr("/ip4/127.0.0.1/udp/30303");
|
||||
const tuples0 = multi0.tuples();
|
||||
|
||||
if (!tuples0[0][1] || !tuples0[1][1]) {
|
||||
throw new Error('invalid multiaddr');
|
||||
throw new Error("invalid multiaddr");
|
||||
}
|
||||
// set underlying records
|
||||
record.set('ip', tuples0[0][1]);
|
||||
record.set('udp', tuples0[1][1]);
|
||||
record.set("ip", tuples0[0][1]);
|
||||
record.set("udp", tuples0[1][1]);
|
||||
// and get the multiaddr
|
||||
expect(record.getLocationMultiaddr('udp')!.toString()).to.equal(
|
||||
expect(record.getLocationMultiaddr("udp")!.toString()).to.equal(
|
||||
multi0.toString()
|
||||
);
|
||||
// set the multiaddr
|
||||
const multi1 = new Multiaddr('/ip4/0.0.0.0/udp/30300');
|
||||
const multi1 = new Multiaddr("/ip4/0.0.0.0/udp/30300");
|
||||
record.setLocationMultiaddr(multi1);
|
||||
// and get the multiaddr
|
||||
expect(record.getLocationMultiaddr('udp')!.toString()).to.equal(
|
||||
expect(record.getLocationMultiaddr("udp")!.toString()).to.equal(
|
||||
multi1.toString()
|
||||
);
|
||||
// and get the underlying records
|
||||
const tuples1 = multi1.tuples();
|
||||
expect(record.get('ip')).to.deep.equal(tuples1[0][1]);
|
||||
expect(record.get('udp')).to.deep.equal(tuples1[1][1]);
|
||||
expect(record.get("ip")).to.deep.equal(tuples1[0][1]);
|
||||
expect(record.get("udp")).to.deep.equal(tuples1[1][1]);
|
||||
});
|
||||
|
||||
it('should get / set TCP multiaddr', () => {
|
||||
const multi0 = new Multiaddr('/ip4/127.0.0.1/tcp/30303');
|
||||
it("should get / set TCP multiaddr", () => {
|
||||
const multi0 = new Multiaddr("/ip4/127.0.0.1/tcp/30303");
|
||||
const tuples0 = multi0.tuples();
|
||||
|
||||
if (!tuples0[0][1] || !tuples0[1][1]) {
|
||||
throw new Error('invalid multiaddr');
|
||||
throw new Error("invalid multiaddr");
|
||||
}
|
||||
|
||||
// set underlying records
|
||||
record.set('ip', tuples0[0][1]);
|
||||
record.set('tcp', tuples0[1][1]);
|
||||
record.set("ip", tuples0[0][1]);
|
||||
record.set("tcp", tuples0[1][1]);
|
||||
// and get the multiaddr
|
||||
expect(record.getLocationMultiaddr('tcp')!.toString()).to.equal(
|
||||
expect(record.getLocationMultiaddr("tcp")!.toString()).to.equal(
|
||||
multi0.toString()
|
||||
);
|
||||
// set the multiaddr
|
||||
const multi1 = new Multiaddr('/ip4/0.0.0.0/tcp/30300');
|
||||
const multi1 = new Multiaddr("/ip4/0.0.0.0/tcp/30300");
|
||||
record.setLocationMultiaddr(multi1);
|
||||
// and get the multiaddr
|
||||
expect(record.getLocationMultiaddr('tcp')!.toString()).to.equal(
|
||||
expect(record.getLocationMultiaddr("tcp")!.toString()).to.equal(
|
||||
multi1.toString()
|
||||
);
|
||||
// and get the underlying records
|
||||
const tuples1 = multi1.tuples();
|
||||
expect(record.get('ip')).to.deep.equal(tuples1[0][1]);
|
||||
expect(record.get('tcp')).to.deep.equal(tuples1[1][1]);
|
||||
expect(record.get("ip")).to.deep.equal(tuples1[0][1]);
|
||||
expect(record.get("tcp")).to.deep.equal(tuples1[1][1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Location multiaddr', async () => {
|
||||
const ip4 = '127.0.0.1';
|
||||
const ip6 = '::1';
|
||||
describe("Location multiaddr", async () => {
|
||||
const ip4 = "127.0.0.1";
|
||||
const ip6 = "::1";
|
||||
const tcp = 8080;
|
||||
const udp = 8080;
|
||||
let peerId;
|
||||
let enr: ENR;
|
||||
|
||||
before(async function () {
|
||||
peerId = await PeerId.create({ keyType: 'secp256k1' });
|
||||
peerId = await PeerId.create({ keyType: "secp256k1" });
|
||||
enr = ENR.createFromPeerId(peerId);
|
||||
enr.ip = ip4;
|
||||
enr.ip6 = ip6;
|
||||
@ -327,63 +327,63 @@ describe('ENR', function () {
|
||||
enr.udp6 = udp;
|
||||
});
|
||||
|
||||
it('should properly create location multiaddrs - udp4', () => {
|
||||
expect(enr.getLocationMultiaddr('udp4')).to.deep.equal(
|
||||
it("should properly create location multiaddrs - udp4", () => {
|
||||
expect(enr.getLocationMultiaddr("udp4")).to.deep.equal(
|
||||
new Multiaddr(`/ip4/${ip4}/udp/${udp}`)
|
||||
);
|
||||
});
|
||||
|
||||
it('should properly create location multiaddrs - tcp4', () => {
|
||||
expect(enr.getLocationMultiaddr('tcp4')).to.deep.equal(
|
||||
it("should properly create location multiaddrs - tcp4", () => {
|
||||
expect(enr.getLocationMultiaddr("tcp4")).to.deep.equal(
|
||||
new Multiaddr(`/ip4/${ip4}/tcp/${tcp}`)
|
||||
);
|
||||
});
|
||||
|
||||
it('should properly create location multiaddrs - udp6', () => {
|
||||
expect(enr.getLocationMultiaddr('udp6')).to.deep.equal(
|
||||
it("should properly create location multiaddrs - udp6", () => {
|
||||
expect(enr.getLocationMultiaddr("udp6")).to.deep.equal(
|
||||
new Multiaddr(`/ip6/${ip6}/udp/${udp}`)
|
||||
);
|
||||
});
|
||||
|
||||
it('should properly create location multiaddrs - tcp6', () => {
|
||||
expect(enr.getLocationMultiaddr('tcp6')).to.deep.equal(
|
||||
it("should properly create location multiaddrs - tcp6", () => {
|
||||
expect(enr.getLocationMultiaddr("tcp6")).to.deep.equal(
|
||||
new Multiaddr(`/ip6/${ip6}/tcp/${tcp}`)
|
||||
);
|
||||
});
|
||||
|
||||
it('should properly create location multiaddrs - udp', () => {
|
||||
it("should properly create location multiaddrs - udp", () => {
|
||||
// default to ip4
|
||||
expect(enr.getLocationMultiaddr('udp')).to.deep.equal(
|
||||
expect(enr.getLocationMultiaddr("udp")).to.deep.equal(
|
||||
new Multiaddr(`/ip4/${ip4}/udp/${udp}`)
|
||||
);
|
||||
// if ip6 is set, use it
|
||||
enr.ip = undefined;
|
||||
expect(enr.getLocationMultiaddr('udp')).to.deep.equal(
|
||||
expect(enr.getLocationMultiaddr("udp")).to.deep.equal(
|
||||
new Multiaddr(`/ip6/${ip6}/udp/${udp}`)
|
||||
);
|
||||
// if ip6 does not exist, use ip4
|
||||
enr.ip6 = undefined;
|
||||
enr.ip = ip4;
|
||||
expect(enr.getLocationMultiaddr('udp')).to.deep.equal(
|
||||
expect(enr.getLocationMultiaddr("udp")).to.deep.equal(
|
||||
new Multiaddr(`/ip4/${ip4}/udp/${udp}`)
|
||||
);
|
||||
enr.ip6 = ip6;
|
||||
});
|
||||
|
||||
it('should properly create location multiaddrs - tcp', () => {
|
||||
it("should properly create location multiaddrs - tcp", () => {
|
||||
// default to ip4
|
||||
expect(enr.getLocationMultiaddr('tcp')).to.deep.equal(
|
||||
expect(enr.getLocationMultiaddr("tcp")).to.deep.equal(
|
||||
new Multiaddr(`/ip4/${ip4}/tcp/${tcp}`)
|
||||
);
|
||||
// if ip6 is set, use it
|
||||
enr.ip = undefined;
|
||||
expect(enr.getLocationMultiaddr('tcp')).to.deep.equal(
|
||||
expect(enr.getLocationMultiaddr("tcp")).to.deep.equal(
|
||||
new Multiaddr(`/ip6/${ip6}/tcp/${tcp}`)
|
||||
);
|
||||
// if ip6 does not exist, use ip4
|
||||
enr.ip6 = undefined;
|
||||
enr.ip = ip4;
|
||||
expect(enr.getLocationMultiaddr('tcp')).to.deep.equal(
|
||||
expect(enr.getLocationMultiaddr("tcp")).to.deep.equal(
|
||||
new Multiaddr(`/ip4/${ip4}/tcp/${tcp}`)
|
||||
);
|
||||
enr.ip6 = ip6;
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import base64url from 'base64url';
|
||||
import { toBigIntBE } from 'bigint-buffer';
|
||||
import { Multiaddr, protocols } from 'multiaddr';
|
||||
import base64url from "base64url";
|
||||
import { toBigIntBE } from "bigint-buffer";
|
||||
import { Multiaddr, protocols } from "multiaddr";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import muConvert from 'multiaddr/src/convert';
|
||||
import PeerId from 'peer-id';
|
||||
import * as RLP from 'rlp';
|
||||
import { encode as varintEncode } from 'varint';
|
||||
import muConvert from "multiaddr/src/convert";
|
||||
import PeerId from "peer-id";
|
||||
import * as RLP from "rlp";
|
||||
import { encode as varintEncode } from "varint";
|
||||
|
||||
import {
|
||||
ERR_INVALID_ID,
|
||||
ERR_NO_SIGNATURE,
|
||||
MAX_RECORD_SIZE,
|
||||
MULTIADDR_LENGTH_SIZE,
|
||||
} from './constants';
|
||||
} from "./constants";
|
||||
import {
|
||||
createKeypair,
|
||||
createKeypairFromPeerId,
|
||||
createPeerIdFromKeypair,
|
||||
IKeypair,
|
||||
KeypairType,
|
||||
} from './keypair';
|
||||
import { ENRKey, ENRValue, NodeId, SequenceNumber } from './types';
|
||||
import * as v4 from './v4';
|
||||
} from "./keypair";
|
||||
import { ENRKey, ENRValue, NodeId, SequenceNumber } from "./types";
|
||||
import * as v4 from "./v4";
|
||||
|
||||
export class ENR extends Map<ENRKey, ENRValue> {
|
||||
public static readonly RECORD_PREFIX = 'enr:';
|
||||
public static readonly RECORD_PREFIX = "enr:";
|
||||
public seq: SequenceNumber;
|
||||
public signature: Buffer | null;
|
||||
|
||||
@ -42,7 +42,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
static createV4(publicKey: Buffer, kvs: Record<ENRKey, ENRValue> = {}): ENR {
|
||||
return new ENR({
|
||||
...kvs,
|
||||
id: Buffer.from('v4'),
|
||||
id: Buffer.from("v4"),
|
||||
secp256k1: publicKey,
|
||||
});
|
||||
}
|
||||
@ -62,18 +62,18 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
static decodeFromValues(decoded: Buffer[]): ENR {
|
||||
if (!Array.isArray(decoded)) {
|
||||
throw new Error('Decoded ENR must be an array');
|
||||
throw new Error("Decoded ENR must be an array");
|
||||
}
|
||||
if (decoded.length % 2 !== 0) {
|
||||
throw new Error('Decoded ENR must have an even number of elements');
|
||||
throw new Error("Decoded ENR must have an even number of elements");
|
||||
}
|
||||
const [signature, seq, ...kvs] = decoded;
|
||||
if (!signature || Array.isArray(signature)) {
|
||||
throw new Error('Decoded ENR invalid signature: must be a byte array');
|
||||
throw new Error("Decoded ENR invalid signature: must be a byte array");
|
||||
}
|
||||
if (!seq || Array.isArray(seq)) {
|
||||
throw new Error(
|
||||
'Decoded ENR invalid sequence number: must be a byte array'
|
||||
"Decoded ENR invalid sequence number: must be a byte array"
|
||||
);
|
||||
}
|
||||
const obj: Record<ENRKey, ENRValue> = {};
|
||||
@ -83,7 +83,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
const enr = new ENR(obj, toBigIntBE(seq), signature);
|
||||
|
||||
if (!enr.verify(RLP.encode([seq, ...kvs]), signature)) {
|
||||
throw new Error('Unable to verify ENR signature');
|
||||
throw new Error("Unable to verify ENR signature");
|
||||
}
|
||||
return enr;
|
||||
}
|
||||
@ -109,14 +109,14 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
const id = this.get('id') as Buffer;
|
||||
if (!id) throw new Error('id not found.');
|
||||
return id.toString('utf8');
|
||||
const id = this.get("id") as Buffer;
|
||||
if (!id) throw new Error("id not found.");
|
||||
return id.toString("utf8");
|
||||
}
|
||||
|
||||
get keypairType(): KeypairType {
|
||||
switch (this.id) {
|
||||
case 'v4':
|
||||
case "v4":
|
||||
return KeypairType.secp256k1;
|
||||
default:
|
||||
throw new Error(ERR_INVALID_ID);
|
||||
@ -125,8 +125,8 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
get publicKey(): Buffer {
|
||||
switch (this.id) {
|
||||
case 'v4':
|
||||
return this.get('secp256k1') as Buffer;
|
||||
case "v4":
|
||||
return this.get("secp256k1") as Buffer;
|
||||
default:
|
||||
throw new Error(ERR_INVALID_ID);
|
||||
}
|
||||
@ -142,7 +142,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
get nodeId(): NodeId {
|
||||
switch (this.id) {
|
||||
case 'v4':
|
||||
case "v4":
|
||||
return v4.nodeId(this.publicKey);
|
||||
default:
|
||||
throw new Error(ERR_INVALID_ID);
|
||||
@ -150,7 +150,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
}
|
||||
|
||||
get ip(): string | undefined {
|
||||
const raw = this.get('ip');
|
||||
const raw = this.get("ip");
|
||||
if (raw) {
|
||||
return muConvert.toString(protocols.names.ip4.code, raw) as string;
|
||||
} else {
|
||||
@ -160,14 +160,14 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
set ip(ip: string | undefined) {
|
||||
if (ip) {
|
||||
this.set('ip', muConvert.toBytes(protocols.names.ip4.code, ip));
|
||||
this.set("ip", muConvert.toBytes(protocols.names.ip4.code, ip));
|
||||
} else {
|
||||
this.delete('ip');
|
||||
this.delete("ip");
|
||||
}
|
||||
}
|
||||
|
||||
get tcp(): number | undefined {
|
||||
const raw = this.get('tcp');
|
||||
const raw = this.get("tcp");
|
||||
if (raw) {
|
||||
return Number(muConvert.toString(protocols.names.tcp.code, raw));
|
||||
} else {
|
||||
@ -177,14 +177,14 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
set tcp(port: number | undefined) {
|
||||
if (port === undefined) {
|
||||
this.delete('tcp');
|
||||
this.delete("tcp");
|
||||
} else {
|
||||
this.set('tcp', muConvert.toBytes(protocols.names.tcp.code, port));
|
||||
this.set("tcp", muConvert.toBytes(protocols.names.tcp.code, port));
|
||||
}
|
||||
}
|
||||
|
||||
get udp(): number | undefined {
|
||||
const raw = this.get('udp');
|
||||
const raw = this.get("udp");
|
||||
if (raw) {
|
||||
return Number(muConvert.toString(protocols.names.udp.code, raw));
|
||||
} else {
|
||||
@ -194,14 +194,14 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
set udp(port: number | undefined) {
|
||||
if (port === undefined) {
|
||||
this.delete('udp');
|
||||
this.delete("udp");
|
||||
} else {
|
||||
this.set('udp', muConvert.toBytes(protocols.names.udp.code, port));
|
||||
this.set("udp", muConvert.toBytes(protocols.names.udp.code, port));
|
||||
}
|
||||
}
|
||||
|
||||
get ip6(): string | undefined {
|
||||
const raw = this.get('ip6');
|
||||
const raw = this.get("ip6");
|
||||
if (raw) {
|
||||
return muConvert.toString(protocols.names.ip6.code, raw) as string;
|
||||
} else {
|
||||
@ -211,14 +211,14 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
set ip6(ip: string | undefined) {
|
||||
if (ip) {
|
||||
this.set('ip6', muConvert.toBytes(protocols.names.ip6.code, ip));
|
||||
this.set("ip6", muConvert.toBytes(protocols.names.ip6.code, ip));
|
||||
} else {
|
||||
this.delete('ip6');
|
||||
this.delete("ip6");
|
||||
}
|
||||
}
|
||||
|
||||
get tcp6(): number | undefined {
|
||||
const raw = this.get('tcp6');
|
||||
const raw = this.get("tcp6");
|
||||
if (raw) {
|
||||
return Number(muConvert.toString(protocols.names.tcp.code, raw));
|
||||
} else {
|
||||
@ -228,14 +228,14 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
set tcp6(port: number | undefined) {
|
||||
if (port === undefined) {
|
||||
this.delete('tcp6');
|
||||
this.delete("tcp6");
|
||||
} else {
|
||||
this.set('tcp6', muConvert.toBytes(protocols.names.tcp.code, port));
|
||||
this.set("tcp6", muConvert.toBytes(protocols.names.tcp.code, port));
|
||||
}
|
||||
}
|
||||
|
||||
get udp6(): number | undefined {
|
||||
const raw = this.get('udp6');
|
||||
const raw = this.get("udp6");
|
||||
if (raw) {
|
||||
return Number(muConvert.toString(protocols.names.udp.code, raw));
|
||||
} else {
|
||||
@ -245,9 +245,9 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
|
||||
set udp6(port: number | undefined) {
|
||||
if (port === undefined) {
|
||||
this.delete('udp6');
|
||||
this.delete("udp6");
|
||||
} else {
|
||||
this.set('udp6', muConvert.toBytes(protocols.names.udp.code, port));
|
||||
this.set("udp6", muConvert.toBytes(protocols.names.udp.code, port));
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,7 +264,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
* The multiaddresses stored in this field are expected to be location multiaddresses, ie, peer id less.
|
||||
*/
|
||||
get multiaddrs(): Multiaddr[] | undefined {
|
||||
const raw = this.get('multiaddrs');
|
||||
const raw = this.get("multiaddrs");
|
||||
|
||||
if (raw) {
|
||||
const multiaddrs = [];
|
||||
@ -286,7 +286,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
index += size + MULTIADDR_LENGTH_SIZE;
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error('Invalid value in multiaddrs field');
|
||||
throw new Error("Invalid value in multiaddrs field");
|
||||
}
|
||||
return multiaddrs;
|
||||
} else {
|
||||
@ -308,13 +308,13 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
*/
|
||||
set multiaddrs(multiaddrs: Multiaddr[] | undefined) {
|
||||
if (multiaddrs === undefined) {
|
||||
this.delete('multiaddrs');
|
||||
this.delete("multiaddrs");
|
||||
} else {
|
||||
let multiaddrsBuf = Buffer.from([]);
|
||||
|
||||
multiaddrs.forEach((multiaddr) => {
|
||||
if (multiaddr.getPeerId())
|
||||
throw new Error('`multiaddr` field MUST not contain peer id');
|
||||
throw new Error("`multiaddr` field MUST not contain peer id");
|
||||
|
||||
const bytes = multiaddr.bytes;
|
||||
|
||||
@ -334,38 +334,38 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
multiaddrsBuf = Buffer.concat([multiaddrsBuf, buf]);
|
||||
});
|
||||
|
||||
this.set('multiaddrs', multiaddrsBuf);
|
||||
this.set("multiaddrs", multiaddrsBuf);
|
||||
}
|
||||
}
|
||||
|
||||
getLocationMultiaddr(
|
||||
protocol: 'udp' | 'udp4' | 'udp6' | 'tcp' | 'tcp4' | 'tcp6'
|
||||
protocol: "udp" | "udp4" | "udp6" | "tcp" | "tcp4" | "tcp6"
|
||||
): Multiaddr | undefined {
|
||||
if (protocol === 'udp') {
|
||||
if (protocol === "udp") {
|
||||
return (
|
||||
this.getLocationMultiaddr('udp4') || this.getLocationMultiaddr('udp6')
|
||||
this.getLocationMultiaddr("udp4") || this.getLocationMultiaddr("udp6")
|
||||
);
|
||||
}
|
||||
if (protocol === 'tcp') {
|
||||
if (protocol === "tcp") {
|
||||
return (
|
||||
this.getLocationMultiaddr('tcp4') || this.getLocationMultiaddr('tcp6')
|
||||
this.getLocationMultiaddr("tcp4") || this.getLocationMultiaddr("tcp6")
|
||||
);
|
||||
}
|
||||
const isIpv6 = protocol.endsWith('6');
|
||||
const ipVal = this.get(isIpv6 ? 'ip6' : 'ip');
|
||||
const isIpv6 = protocol.endsWith("6");
|
||||
const ipVal = this.get(isIpv6 ? "ip6" : "ip");
|
||||
if (!ipVal) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const isUdp = protocol.startsWith('udp');
|
||||
const isTcp = protocol.startsWith('tcp');
|
||||
const isUdp = protocol.startsWith("udp");
|
||||
const isTcp = protocol.startsWith("tcp");
|
||||
let protoName, protoVal;
|
||||
if (isUdp) {
|
||||
protoName = 'udp';
|
||||
protoVal = isIpv6 ? this.get('udp6') : this.get('udp');
|
||||
protoName = "udp";
|
||||
protoVal = isIpv6 ? this.get("udp6") : this.get("udp");
|
||||
} else if (isTcp) {
|
||||
protoName = 'tcp';
|
||||
protoVal = isIpv6 ? this.get('tcp6') : this.get('tcp');
|
||||
protoName = "tcp";
|
||||
protoVal = isIpv6 ? this.get("tcp6") : this.get("tcp");
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
@ -379,7 +379,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
// N bytes for the ip address
|
||||
// 1 or 2 bytes for the protocol as buffer (tcp or udp)
|
||||
// 2 bytes for the port
|
||||
const ipMa = protocols.names[isIpv6 ? 'ip6' : 'ip4'];
|
||||
const ipMa = protocols.names[isIpv6 ? "ip6" : "ip4"];
|
||||
const ipByteLen = ipMa.size / 8;
|
||||
const protoMa = protocols.names[protoName];
|
||||
const protoBuf = varintEncode(protoMa.code);
|
||||
@ -396,23 +396,23 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
const protoNames = multiaddr.protoNames();
|
||||
if (
|
||||
protoNames.length !== 2 &&
|
||||
protoNames[1] !== 'udp' &&
|
||||
protoNames[1] !== 'tcp'
|
||||
protoNames[1] !== "udp" &&
|
||||
protoNames[1] !== "tcp"
|
||||
) {
|
||||
throw new Error('Invalid multiaddr');
|
||||
throw new Error("Invalid multiaddr");
|
||||
}
|
||||
const tuples = multiaddr.tuples();
|
||||
if (!tuples[0][1] || !tuples[1][1]) {
|
||||
throw new Error('Invalid multiaddr');
|
||||
throw new Error("Invalid multiaddr");
|
||||
}
|
||||
|
||||
// IPv4
|
||||
if (tuples[0][0] === 4) {
|
||||
this.set('ip', tuples[0][1]);
|
||||
this.set("ip", tuples[0][1]);
|
||||
this.set(protoNames[1], tuples[1][1]);
|
||||
} else {
|
||||
this.set('ip6', tuples[0][1]);
|
||||
this.set(protoNames[1] + '6', tuples[1][1]);
|
||||
this.set("ip6", tuples[0][1]);
|
||||
this.set(protoNames[1] + "6", tuples[1][1]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -425,7 +425,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
* @param protocol
|
||||
*/
|
||||
getFullMultiaddr(
|
||||
protocol: 'udp' | 'udp4' | 'udp6' | 'tcp' | 'tcp4' | 'tcp6'
|
||||
protocol: "udp" | "udp4" | "udp6" | "tcp" | "tcp4" | "tcp6"
|
||||
): Multiaddr | undefined {
|
||||
const locationMultiaddr = this.getLocationMultiaddr(protocol);
|
||||
if (locationMultiaddr) {
|
||||
@ -447,18 +447,18 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
}
|
||||
|
||||
verify(data: Buffer, signature: Buffer): boolean {
|
||||
if (!this.get('id') || this.id !== 'v4') {
|
||||
if (!this.get("id") || this.id !== "v4") {
|
||||
throw new Error(ERR_INVALID_ID);
|
||||
}
|
||||
if (!this.publicKey) {
|
||||
throw new Error('Failed to verify ENR: No public key');
|
||||
throw new Error("Failed to verify ENR: No public key");
|
||||
}
|
||||
return v4.verify(this.publicKey, data, signature);
|
||||
}
|
||||
|
||||
sign(data: Buffer, privateKey: Buffer): Buffer {
|
||||
switch (this.id) {
|
||||
case 'v4':
|
||||
case "v4":
|
||||
this.signature = v4.sign(privateKey, data);
|
||||
break;
|
||||
default:
|
||||
@ -488,7 +488,7 @@ export class ENR extends Map<ENRKey, ENRValue> {
|
||||
encode(privateKey?: Buffer): Buffer {
|
||||
const encoded = RLP.encode(this.encodeToValues(privateKey));
|
||||
if (encoded.length >= MAX_RECORD_SIZE) {
|
||||
throw new Error('ENR must be less than 300 bytes');
|
||||
throw new Error("ENR must be less than 300 bytes");
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as v4Crypto from './v4';
|
||||
import * as v4Crypto from "./v4";
|
||||
export const v4 = v4Crypto;
|
||||
export * from './constants';
|
||||
export * from './enr';
|
||||
export * from './types';
|
||||
export * from './create';
|
||||
export * from './keypair';
|
||||
export * from "./constants";
|
||||
export * from "./enr";
|
||||
export * from "./types";
|
||||
export * from "./create";
|
||||
export * from "./keypair";
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
export const ERR_TYPE_NOT_IMPLEMENTED = 'Keypair type not implemented';
|
||||
export const ERR_INVALID_KEYPAIR_TYPE = 'Invalid keypair type';
|
||||
export const ERR_TYPE_NOT_IMPLEMENTED = "Keypair type not implemented";
|
||||
export const ERR_INVALID_KEYPAIR_TYPE = "Invalid keypair type";
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { expect } from 'chai';
|
||||
import { keys } from 'libp2p-crypto';
|
||||
import PeerId from 'peer-id';
|
||||
import { expect } from "chai";
|
||||
import { keys } from "libp2p-crypto";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import {
|
||||
AbstractKeypair,
|
||||
createPeerIdFromKeypair,
|
||||
generateKeypair,
|
||||
KeypairType,
|
||||
} from './index';
|
||||
} from "./index";
|
||||
|
||||
const { supportedKeys } = keys;
|
||||
|
||||
describe('createPeerIdFromKeypair', function () {
|
||||
it('should properly create a PeerId from a secp256k1 keypair with private key', async function () {
|
||||
describe("createPeerIdFromKeypair", function () {
|
||||
it("should properly create a PeerId from a secp256k1 keypair with private key", async function () {
|
||||
const keypair = await generateKeypair(KeypairType.secp256k1);
|
||||
const privKey = new supportedKeys.secp256k1.Secp256k1PrivateKey(
|
||||
keypair.privateKey,
|
||||
@ -25,7 +25,7 @@ describe('createPeerIdFromKeypair', function () {
|
||||
expect(actualPeerId).to.be.deep.equal(expectedPeerId);
|
||||
});
|
||||
|
||||
it('should properly create a PeerId from a secp256k1 keypair without private key', async function () {
|
||||
it("should properly create a PeerId from a secp256k1 keypair without private key", async function () {
|
||||
const keypair = await generateKeypair(KeypairType.secp256k1);
|
||||
delete (keypair as AbstractKeypair)._privateKey;
|
||||
const pubKey = new supportedKeys.secp256k1.Secp256k1PublicKey(
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { keys } from 'libp2p-crypto';
|
||||
import mh from 'multihashes';
|
||||
import PeerId from 'peer-id';
|
||||
import { keys } from "libp2p-crypto";
|
||||
import mh from "multihashes";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
const { keysPBM, supportedKeys } = keys;
|
||||
|
||||
import { ERR_TYPE_NOT_IMPLEMENTED } from './constants';
|
||||
import { Secp256k1Keypair } from './secp256k1';
|
||||
import { IKeypair, KeypairType } from './types';
|
||||
import { ERR_TYPE_NOT_IMPLEMENTED } from "./constants";
|
||||
import { Secp256k1Keypair } from "./secp256k1";
|
||||
import { IKeypair, KeypairType } from "./types";
|
||||
|
||||
export * from './types';
|
||||
export * from './secp256k1';
|
||||
export * from "./types";
|
||||
export * from "./secp256k1";
|
||||
|
||||
export async function generateKeypair(type: KeypairType): Promise<IKeypair> {
|
||||
switch (type) {
|
||||
@ -47,7 +47,7 @@ export function createPeerIdFromKeypair(keypair: IKeypair): PeerId {
|
||||
const pubKey = new supportedKeys.secp256k1.Secp256k1PublicKey(
|
||||
keypair.publicKey
|
||||
);
|
||||
const id = mh.encode(pubKey.bytes, 'identity');
|
||||
const id = mh.encode(pubKey.bytes, "identity");
|
||||
return new PeerId(id, privKey, pubKey);
|
||||
}
|
||||
default:
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import crypto from 'crypto';
|
||||
import { Buffer } from "buffer";
|
||||
import crypto from "crypto";
|
||||
|
||||
import * as secp256k1 from 'secp256k1';
|
||||
import * as secp256k1 from "secp256k1";
|
||||
|
||||
import { AbstractKeypair, IKeypair, IKeypairClass, KeypairType } from './types';
|
||||
import { AbstractKeypair, IKeypair, IKeypairClass, KeypairType } from "./types";
|
||||
|
||||
export function secp256k1PublicKeyToCompressed(publicKey: Uint8Array): Buffer {
|
||||
if (publicKey.length === 64) {
|
||||
@ -69,7 +69,7 @@ export const Secp256k1Keypair: IKeypairClass = class Secp256k1Keypair
|
||||
};
|
||||
|
||||
function randomBytes(length: number): Uint8Array {
|
||||
if (typeof window !== 'undefined' && window && window.crypto) {
|
||||
if (typeof window !== "undefined" && window && window.crypto) {
|
||||
const array = new Uint8Array(length);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array;
|
||||
|
||||
@ -26,10 +26,10 @@ export abstract class AbstractKeypair {
|
||||
|
||||
constructor(privateKey?: Buffer, publicKey?: Buffer) {
|
||||
if ((this._privateKey = privateKey) && !this.privateKeyVerify()) {
|
||||
throw new Error('Invalid private key');
|
||||
throw new Error("Invalid private key");
|
||||
}
|
||||
if ((this._publicKey = publicKey) && !this.publicKeyVerify()) {
|
||||
throw new Error('Invalid private key');
|
||||
throw new Error("Invalid private key");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import crypto from 'crypto';
|
||||
import crypto from "crypto";
|
||||
|
||||
import { keccak256 } from 'js-sha3';
|
||||
import * as secp256k1 from 'secp256k1';
|
||||
import { keccak256 } from "js-sha3";
|
||||
import * as secp256k1 from "secp256k1";
|
||||
|
||||
import { createNodeId } from './create';
|
||||
import { NodeId } from './types';
|
||||
import { createNodeId } from "./create";
|
||||
import { NodeId } from "./types";
|
||||
|
||||
export function hash(input: Uint8Array): Buffer {
|
||||
return Buffer.from(keccak256.arrayBuffer(input));
|
||||
@ -44,7 +44,7 @@ export class ENRKeyPair {
|
||||
public static async create(privateKey?: Buffer): Promise<ENRKeyPair> {
|
||||
if (privateKey) {
|
||||
if (!secp256k1.privateKeyVerify(privateKey)) {
|
||||
throw new Error('Invalid private key');
|
||||
throw new Error("Invalid private key");
|
||||
}
|
||||
}
|
||||
const _privateKey = privateKey || (await createPrivateKey());
|
||||
@ -64,7 +64,7 @@ export class ENRKeyPair {
|
||||
}
|
||||
|
||||
function randomBytes(length: number): Uint8Array {
|
||||
if (typeof window !== 'undefined' && window && window.crypto) {
|
||||
if (typeof window !== "undefined" && window && window.crypto) {
|
||||
const array = new Uint8Array(length);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import Libp2p from 'libp2p';
|
||||
import { Peer } from 'libp2p/src/peer-store';
|
||||
import Libp2p from "libp2p";
|
||||
import { Peer } from "libp2p/src/peer-store";
|
||||
|
||||
/**
|
||||
* Returns a pseudo-random peer that supports the given protocol.
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { keccak256, Message } from 'js-sha3';
|
||||
import { keccak256, Message } from "js-sha3";
|
||||
|
||||
export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer {
|
||||
if (typeof hex === 'string') {
|
||||
return Buffer.from(hex.replace(/^0x/i, ''), 'hex');
|
||||
if (typeof hex === "string") {
|
||||
return Buffer.from(hex.replace(/^0x/i, ""), "hex");
|
||||
} else {
|
||||
return Buffer.from(hex);
|
||||
}
|
||||
@ -10,7 +10,7 @@ export function hexToBuf(hex: string | Buffer | Uint8Array): Buffer {
|
||||
|
||||
export function bufToHex(buf: Uint8Array | Buffer | ArrayBuffer): string {
|
||||
const _buf = Buffer.from(buf);
|
||||
return _buf.toString('hex');
|
||||
return _buf.toString("hex");
|
||||
}
|
||||
|
||||
export function equalByteArrays(
|
||||
@ -19,13 +19,13 @@ export function equalByteArrays(
|
||||
): boolean {
|
||||
let aBuf: Buffer;
|
||||
let bBuf: Buffer;
|
||||
if (typeof a === 'string') {
|
||||
if (typeof a === "string") {
|
||||
aBuf = hexToBuf(a);
|
||||
} else {
|
||||
aBuf = Buffer.from(a);
|
||||
}
|
||||
|
||||
if (typeof b === 'string') {
|
||||
if (typeof b === "string") {
|
||||
bBuf = hexToBuf(b);
|
||||
} else {
|
||||
bBuf = Buffer.from(b);
|
||||
|
||||
@ -1,33 +1,33 @@
|
||||
import { expect } from 'chai';
|
||||
import debug from 'debug';
|
||||
import PeerId from 'peer-id';
|
||||
import { expect } from "chai";
|
||||
import debug from "debug";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
NOISE_KEY_2,
|
||||
} from '../test_utils/';
|
||||
} from "../test_utils/";
|
||||
|
||||
import { Protocols, Waku } from './waku';
|
||||
import { WakuMessage } from './waku_message';
|
||||
import { generateSymmetricKey } from './waku_message/version_1';
|
||||
import { Protocols, Waku } from "./waku";
|
||||
import { WakuMessage } from "./waku_message";
|
||||
import { generateSymmetricKey } from "./waku_message/version_1";
|
||||
|
||||
const dbg = debug('waku:test');
|
||||
const dbg = debug("waku:test");
|
||||
|
||||
const TestContentTopic = '/test/1/waku/utf8';
|
||||
const TestContentTopic = "/test/1/waku/utf8";
|
||||
|
||||
describe('Waku Dial [node only]', function () {
|
||||
describe('Interop: Nim', function () {
|
||||
describe("Waku Dial [node only]", function () {
|
||||
describe("Interop: Nim", function () {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('js connects to nim', async function () {
|
||||
it("js connects to nim", async function () {
|
||||
this.timeout(20_000);
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start();
|
||||
@ -44,16 +44,16 @@ describe('Waku Dial [node only]', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Bootstrap', function () {
|
||||
describe("Bootstrap", function () {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Passing an array', async function () {
|
||||
it("Passing an array", async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -66,7 +66,7 @@ describe('Waku Dial [node only]', function () {
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
waku.libp2p.connectionManager.on("peer:connect", (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
@ -74,7 +74,7 @@ describe('Waku Dial [node only]', function () {
|
||||
expect(connectedPeerID.toB58String()).to.eq(multiAddrWithId.getPeerId());
|
||||
});
|
||||
|
||||
it('Passing a function', async function () {
|
||||
it("Passing a function", async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -90,7 +90,7 @@ describe('Waku Dial [node only]', function () {
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
waku.libp2p.connectionManager.on("peer:connect", (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
@ -101,9 +101,9 @@ describe('Waku Dial [node only]', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Decryption Keys', () => {
|
||||
describe("Decryption Keys", () => {
|
||||
afterEach(function () {
|
||||
if (this.currentTest?.state === 'failed') {
|
||||
if (this.currentTest?.state === "failed") {
|
||||
console.log(`Test failed, log file name is ${makeLogFileName(this)}`);
|
||||
}
|
||||
});
|
||||
@ -116,7 +116,7 @@ describe('Decryption Keys', () => {
|
||||
Waku.create({ staticNoiseKey: NOISE_KEY_1 }),
|
||||
Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: { addresses: { listen: ['/ip4/0.0.0.0/tcp/0/ws'] } },
|
||||
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
|
||||
}),
|
||||
]);
|
||||
|
||||
@ -129,19 +129,19 @@ describe('Decryption Keys', () => {
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
!!waku1 && waku1.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku1 && waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Used by Waku Relay', async function () {
|
||||
it("Used by Waku Relay", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
waku2.addDecryptionKey(symKey);
|
||||
|
||||
const messageText = 'Message is encrypted';
|
||||
const messageTimestamp = new Date('1995-12-17T03:24:00');
|
||||
const messageText = "Message is encrypted";
|
||||
const messageTimestamp = new Date("1995-12-17T03:24:00");
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic,
|
||||
@ -166,30 +166,30 @@ describe('Decryption Keys', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Wait for remote peer / get peers', function () {
|
||||
describe("Wait for remote peer / get peers", function () {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Relay', async function () {
|
||||
it("Relay", async function () {
|
||||
this.timeout(20_000);
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start();
|
||||
const multiAddrWithId = await nimWaku.getMultiaddrWithId();
|
||||
|
||||
dbg('Create');
|
||||
dbg("Create");
|
||||
waku = await Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
});
|
||||
dbg('Dial');
|
||||
dbg("Dial");
|
||||
await waku.dial(multiAddrWithId);
|
||||
dbg('waitForRemotePeer');
|
||||
dbg("waitForRemotePeer");
|
||||
await waku.waitForRemotePeer([Protocols.Relay]);
|
||||
dbg('Done, get peers');
|
||||
dbg("Done, get peers");
|
||||
const peers = waku.relay.getPeers();
|
||||
const nimPeerId = multiAddrWithId.getPeerId();
|
||||
|
||||
@ -197,7 +197,7 @@ describe('Wait for remote peer / get peers', function () {
|
||||
expect(peers.has(nimPeerId as string)).to.be.true;
|
||||
});
|
||||
|
||||
it('Store', async function () {
|
||||
it("Store", async function () {
|
||||
this.timeout(20_000);
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ persistMessages: true });
|
||||
@ -220,7 +220,7 @@ describe('Wait for remote peer / get peers', function () {
|
||||
expect(peers.includes(nimPeerId as string)).to.be.true;
|
||||
});
|
||||
|
||||
it('LightPush', async function () {
|
||||
it("LightPush", async function () {
|
||||
this.timeout(20_000);
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ lightpush: true });
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { expect } from 'chai';
|
||||
import PeerId from 'peer-id';
|
||||
import { expect } from "chai";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import { Waku } from './waku';
|
||||
import { Waku } from "./waku";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -9,12 +9,12 @@ declare global {
|
||||
}
|
||||
}
|
||||
|
||||
describe('Waku Dial', function () {
|
||||
describe('Bootstrap [live data]', function () {
|
||||
describe("Waku Dial", function () {
|
||||
describe("Bootstrap [live data]", function () {
|
||||
let waku: Waku;
|
||||
|
||||
afterEach(function () {
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
before(function () {
|
||||
@ -23,7 +23,7 @@ describe('Waku Dial', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('Enabling default [live data]', async function () {
|
||||
it("Enabling default [live data]", async function () {
|
||||
// This test depends on fleets.status.im being online.
|
||||
// This dependence must be removed once DNS discovery is implemented
|
||||
this.timeout(20_000);
|
||||
@ -33,7 +33,7 @@ describe('Waku Dial', function () {
|
||||
});
|
||||
|
||||
const connectedPeerID: PeerId = await new Promise((resolve) => {
|
||||
waku.libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
waku.libp2p.connectionManager.on("peer:connect", (connection) => {
|
||||
resolve(connection.remotePeer);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import { bytes } from '@chainsafe/libp2p-noise/dist/src/@types/basic';
|
||||
import { Noise } from '@chainsafe/libp2p-noise/dist/src/noise';
|
||||
import debug from 'debug';
|
||||
import Libp2p, { Connection, Libp2pModules, Libp2pOptions } from 'libp2p';
|
||||
import Libp2pBootstrap from 'libp2p-bootstrap';
|
||||
import { MuxedStream } from 'libp2p-interfaces/dist/src/stream-muxer/types';
|
||||
import { bytes } from "@chainsafe/libp2p-noise/dist/src/@types/basic";
|
||||
import { Noise } from "@chainsafe/libp2p-noise/dist/src/noise";
|
||||
import debug from "debug";
|
||||
import Libp2p, { Connection, Libp2pModules, Libp2pOptions } from "libp2p";
|
||||
import Libp2pBootstrap from "libp2p-bootstrap";
|
||||
import { MuxedStream } from "libp2p-interfaces/dist/src/stream-muxer/types";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import Mplex from 'libp2p-mplex';
|
||||
import Mplex from "libp2p-mplex";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import Websockets from 'libp2p-websockets';
|
||||
import Websockets from "libp2p-websockets";
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: No types available
|
||||
import filters from 'libp2p-websockets/src/filters';
|
||||
import PingService from 'libp2p/src/ping';
|
||||
import { Multiaddr, multiaddr } from 'multiaddr';
|
||||
import PeerId from 'peer-id';
|
||||
import filters from "libp2p-websockets/src/filters";
|
||||
import PingService from "libp2p/src/ping";
|
||||
import { Multiaddr, multiaddr } from "multiaddr";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import { Bootstrap, BootstrapOptions } from './discovery';
|
||||
import { LightPushCodec, WakuLightPush } from './waku_light_push';
|
||||
import { DecryptionMethod, WakuMessage } from './waku_message';
|
||||
import { RelayCodecs, WakuRelay } from './waku_relay';
|
||||
import { RelayPingContentTopic } from './waku_relay/constants';
|
||||
import { StoreCodec, WakuStore } from './waku_store';
|
||||
import { Bootstrap, BootstrapOptions } from "./discovery";
|
||||
import { LightPushCodec, WakuLightPush } from "./waku_light_push";
|
||||
import { DecryptionMethod, WakuMessage } from "./waku_message";
|
||||
import { RelayCodecs, WakuRelay } from "./waku_relay";
|
||||
import { RelayPingContentTopic } from "./waku_relay/constants";
|
||||
import { StoreCodec, WakuStore } from "./waku_store";
|
||||
|
||||
const websocketsTransportKey = Websockets.prototype[Symbol.toStringTag];
|
||||
|
||||
@ -32,14 +32,14 @@ export const DefaultRelayKeepAliveValueSecs = 5 * 60;
|
||||
/**
|
||||
* DefaultPubSubTopic is the default gossipsub topic to use for Waku.
|
||||
*/
|
||||
export const DefaultPubSubTopic = '/waku/2/default-waku/proto';
|
||||
export const DefaultPubSubTopic = "/waku/2/default-waku/proto";
|
||||
|
||||
const dbg = debug('waku:waku');
|
||||
const dbg = debug("waku:waku");
|
||||
|
||||
export enum Protocols {
|
||||
Relay = 'relay',
|
||||
Store = 'store',
|
||||
LightPush = 'lightpush',
|
||||
Relay = "relay",
|
||||
Store = "store",
|
||||
LightPush = "lightpush",
|
||||
}
|
||||
|
||||
export interface CreateOptions {
|
||||
@ -78,7 +78,7 @@ export interface CreateOptions {
|
||||
* allowing its omission and letting Waku set good defaults.
|
||||
* Notes that some values are overridden by {@link Waku} to ensure it implements the Waku protocol.
|
||||
*/
|
||||
libp2p?: Omit<Libp2pOptions & import('libp2p').CreateOptions, 'modules'> & {
|
||||
libp2p?: Omit<Libp2pOptions & import("libp2p").CreateOptions, "modules"> & {
|
||||
modules?: Partial<Libp2pModules>;
|
||||
};
|
||||
/**
|
||||
@ -130,11 +130,11 @@ export class Waku {
|
||||
const relayKeepAlive =
|
||||
options.relayKeepAlive || DefaultRelayKeepAliveValueSecs;
|
||||
|
||||
libp2p.connectionManager.on('peer:connect', (connection: Connection) => {
|
||||
libp2p.connectionManager.on("peer:connect", (connection: Connection) => {
|
||||
this.startKeepAlive(connection.remotePeer, pingKeepAlive, relayKeepAlive);
|
||||
});
|
||||
|
||||
libp2p.connectionManager.on('peer:disconnect', (connection: Connection) => {
|
||||
libp2p.connectionManager.on("peer:disconnect", (connection: Connection) => {
|
||||
this.stopKeepAlive(connection.remotePeer);
|
||||
});
|
||||
|
||||
@ -210,7 +210,7 @@ export class Waku {
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
dbg('Failed to retrieve bootstrap nodes', e);
|
||||
dbg("Failed to retrieve bootstrap nodes", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,13 +249,13 @@ export class Waku {
|
||||
multiaddrs: Multiaddr[] | string[]
|
||||
): void {
|
||||
let peer;
|
||||
if (typeof peerId === 'string') {
|
||||
if (typeof peerId === "string") {
|
||||
peer = PeerId.createFromB58String(peerId);
|
||||
} else {
|
||||
peer = peerId;
|
||||
}
|
||||
const addresses = multiaddrs.map((addr: Multiaddr | string) => {
|
||||
if (typeof addr === 'string') {
|
||||
if (typeof addr === "string") {
|
||||
return multiaddr(addr);
|
||||
} else {
|
||||
return addr;
|
||||
@ -302,10 +302,10 @@ export class Waku {
|
||||
const localMultiaddr = this.libp2p.multiaddrs.find((addr) =>
|
||||
addr.toString().match(/127\.0\.0\.1/)
|
||||
);
|
||||
if (!localMultiaddr || localMultiaddr.toString() === '') {
|
||||
throw 'Not listening on localhost';
|
||||
if (!localMultiaddr || localMultiaddr.toString() === "") {
|
||||
throw "Not listening on localhost";
|
||||
}
|
||||
return localMultiaddr + '/p2p/' + this.libp2p.peerId.toB58String();
|
||||
return localMultiaddr + "/p2p/" + this.libp2p.peerId.toB58String();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -325,10 +325,10 @@ export class Waku {
|
||||
if (peers.size == 0) {
|
||||
// No peer yet available, wait for a subscription
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
this.libp2p.pubsub.once('pubsub:subscription-change', () => {
|
||||
this.libp2p.pubsub.once("pubsub:subscription-change", () => {
|
||||
// Remote peer subscribed to topic, now wait for a heartbeat
|
||||
// so that the mesh is updated and the remote peer added to it
|
||||
this.libp2p.pubsub.once('gossipsub:heartbeat', resolve);
|
||||
this.libp2p.pubsub.once("gossipsub:heartbeat", resolve);
|
||||
});
|
||||
});
|
||||
promises.push(promise);
|
||||
@ -347,10 +347,10 @@ export class Waku {
|
||||
// No peer available for this protocol, waiting to connect to one.
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
this.libp2p.peerStore.on(
|
||||
'change:protocols',
|
||||
"change:protocols",
|
||||
({ protocols: connectedPeerProtocols }) => {
|
||||
if (connectedPeerProtocols.includes(StoreCodec)) {
|
||||
dbg('Resolving for', StoreCodec, connectedPeerProtocols);
|
||||
dbg("Resolving for", StoreCodec, connectedPeerProtocols);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
@ -372,10 +372,10 @@ export class Waku {
|
||||
// No peer available for this protocol, waiting to connect to one.
|
||||
const promise = new Promise<void>((resolve) => {
|
||||
this.libp2p.peerStore.on(
|
||||
'change:protocols',
|
||||
"change:protocols",
|
||||
({ protocols: connectedPeerProtocols }) => {
|
||||
if (connectedPeerProtocols.includes(LightPushCodec)) {
|
||||
dbg('Resolving for', LightPushCodec, connectedPeerProtocols);
|
||||
dbg("Resolving for", LightPushCodec, connectedPeerProtocols);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,25 +1,25 @@
|
||||
import { expect } from 'chai';
|
||||
import debug from 'debug';
|
||||
import { expect } from "chai";
|
||||
import debug from "debug";
|
||||
|
||||
import { makeLogFileName, NimWaku, NOISE_KEY_1 } from '../../test_utils';
|
||||
import { delay } from '../delay';
|
||||
import { Protocols, Waku } from '../waku';
|
||||
import { WakuMessage } from '../waku_message';
|
||||
import { makeLogFileName, NimWaku, NOISE_KEY_1 } from "../../test_utils";
|
||||
import { delay } from "../delay";
|
||||
import { Protocols, Waku } from "../waku";
|
||||
import { WakuMessage } from "../waku_message";
|
||||
|
||||
const dbg = debug('waku:test:lightpush');
|
||||
const dbg = debug("waku:test:lightpush");
|
||||
|
||||
const TestContentTopic = '/test/1/waku-light-push/utf8';
|
||||
const TestContentTopic = "/test/1/waku-light-push/utf8";
|
||||
|
||||
describe('Waku Light Push [node only]', () => {
|
||||
describe("Waku Light Push [node only]", () => {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Push successfully', async function () {
|
||||
it("Push successfully", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -31,7 +31,7 @@ describe('Waku Light Push [node only]', () => {
|
||||
await waku.dial(await nimWaku.getMultiaddrWithId());
|
||||
await waku.waitForRemotePeer([Protocols.LightPush]);
|
||||
|
||||
const messageText = 'Light Push works!';
|
||||
const messageText = "Light Push works!";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic
|
||||
@ -52,10 +52,10 @@ describe('Waku Light Push [node only]', () => {
|
||||
expect(msgs[0].payloadAsUtf8).to.equal(messageText);
|
||||
});
|
||||
|
||||
it('Push on custom pubsub topic', async function () {
|
||||
it("Push on custom pubsub topic", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
const customPubSubTopic = '/waku/2/custom-dapp/proto';
|
||||
const customPubSubTopic = "/waku/2/custom-dapp/proto";
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ lightpush: true, topics: customPubSubTopic });
|
||||
@ -69,22 +69,22 @@ describe('Waku Light Push [node only]', () => {
|
||||
|
||||
const nimPeerId = await nimWaku.getPeerId();
|
||||
|
||||
const messageText = 'Light Push works!';
|
||||
const messageText = "Light Push works!";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic
|
||||
);
|
||||
|
||||
dbg('Send message via lightpush');
|
||||
dbg("Send message via lightpush");
|
||||
const pushResponse = await waku.lightPush.push(message, {
|
||||
peerId: nimPeerId,
|
||||
});
|
||||
dbg('Ack received', pushResponse);
|
||||
dbg("Ack received", pushResponse);
|
||||
expect(pushResponse?.isSuccess).to.be.true;
|
||||
|
||||
let msgs: WakuMessage[] = [];
|
||||
|
||||
dbg('Waiting for message to show on nim-waku side');
|
||||
dbg("Waiting for message to show on nim-waku side");
|
||||
while (msgs.length === 0) {
|
||||
await delay(200);
|
||||
msgs = await nimWaku.messages();
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import concat from 'it-concat';
|
||||
import lp from 'it-length-prefixed';
|
||||
import pipe from 'it-pipe';
|
||||
import Libp2p from 'libp2p';
|
||||
import { Peer } from 'libp2p/src/peer-store';
|
||||
import PeerId from 'peer-id';
|
||||
import concat from "it-concat";
|
||||
import lp from "it-length-prefixed";
|
||||
import pipe from "it-pipe";
|
||||
import Libp2p from "libp2p";
|
||||
import { Peer } from "libp2p/src/peer-store";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import { PushResponse } from '../../proto/waku/v2/light_push';
|
||||
import { getPeersForProtocol, selectRandomPeer } from '../select_peer';
|
||||
import { DefaultPubSubTopic } from '../waku';
|
||||
import { WakuMessage } from '../waku_message';
|
||||
import { PushResponse } from "../../proto/waku/v2/light_push";
|
||||
import { getPeersForProtocol, selectRandomPeer } from "../select_peer";
|
||||
import { DefaultPubSubTopic } from "../waku";
|
||||
import { WakuMessage } from "../waku_message";
|
||||
|
||||
import { PushRPC } from './push_rpc';
|
||||
import { PushRPC } from "./push_rpc";
|
||||
|
||||
export const LightPushCodec = '/vac/waku/lightpush/2.0.0-beta1';
|
||||
export const LightPushCodec = "/vac/waku/lightpush/2.0.0-beta1";
|
||||
export { PushResponse };
|
||||
|
||||
export interface CreateOptions {
|
||||
@ -53,16 +53,16 @@ export class WakuLightPush {
|
||||
let peer;
|
||||
if (opts?.peerId) {
|
||||
peer = await this.libp2p.peerStore.get(opts.peerId);
|
||||
if (!peer) throw 'Peer is unknown';
|
||||
if (!peer) throw "Peer is unknown";
|
||||
} else {
|
||||
peer = await this.randomPeer;
|
||||
}
|
||||
if (!peer) throw 'No peer available';
|
||||
if (!peer) throw "No peer available";
|
||||
if (!peer.protocols.includes(LightPushCodec))
|
||||
throw 'Peer does not register waku light push protocol';
|
||||
throw "Peer does not register waku light push protocol";
|
||||
|
||||
const connection = this.libp2p.connectionManager.get(peer.id);
|
||||
if (!connection) throw 'Failed to get a connection to the peer';
|
||||
if (!connection) throw "Failed to get a connection to the peer";
|
||||
|
||||
const { stream } = await connection.newStream(LightPushCodec);
|
||||
try {
|
||||
@ -81,16 +81,16 @@ export class WakuLightPush {
|
||||
const response = PushRPC.decode(res.slice()).response;
|
||||
|
||||
if (!response) {
|
||||
console.log('No response in PushRPC');
|
||||
console.log("No response in PushRPC");
|
||||
return null;
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (err) {
|
||||
console.log('Failed to decode push reply', err);
|
||||
console.log("Failed to decode push reply", err);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Failed to send waku light push request', err);
|
||||
console.log("Failed to send waku light push request", err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Reader } from 'protobufjs/minimal';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { Reader } from "protobufjs/minimal";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
import * as proto from '../../proto/waku/v2/light_push';
|
||||
import { WakuMessage } from '../waku_message';
|
||||
import * as proto from "../../proto/waku/v2/light_push";
|
||||
import { WakuMessage } from "../waku_message";
|
||||
|
||||
export class PushRPC {
|
||||
public constructor(public proto: proto.PushRPC) {}
|
||||
|
||||
@ -1,30 +1,30 @@
|
||||
import { expect } from 'chai';
|
||||
import debug from 'debug';
|
||||
import { expect } from "chai";
|
||||
import debug from "debug";
|
||||
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
WakuRelayMessage,
|
||||
} from '../../test_utils';
|
||||
import { delay } from '../delay';
|
||||
import { hexToBuf } from '../utils';
|
||||
import { Protocols, Waku } from '../waku';
|
||||
} from "../../test_utils";
|
||||
import { delay } from "../delay";
|
||||
import { hexToBuf } from "../utils";
|
||||
import { Protocols, Waku } from "../waku";
|
||||
|
||||
import {
|
||||
generatePrivateKey,
|
||||
generateSymmetricKey,
|
||||
getPublicKey,
|
||||
} from './version_1';
|
||||
} from "./version_1";
|
||||
|
||||
import { WakuMessage } from './index';
|
||||
import { WakuMessage } from "./index";
|
||||
|
||||
const dbg = debug('waku:test:message');
|
||||
const dbg = debug("waku:test:message");
|
||||
|
||||
const TestContentTopic = '/test/1/waku-message/utf8';
|
||||
const TestContentTopic = "/test/1/waku-message/utf8";
|
||||
|
||||
describe('Waku Message [node only]', function () {
|
||||
describe('Interop: Nim', function () {
|
||||
describe("Waku Message [node only]", function () {
|
||||
describe("Interop: Nim", function () {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
@ -35,14 +35,14 @@ describe('Waku Message [node only]', function () {
|
||||
});
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
dbg('Starting nim-waku node');
|
||||
dbg("Starting nim-waku node");
|
||||
await nimWaku.start({ rpcPrivate: true });
|
||||
|
||||
dbg('Dialing to nim-waku node');
|
||||
dbg("Dialing to nim-waku node");
|
||||
await waku.dial(await nimWaku.getMultiaddrWithId());
|
||||
dbg('Wait for remote peer');
|
||||
dbg("Wait for remote peer");
|
||||
await waku.waitForRemotePeer([Protocols.Relay]);
|
||||
dbg('Remote peer ready');
|
||||
dbg("Remote peer ready");
|
||||
// As this test uses the nim-waku RPC API, we somehow often face
|
||||
// Race conditions where the nim-waku node does not have the js-waku
|
||||
// Node in its relay mesh just yet.
|
||||
@ -51,16 +51,16 @@ describe('Waku Message [node only]', function () {
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('JS decrypts nim message [asymmetric, no signature]', async function () {
|
||||
it("JS decrypts nim message [asymmetric, no signature]", async function () {
|
||||
this.timeout(5000);
|
||||
|
||||
const messageText = 'Here is an encrypted message.';
|
||||
const messageText = "Here is an encrypted message.";
|
||||
const message: WakuRelayMessage = {
|
||||
contentTopic: TestContentTopic,
|
||||
payload: Buffer.from(messageText, 'utf-8').toString('hex'),
|
||||
payload: Buffer.from(messageText, "utf-8").toString("hex"),
|
||||
};
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
@ -74,7 +74,7 @@ describe('Waku Message [node only]', function () {
|
||||
);
|
||||
|
||||
const publicKey = getPublicKey(privateKey);
|
||||
dbg('Post message');
|
||||
dbg("Post message");
|
||||
const res = await nimWaku.postAsymmetricMessage(message, publicKey);
|
||||
expect(res).to.be.true;
|
||||
|
||||
@ -85,16 +85,16 @@ describe('Waku Message [node only]', function () {
|
||||
expect(receivedMsg.payloadAsUtf8).to.eq(messageText);
|
||||
});
|
||||
|
||||
it('Js encrypts message for nim [asymmetric, no signature]', async function () {
|
||||
it("Js encrypts message for nim [asymmetric, no signature]", async function () {
|
||||
this.timeout(5000);
|
||||
|
||||
dbg('Ask nim-waku to generate asymmetric key pair');
|
||||
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 messageText = 'This is a message I am going to encrypt';
|
||||
dbg('Encrypt message');
|
||||
const messageText = "This is a message I am going to encrypt";
|
||||
dbg("Encrypt message");
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic,
|
||||
@ -103,32 +103,32 @@ describe('Waku Message [node only]', function () {
|
||||
}
|
||||
);
|
||||
|
||||
dbg('Send message over relay');
|
||||
dbg("Send message over relay");
|
||||
await waku.relay.send(message);
|
||||
|
||||
let msgs: WakuRelayMessage[] = [];
|
||||
|
||||
while (msgs.length === 0) {
|
||||
dbg('Wait for message to be seen by nim-waku');
|
||||
dbg("Wait for message to be seen by nim-waku");
|
||||
await delay(200);
|
||||
msgs = await nimWaku.getAsymmetricMessages(privateKey);
|
||||
}
|
||||
|
||||
dbg('Check message content');
|
||||
dbg("Check message content");
|
||||
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
||||
expect(hexToBuf(msgs[0].payload).toString('utf-8')).to.equal(messageText);
|
||||
expect(hexToBuf(msgs[0].payload).toString("utf-8")).to.equal(messageText);
|
||||
});
|
||||
|
||||
it('JS decrypts nim message [symmetric, no signature]', async function () {
|
||||
it("JS decrypts nim message [symmetric, no signature]", async function () {
|
||||
this.timeout(5000);
|
||||
|
||||
const messageText = 'Here is a message encrypted in a symmetric manner.';
|
||||
const messageText = "Here is a message encrypted in a symmetric manner.";
|
||||
const message: WakuRelayMessage = {
|
||||
contentTopic: TestContentTopic,
|
||||
payload: Buffer.from(messageText, 'utf-8').toString('hex'),
|
||||
payload: Buffer.from(messageText, "utf-8").toString("hex"),
|
||||
};
|
||||
|
||||
dbg('Generate symmetric key');
|
||||
dbg("Generate symmetric key");
|
||||
const symKey = generateSymmetricKey();
|
||||
|
||||
waku.relay.addDecryptionKey(symKey);
|
||||
@ -139,25 +139,25 @@ describe('Waku Message [node only]', function () {
|
||||
}
|
||||
);
|
||||
|
||||
dbg('Post message using nim-waku');
|
||||
dbg("Post message using nim-waku");
|
||||
await nimWaku.postSymmetricMessage(message, symKey);
|
||||
dbg('Wait for message to be received by js-waku');
|
||||
dbg("Wait for message to be received by js-waku");
|
||||
const receivedMsg = await receivedMsgPromise;
|
||||
dbg('Message received by js-waku');
|
||||
dbg("Message received by js-waku");
|
||||
|
||||
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 [symmetric, no signature]', async function () {
|
||||
it("Js encrypts message for nim [symmetric, no signature]", async function () {
|
||||
this.timeout(5000);
|
||||
|
||||
dbg('Getting symmetric key from nim-waku');
|
||||
dbg("Getting symmetric key from nim-waku");
|
||||
const symKey = await nimWaku.getSymmetricKey();
|
||||
dbg('Encrypting message with js-waku');
|
||||
dbg("Encrypting message with js-waku");
|
||||
const messageText =
|
||||
'This is a message I am going to encrypt with a symmetric key';
|
||||
"This is a message I am going to encrypt with a symmetric key";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic,
|
||||
@ -165,19 +165,19 @@ describe('Waku Message [node only]', function () {
|
||||
symKey: symKey,
|
||||
}
|
||||
);
|
||||
dbg('Sending message over relay');
|
||||
dbg("Sending message over relay");
|
||||
await waku.relay.send(message);
|
||||
|
||||
let msgs: WakuRelayMessage[] = [];
|
||||
|
||||
while (msgs.length === 0) {
|
||||
await delay(200);
|
||||
dbg('Getting messages from nim-waku');
|
||||
dbg("Getting messages from nim-waku");
|
||||
msgs = await nimWaku.getSymmetricMessages(symKey);
|
||||
}
|
||||
|
||||
expect(msgs[0].contentTopic).to.equal(message.contentTopic);
|
||||
expect(hexToBuf(msgs[0].payload).toString('utf-8')).to.equal(messageText);
|
||||
expect(hexToBuf(msgs[0].payload).toString("utf-8")).to.equal(messageText);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { expect } from 'chai';
|
||||
import fc from 'fast-check';
|
||||
import { expect } from "chai";
|
||||
import fc from "fast-check";
|
||||
|
||||
import { getPublicKey } from './version_1';
|
||||
import { getPublicKey } from "./version_1";
|
||||
|
||||
import { WakuMessage } from './index';
|
||||
import { WakuMessage } from "./index";
|
||||
|
||||
const TestContentTopic = '/test/1/waku-message/utf8';
|
||||
const TestContentTopic = "/test/1/waku-message/utf8";
|
||||
|
||||
describe('Waku Message: Browser & Node', function () {
|
||||
it('Waku message round trip binary serialization [clear]', async function () {
|
||||
describe("Waku Message: Browser & Node", 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, TestContentTopic);
|
||||
@ -20,7 +20,7 @@ describe('Waku Message: Browser & Node', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Payload to utf-8', async function () {
|
||||
it("Payload to utf-8", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(fc.string(), async (s) => {
|
||||
const msg = await WakuMessage.fromUtf8String(s, TestContentTopic);
|
||||
@ -31,7 +31,7 @@ describe('Waku Message: Browser & Node', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip binary encryption [asymmetric, no signature]', async function () {
|
||||
it("Waku message round trip binary encryption [asymmetric, no signature]", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
@ -52,7 +52,7 @@ describe('Waku Message: Browser & Node', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip binary encryption [asymmetric, signature]', async function () {
|
||||
it("Waku message round trip binary encryption [asymmetric, signature]", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
@ -79,7 +79,7 @@ describe('Waku Message: Browser & Node', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip binary encryption [symmetric, no signature]', async function () {
|
||||
it("Waku message round trip binary encryption [symmetric, no signature]", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
@ -98,7 +98,7 @@ describe('Waku Message: Browser & Node', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip binary encryption [symmetric, signature]', async function () {
|
||||
it("Waku message round trip binary encryption [symmetric, signature]", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
@ -122,8 +122,8 @@ describe('Waku Message: Browser & Node', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Waku message round trip utf-8 including emojis', async function () {
|
||||
const messageText = '😁🤣🥧🤦👩🎓';
|
||||
it("Waku message round trip utf-8 including emojis", async function () {
|
||||
const messageText = "😁🤣🥧🤦👩🎓";
|
||||
const wakuMessage = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
// Ensure that this class matches the proto interface while
|
||||
import { Buffer } from 'buffer';
|
||||
import { Buffer } from "buffer";
|
||||
|
||||
import debug from 'debug';
|
||||
import { Reader } from 'protobufjs/minimal';
|
||||
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 proto from "../../proto/waku/v2/message";
|
||||
|
||||
import * as version_1 from './version_1';
|
||||
import * as version_1 from "./version_1";
|
||||
|
||||
const DefaultVersion = 0;
|
||||
const dbg = debug('waku:message');
|
||||
const dbg = debug("waku:message");
|
||||
|
||||
export enum DecryptionMethod {
|
||||
Asymmetric = 'asymmetric',
|
||||
Symmetric = 'symmetric',
|
||||
Asymmetric = "asymmetric",
|
||||
Symmetric = "symmetric",
|
||||
}
|
||||
|
||||
export interface Options {
|
||||
@ -56,7 +56,7 @@ export class WakuMessage {
|
||||
contentTopic: string,
|
||||
opts?: Options
|
||||
): Promise<WakuMessage> {
|
||||
const payload = Buffer.from(utf8, 'utf-8');
|
||||
const payload = Buffer.from(utf8, "utf-8");
|
||||
return WakuMessage.fromBytes(payload, contentTopic, opts);
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ export class WakuMessage {
|
||||
let sig;
|
||||
|
||||
if (encPublicKey && symKey) {
|
||||
throw 'Pass either `encPublicKey` or `symKey`, not both.';
|
||||
throw "Pass either `encPublicKey` or `symKey`, not both.";
|
||||
}
|
||||
|
||||
if (encPublicKey) {
|
||||
@ -154,7 +154,7 @@ export class WakuMessage {
|
||||
}>
|
||||
): Promise<WakuMessage | undefined> {
|
||||
if (protoBuf.payload === undefined) {
|
||||
dbg('Payload is undefined');
|
||||
dbg("Payload is undefined");
|
||||
return;
|
||||
}
|
||||
const payload = protoBuf.payload;
|
||||
@ -163,7 +163,7 @@ export class WakuMessage {
|
||||
let signature;
|
||||
if (protoBuf.version === 1 && protoBuf.payload) {
|
||||
if (decryptionKeys === undefined) {
|
||||
dbg('Payload is encrypted but no private keys have been provided.');
|
||||
dbg("Payload is encrypted but no private keys have been provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ export class WakuMessage {
|
||||
return await version_1.decryptAsymmetric(payload, key);
|
||||
} catch (e) {
|
||||
dbg(
|
||||
'Failed to decrypt message using symmetric encryption despite decryption method being specified',
|
||||
"Failed to decrypt message using symmetric encryption despite decryption method being specified",
|
||||
e
|
||||
);
|
||||
return;
|
||||
@ -191,7 +191,7 @@ export class WakuMessage {
|
||||
return await version_1.decryptSymmetric(payload, key);
|
||||
} catch (e) {
|
||||
dbg(
|
||||
'Failed to decrypt message using asymmetric encryption despite decryption method being specified',
|
||||
"Failed to decrypt message using asymmetric encryption despite decryption method being specified",
|
||||
e
|
||||
);
|
||||
return;
|
||||
@ -201,14 +201,14 @@ export class WakuMessage {
|
||||
return await version_1.decryptSymmetric(payload, key);
|
||||
} catch (e) {
|
||||
dbg(
|
||||
'Failed to decrypt message using symmetric encryption',
|
||||
"Failed to decrypt message using symmetric encryption",
|
||||
e
|
||||
);
|
||||
try {
|
||||
return await version_1.decryptAsymmetric(payload, key);
|
||||
} catch (e) {
|
||||
dbg(
|
||||
'Failed to decrypt message using asymmetric encryption',
|
||||
"Failed to decrypt message using asymmetric encryption",
|
||||
e
|
||||
);
|
||||
return;
|
||||
@ -229,14 +229,14 @@ export class WakuMessage {
|
||||
const decodedResults = allResults.filter(isDefined);
|
||||
|
||||
if (decodedResults.length === 0) {
|
||||
dbg('Failed to decrypt payload.');
|
||||
dbg("Failed to decrypt payload.");
|
||||
return;
|
||||
}
|
||||
const dec = decodedResults[0];
|
||||
|
||||
const res = await version_1.clearDecode(dec);
|
||||
if (!res) {
|
||||
dbg('Failed to decode payload.');
|
||||
dbg("Failed to decode payload.");
|
||||
return;
|
||||
}
|
||||
Object.assign(protoBuf, { payload: res.payload });
|
||||
@ -253,10 +253,10 @@ export class WakuMessage {
|
||||
|
||||
get payloadAsUtf8(): string {
|
||||
if (!this.proto.payload) {
|
||||
return '';
|
||||
return "";
|
||||
}
|
||||
|
||||
return Buffer.from(this.proto.payload).toString('utf-8');
|
||||
return Buffer.from(this.proto.payload).toString("utf-8");
|
||||
}
|
||||
|
||||
get payload(): Uint8Array | undefined {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { IvSize } from './index';
|
||||
import { IvSize } from "./index";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
@ -12,10 +12,10 @@ declare global {
|
||||
const crypto = window.crypto || window.msCrypto;
|
||||
const subtle: SubtleCrypto = crypto.subtle || crypto.webkitSubtle;
|
||||
|
||||
const Algorithm = { name: 'AES-GCM', length: 128 };
|
||||
const Algorithm = { name: "AES-GCM", length: 128 };
|
||||
|
||||
if (subtle === undefined) {
|
||||
throw new Error('Failed to load Subtle CryptoAPI');
|
||||
throw new Error("Failed to load Subtle CryptoAPI");
|
||||
}
|
||||
|
||||
export async function encrypt(
|
||||
@ -24,7 +24,7 @@ export async function encrypt(
|
||||
clearText: Buffer
|
||||
): Promise<Buffer> {
|
||||
return subtle
|
||||
.importKey('raw', key, Algorithm, false, ['encrypt'])
|
||||
.importKey("raw", key, Algorithm, false, ["encrypt"])
|
||||
.then((cryptoKey) =>
|
||||
subtle.encrypt({ iv, ...Algorithm }, cryptoKey, clearText)
|
||||
)
|
||||
@ -37,7 +37,7 @@ export async function decrypt(
|
||||
cipherText: Buffer
|
||||
): Promise<Buffer> {
|
||||
return subtle
|
||||
.importKey('raw', key, Algorithm, false, ['decrypt'])
|
||||
.importKey("raw", key, Algorithm, false, ["decrypt"])
|
||||
.then((cryptoKey) =>
|
||||
subtle.decrypt({ iv, ...Algorithm }, cryptoKey, cipherText)
|
||||
)
|
||||
|
||||
@ -23,12 +23,12 @@ export interface Symmetric {
|
||||
|
||||
export let symmetric: Symmetric = {} as unknown as Symmetric;
|
||||
|
||||
import('./browser')
|
||||
import("./browser")
|
||||
.then((mod) => {
|
||||
symmetric = mod;
|
||||
})
|
||||
.catch((eBrowser) => {
|
||||
import('./node')
|
||||
import("./node")
|
||||
.then((mod) => {
|
||||
symmetric = mod;
|
||||
})
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';
|
||||
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
||||
|
||||
import { IvSize, TagSize } from './index';
|
||||
import { IvSize, TagSize } from "./index";
|
||||
|
||||
const Algorithm = 'aes-256-gcm';
|
||||
const Algorithm = "aes-256-gcm";
|
||||
|
||||
export async function encrypt(
|
||||
iv: Buffer | Uint8Array,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { expect } from 'chai';
|
||||
import fc from 'fast-check';
|
||||
import { expect } from "chai";
|
||||
import fc from "fast-check";
|
||||
|
||||
import {
|
||||
clearDecode,
|
||||
@ -9,10 +9,10 @@ import {
|
||||
encryptAsymmetric,
|
||||
encryptSymmetric,
|
||||
getPublicKey,
|
||||
} from './version_1';
|
||||
} from "./version_1";
|
||||
|
||||
describe('Waku Message Version 1', function () {
|
||||
it('Sign & Recover', function () {
|
||||
describe("Waku Message Version 1", function () {
|
||||
it("Sign & Recover", function () {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.uint8Array(),
|
||||
@ -25,22 +25,22 @@ describe('Waku Message Version 1', function () {
|
||||
|
||||
expect(res?.payload).deep.equal(
|
||||
message,
|
||||
'Payload was not encrypted then decrypted correctly'
|
||||
"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'
|
||||
"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'
|
||||
"Incorrect signature public key was returned when signing the payload"
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it('Asymmetric encrypt & Decrypt', async function () {
|
||||
it("Asymmetric encrypt & Decrypt", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array({ minLength: 1 }),
|
||||
@ -57,7 +57,7 @@ describe('Waku Message Version 1', function () {
|
||||
);
|
||||
});
|
||||
|
||||
it('Symmetric encrypt & Decrypt', async function () {
|
||||
it("Symmetric encrypt & Decrypt", async function () {
|
||||
await fc.assert(
|
||||
fc.asyncProperty(
|
||||
fc.uint8Array(),
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { Buffer } from 'buffer';
|
||||
import * as crypto from 'crypto';
|
||||
import { Buffer } from "buffer";
|
||||
import * as crypto from "crypto";
|
||||
|
||||
import * as ecies from 'ecies-geth';
|
||||
import { keccak256 } from 'js-sha3';
|
||||
import * as secp256k1 from 'secp256k1';
|
||||
import * as ecies from "ecies-geth";
|
||||
import { keccak256 } from "js-sha3";
|
||||
import * as secp256k1 from "secp256k1";
|
||||
|
||||
import { hexToBuf } from '../utils';
|
||||
import { hexToBuf } from "../utils";
|
||||
|
||||
import { IvSize, symmetric, SymmetricKeySize } from './symmetric';
|
||||
import { IvSize, symmetric, SymmetricKeySize } from "./symmetric";
|
||||
|
||||
const FlagsLength = 1;
|
||||
const FlagMask = 3; // 0011
|
||||
@ -49,7 +49,7 @@ export function clearEncode(
|
||||
const pad = Buffer.from(randomBytes(paddingSize));
|
||||
|
||||
if (!validateDataIntegrity(pad, paddingSize)) {
|
||||
throw new Error('failed to generate random padding of size ' + paddingSize);
|
||||
throw new Error("failed to generate random padding of size " + paddingSize);
|
||||
}
|
||||
|
||||
envelope = Buffer.concat([envelope, pad]);
|
||||
@ -256,7 +256,7 @@ function ecRecoverPubKey(messageHash: string, signature: Buffer): Uint8Array {
|
||||
}
|
||||
|
||||
function randomBytes(length: number): Uint8Array {
|
||||
if (typeof window !== 'undefined' && window && window.crypto) {
|
||||
if (typeof window !== "undefined" && window && window.crypto) {
|
||||
const array = new Uint8Array(length);
|
||||
window.crypto.getRandomValues(array);
|
||||
return array;
|
||||
|
||||
@ -5,11 +5,11 @@ export const minute = 60 * second;
|
||||
* RelayCodec is the libp2p identifier for the waku relay protocol
|
||||
*/
|
||||
export const RelayCodecs = [
|
||||
'/vac/waku/relay/2.0.0-beta2',
|
||||
'/vac/waku/relay/2.0.0',
|
||||
"/vac/waku/relay/2.0.0-beta2",
|
||||
"/vac/waku/relay/2.0.0",
|
||||
];
|
||||
|
||||
export const RelayPingContentTopic = '/relay-ping/1/ping/null';
|
||||
export const RelayPingContentTopic = "/relay-ping/1/ping/null";
|
||||
|
||||
/**
|
||||
* RelayGossipFactor affects how many peers we will emit gossip to at each heartbeat.
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Gossipsub from 'libp2p-gossipsub';
|
||||
import { shuffle } from 'libp2p-gossipsub/src/utils';
|
||||
import Gossipsub from "libp2p-gossipsub";
|
||||
import { shuffle } from "libp2p-gossipsub/src/utils";
|
||||
|
||||
import { RelayCodecs } from './index';
|
||||
import { RelayCodecs } from "./index";
|
||||
|
||||
/**
|
||||
* Given a topic, returns up to count peers subscribed to that topic
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import { expect } from 'chai';
|
||||
import debug from 'debug';
|
||||
import { expect } from "chai";
|
||||
import debug from "debug";
|
||||
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
NOISE_KEY_2,
|
||||
} from '../../test_utils';
|
||||
import { delay } from '../delay';
|
||||
import { DefaultPubSubTopic, Protocols, Waku } from '../waku';
|
||||
import { DecryptionMethod, WakuMessage } from '../waku_message';
|
||||
} from "../../test_utils";
|
||||
import { delay } from "../delay";
|
||||
import { DefaultPubSubTopic, Protocols, Waku } from "../waku";
|
||||
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
||||
import {
|
||||
generatePrivateKey,
|
||||
generateSymmetricKey,
|
||||
getPublicKey,
|
||||
} from '../waku_message/version_1';
|
||||
} from "../waku_message/version_1";
|
||||
|
||||
const log = debug('waku:test');
|
||||
const log = debug("waku:test");
|
||||
|
||||
const TestContentTopic = '/test/1/waku-relay/utf8';
|
||||
const TestContentTopic = "/test/1/waku-relay/utf8";
|
||||
|
||||
describe('Waku Relay [node only]', () => {
|
||||
describe("Waku Relay [node only]", () => {
|
||||
// Node needed as we don't have a way to connect 2 js waku
|
||||
// nodes in the browser yet
|
||||
describe('2 js nodes', () => {
|
||||
describe("2 js nodes", () => {
|
||||
afterEach(function () {
|
||||
if (this.currentTest?.state === 'failed') {
|
||||
if (this.currentTest?.state === "failed") {
|
||||
console.log(`Test failed, log file name is ${makeLogFileName(this)}`);
|
||||
}
|
||||
});
|
||||
@ -35,56 +35,56 @@ describe('Waku Relay [node only]', () => {
|
||||
beforeEach(async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
log('Starting JS Waku instances');
|
||||
log("Starting JS Waku instances");
|
||||
[waku1, waku2] = await Promise.all([
|
||||
Waku.create({ staticNoiseKey: NOISE_KEY_1 }),
|
||||
Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: { addresses: { listen: ['/ip4/0.0.0.0/tcp/0/ws'] } },
|
||||
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
|
||||
}),
|
||||
]);
|
||||
log("Instances started, adding waku2 to waku1's address book");
|
||||
waku1.addPeerToAddressBook(waku2.libp2p.peerId, waku2.libp2p.multiaddrs);
|
||||
|
||||
log('Wait for mutual pubsub subscription');
|
||||
log("Wait for mutual pubsub subscription");
|
||||
await Promise.all([
|
||||
waku1.waitForRemotePeer([Protocols.Relay]),
|
||||
waku2.waitForRemotePeer([Protocols.Relay]),
|
||||
]);
|
||||
log('before each hook done');
|
||||
log("before each hook done");
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
!!waku1 &&
|
||||
waku1.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 &&
|
||||
waku2.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Subscribe', async function () {
|
||||
log('Getting subscribers');
|
||||
it("Subscribe", async function () {
|
||||
log("Getting subscribers");
|
||||
const subscribers1 =
|
||||
waku1.libp2p.pubsub.getSubscribers(DefaultPubSubTopic);
|
||||
const subscribers2 =
|
||||
waku2.libp2p.pubsub.getSubscribers(DefaultPubSubTopic);
|
||||
|
||||
log('Asserting mutual subscription');
|
||||
log("Asserting mutual subscription");
|
||||
expect(subscribers1).to.contain(waku2.libp2p.peerId.toB58String());
|
||||
expect(subscribers2).to.contain(waku1.libp2p.peerId.toB58String());
|
||||
});
|
||||
|
||||
it('Register correct protocols', async function () {
|
||||
it("Register correct protocols", async function () {
|
||||
const protocols = Array.from(waku1.libp2p.upgrader.protocols.keys());
|
||||
|
||||
expect(protocols).to.contain('/vac/waku/relay/2.0.0');
|
||||
expect(protocols).to.contain("/vac/waku/relay/2.0.0");
|
||||
expect(protocols.findIndex((value) => value.match(/sub/))).to.eq(-1);
|
||||
});
|
||||
|
||||
it('Publish', async function () {
|
||||
it("Publish", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const messageText = 'JS to JS communication works';
|
||||
const messageTimestamp = new Date('1995-12-17T03:24:00');
|
||||
const messageText = "JS to JS communication works";
|
||||
const messageTimestamp = new Date("1995-12-17T03:24:00");
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic,
|
||||
@ -111,23 +111,23 @@ describe('Waku Relay [node only]', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('Filter on content topics', async function () {
|
||||
it("Filter on content topics", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const fooMessageText = 'Published on content topic foo';
|
||||
const barMessageText = 'Published on content topic bar';
|
||||
const fooMessageText = "Published on content topic foo";
|
||||
const barMessageText = "Published on content topic bar";
|
||||
const fooMessage = await WakuMessage.fromUtf8String(
|
||||
fooMessageText,
|
||||
'foo'
|
||||
"foo"
|
||||
);
|
||||
const barMessage = await WakuMessage.fromUtf8String(
|
||||
barMessageText,
|
||||
'bar'
|
||||
"bar"
|
||||
);
|
||||
|
||||
const receivedBarMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve) => {
|
||||
waku2.relay.addObserver(resolve, ['bar']);
|
||||
waku2.relay.addObserver(resolve, ["bar"]);
|
||||
}
|
||||
);
|
||||
|
||||
@ -153,15 +153,15 @@ describe('Waku Relay [node only]', () => {
|
||||
expect(allMessages[1].payloadAsUtf8).to.eq(barMessageText);
|
||||
});
|
||||
|
||||
it('Decrypt messages', async function () {
|
||||
it("Decrypt messages", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const encryptedAsymmetricMessageText =
|
||||
'This message is encrypted using asymmetric';
|
||||
const encryptedAsymmetricContentTopic = '/test/1/asymmetric/proto';
|
||||
"This message is encrypted using asymmetric";
|
||||
const encryptedAsymmetricContentTopic = "/test/1/asymmetric/proto";
|
||||
const encryptedSymmetricMessageText =
|
||||
'This message is encrypted using symmetric encryption';
|
||||
const encryptedSymmetricContentTopic = '/test/1/symmetric/proto';
|
||||
"This message is encrypted using symmetric encryption";
|
||||
const encryptedSymmetricContentTopic = "/test/1/symmetric/proto";
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const symKey = generateSymmetricKey();
|
||||
@ -219,21 +219,21 @@ describe('Waku Relay [node only]', () => {
|
||||
expect(msgs[1].payloadAsUtf8).to.eq(encryptedSymmetricMessageText);
|
||||
});
|
||||
|
||||
it('Delete observer', async function () {
|
||||
it("Delete observer", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const messageText =
|
||||
'Published on content topic with added then deleted observer';
|
||||
"Published on content topic with added then deleted observer";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
'added-then-deleted-observer'
|
||||
"added-then-deleted-observer"
|
||||
);
|
||||
|
||||
// The promise **fails** if we receive a message on this observer.
|
||||
const receivedMsgPromise: Promise<WakuMessage> = new Promise(
|
||||
(resolve, reject) => {
|
||||
waku2.relay.addObserver(reject, ['added-then-deleted-observer']);
|
||||
waku2.relay.deleteObserver(reject, ['added-then-deleted-observer']);
|
||||
waku2.relay.addObserver(reject, ["added-then-deleted-observer"]);
|
||||
waku2.relay.deleteObserver(reject, ["added-then-deleted-observer"]);
|
||||
setTimeout(resolve, 500);
|
||||
}
|
||||
);
|
||||
@ -244,11 +244,11 @@ describe('Waku Relay [node only]', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Custom pubsub topic', () => {
|
||||
it('Publish', async function () {
|
||||
describe("Custom pubsub topic", () => {
|
||||
it("Publish", async function () {
|
||||
this.timeout(10000);
|
||||
|
||||
const pubSubTopic = '/some/pubsub/topic';
|
||||
const pubSubTopic = "/some/pubsub/topic";
|
||||
|
||||
// 1 and 2 uses a custom pubsub
|
||||
const [waku1, waku2, waku3] = await Promise.all([
|
||||
@ -259,7 +259,7 @@ describe('Waku Relay [node only]', () => {
|
||||
Waku.create({
|
||||
pubSubTopic: pubSubTopic,
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
libp2p: { addresses: { listen: ['/ip4/0.0.0.0/tcp/0/ws'] } },
|
||||
libp2p: { addresses: { listen: ["/ip4/0.0.0.0/tcp/0/ws"] } },
|
||||
}),
|
||||
Waku.create({
|
||||
staticNoiseKey: NOISE_KEY_2,
|
||||
@ -275,7 +275,7 @@ describe('Waku Relay [node only]', () => {
|
||||
// No subscription change expected for Waku 3
|
||||
]);
|
||||
|
||||
const messageText = 'Communicating using a custom pubsub topic';
|
||||
const messageText = "Communicating using a custom pubsub topic";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic
|
||||
@ -305,7 +305,7 @@ describe('Waku Relay [node only]', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Interop: Nim', function () {
|
||||
describe("Interop: Nim", function () {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
@ -315,7 +315,7 @@ describe('Waku Relay [node only]', () => {
|
||||
staticNoiseKey: NOISE_KEY_1,
|
||||
});
|
||||
|
||||
nimWaku = new NimWaku(this.test?.ctx?.currentTest?.title + '');
|
||||
nimWaku = new NimWaku(this.test?.ctx?.currentTest?.title + "");
|
||||
await nimWaku.start();
|
||||
|
||||
await waku.dial(await nimWaku.getMultiaddrWithId());
|
||||
@ -324,10 +324,10 @@ describe('Waku Relay [node only]', () => {
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('nim subscribes to js', async function () {
|
||||
it("nim subscribes to js", async function () {
|
||||
let subscribers: string[] = [];
|
||||
|
||||
while (subscribers.length === 0) {
|
||||
@ -339,10 +339,10 @@ describe('Waku Relay [node only]', () => {
|
||||
expect(subscribers).to.contain(nimPeerId.toB58String());
|
||||
});
|
||||
|
||||
it('Js publishes to nim', async function () {
|
||||
it("Js publishes to nim", async function () {
|
||||
this.timeout(30000);
|
||||
|
||||
const messageText = 'This is a message';
|
||||
const messageText = "This is a message";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic
|
||||
@ -353,7 +353,7 @@ describe('Waku Relay [node only]', () => {
|
||||
let msgs: WakuMessage[] = [];
|
||||
|
||||
while (msgs.length === 0) {
|
||||
console.log('Waiting for messages');
|
||||
console.log("Waiting for messages");
|
||||
await delay(200);
|
||||
msgs = await nimWaku.messages();
|
||||
}
|
||||
@ -363,10 +363,10 @@ describe('Waku Relay [node only]', () => {
|
||||
expect(msgs[0].payloadAsUtf8).to.equal(messageText);
|
||||
});
|
||||
|
||||
it('Nim publishes to js', async function () {
|
||||
it("Nim publishes to js", async function () {
|
||||
await delay(200);
|
||||
|
||||
const messageText = 'Here is another message.';
|
||||
const messageText = "Here is another message.";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
messageText,
|
||||
TestContentTopic
|
||||
@ -387,7 +387,7 @@ describe('Waku Relay [node only]', () => {
|
||||
expect(receivedMsg.payloadAsUtf8).to.eq(messageText);
|
||||
});
|
||||
|
||||
describe.skip('js to nim to js', function () {
|
||||
describe.skip("js to nim to js", function () {
|
||||
let waku1: Waku;
|
||||
let waku2: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
@ -395,12 +395,12 @@ describe('Waku Relay [node only]', () => {
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku1 &&
|
||||
waku1.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 &&
|
||||
waku2.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Js publishes, other Js receives', async function () {
|
||||
it("Js publishes, other Js receives", async function () {
|
||||
this.timeout(60_000);
|
||||
[waku1, waku2] = await Promise.all([
|
||||
Waku.create({
|
||||
@ -432,7 +432,7 @@ describe('Waku Relay [node only]', () => {
|
||||
.false;
|
||||
expect(waku2.libp2p.peerStore.has(waku1.libp2p.peerId)).to.be.false;
|
||||
|
||||
const msgStr = 'Hello there!';
|
||||
const msgStr = "Hello there!";
|
||||
const message = await WakuMessage.fromUtf8String(
|
||||
msgStr,
|
||||
TestContentTopic
|
||||
@ -445,7 +445,7 @@ describe('Waku Relay [node only]', () => {
|
||||
);
|
||||
|
||||
await waku1.relay.send(message);
|
||||
console.log('Waiting for message');
|
||||
console.log("Waiting for message");
|
||||
const waku2ReceivedMsg = await waku2ReceivedMsgPromise;
|
||||
|
||||
expect(waku2ReceivedMsg.payloadAsUtf8).to.eq(msgStr);
|
||||
|
||||
@ -1,28 +1,28 @@
|
||||
import debug from 'debug';
|
||||
import Libp2p from 'libp2p';
|
||||
import Gossipsub from 'libp2p-gossipsub';
|
||||
import { AddrInfo, MessageIdFunction } from 'libp2p-gossipsub/src/interfaces';
|
||||
import { MessageCache } from 'libp2p-gossipsub/src/message-cache';
|
||||
import { RPC } from 'libp2p-gossipsub/src/message/rpc';
|
||||
import debug from "debug";
|
||||
import Libp2p from "libp2p";
|
||||
import Gossipsub from "libp2p-gossipsub";
|
||||
import { AddrInfo, MessageIdFunction } from "libp2p-gossipsub/src/interfaces";
|
||||
import { MessageCache } from "libp2p-gossipsub/src/message-cache";
|
||||
import { RPC } from "libp2p-gossipsub/src/message/rpc";
|
||||
import {
|
||||
PeerScoreParams,
|
||||
PeerScoreThresholds,
|
||||
} from 'libp2p-gossipsub/src/score';
|
||||
import { createGossipRpc, shuffle } from 'libp2p-gossipsub/src/utils';
|
||||
import { InMessage } from 'libp2p-interfaces/src/pubsub';
|
||||
import { SignaturePolicy } from 'libp2p-interfaces/src/pubsub/signature-policy';
|
||||
import PeerId from 'peer-id';
|
||||
} from "libp2p-gossipsub/src/score";
|
||||
import { createGossipRpc, shuffle } from "libp2p-gossipsub/src/utils";
|
||||
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 { CreateOptions, DefaultPubSubTopic } from '../waku';
|
||||
import { DecryptionMethod, WakuMessage } from '../waku_message';
|
||||
import { hexToBuf } from "../utils";
|
||||
import { CreateOptions, DefaultPubSubTopic } from "../waku";
|
||||
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
||||
|
||||
import * as constants from './constants';
|
||||
import { RelayCodecs } from './constants';
|
||||
import { getRelayPeers } from './get_relay_peers';
|
||||
import { RelayHeartbeat } from './relay_heartbeat';
|
||||
import * as constants from "./constants";
|
||||
import { RelayCodecs } from "./constants";
|
||||
import { getRelayPeers } from "./get_relay_peers";
|
||||
import { RelayHeartbeat } from "./relay_heartbeat";
|
||||
|
||||
const dbg = debug('waku:relay');
|
||||
const dbg = debug("waku:relay");
|
||||
|
||||
export { RelayCodecs };
|
||||
|
||||
@ -161,10 +161,10 @@ export class WakuRelay extends Gossipsub {
|
||||
contentTopics: string[] = []
|
||||
): void {
|
||||
if (contentTopics.length === 0) {
|
||||
if (!this.observers['']) {
|
||||
this.observers[''] = new Set();
|
||||
if (!this.observers[""]) {
|
||||
this.observers[""] = new Set();
|
||||
}
|
||||
this.observers[''].add(callback);
|
||||
this.observers[""].add(callback);
|
||||
} else {
|
||||
contentTopics.forEach((contentTopic) => {
|
||||
if (!this.observers[contentTopic]) {
|
||||
@ -185,8 +185,8 @@ export class WakuRelay extends Gossipsub {
|
||||
contentTopics: string[] = []
|
||||
): void {
|
||||
if (contentTopics.length === 0) {
|
||||
if (this.observers['']) {
|
||||
this.observers[''].delete(callback);
|
||||
if (this.observers[""]) {
|
||||
this.observers[""].delete(callback);
|
||||
}
|
||||
} else {
|
||||
contentTopics.forEach((contentTopic) => {
|
||||
@ -230,12 +230,12 @@ export class WakuRelay extends Gossipsub {
|
||||
WakuMessage.decode(event.data, decryptionKeys)
|
||||
.then((wakuMsg) => {
|
||||
if (!wakuMsg) {
|
||||
dbg('Failed to decode Waku Message');
|
||||
dbg("Failed to decode Waku Message");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.observers['']) {
|
||||
this.observers[''].forEach((callbackFn) => {
|
||||
if (this.observers[""]) {
|
||||
this.observers[""].forEach((callbackFn) => {
|
||||
callbackFn(wakuMsg);
|
||||
});
|
||||
}
|
||||
@ -248,7 +248,7 @@ export class WakuRelay extends Gossipsub {
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
dbg('Failed to decode Waku Message', e);
|
||||
dbg("Failed to decode Waku Message", e);
|
||||
});
|
||||
});
|
||||
|
||||
@ -267,7 +267,7 @@ export class WakuRelay extends Gossipsub {
|
||||
*/
|
||||
join(topic: string): void {
|
||||
if (!this.started) {
|
||||
throw new Error('WakuRelayPubSub has not started');
|
||||
throw new Error("WakuRelayPubSub has not started");
|
||||
}
|
||||
|
||||
const fanoutPeers = this.fanout.get(topic);
|
||||
@ -311,7 +311,7 @@ export class WakuRelay extends Gossipsub {
|
||||
this.mesh.set(topic, peers);
|
||||
}
|
||||
this.mesh.get(topic)?.forEach((id) => {
|
||||
this.log('JOIN: Add mesh link to %s in %s', id, topic);
|
||||
this.log("JOIN: Add mesh link to %s in %s", id, topic);
|
||||
this._sendGraft(id, topic);
|
||||
});
|
||||
}
|
||||
@ -385,7 +385,7 @@ export class WakuRelay extends Gossipsub {
|
||||
if (id === msg.from) {
|
||||
return;
|
||||
}
|
||||
dbg('Relay message to', id);
|
||||
dbg("Relay message to", id);
|
||||
this._sendRpc(id, rpc);
|
||||
});
|
||||
}
|
||||
@ -415,7 +415,7 @@ export class WakuRelay extends Gossipsub {
|
||||
if (messageIDs.length > constants.RelayMaxIHaveLength) {
|
||||
// we do the truncation (with shuffling) per peer below
|
||||
this.log(
|
||||
'too many messages for gossip; will truncate IHAVE list (%d messages)',
|
||||
"too many messages for gossip; will truncate IHAVE list (%d messages)",
|
||||
messageIDs.length
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,12 +3,12 @@
|
||||
* @module
|
||||
*/
|
||||
|
||||
import Gossipsub from 'libp2p-gossipsub';
|
||||
import { Heartbeat } from 'libp2p-gossipsub/src/heartbeat';
|
||||
import { shuffle } from 'libp2p-gossipsub/src/utils';
|
||||
import Gossipsub from "libp2p-gossipsub";
|
||||
import { Heartbeat } from "libp2p-gossipsub/src/heartbeat";
|
||||
import { shuffle } from "libp2p-gossipsub/src/utils";
|
||||
|
||||
import * as constants from './constants';
|
||||
import { getRelayPeers } from './get_relay_peers';
|
||||
import * as constants from "./constants";
|
||||
import { getRelayPeers } from "./get_relay_peers";
|
||||
|
||||
export class RelayHeartbeat extends Heartbeat {
|
||||
/**
|
||||
@ -107,7 +107,7 @@ export class RelayHeartbeat extends Heartbeat {
|
||||
// prune/graft helper functions (defined per topic)
|
||||
const prunePeer = (id: string): void => {
|
||||
this.gossipsub.log(
|
||||
'HEARTBEAT: Remove mesh link to %s in %s',
|
||||
"HEARTBEAT: Remove mesh link to %s in %s",
|
||||
id,
|
||||
topic
|
||||
);
|
||||
@ -126,7 +126,7 @@ export class RelayHeartbeat extends Heartbeat {
|
||||
}
|
||||
};
|
||||
const graftPeer = (id: string): void => {
|
||||
this.gossipsub.log('HEARTBEAT: Add mesh link to %s in %s', id, topic);
|
||||
this.gossipsub.log("HEARTBEAT: Add mesh link to %s in %s", id, topic);
|
||||
// update peer score
|
||||
this.gossipsub.score.graft(id, topic);
|
||||
// add peer to mesh
|
||||
@ -145,7 +145,7 @@ export class RelayHeartbeat extends Heartbeat {
|
||||
const score = getScore(id);
|
||||
if (score < 0) {
|
||||
this.gossipsub.log(
|
||||
'HEARTBEAT: Prune peer %s with negative score: score=%d, topic=%s',
|
||||
"HEARTBEAT: Prune peer %s with negative score: score=%d, topic=%s",
|
||||
id,
|
||||
score,
|
||||
topic
|
||||
@ -301,7 +301,7 @@ export class RelayHeartbeat extends Heartbeat {
|
||||
);
|
||||
peersToGraft.forEach((id: string) => {
|
||||
this.gossipsub.log(
|
||||
'HEARTBEAT: Opportunistically graft peer %s on topic %s',
|
||||
"HEARTBEAT: Opportunistically graft peer %s on topic %s",
|
||||
id,
|
||||
topic
|
||||
);
|
||||
@ -374,6 +374,6 @@ export class RelayHeartbeat extends Heartbeat {
|
||||
// advance the message history window
|
||||
this.gossipsub.messageCache.shift();
|
||||
|
||||
this.gossipsub.emit('gossipsub:heartbeat');
|
||||
this.gossipsub.emit("gossipsub:heartbeat");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { Reader } from 'protobufjs/minimal';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import { Reader } from "protobufjs/minimal";
|
||||
import { v4 as uuid } from "uuid";
|
||||
|
||||
import * as proto from '../../proto/waku/v2/store';
|
||||
import * as proto from "../../proto/waku/v2/store";
|
||||
|
||||
export enum PageDirection {
|
||||
BACKWARD = 'backward',
|
||||
FORWARD = 'forward',
|
||||
BACKWARD = "backward",
|
||||
FORWARD = "forward",
|
||||
}
|
||||
|
||||
export interface Params {
|
||||
|
||||
@ -1,37 +1,37 @@
|
||||
import { expect } from 'chai';
|
||||
import debug from 'debug';
|
||||
import { expect } from "chai";
|
||||
import debug from "debug";
|
||||
|
||||
import {
|
||||
makeLogFileName,
|
||||
NimWaku,
|
||||
NOISE_KEY_1,
|
||||
NOISE_KEY_2,
|
||||
} from '../../test_utils';
|
||||
import { delay } from '../delay';
|
||||
import { Protocols, Waku } from '../waku';
|
||||
import { DecryptionMethod, WakuMessage } from '../waku_message';
|
||||
} from "../../test_utils";
|
||||
import { delay } from "../delay";
|
||||
import { Protocols, Waku } from "../waku";
|
||||
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
||||
import {
|
||||
generatePrivateKey,
|
||||
generateSymmetricKey,
|
||||
getPublicKey,
|
||||
} from '../waku_message/version_1';
|
||||
} from "../waku_message/version_1";
|
||||
|
||||
import { PageDirection } from './history_rpc';
|
||||
import { PageDirection } from "./history_rpc";
|
||||
|
||||
const dbg = debug('waku:test:store');
|
||||
const dbg = debug("waku:test:store");
|
||||
|
||||
const TestContentTopic = '/test/1/waku-store/utf8';
|
||||
const TestContentTopic = "/test/1/waku-store/utf8";
|
||||
|
||||
describe('Waku Store', () => {
|
||||
describe("Waku Store", () => {
|
||||
let waku: Waku;
|
||||
let nimWaku: NimWaku;
|
||||
|
||||
afterEach(async function () {
|
||||
!!nimWaku && nimWaku.stop();
|
||||
!!waku && waku.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku && waku.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Retrieves history', async function () {
|
||||
it("Retrieves history", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -54,12 +54,12 @@ describe('Waku Store', () => {
|
||||
|
||||
expect(messages?.length).eq(2);
|
||||
const result = messages?.findIndex((msg) => {
|
||||
return msg.payloadAsUtf8 === 'Message 0';
|
||||
return msg.payloadAsUtf8 === "Message 0";
|
||||
});
|
||||
expect(result).to.not.eq(-1);
|
||||
});
|
||||
|
||||
it('Retrieves history using callback', async function () {
|
||||
it("Retrieves history using callback", async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -91,12 +91,12 @@ describe('Waku Store', () => {
|
||||
|
||||
expect(messages?.length).eq(totalMsgs);
|
||||
const result = messages?.findIndex((msg) => {
|
||||
return msg.payloadAsUtf8 === 'Message 0';
|
||||
return msg.payloadAsUtf8 === "Message 0";
|
||||
});
|
||||
expect(result).to.not.eq(-1);
|
||||
});
|
||||
|
||||
it('Retrieval aborts when callback returns true', async function () {
|
||||
it("Retrieval aborts when callback returns true", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -132,7 +132,7 @@ describe('Waku Store', () => {
|
||||
expect(messages?.length).eq(desiredMsgs);
|
||||
});
|
||||
|
||||
it('Retrieves all historical elements in chronological order through paging', async function () {
|
||||
it("Retrieves all historical elements in chronological order through paging", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -166,10 +166,10 @@ describe('Waku Store', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('Retrieves history using custom pubsub topic', async function () {
|
||||
it("Retrieves history using custom pubsub topic", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
const customPubSubTopic = '/waku/2/custom-dapp/proto';
|
||||
const customPubSubTopic = "/waku/2/custom-dapp/proto";
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ persistMessages: true, topics: customPubSubTopic });
|
||||
|
||||
@ -197,25 +197,25 @@ describe('Waku Store', () => {
|
||||
|
||||
expect(messages?.length).eq(2);
|
||||
const result = messages?.findIndex((msg) => {
|
||||
return msg.payloadAsUtf8 === 'Message 0';
|
||||
return msg.payloadAsUtf8 === "Message 0";
|
||||
});
|
||||
expect(result).to.not.eq(-1);
|
||||
});
|
||||
|
||||
it('Retrieves history with asymmetric & symmetric encrypted messages', async function () {
|
||||
it("Retrieves history with asymmetric & symmetric encrypted messages", async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ persistMessages: true, lightpush: true });
|
||||
|
||||
const encryptedAsymmetricMessageText =
|
||||
'This message is encrypted for me using asymmetric';
|
||||
"This message is encrypted for me using asymmetric";
|
||||
const encryptedSymmetricMessageText =
|
||||
'This message is encrypted for me using symmetric encryption';
|
||||
"This message is encrypted for me using symmetric encryption";
|
||||
const clearMessageText =
|
||||
'This is a clear text message for everyone to read';
|
||||
"This is a clear text message for everyone to read";
|
||||
const otherEncMessageText =
|
||||
'This message is not for and I must not be able to read it';
|
||||
"This message is not for and I must not be able to read it";
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const symKey = generateSymmetricKey();
|
||||
@ -247,7 +247,7 @@ describe('Waku Store', () => {
|
||||
}),
|
||||
]);
|
||||
|
||||
dbg('Messages have been encrypted');
|
||||
dbg("Messages have been encrypted");
|
||||
|
||||
const [waku1, waku2, nimWakuMultiaddr] = await Promise.all([
|
||||
Waku.create({
|
||||
@ -259,14 +259,14 @@ describe('Waku Store', () => {
|
||||
nimWaku.getMultiaddrWithId(),
|
||||
]);
|
||||
|
||||
dbg('Waku nodes created');
|
||||
dbg("Waku nodes created");
|
||||
|
||||
await Promise.all([
|
||||
waku1.dial(nimWakuMultiaddr),
|
||||
waku2.dial(nimWakuMultiaddr),
|
||||
]);
|
||||
|
||||
dbg('Waku nodes connected to nim Waku');
|
||||
dbg("Waku nodes connected to nim Waku");
|
||||
|
||||
let lightPushPeerFound = false;
|
||||
while (!lightPushPeerFound) {
|
||||
@ -277,7 +277,7 @@ describe('Waku Store', () => {
|
||||
}
|
||||
}
|
||||
|
||||
dbg('Sending messages using light push');
|
||||
dbg("Sending messages using light push");
|
||||
await Promise.all([
|
||||
waku1.lightPush.push(encryptedAsymmetricMessage),
|
||||
waku1.lightPush.push(encryptedSymmetricMessage),
|
||||
@ -296,37 +296,37 @@ describe('Waku Store', () => {
|
||||
|
||||
waku2.store.addDecryptionKey(symKey);
|
||||
|
||||
dbg('Retrieve messages from store');
|
||||
dbg("Retrieve messages from store");
|
||||
const messages = await waku2.store.queryHistory([], {
|
||||
decryptionKeys: [privateKey],
|
||||
});
|
||||
|
||||
expect(messages?.length).eq(3);
|
||||
if (!messages) throw 'Length was tested';
|
||||
if (!messages) throw "Length was tested";
|
||||
expect(messages[0].payloadAsUtf8).to.eq(clearMessageText);
|
||||
expect(messages[1].payloadAsUtf8).to.eq(encryptedSymmetricMessageText);
|
||||
expect(messages[2].payloadAsUtf8).to.eq(encryptedAsymmetricMessageText);
|
||||
|
||||
!!waku1 && waku1.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku1 && waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Retrieves history with asymmetric & symmetric encrypted messages on different content topics', async function () {
|
||||
it("Retrieves history with asymmetric & symmetric encrypted messages on different content topics", async function () {
|
||||
this.timeout(10_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
await nimWaku.start({ persistMessages: true, lightpush: true });
|
||||
|
||||
const encryptedAsymmetricMessageText =
|
||||
'This message is encrypted for me using asymmetric';
|
||||
const encryptedAsymmetricContentTopic = '/test/1/asymmetric/proto';
|
||||
"This message is encrypted for me using asymmetric";
|
||||
const encryptedAsymmetricContentTopic = "/test/1/asymmetric/proto";
|
||||
const encryptedSymmetricMessageText =
|
||||
'This message is encrypted for me using symmetric encryption';
|
||||
const encryptedSymmetricContentTopic = '/test/1/symmetric/proto';
|
||||
"This message is encrypted for me using symmetric encryption";
|
||||
const encryptedSymmetricContentTopic = "/test/1/symmetric/proto";
|
||||
const clearMessageText =
|
||||
'This is a clear text message for everyone to read';
|
||||
"This is a clear text message for everyone to read";
|
||||
const otherEncMessageText =
|
||||
'This message is not for and I must not be able to read it';
|
||||
"This message is not for and I must not be able to read it";
|
||||
|
||||
const privateKey = generatePrivateKey();
|
||||
const symKey = generateSymmetricKey();
|
||||
@ -365,7 +365,7 @@ describe('Waku Store', () => {
|
||||
),
|
||||
]);
|
||||
|
||||
dbg('Messages have been encrypted');
|
||||
dbg("Messages have been encrypted");
|
||||
|
||||
const [waku1, waku2, nimWakuMultiaddr] = await Promise.all([
|
||||
Waku.create({
|
||||
@ -377,14 +377,14 @@ describe('Waku Store', () => {
|
||||
nimWaku.getMultiaddrWithId(),
|
||||
]);
|
||||
|
||||
dbg('Waku nodes created');
|
||||
dbg("Waku nodes created");
|
||||
|
||||
await Promise.all([
|
||||
waku1.dial(nimWakuMultiaddr),
|
||||
waku2.dial(nimWakuMultiaddr),
|
||||
]);
|
||||
|
||||
dbg('Waku nodes connected to nim Waku');
|
||||
dbg("Waku nodes connected to nim Waku");
|
||||
|
||||
let lightPushPeerFound = false;
|
||||
while (!lightPushPeerFound) {
|
||||
@ -395,7 +395,7 @@ describe('Waku Store', () => {
|
||||
}
|
||||
}
|
||||
|
||||
dbg('Sending messages using light push');
|
||||
dbg("Sending messages using light push");
|
||||
await Promise.all([
|
||||
waku1.lightPush.push(encryptedAsymmetricMessage),
|
||||
waku1.lightPush.push(encryptedSymmetricMessage),
|
||||
@ -417,22 +417,22 @@ describe('Waku Store', () => {
|
||||
method: DecryptionMethod.Symmetric,
|
||||
});
|
||||
|
||||
dbg('Retrieve messages from store');
|
||||
dbg("Retrieve messages from store");
|
||||
const messages = await waku2.store.queryHistory([], {
|
||||
decryptionKeys: [privateKey],
|
||||
});
|
||||
|
||||
expect(messages?.length).eq(3);
|
||||
if (!messages) throw 'Length was tested';
|
||||
if (!messages) throw "Length was tested";
|
||||
expect(messages[0].payloadAsUtf8).to.eq(clearMessageText);
|
||||
expect(messages[1].payloadAsUtf8).to.eq(encryptedSymmetricMessageText);
|
||||
expect(messages[2].payloadAsUtf8).to.eq(encryptedAsymmetricMessageText);
|
||||
|
||||
!!waku1 && waku1.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log('Waku failed to stop', e));
|
||||
!!waku1 && waku1.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
!!waku2 && waku2.stop().catch((e) => console.log("Waku failed to stop", e));
|
||||
});
|
||||
|
||||
it('Retrieves history using start and end time', async function () {
|
||||
it("Retrieves history using start and end time", async function () {
|
||||
this.timeout(5_000);
|
||||
|
||||
nimWaku = new NimWaku(makeLogFileName(this));
|
||||
@ -484,7 +484,7 @@ describe('Waku Store', () => {
|
||||
|
||||
expect(firstMessage?.length).eq(1);
|
||||
|
||||
expect(firstMessage[0]?.payloadAsUtf8).eq('Message 0');
|
||||
expect(firstMessage[0]?.payloadAsUtf8).eq("Message 0");
|
||||
|
||||
expect(bothMessages?.length).eq(2);
|
||||
});
|
||||
|
||||
@ -1,22 +1,22 @@
|
||||
import debug from 'debug';
|
||||
import concat from 'it-concat';
|
||||
import lp from 'it-length-prefixed';
|
||||
import pipe from 'it-pipe';
|
||||
import Libp2p from 'libp2p';
|
||||
import { Peer } from 'libp2p/src/peer-store';
|
||||
import PeerId from 'peer-id';
|
||||
import debug from "debug";
|
||||
import concat from "it-concat";
|
||||
import lp from "it-length-prefixed";
|
||||
import pipe from "it-pipe";
|
||||
import Libp2p from "libp2p";
|
||||
import { Peer } from "libp2p/src/peer-store";
|
||||
import PeerId from "peer-id";
|
||||
|
||||
import { HistoryResponse_Error } from '../../proto';
|
||||
import { getPeersForProtocol, selectRandomPeer } from '../select_peer';
|
||||
import { hexToBuf } from '../utils';
|
||||
import { DefaultPubSubTopic } from '../waku';
|
||||
import { DecryptionMethod, WakuMessage } from '../waku_message';
|
||||
import { HistoryResponse_Error } from "../../proto";
|
||||
import { getPeersForProtocol, selectRandomPeer } from "../select_peer";
|
||||
import { hexToBuf } from "../utils";
|
||||
import { DefaultPubSubTopic } from "../waku";
|
||||
import { DecryptionMethod, WakuMessage } from "../waku_message";
|
||||
|
||||
import { HistoryRPC, PageDirection } from './history_rpc';
|
||||
import { HistoryRPC, PageDirection } from "./history_rpc";
|
||||
|
||||
const dbg = debug('waku:store');
|
||||
const dbg = debug("waku:store");
|
||||
|
||||
export const StoreCodec = '/vac/waku/store/2.0.0-beta3';
|
||||
export const StoreCodec = "/vac/waku/store/2.0.0-beta3";
|
||||
|
||||
export const DefaultPageSize = 10;
|
||||
|
||||
@ -143,7 +143,7 @@ export class WakuStore {
|
||||
},
|
||||
{ contentTopics }
|
||||
);
|
||||
dbg('Querying history with the following options', {
|
||||
dbg("Querying history with the following options", {
|
||||
peerId: options?.peerId?.toB58String(),
|
||||
...options,
|
||||
});
|
||||
@ -156,12 +156,12 @@ export class WakuStore {
|
||||
} else {
|
||||
peer = await this.randomPeer;
|
||||
if (!peer)
|
||||
throw 'Failed to find known peer that registers waku store protocol';
|
||||
throw "Failed to find known peer that registers waku store protocol";
|
||||
}
|
||||
if (!peer.protocols.includes(StoreCodec))
|
||||
throw `Peer does not register waku store protocol: ${peer.id.toB58String()}`;
|
||||
const connection = this.libp2p.connectionManager.get(peer.id);
|
||||
if (!connection) throw 'Failed to get a connection to the peer';
|
||||
if (!connection) throw "Failed to get a connection to the peer";
|
||||
|
||||
const decryptionKeys = Array.from(this.decryptionKeys).map(
|
||||
([key, { method, contentTopics }]) => {
|
||||
@ -191,7 +191,7 @@ export class WakuStore {
|
||||
const { stream } = await connection.newStream(StoreCodec);
|
||||
const queryOpts = Object.assign(opts, { cursor });
|
||||
const historyRpcQuery = HistoryRPC.createQuery(queryOpts);
|
||||
dbg('Querying store peer', connection.remoteAddr.toString());
|
||||
dbg("Querying store peer", connection.remoteAddr.toString());
|
||||
|
||||
const res = await pipe(
|
||||
[historyRpcQuery.encode()],
|
||||
@ -204,19 +204,19 @@ export class WakuStore {
|
||||
|
||||
const response = reply.response;
|
||||
if (!response) {
|
||||
throw 'History response misses response field';
|
||||
throw "History response misses response field";
|
||||
}
|
||||
|
||||
if (
|
||||
response.error &&
|
||||
response.error === HistoryResponse_Error.ERROR_INVALID_CURSOR
|
||||
) {
|
||||
throw 'History response contains an Error: INVALID CURSOR';
|
||||
throw "History response contains an Error: INVALID CURSOR";
|
||||
}
|
||||
|
||||
if (!response.messages || !response.messages.length) {
|
||||
// No messages left (or stored)
|
||||
console.log('No messages present in HistoryRPC response');
|
||||
console.log("No messages present in HistoryRPC response");
|
||||
return messages;
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ export class WakuStore {
|
||||
if (cursor === undefined) {
|
||||
// If the server does not return cursor then there is an issue,
|
||||
// Need to abort or we end up in an infinite loop
|
||||
console.log('No cursor returned by peer.');
|
||||
console.log("No cursor returned by peer.");
|
||||
return messages;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
export { WakuMessage } from './waku/v2/message';
|
||||
export { WakuMessage } from "./waku/v2/message";
|
||||
|
||||
export {
|
||||
Index,
|
||||
@ -9,4 +9,4 @@ export {
|
||||
HistoryResponse,
|
||||
HistoryResponse_Error,
|
||||
HistoryRPC,
|
||||
} from './waku/v2/store';
|
||||
} from "./waku/v2/store";
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
/* eslint-disable */
|
||||
import Long from 'long';
|
||||
import _m0 from 'protobufjs/minimal';
|
||||
import { WakuMessage } from '../../waku/v2/message';
|
||||
import Long from "long";
|
||||
import _m0 from "protobufjs/minimal";
|
||||
import { WakuMessage } from "../../waku/v2/message";
|
||||
|
||||
export const protobufPackage = 'waku.v2';
|
||||
export const protobufPackage = "waku.v2";
|
||||
|
||||
export interface PushRequest {
|
||||
pubSubTopic: string;
|
||||
@ -22,7 +22,7 @@ export interface PushRPC {
|
||||
}
|
||||
|
||||
function createBasePushRequest(): PushRequest {
|
||||
return { pubSubTopic: '', message: undefined };
|
||||
return { pubSubTopic: "", message: undefined };
|
||||
}
|
||||
|
||||
export const PushRequest = {
|
||||
@ -30,7 +30,7 @@ export const PushRequest = {
|
||||
message: PushRequest,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.pubSubTopic !== '') {
|
||||
if (message.pubSubTopic !== "") {
|
||||
writer.uint32(10).string(message.pubSubTopic);
|
||||
}
|
||||
if (message.message !== undefined) {
|
||||
@ -62,7 +62,7 @@ export const PushRequest = {
|
||||
|
||||
fromJSON(object: any): PushRequest {
|
||||
return {
|
||||
pubSubTopic: isSet(object.pubSubTopic) ? String(object.pubSubTopic) : '',
|
||||
pubSubTopic: isSet(object.pubSubTopic) ? String(object.pubSubTopic) : "",
|
||||
message: isSet(object.message)
|
||||
? WakuMessage.fromJSON(object.message)
|
||||
: undefined,
|
||||
@ -84,7 +84,7 @@ export const PushRequest = {
|
||||
object: I
|
||||
): PushRequest {
|
||||
const message = createBasePushRequest();
|
||||
message.pubSubTopic = object.pubSubTopic ?? '';
|
||||
message.pubSubTopic = object.pubSubTopic ?? "";
|
||||
message.message =
|
||||
object.message !== undefined && object.message !== null
|
||||
? WakuMessage.fromPartial(object.message)
|
||||
@ -94,7 +94,7 @@ export const PushRequest = {
|
||||
};
|
||||
|
||||
function createBasePushResponse(): PushResponse {
|
||||
return { isSuccess: false, info: '' };
|
||||
return { isSuccess: false, info: "" };
|
||||
}
|
||||
|
||||
export const PushResponse = {
|
||||
@ -105,7 +105,7 @@ export const PushResponse = {
|
||||
if (message.isSuccess === true) {
|
||||
writer.uint32(8).bool(message.isSuccess);
|
||||
}
|
||||
if (message.info !== '') {
|
||||
if (message.info !== "") {
|
||||
writer.uint32(18).string(message.info);
|
||||
}
|
||||
return writer;
|
||||
@ -135,7 +135,7 @@ export const PushResponse = {
|
||||
fromJSON(object: any): PushResponse {
|
||||
return {
|
||||
isSuccess: isSet(object.isSuccess) ? Boolean(object.isSuccess) : false,
|
||||
info: isSet(object.info) ? String(object.info) : '',
|
||||
info: isSet(object.info) ? String(object.info) : "",
|
||||
};
|
||||
},
|
||||
|
||||
@ -151,13 +151,13 @@ export const PushResponse = {
|
||||
): PushResponse {
|
||||
const message = createBasePushResponse();
|
||||
message.isSuccess = object.isSuccess ?? false;
|
||||
message.info = object.info ?? '';
|
||||
message.info = object.info ?? "";
|
||||
return message;
|
||||
},
|
||||
};
|
||||
|
||||
function createBasePushRPC(): PushRPC {
|
||||
return { requestId: '', request: undefined, response: undefined };
|
||||
return { requestId: "", request: undefined, response: undefined };
|
||||
}
|
||||
|
||||
export const PushRPC = {
|
||||
@ -165,7 +165,7 @@ export const PushRPC = {
|
||||
message: PushRPC,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.requestId !== '') {
|
||||
if (message.requestId !== "") {
|
||||
writer.uint32(10).string(message.requestId);
|
||||
}
|
||||
if (message.request !== undefined) {
|
||||
@ -203,7 +203,7 @@ export const PushRPC = {
|
||||
|
||||
fromJSON(object: any): PushRPC {
|
||||
return {
|
||||
requestId: isSet(object.requestId) ? String(object.requestId) : '',
|
||||
requestId: isSet(object.requestId) ? String(object.requestId) : "",
|
||||
request: isSet(object.request)
|
||||
? PushRequest.fromJSON(object.request)
|
||||
: undefined,
|
||||
@ -229,7 +229,7 @@ export const PushRPC = {
|
||||
|
||||
fromPartial<I extends Exact<DeepPartial<PushRPC>, I>>(object: I): PushRPC {
|
||||
const message = createBasePushRPC();
|
||||
message.requestId = object.requestId ?? '';
|
||||
message.requestId = object.requestId ?? "";
|
||||
message.request =
|
||||
object.request !== undefined && object.request !== null
|
||||
? PushRequest.fromPartial(object.request)
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
/* eslint-disable */
|
||||
import Long from 'long';
|
||||
import _m0 from 'protobufjs/minimal';
|
||||
import Long from "long";
|
||||
import _m0 from "protobufjs/minimal";
|
||||
|
||||
export const protobufPackage = 'waku.v2';
|
||||
export const protobufPackage = "waku.v2";
|
||||
|
||||
export interface WakuMessage {
|
||||
payload?: Uint8Array | undefined;
|
||||
@ -111,16 +111,16 @@ declare var self: any | undefined;
|
||||
declare var window: any | undefined;
|
||||
declare var global: any | undefined;
|
||||
var globalThis: any = (() => {
|
||||
if (typeof globalThis !== 'undefined') return globalThis;
|
||||
if (typeof self !== 'undefined') return self;
|
||||
if (typeof window !== 'undefined') return window;
|
||||
if (typeof global !== 'undefined') return global;
|
||||
throw 'Unable to locate global object';
|
||||
if (typeof globalThis !== "undefined") return globalThis;
|
||||
if (typeof self !== "undefined") return self;
|
||||
if (typeof window !== "undefined") return window;
|
||||
if (typeof global !== "undefined") return global;
|
||||
throw "Unable to locate global object";
|
||||
})();
|
||||
|
||||
const atob: (b64: string) => string =
|
||||
globalThis.atob ||
|
||||
((b64) => globalThis.Buffer.from(b64, 'base64').toString('binary'));
|
||||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
|
||||
function bytesFromBase64(b64: string): Uint8Array {
|
||||
const bin = atob(b64);
|
||||
const arr = new Uint8Array(bin.length);
|
||||
@ -132,13 +132,13 @@ function bytesFromBase64(b64: string): Uint8Array {
|
||||
|
||||
const btoa: (bin: string) => string =
|
||||
globalThis.btoa ||
|
||||
((bin) => globalThis.Buffer.from(bin, 'binary').toString('base64'));
|
||||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
|
||||
function base64FromBytes(arr: Uint8Array): string {
|
||||
const bin: string[] = [];
|
||||
for (const byte of arr) {
|
||||
bin.push(String.fromCharCode(byte));
|
||||
}
|
||||
return btoa(bin.join(''));
|
||||
return btoa(bin.join(""));
|
||||
}
|
||||
|
||||
type Builtin =
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
/* eslint-disable */
|
||||
import Long from 'long';
|
||||
import _m0 from 'protobufjs/minimal';
|
||||
import { WakuMessage } from '../../waku/v2/message';
|
||||
import Long from "long";
|
||||
import _m0 from "protobufjs/minimal";
|
||||
import { WakuMessage } from "../../waku/v2/message";
|
||||
|
||||
export const protobufPackage = 'waku.v2';
|
||||
export const protobufPackage = "waku.v2";
|
||||
|
||||
export interface Index {
|
||||
digest: Uint8Array;
|
||||
@ -28,13 +28,13 @@ export function pagingInfo_DirectionFromJSON(
|
||||
): PagingInfo_Direction {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case 'DIRECTION_BACKWARD_UNSPECIFIED':
|
||||
case "DIRECTION_BACKWARD_UNSPECIFIED":
|
||||
return PagingInfo_Direction.DIRECTION_BACKWARD_UNSPECIFIED;
|
||||
case 1:
|
||||
case 'DIRECTION_FORWARD':
|
||||
case "DIRECTION_FORWARD":
|
||||
return PagingInfo_Direction.DIRECTION_FORWARD;
|
||||
case -1:
|
||||
case 'UNRECOGNIZED':
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return PagingInfo_Direction.UNRECOGNIZED;
|
||||
}
|
||||
@ -45,11 +45,11 @@ export function pagingInfo_DirectionToJSON(
|
||||
): string {
|
||||
switch (object) {
|
||||
case PagingInfo_Direction.DIRECTION_BACKWARD_UNSPECIFIED:
|
||||
return 'DIRECTION_BACKWARD_UNSPECIFIED';
|
||||
return "DIRECTION_BACKWARD_UNSPECIFIED";
|
||||
case PagingInfo_Direction.DIRECTION_FORWARD:
|
||||
return 'DIRECTION_FORWARD';
|
||||
return "DIRECTION_FORWARD";
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,13 +82,13 @@ export function historyResponse_ErrorFromJSON(
|
||||
): HistoryResponse_Error {
|
||||
switch (object) {
|
||||
case 0:
|
||||
case 'ERROR_NONE_UNSPECIFIED':
|
||||
case "ERROR_NONE_UNSPECIFIED":
|
||||
return HistoryResponse_Error.ERROR_NONE_UNSPECIFIED;
|
||||
case 1:
|
||||
case 'ERROR_INVALID_CURSOR':
|
||||
case "ERROR_INVALID_CURSOR":
|
||||
return HistoryResponse_Error.ERROR_INVALID_CURSOR;
|
||||
case -1:
|
||||
case 'UNRECOGNIZED':
|
||||
case "UNRECOGNIZED":
|
||||
default:
|
||||
return HistoryResponse_Error.UNRECOGNIZED;
|
||||
}
|
||||
@ -99,11 +99,11 @@ export function historyResponse_ErrorToJSON(
|
||||
): string {
|
||||
switch (object) {
|
||||
case HistoryResponse_Error.ERROR_NONE_UNSPECIFIED:
|
||||
return 'ERROR_NONE_UNSPECIFIED';
|
||||
return "ERROR_NONE_UNSPECIFIED";
|
||||
case HistoryResponse_Error.ERROR_INVALID_CURSOR:
|
||||
return 'ERROR_INVALID_CURSOR';
|
||||
return "ERROR_INVALID_CURSOR";
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ export const PagingInfo = {
|
||||
};
|
||||
|
||||
function createBaseContentFilter(): ContentFilter {
|
||||
return { contentTopic: '' };
|
||||
return { contentTopic: "" };
|
||||
}
|
||||
|
||||
export const ContentFilter = {
|
||||
@ -277,7 +277,7 @@ export const ContentFilter = {
|
||||
message: ContentFilter,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.contentTopic !== '') {
|
||||
if (message.contentTopic !== "") {
|
||||
writer.uint32(10).string(message.contentTopic);
|
||||
}
|
||||
return writer;
|
||||
@ -305,7 +305,7 @@ export const ContentFilter = {
|
||||
return {
|
||||
contentTopic: isSet(object.contentTopic)
|
||||
? String(object.contentTopic)
|
||||
: '',
|
||||
: "",
|
||||
};
|
||||
},
|
||||
|
||||
@ -320,7 +320,7 @@ export const ContentFilter = {
|
||||
object: I
|
||||
): ContentFilter {
|
||||
const message = createBaseContentFilter();
|
||||
message.contentTopic = object.contentTopic ?? '';
|
||||
message.contentTopic = object.contentTopic ?? "";
|
||||
return message;
|
||||
},
|
||||
};
|
||||
@ -536,7 +536,7 @@ export const HistoryResponse = {
|
||||
};
|
||||
|
||||
function createBaseHistoryRPC(): HistoryRPC {
|
||||
return { requestId: '', query: undefined, response: undefined };
|
||||
return { requestId: "", query: undefined, response: undefined };
|
||||
}
|
||||
|
||||
export const HistoryRPC = {
|
||||
@ -544,7 +544,7 @@ export const HistoryRPC = {
|
||||
message: HistoryRPC,
|
||||
writer: _m0.Writer = _m0.Writer.create()
|
||||
): _m0.Writer {
|
||||
if (message.requestId !== '') {
|
||||
if (message.requestId !== "") {
|
||||
writer.uint32(10).string(message.requestId);
|
||||
}
|
||||
if (message.query !== undefined) {
|
||||
@ -585,7 +585,7 @@ export const HistoryRPC = {
|
||||
|
||||
fromJSON(object: any): HistoryRPC {
|
||||
return {
|
||||
requestId: isSet(object.requestId) ? String(object.requestId) : '',
|
||||
requestId: isSet(object.requestId) ? String(object.requestId) : "",
|
||||
query: isSet(object.query)
|
||||
? HistoryQuery.fromJSON(object.query)
|
||||
: undefined,
|
||||
@ -613,7 +613,7 @@ export const HistoryRPC = {
|
||||
object: I
|
||||
): HistoryRPC {
|
||||
const message = createBaseHistoryRPC();
|
||||
message.requestId = object.requestId ?? '';
|
||||
message.requestId = object.requestId ?? "";
|
||||
message.query =
|
||||
object.query !== undefined && object.query !== null
|
||||
? HistoryQuery.fromPartial(object.query)
|
||||
@ -630,16 +630,16 @@ declare var self: any | undefined;
|
||||
declare var window: any | undefined;
|
||||
declare var global: any | undefined;
|
||||
var globalThis: any = (() => {
|
||||
if (typeof globalThis !== 'undefined') return globalThis;
|
||||
if (typeof self !== 'undefined') return self;
|
||||
if (typeof window !== 'undefined') return window;
|
||||
if (typeof global !== 'undefined') return global;
|
||||
throw 'Unable to locate global object';
|
||||
if (typeof globalThis !== "undefined") return globalThis;
|
||||
if (typeof self !== "undefined") return self;
|
||||
if (typeof window !== "undefined") return window;
|
||||
if (typeof global !== "undefined") return global;
|
||||
throw "Unable to locate global object";
|
||||
})();
|
||||
|
||||
const atob: (b64: string) => string =
|
||||
globalThis.atob ||
|
||||
((b64) => globalThis.Buffer.from(b64, 'base64').toString('binary'));
|
||||
((b64) => globalThis.Buffer.from(b64, "base64").toString("binary"));
|
||||
function bytesFromBase64(b64: string): Uint8Array {
|
||||
const bin = atob(b64);
|
||||
const arr = new Uint8Array(bin.length);
|
||||
@ -651,13 +651,13 @@ function bytesFromBase64(b64: string): Uint8Array {
|
||||
|
||||
const btoa: (bin: string) => string =
|
||||
globalThis.btoa ||
|
||||
((bin) => globalThis.Buffer.from(bin, 'binary').toString('base64'));
|
||||
((bin) => globalThis.Buffer.from(bin, "binary").toString("base64"));
|
||||
function base64FromBytes(arr: Uint8Array): string {
|
||||
const bin: string[] = [];
|
||||
for (const byte of arr) {
|
||||
bin.push(String.fromCharCode(byte));
|
||||
}
|
||||
return btoa(bin.join(''));
|
||||
return btoa(bin.join(""));
|
||||
}
|
||||
|
||||
type Builtin =
|
||||
@ -689,7 +689,7 @@ export type Exact<P, I extends P> = P extends Builtin
|
||||
|
||||
function longToNumber(long: Long): number {
|
||||
if (long.gt(Number.MAX_SAFE_INTEGER)) {
|
||||
throw new globalThis.Error('Value is larger than Number.MAX_SAFE_INTEGER');
|
||||
throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER");
|
||||
}
|
||||
return long.toNumber();
|
||||
}
|
||||
|
||||
@ -5,10 +5,10 @@
|
||||
* @module
|
||||
*/
|
||||
|
||||
import fs, { promises as asyncFs } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import fs, { promises as asyncFs } from "fs";
|
||||
import { promisify } from "util";
|
||||
|
||||
import { delay } from '../lib/delay';
|
||||
import { delay } from "../lib/delay";
|
||||
export const existsAsync = (filepath: string): Promise<void> =>
|
||||
asyncFs.access(filepath, fs.constants.F_OK);
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* @module
|
||||
*/
|
||||
|
||||
export * from './async_fs';
|
||||
export * from './constants';
|
||||
export * from './log_file';
|
||||
export * from './nim_waku';
|
||||
export * from "./async_fs";
|
||||
export * from "./constants";
|
||||
export * from "./log_file";
|
||||
export * from "./nim_waku";
|
||||
|
||||
@ -1,21 +1,21 @@
|
||||
import { expect } from 'chai';
|
||||
import { expect } from "chai";
|
||||
|
||||
import { makeLogFileName } from './log_file';
|
||||
import { makeLogFileName } from "./log_file";
|
||||
|
||||
describe('This', function () {
|
||||
describe('Is', function () {
|
||||
it('A test', function () {
|
||||
expect(makeLogFileName(this)).to.equal('This_Is_A_test');
|
||||
describe("This", function () {
|
||||
describe("Is", function () {
|
||||
it("A test", function () {
|
||||
expect(makeLogFileName(this)).to.equal("This_Is_A_test");
|
||||
});
|
||||
});
|
||||
|
||||
describe('Is also', function () {
|
||||
describe("Is also", function () {
|
||||
let testName: string;
|
||||
beforeEach(function () {
|
||||
testName = makeLogFileName(this);
|
||||
});
|
||||
it('A test', function () {
|
||||
expect(testName).to.equal('This_Is_also_A_test');
|
||||
it("A test", function () {
|
||||
expect(testName).to.equal("This_Is_also_A_test");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -5,11 +5,11 @@
|
||||
* @module
|
||||
*/
|
||||
|
||||
import { Context } from 'mocha';
|
||||
import pTimeout from 'p-timeout';
|
||||
import { Tail } from 'tail';
|
||||
import { Context } from "mocha";
|
||||
import pTimeout from "p-timeout";
|
||||
import { Tail } from "tail";
|
||||
|
||||
import { waitForFile } from './async_fs';
|
||||
import { waitForFile } from "./async_fs";
|
||||
|
||||
export default async function waitForLine(
|
||||
filepath: string,
|
||||
@ -35,20 +35,20 @@ export default async function waitForLine(
|
||||
|
||||
async function find(tail: Tail, line: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
tail.on('line', (data: string) => {
|
||||
tail.on("line", (data: string) => {
|
||||
if (data.includes(line)) {
|
||||
resolve(data);
|
||||
}
|
||||
});
|
||||
|
||||
tail.on('error', (err) => {
|
||||
tail.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clean(str: string): string {
|
||||
return str.replace(/ /g, '_').replace(/[':()/]/g, '');
|
||||
return str.replace(/ /g, "_").replace(/[':()/]/g, "");
|
||||
}
|
||||
|
||||
export function makeLogFileName(ctx: Context): string {
|
||||
@ -57,7 +57,7 @@ export function makeLogFileName(ctx: Context): string {
|
||||
let suite = unitTest?.parent;
|
||||
|
||||
while (suite && suite.title) {
|
||||
name = clean(suite.title) + '_' + name;
|
||||
name = clean(suite.title) + "_" + name;
|
||||
suite = suite.parent;
|
||||
}
|
||||
return name;
|
||||
|
||||
@ -1,41 +1,41 @@
|
||||
import { expect } from 'chai';
|
||||
import { expect } from "chai";
|
||||
|
||||
import { argsToArray, bufToHex, defaultArgs, strToHex } from './nim_waku';
|
||||
import { argsToArray, bufToHex, defaultArgs, strToHex } from "./nim_waku";
|
||||
|
||||
describe('nim_waku', () => {
|
||||
it('Correctly serialized arguments', function () {
|
||||
describe("nim_waku", () => {
|
||||
it("Correctly serialized arguments", function () {
|
||||
const args = defaultArgs();
|
||||
Object.assign(args, { portsShift: 42 });
|
||||
|
||||
const actual = argsToArray(args);
|
||||
|
||||
const expected = [
|
||||
'--nat=none',
|
||||
'--listen-address=127.0.0.1',
|
||||
'--relay=true',
|
||||
'--rpc=true',
|
||||
'--rpc-admin=true',
|
||||
'--websocket-support=true',
|
||||
'--ports-shift=42',
|
||||
"--nat=none",
|
||||
"--listen-address=127.0.0.1",
|
||||
"--relay=true",
|
||||
"--rpc=true",
|
||||
"--rpc-admin=true",
|
||||
"--websocket-support=true",
|
||||
"--ports-shift=42",
|
||||
];
|
||||
|
||||
expect(actual).to.deep.equal(expected);
|
||||
});
|
||||
|
||||
it('Convert utf-8 string to hex', function () {
|
||||
const str = 'This is an utf-8 string.';
|
||||
const expected = '5468697320697320616e207574662d3820737472696e672e';
|
||||
it("Convert utf-8 string to hex", function () {
|
||||
const str = "This is an utf-8 string.";
|
||||
const expected = "5468697320697320616e207574662d3820737472696e672e";
|
||||
|
||||
const actual = strToHex(str);
|
||||
expect(actual).deep.equal(expected);
|
||||
});
|
||||
|
||||
it('Convert buffer to hex', function () {
|
||||
it("Convert buffer to hex", function () {
|
||||
const buf = Uint8Array.from([
|
||||
0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x6e, 0x20, 0x75,
|
||||
0x74, 0x66, 0x2d, 0x38, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e,
|
||||
]);
|
||||
const expected = '5468697320697320616e207574662d3820737472696e672e';
|
||||
const expected = "5468697320697320616e207574662d3820737472696e672e";
|
||||
|
||||
const actual = bufToHex(buf);
|
||||
expect(actual).to.deep.equal(expected);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user