Merge pull request #3 from NodeFactoryIo/morrigan/interface

New interface with XX handshake
This commit is contained in:
Belma Gutlic
2019-11-25 10:53:15 +01:00
committed by GitHub
19 changed files with 574 additions and 66 deletions

View File

@@ -16,6 +16,7 @@
"devDependencies": {
"@babel/cli": "^7.6.4",
"@babel/core": "^7.6.4",
"@babel/plugin-proposal-async-generator-functions": "^7.7.0",
"@babel/plugin-proposal-object-rest-spread": "^7.6.2",
"@babel/preset-env": "^7.6.3",
"@babel/preset-typescript": "^7.6.0",
@@ -45,13 +46,16 @@
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-proposal-object-rest-spread"
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-async-generator-functions"
]
},
"dependencies": {
"bcrypto": "^4.2.3",
"bn.js": "^5.0.0",
"buffer": "^5.4.3",
"it-pair": "^1.0.0",
"it-pb-rpc": "^0.1.3",
"protobufjs": "~6.8.8"
}
}

6
src/@types/it-pair/index.d.ts vendored Normal file
View File

@@ -0,0 +1,6 @@
export type Duplex = [Stream, Stream];
type Stream = {
sink(source: Iterable<any>);
source: Record<string, any>;
}

15
src/@types/it-pb-rpc/index.d.ts vendored Normal file
View File

@@ -0,0 +1,15 @@
declare module "it-pb-rpc" {
import { Buffer } from "buffer";
import { Duplex } from "it-pair";
type WrappedDuplex = {
read(bytes: number): Buffer;
readLP(): Buffer;
write(input: Buffer): void;
writeLP(input: Buffer): void;
unwrap(): Duplex;
}
function Wrap (duplex: any): WrappedDuplex;
export = Wrap;
}

25
src/@types/libp2p.ts Normal file
View File

@@ -0,0 +1,25 @@
import { bytes, bytes32 } from "./basic";
import { Duplex } from "it-pair";
export interface KeyPair {
publicKey: bytes32;
privateKey: bytes32;
}
export type PeerId = {
id: string;
privKey: string;
pubKey: string;
};
export interface NoiseConnection {
remoteEarlyData?(): bytes;
secureOutbound(localPeer: PeerId, insecure: any, remotePeer: PeerId): Promise<SecureOutbound>;
secureInbound(localPeer: PeerId, insecure: any, remotePeer: PeerId): Promise<SecureOutbound>;
}
export type SecureOutbound = {
conn: Duplex;
remotePeer: PeerId;
}

15
src/crypto.ts Normal file
View File

@@ -0,0 +1,15 @@
import { Duplex } from "it-pair";
import { NoiseSession } from "./xx";
// Send encrypted payload from the user to stream
export async function encryptStreams(streams: Duplex, session: NoiseSession): Promise<Duplex> {
// TODO: implement
return streams;
}
// Decrypt received payload from the stream and pipe to user
export async function decryptStreams(streams: Duplex, session: NoiseSession): Promise<Duplex> {
// TODO: implement
return streams;
}

View File

@@ -1,3 +0,0 @@
export function encrypt() {
return "Encrypt world";
}

89
src/handshake.ts Normal file
View File

@@ -0,0 +1,89 @@
import { bytes, bytes32 } from "./@types/basic";
import { NoiseSession, XXHandshake } from "./xx";
import { KeyPair } from "./@types/libp2p";
import { Buffer } from "buffer";
import {
createHandshakePayload,
decodeMessageBuffer,
encodeMessageBuffer,
getHandshakePayload,
signPayload
} from "./utils";
import { WrappedConnection } from "./noise";
type handshakeType = "XX";
export class Handshake {
private type: handshakeType;
private remotePublicKey: bytes;
private prologue: bytes32;
private staticKeys: KeyPair;
private connection: WrappedConnection;
private xx: XXHandshake;
constructor(
type: handshakeType,
remotePublicKey: bytes,
prologue: bytes32,
staticKeys: KeyPair,
connection: WrappedConnection,
) {
this.type = type;
this.remotePublicKey = remotePublicKey;
this.prologue = prologue;
this.staticKeys = staticKeys;
this.connection = connection;
this.xx = new XXHandshake();
}
// stage 0
async propose(isInitiator: boolean, earlyData?: bytes): Promise<NoiseSession> {
const ns = await this.xx.initSession(isInitiator, this.prologue, this.staticKeys, this.remotePublicKey);
if (isInitiator) {
const signedPayload = signPayload(this.staticKeys.privateKey, getHandshakePayload(this.staticKeys.publicKey));
const handshakePayload = await createHandshakePayload(
this.staticKeys.publicKey,
signedPayload,
earlyData,
this.staticKeys.privateKey
);
const message = Buffer.concat([Buffer.alloc(0), handshakePayload]);
const messageBuffer = await this.xx.sendMessage(ns, message);
this.connection.writeLP(encodeMessageBuffer(messageBuffer));
} else {
const receivedMessageBuffer = (await this.connection.readLP()).slice();
const plaintext = await this.xx.recvMessage(ns, decodeMessageBuffer(receivedMessageBuffer));
}
return ns;
}
// stage 1
async exchange(isInitiator: boolean, session: NoiseSession): Promise<void> {
if (isInitiator) {
const receivedMessageBuffer = (await this.connection.readLP()).slice();
const plaintext = await this.xx.recvMessage(session, decodeMessageBuffer(receivedMessageBuffer));
} else {
// create payload as responder
const signedPayload = signPayload(this.staticKeys.privateKey, getHandshakePayload(this.staticKeys.publicKey));
const handshakePayload = await createHandshakePayload(this.remotePublicKey, signedPayload);
const message = Buffer.concat([Buffer.alloc(0), handshakePayload]);
const messageBuffer = await this.xx.sendMessage(session, message);
this.connection.writeLP(encodeMessageBuffer(messageBuffer));
}
}
// stage 2
async finish(isInitiator: boolean, session: NoiseSession): Promise<void> {
if (isInitiator) {
const messageBuffer = await this.xx.sendMessage(session, Buffer.alloc(0));
this.connection.writeLP(encodeMessageBuffer(messageBuffer));
} else {
const receivedMessageBuffer = (await this.connection.readLP()).slice();
const plaintext = await this.xx.recvMessage(session, decodeMessageBuffer(receivedMessageBuffer));
}
}
}

View File

@@ -1,8 +1 @@
import { encrypt } from './encrypt';
const tag = '/noise';
export {
tag,
encrypt,
}
export * from "./noise";

85
src/noise.ts Normal file
View File

@@ -0,0 +1,85 @@
import { x25519 } from 'bcrypto';
import { Buffer } from "buffer";
import Wrap from 'it-pb-rpc';
import { Handshake } from "./handshake";
import { generateKeypair } from "./utils";
import { decryptStreams, encryptStreams } from "./crypto";
import { bytes } from "./@types/basic";
import { NoiseConnection, PeerId, KeyPair, SecureOutbound } from "./@types/libp2p";
import { Duplex } from "./@types/it-pair";
export type WrappedConnection = ReturnType<typeof Wrap>;
export class Noise implements NoiseConnection {
public protocol = "/noise";
private readonly privateKey: bytes;
private readonly staticKeys: KeyPair;
private readonly earlyData?: bytes;
constructor(privateKey: bytes, staticNoiseKey?: bytes, earlyData?: bytes) {
this.privateKey = privateKey;
this.earlyData = earlyData;
if (staticNoiseKey) {
const publicKey = x25519.publicKeyCreate(staticNoiseKey);
this.staticKeys = {
privateKey: staticNoiseKey,
publicKey,
}
} else {
this.staticKeys = generateKeypair();
}
}
/**
* Encrypt outgoing data to the remote party (handshake as initiator)
* @param {PeerId} localPeer - PeerId of the receiving peer
* @param connection - streaming iterable duplex that will be encrypted
* @param {PeerId} remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer.
* @returns {Promise<SecureOutbound>}
*/
public async secureOutbound(localPeer: PeerId, connection: any, remotePeer: PeerId): Promise<SecureOutbound> {
const wrappedConnection = Wrap(connection);
const remotePublicKey = Buffer.from(remotePeer.pubKey);
const session = await this.createSecureConnection(wrappedConnection, remotePublicKey, true);
return {
conn: session,
remotePeer,
}
}
/**
* Decrypt incoming data (handshake as responder).
* @param {PeerId} localPeer - PeerId of the receiving peer.
* @param connection - streaming iterable duplex that will be encryption.
* @param {PeerId} remotePeer - optional PeerId of the initiating peer, if known. This may only exist during transport upgrades.
* @returns {Promise<SecureOutbound>}
*/
// tslint:disable-next-line
public async secureInbound(localPeer: PeerId, connection: any, remotePeer: PeerId): Promise<SecureOutbound> {
return {
conn: undefined,
remotePeer
}
}
private async createSecureConnection(
connection: WrappedConnection,
remotePublicKey: bytes,
isInitiator: boolean,
): Promise<Duplex> {
const prologue = Buffer.from(this.protocol);
const handshake = new Handshake('XX', remotePublicKey, prologue, this.staticKeys, connection);
const session = await handshake.propose(isInitiator, this.earlyData);
await handshake.exchange(isInitiator, session);
await handshake.finish(isInitiator, session);
return await encryptStreams(connection, session);
}
}

73
src/utils.ts Normal file
View File

@@ -0,0 +1,73 @@
import { x25519, ed25519 } from 'bcrypto';
import protobuf from "protobufjs";
import { Buffer } from "buffer";
import { KeyPair } from "./@types/libp2p";
import { bytes } from "./@types/basic";
import { MessageBuffer } from "./xx";
export async function loadPayloadProto () {
const payloadProtoBuf = await protobuf.load("protos/payload.proto");
return payloadProtoBuf.lookupType("pb.NoiseHandshakePayload");
}
export function generateKeypair(): KeyPair {
const privateKey = x25519.privateKeyGenerate();
const publicKey = x25519.publicKeyCreate(privateKey);
return {
publicKey,
privateKey,
}
}
export async function createHandshakePayload(
libp2pPublicKey: bytes,
signedPayload: bytes,
earlyData?: bytes,
libp2pPrivateKey?: bytes,
): Promise<bytes> {
const NoiseHandshakePayload = await loadPayloadProto();
const payloadInit = NoiseHandshakePayload.create({
libp2pKey: libp2pPublicKey,
noiseStaticKeySignature: signedPayload,
...resolveEarlyDataPayload(libp2pPrivateKey, earlyData),
});
return Buffer.from(NoiseHandshakePayload.encode(payloadInit).finish());
}
export function signPayload(privateKey: bytes, payload: bytes) {
return ed25519.sign(payload, privateKey);
}
export const getHandshakePayload = (publicKey: bytes ) => Buffer.concat([Buffer.from("noise-libp2p-static-key:"), publicKey]);
export const getEarlyDataPayload = (earlyData: bytes) => Buffer.concat([Buffer.from("noise-libp2p-early-data:"), earlyData]);
function resolveEarlyDataPayload(privateKey?: bytes, earlyData?: bytes): Record<string, any> {
if (!earlyData || !privateKey) {
return {};
}
const payload = getEarlyDataPayload(earlyData);
const signedPayload = signPayload(privateKey, payload);
return {
libp2pData: payload,
libp2pDataSignature: signedPayload,
}
}
export function encodeMessageBuffer(message: MessageBuffer): bytes {
return Buffer.concat([message.ne, message.ns, message.ciphertext]);
}
export function decodeMessageBuffer(message: bytes): MessageBuffer {
return {
ne: message.slice(0, 32),
ns: message.slice(32, 80),
ciphertext: message.slice(80, message.length),
}
}

View File

@@ -1,14 +1,12 @@
import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic'
import { Buffer } from 'buffer';
import { AEAD, x25519, HKDF, SHA256 } from 'bcrypto';
import { BN } from 'bn.js';
export interface KeyPair {
publicKey: bytes32;
privateKey: bytes32;
}
import { bytes32, uint32, uint64, bytes } from './@types/basic'
import { KeyPair } from './@types/libp2p'
import { generateKeypair } from './utils';
interface MessageBuffer {
export interface MessageBuffer {
ne: bytes32;
ns: bytes;
ciphertext: bytes;
@@ -34,7 +32,7 @@ type HandshakeState = {
psk: bytes32;
}
type NoiseSession = {
export type NoiseSession = {
hs: HandshakeState;
h?: bytes32;
cs1?: CipherState;
@@ -157,7 +155,7 @@ export class XXHandshake {
return { cs, ck, h };
}
private mixKey(ss: SymmetricState, ikm: bytes32) {
private mixKey(ss: SymmetricState, ikm: bytes32): void {
const [ ck, tempK ] = this.getHkdf(ss.ck, ikm);
ss.cs = this.initializeKey(tempK) as CipherState;
ss.ck = ck;
@@ -185,7 +183,7 @@ export class XXHandshake {
return [ k1, k2, k3 ];
}
private mixHash(ss: SymmetricState, data: bytes) {
private mixHash(ss: SymmetricState, data: bytes): void {
ss.h = this.getHash(ss.h, data);
}
@@ -227,7 +225,7 @@ export class XXHandshake {
private async writeMessageA(hs: HandshakeState, payload: bytes): Promise<MessageBuffer> {
const ns = Buffer.alloc(0);
hs.e = await this.generateKeypair();
hs.e = generateKeypair();
const ne = hs.e.publicKey;
this.mixHash(hs.ss, ne);
@@ -237,7 +235,7 @@ export class XXHandshake {
}
private async writeMessageB(hs: HandshakeState, payload: bytes): Promise<MessageBuffer> {
hs.e = await this.generateKeypair();
hs.e = generateKeypair();
const ne = hs.e.publicKey;
this.mixHash(hs.ss, ne);
@@ -318,16 +316,6 @@ export class XXHandshake {
return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext);
}
public async generateKeypair(): Promise<KeyPair> {
const privateKey = x25519.privateKeyGenerate();
const publicKey = x25519.publicKeyCreate(privateKey);
return {
publicKey,
privateKey,
}
}
public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32): Promise<NoiseSession> {
const psk = this.createEmptyKey();
let hs;

38
test/handshake.test.ts Normal file
View File

@@ -0,0 +1,38 @@
import {assert} from "chai";
import Duplex from 'it-pair/duplex';
import {Buffer} from "buffer";
import Wrap from "it-pb-rpc";
import {Handshake} from "../src/handshake";
import {generateKeypair} from "../src/utils";
describe("Handshake", () => {
it("should propose, exchange and finish handshake", async() => {
const duplex = Duplex();
const connectionFrom = Wrap(duplex[0]);
const connectionTo = Wrap(duplex[1]);
const prologue = Buffer.from('/noise');
const staticKeysInitiator = generateKeypair();
const staticKeysResponder = generateKeypair();
const handshakeInitator = new Handshake('XX', staticKeysResponder.publicKey, prologue, staticKeysInitiator, connectionFrom);
const handshakeResponder = new Handshake('XX', staticKeysInitiator.publicKey, prologue, staticKeysResponder, connectionTo);
const sessionInitator = await handshakeInitator.propose(true);
const sessionResponder = await handshakeResponder.propose(false);
await handshakeResponder.exchange(false, sessionResponder);
await handshakeInitator.exchange(true, sessionInitator);
await handshakeInitator.finish(true, sessionInitator);
await handshakeResponder.finish(false, sessionResponder);
if (sessionInitator.cs1 && sessionResponder.cs1 && sessionInitator.cs2 && sessionResponder.cs2) {
assert(sessionInitator.cs1.k.equals(sessionResponder.cs1.k));
assert(sessionInitator.cs2.k.equals(sessionResponder.cs2.k));
} else {
assert(false);
}
});
});

View File

@@ -1,9 +1,11 @@
import { expect } from "chai";
import { tag, encrypt} from "../src";
import { Noise } from "../src";
describe("Index", () => {
it("should expose right tag and encrypt function", () => {
expect(tag).to.equal('/noise');
expect(typeof(encrypt)).to.equal('function');
it("should expose class with tag and required functions", () => {
const noise = new Noise(Buffer.from("privatekey"));
expect(noise.protocol).to.equal('/noise');
expect(typeof(noise.secureInbound)).to.equal('function');
expect(typeof(noise.secureOutbound)).to.equal('function');
})
});

14
test/noise.test.ts Normal file
View File

@@ -0,0 +1,14 @@
import { expect } from "chai";
import DuplexPair from 'it-pair/duplex';
import { Noise } from "../src";
import {generateEd25519Keys} from "./utils";
describe("Noise", () => {
it("should encrypt outgoing data using secureOutbound", async() => {
// const libp2pKeys = await generateEd25519Keys();
//
// const noise = new Noise(libp2pKeys._key);
// await noise.secureOutbound();
})
});

View File

@@ -1,11 +1,5 @@
import protobuf from "protobufjs";
import * as crypto from 'libp2p-crypto';
export async function loadPayloadProto () {
const payloadProtoBuf = await protobuf.load("protos/payload.proto");
return payloadProtoBuf.lookupType("pb.NoiseHandshakePayload");
}
export async function generateEd25519Keys() {
return await crypto.keys.generateKeyPair('ed25519');
}

View File

@@ -1,8 +1,10 @@
import { expect, assert } from "chai";
import { Buffer } from 'buffer';
import { XXHandshake, KeyPair } from "../src/xx";
import { loadPayloadProto, generateEd25519Keys } from "./utils";
import { XXHandshake } from "../src/xx";
import { KeyPair } from "../src/@types/libp2p";
import { generateEd25519Keys } from "./utils";
import {createHandshakePayload, generateKeypair, getHandshakePayload} from "../src/utils";
describe("Index", () => {
const prologue = Buffer.from("/noise", "utf-8");
@@ -10,12 +12,12 @@ describe("Index", () => {
it("Test creating new XX session", async () => {
const xx = new XXHandshake();
const kpInitiator: KeyPair = await xx.generateKeypair();
const kpResponder: KeyPair = await xx.generateKeypair();
const kpInitiator: KeyPair = await generateKeypair();
const kpResponder: KeyPair = await generateKeypair();
const session = await xx.initSession(true, prologue, kpInitiator, kpResponder.publicKey);
})
});
it("Test get HKDF", async () => {
const xx = new XXHandshake();
@@ -28,20 +30,19 @@ describe("Index", () => {
expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914');
expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa');
expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68');
})
});
async function doHandshake(xx) {
const kpInit = await xx.generateKeypair();
const kpResp = await xx.generateKeypair();
const payloadString = Buffer.from("noise-libp2p-static-key:");
const kpInit = await generateKeypair();
const kpResp = await generateKeypair();
// initiator setup
const libp2pInitKeys = await generateEd25519Keys();
const initSignedPayload = await libp2pInitKeys.sign(Buffer.concat([payloadString, kpInit.publicKey]));
const initSignedPayload = await libp2pInitKeys.sign(getHandshakePayload(kpInit.publicKey));
// responder setup
const libp2pRespKeys = await generateEd25519Keys();
const respSignedPayload = await libp2pRespKeys.sign(Buffer.concat([payloadString, kpResp.publicKey]));
const respSignedPayload = await libp2pRespKeys.sign(getHandshakePayload(kpResp.publicKey));
// initiator: new XX noise session
const nsInit = await xx.initSession(true, prologue, kpInit, kpResp.publicKey);
@@ -51,12 +52,7 @@ describe("Index", () => {
/* STAGE 0 */
// initiator creates payload
const NoiseHandshakePayload = await loadPayloadProto();
const payloadInit = NoiseHandshakePayload.create({
libp2pKey: libp2pInitKeys.bytes,
noiseStaticKeySignature: initSignedPayload,
});
const payloadInitEnc = NoiseHandshakePayload.encode(payloadInit).finish();
const payloadInitEnc = await createHandshakePayload(libp2pInitKeys.bytes, initSignedPayload)
// initiator sends message
const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]);
@@ -71,11 +67,7 @@ describe("Index", () => {
/* STAGE 1 */
// responder creates payload
const payloadResp = NoiseHandshakePayload.create({
libp2pKey: libp2pRespKeys.bytes,
noiseStaticKeySignature: respSignedPayload,
});
const payloadRespEnc = NoiseHandshakePayload.encode(payloadResp).finish();
const payloadRespEnc = await createHandshakePayload(libp2pRespKeys.bytes, respSignedPayload);
const message1 = Buffer.concat([message, payloadRespEnc]);
const messageBuffer2 = await xx.sendMessage(nsResp, message1);

View File

@@ -7,7 +7,8 @@
"noImplicitAny": false,
"typeRoots": [
"./node_modules/@types",
"./node_modules/bn.js-typings/index.d.ts"
"./node_modules/bn.js-typings/index.d.ts",
"./src/@types"
]
},
"include": [

177
yarn.lock
View File

@@ -56,6 +56,16 @@
lodash "^4.17.13"
source-map "^0.5.0"
"@babel/generator@^7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.2.tgz#2f4852d04131a5e17ea4f6645488b5da66ebf3af"
integrity sha512-WthSArvAjYLz4TcbKOi88me+KmDJdKSlfwwN8CnUYn9jBkzhq0ZEPuBfkAWIvjJ3AdEV1Cf/+eSQTnp3IDJKlQ==
dependencies:
"@babel/types" "^7.7.2"
jsesc "^2.5.1"
lodash "^4.17.13"
source-map "^0.5.0"
"@babel/helper-annotate-as-pure@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
@@ -63,6 +73,13 @@
dependencies:
"@babel/types" "^7.0.0"
"@babel/helper-annotate-as-pure@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.0.tgz#efc54032d43891fe267679e63f6860aa7dbf4a5e"
integrity sha512-k50CQxMlYTYo+GGyUGFwpxKVtxVJi9yh61sXZji3zYHccK9RYliZGSTOgci85T+r+0VFN2nWbGM04PIqwfrpMg==
dependencies:
"@babel/types" "^7.7.0"
"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0":
version "7.1.0"
resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f"
@@ -118,6 +135,15 @@
"@babel/template" "^7.1.0"
"@babel/types" "^7.0.0"
"@babel/helper-function-name@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.7.0.tgz#44a5ad151cfff8ed2599c91682dda2ec2c8430a3"
integrity sha512-tDsJgMUAP00Ugv8O2aGEua5I2apkaQO7lBGUq1ocwN3G23JE5Dcq0uh3GvFTChPa4b40AWiAsLvCZOA2rdnQ7Q==
dependencies:
"@babel/helper-get-function-arity" "^7.7.0"
"@babel/template" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/helper-get-function-arity@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
@@ -125,6 +151,13 @@
dependencies:
"@babel/types" "^7.0.0"
"@babel/helper-get-function-arity@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.0.tgz#c604886bc97287a1d1398092bc666bc3d7d7aa2d"
integrity sha512-tLdojOTz4vWcEnHWHCuPN5P85JLZWbm5Fx5ZsMEMPhF3Uoe3O7awrbM2nQ04bDOUToH/2tH/ezKEOR8zEYzqyw==
dependencies:
"@babel/types" "^7.7.0"
"@babel/helper-hoist-variables@^7.4.4":
version "7.4.4"
resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
@@ -188,6 +221,17 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.0.0"
"@babel/helper-remap-async-to-generator@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.7.0.tgz#4d69ec653e8bff5bce62f5d33fc1508f223c75a7"
integrity sha512-pHx7RN8X0UNHPB/fnuDnRXVZ316ZigkO8y8D835JlZ2SSdFKb6yH9MIYRU4fy/KPe5sPHDFOPvf8QLdbAGGiyw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.7.0"
"@babel/helper-wrap-function" "^7.7.0"
"@babel/template" "^7.7.0"
"@babel/traverse" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/helper-replace-supers@^7.5.5":
version "7.5.5"
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.5.5.tgz#f84ce43df031222d2bad068d2626cb5799c34bc2"
@@ -213,6 +257,13 @@
dependencies:
"@babel/types" "^7.4.4"
"@babel/helper-split-export-declaration@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.7.0.tgz#1365e74ea6c614deeb56ebffabd71006a0eb2300"
integrity sha512-HgYSI8rH08neWlAH3CcdkFg9qX9YsZysZI5GD8LjhQib/mM0jGOZOVkoUiiV2Hu978fRtjtsGsW6w0pKHUWtqA==
dependencies:
"@babel/types" "^7.7.0"
"@babel/helper-wrap-function@^7.1.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa"
@@ -223,6 +274,16 @@
"@babel/traverse" "^7.1.0"
"@babel/types" "^7.2.0"
"@babel/helper-wrap-function@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.0.tgz#15af3d3e98f8417a60554acbb6c14e75e0b33b74"
integrity sha512-sd4QjeMgQqzshSjecZjOp8uKfUtnpmCyQhKQrVJBBgeHAB/0FPi33h3AbVlVp07qQtMD4QgYSzaMI7VwncNK/w==
dependencies:
"@babel/helper-function-name" "^7.7.0"
"@babel/template" "^7.7.0"
"@babel/traverse" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/helpers@^7.6.2":
version "7.6.2"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.6.2.tgz#681ffe489ea4dcc55f23ce469e58e59c1c045153"
@@ -246,6 +307,11 @@
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.6.4.tgz#cb9b36a7482110282d5cb6dd424ec9262b473d81"
integrity sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==
"@babel/parser@^7.7.0", "@babel/parser@^7.7.2":
version "7.7.3"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.3.tgz#5fad457c2529de476a248f75b0f090b3060af043"
integrity sha512-bqv+iCo9i+uLVbI0ILzKkvMorqxouI+GbV13ivcARXn9NNEabi2IEz912IgNpT/60BNXac5dgcfjb94NjsF33A==
"@babel/plugin-proposal-async-generator-functions@^7.2.0":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
@@ -255,6 +321,15 @@
"@babel/helper-remap-async-to-generator" "^7.1.0"
"@babel/plugin-syntax-async-generators" "^7.2.0"
"@babel/plugin-proposal-async-generator-functions@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.0.tgz#83ef2d6044496b4c15d8b4904e2219e6dccc6971"
integrity sha512-ot/EZVvf3mXtZq0Pd0+tSOfGWMizqmOohXmNZg6LNFjHOV+wOPv7BvVYh8oPR8LhpIP3ye8nNooKL50YRWxpYA==
dependencies:
"@babel/helper-plugin-utils" "^7.0.0"
"@babel/helper-remap-async-to-generator" "^7.7.0"
"@babel/plugin-syntax-async-generators" "^7.2.0"
"@babel/plugin-proposal-dynamic-import@^7.5.0":
version "7.5.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506"
@@ -684,6 +759,15 @@
"@babel/parser" "^7.6.0"
"@babel/types" "^7.6.0"
"@babel/template@^7.7.0":
version "7.7.0"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.0.tgz#4fadc1b8e734d97f56de39c77de76f2562e597d0"
integrity sha512-OKcwSYOW1mhWbnTBgQY5lvg1Fxg+VyfQGjcBduZFljfc044J5iDlnDSfhQ867O17XHiSCxYHUxHg2b7ryitbUQ==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/parser" "^7.7.0"
"@babel/types" "^7.7.0"
"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.5", "@babel/traverse@^7.6.2", "@babel/traverse@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.6.3.tgz#66d7dba146b086703c0fb10dd588b7364cec47f9"
@@ -699,6 +783,21 @@
globals "^11.1.0"
lodash "^4.17.13"
"@babel/traverse@^7.7.0":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.2.tgz#ef0a65e07a2f3c550967366b3d9b62a2dcbeae09"
integrity sha512-TM01cXib2+rgIZrGJOLaHV/iZUAxf4A0dt5auY6KNZ+cm6aschuJGqKJM3ROTt3raPUdIDk9siAufIFEleRwtw==
dependencies:
"@babel/code-frame" "^7.5.5"
"@babel/generator" "^7.7.2"
"@babel/helper-function-name" "^7.7.0"
"@babel/helper-split-export-declaration" "^7.7.0"
"@babel/parser" "^7.7.2"
"@babel/types" "^7.7.2"
debug "^4.1.0"
globals "^11.1.0"
lodash "^4.17.13"
"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.5", "@babel/types@^7.6.0", "@babel/types@^7.6.3":
version "7.6.3"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.6.3.tgz#3f07d96f854f98e2fbd45c64b0cb942d11e8ba09"
@@ -708,6 +807,15 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@babel/types@^7.7.0", "@babel/types@^7.7.2":
version "7.7.2"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.2.tgz#550b82e5571dcd174af576e23f0adba7ffc683f7"
integrity sha512-YTf6PXoh3+eZgRCBzzP25Bugd2ngmpQVrk7kXX0i5N9BO7TFBtIgZYs7WtxtOGs8e6A4ZI7ECkbBCEHeXocvOA==
dependencies:
esutils "^2.0.2"
lodash "^4.17.13"
to-fast-properties "^2.0.0"
"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf"
@@ -1049,6 +1157,13 @@ bip66@^1.1.5:
dependencies:
safe-buffer "^5.0.1"
bl@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.0.tgz#fc7351c473992110749d3552087e1fe942021e65"
integrity sha512-QwQvAZZA1Bw1FWnhNj2X5lu+sPxxB2ITH3mqEqYyahN6JZR13ONjk+XiTnBaGEzMPUrAgOkaD68pBH1rvPRPsw==
dependencies:
readable-stream "^3.4.0"
blakejs@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5"
@@ -1735,6 +1850,11 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
fast-fifo@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.0.0.tgz#9bc72e6860347bb045a876d1c5c0af11e9b984e7"
integrity sha512-4VEXmjxLj7sbs8J//cn2qhRap50dGzF5n8fjay8mau+Jn4hxSeR3xPFwxMaQq/pDaq7+KQk0PAbC2+nWDkJrmQ==
fast-json-stable-stringify@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@@ -1882,6 +2002,11 @@ get-func-name@^2.0.0:
resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41"
integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=
get-iterator@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-1.0.2.tgz#cd747c02b4c084461fac14f48f6b45a80ed25c82"
integrity sha512-v+dm9bNVfOYsY1OrhaCrmyOcYoSeVvbt+hHZ0Au+T+p1y+0Uyj9aMaGIeUTT6xdpRbWzDeYKvfOslPhggQMcsg==
get-value@^2.0.3, get-value@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
@@ -2304,6 +2429,53 @@ isobject@^3.0.0, isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
it-handshake@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/it-handshake/-/it-handshake-1.0.1.tgz#ed37a5622fcb82cfcb1e7eaebcf4872361cabe11"
integrity sha512-ZDN6HfaS9ZMOohEUr5j0TYI8nCtiSJsucXHwoeiH9IHal3sLDYcSpYWQe+CsUHHK5rMnPHwDiiPptP/Yioc0kg==
dependencies:
it-pushable "^1.4.0"
it-reader "^2.0.0"
p-defer "^3.0.0"
it-length-prefixed@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/it-length-prefixed/-/it-length-prefixed-3.0.0.tgz#cdedb3a785796ba8263c97d9bd4816c9fe33a6d2"
integrity sha512-OQPbWaGDcSK1Wzzi8XtyXscBV1sMhFz6q5zHGchBc5oV4hM6ifIl6PTS8stk8MqkBELSyWO6CbEluS1rg4UUTw==
dependencies:
bl "^4.0.0"
buffer "^5.4.3"
varint "^5.0.0"
it-pair@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/it-pair/-/it-pair-1.0.0.tgz#b1add81f49af16a10b2939dbef7b1974fae87d6a"
integrity sha512-9raOiDu5OAuDOahtMtapKQDrQTxBfzlzrNcB6o7JARHkt+7Bb1dMkW/TpYdAjBJE77KH3e2zGzwpGUP9tXbLww==
dependencies:
get-iterator "^1.0.2"
it-pb-rpc@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/it-pb-rpc/-/it-pb-rpc-0.1.3.tgz#3d8e98454cd3fda31a4767b86267b45a7a141aa6"
integrity sha512-Zzq7ODzzFSZLsYzQVRqqaOnQENslRt0kY6QQ8ApaciCaX4xXJhtIFK9UrPbWAgXkyTDFJuLH5GgDAph/JN7JQg==
dependencies:
it-handshake "^1.0.1"
it-length-prefixed "^3.0.0"
it-pushable@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/it-pushable/-/it-pushable-1.4.0.tgz#772d81b40ccab93c963a20420ab1ef2ecfc9b97d"
integrity sha512-W7251Tj88YBqUIEDWCwd3F8JettSbze+bBp5B3ASzz5tYWaLUI1VDNGbjllH1T6RJ71a5jUSTSt5vHjvuzwoFw==
dependencies:
fast-fifo "^1.0.0"
it-reader@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/it-reader/-/it-reader-2.0.0.tgz#2ddc15a976b39906e805c88c5fb315c3805071ae"
integrity sha512-y+GeTA3wq4z5yol7s/aXr0fIi4jMkPeo2DcX5AJo6IPgonjiQA7q1Y/yCMWro7PxGXj9mDUj9m/gAsSUrVRw7A==
dependencies:
bl "^4.0.0"
js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
@@ -2921,6 +3093,11 @@ output-file-sync@^2.0.0:
is-plain-obj "^1.1.0"
mkdirp "^0.5.1"
p-defer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-3.0.0.tgz#d1dceb4ee9b2b604b1d94ffec83760175d4e6f83"
integrity sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==
p-limit@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537"