From 301e3eacead6d187c656a5e72ba18ba88b8d5831 Mon Sep 17 00:00:00 2001 From: Bronwen Date: Thu, 1 Apr 2021 23:22:16 -0400 Subject: [PATCH] Merge branch 'service-testing' --- client/index.js | 26 ------- lib/Gateway.js | 136 ++++++++++++++++++++++++++++++++++++ lib/Identity.js | 6 +- lib/STP/index.js | 73 ++++++++++++++------ lib/STP/packets.js | 97 ++++++++++++++++++++++---- lib/appdata.js | 3 + lib/config.js | 39 +++++++++++ lib/node.js | 106 +++++++++++++++++++++++++++- lib/packet.js | 0 lib/upnp.js | 22 +++--- lib/vns.js | 0 name-server/index.js | 27 -------- package.json | 13 ++-- relay/index.js | 49 ++----------- relay/service.js | 24 ++++--- upnp.js | 2 - yarn.lock | 160 ++++++++++++++++++++++++++++++++++++++++++- 17 files changed, 624 insertions(+), 159 deletions(-) delete mode 100644 client/index.js create mode 100644 lib/Gateway.js create mode 100644 lib/appdata.js create mode 100644 lib/config.js delete mode 100644 lib/packet.js delete mode 100644 lib/vns.js delete mode 100644 name-server/index.js diff --git a/client/index.js b/client/index.js deleted file mode 100644 index 35c60d9..0000000 --- a/client/index.js +++ /dev/null @@ -1,26 +0,0 @@ -(async () => { -const { title } = require('../lib/title'); -const net = require('net'); -const os = require('os'); -const log = require('signale'); -const { config } = require('./../package.json'); -const { hri } = require('human-readable-ids'); -const { Profiles } = require('../lib/Profiles'); -const profiles = new Profiles('client'); -const yargs = require('yargs').argv; -const identity = yargs.profile ? - await profiles.get(yargs.profile) : - await profiles.get((await profiles.all())[0]); - -// const id = hri.random(); - -// console.log(id) - -// title(id); -// title(identity.name.replace(/-/g, ' ')); - -// await profiles.create(); - - - -})(); \ No newline at end of file diff --git a/lib/Gateway.js b/lib/Gateway.js new file mode 100644 index 0000000..dfe3732 --- /dev/null +++ b/lib/Gateway.js @@ -0,0 +1,136 @@ +const { config } = require('./config'); +const Keyv = require('keyv'); +const { KeyvFile } = require('keyv-file'); +const { Signale } = require('signale'); +const log = new Signale().scope('GTWY'); +const interactive = new Signale({ interactive: true, scope: 'GTWY' }); +const stp = require('./STP'); +const appdata = require('./appdata'); + +class Gateway { + constructor(identity, endpoints) { + this.identity = identity; + + this.endpoints = new Keyv({ + store: new KeyvFile({ + filename: `${appdata}/valnet/relay/${this.identity.name}-endpoints.json` + }) + }); + + this.ready = this.insertEndpoints(endpoints) + .then(this.networkTest.bind(this)); + } + + async insertEndpoints(endpoints) { + for (const endpoint of endpoints) { + const storeValue = await this.endpoints.get(endpoint); + if (storeValue) continue; + + const [host, port] = endpoint.split(':'); + const record = new EndpointRecord(host, port, null, 'unknown'); + const currentEnpoints = await this.endpoints.get('cache') || []; + + if (currentEnpoints.indexOf(endpoint) === -1) { + currentEnpoints.push(endpoint); + await this.endpoints.set('cache', currentEnpoints); + } + + await this.endpoints.set(endpoint, record); + } + + log.info('gateway endpoints:'); + log.info('\t' + (await this.endpoints.get('cache')).join('\n\t')); + } + + async networkTest() { + const endpoints = (await Promise.all( + (await this.endpoints.get('cache')) + .map(endpoint => this.endpoints.get(endpoint)) + )).map(EndpointRecord.fromJson); + + for (const endpoint of endpoints) { + await this.testEndpoint(endpoint.host, endpoint.port); + } + } + + async testEndpoint(host, port) { + await new Promise(async (res, rej) => { + let pings = []; + let maxPings = 10; + let connectionAttempts = 0; + log.info(`Connecting to ${host}:${port}...`); + + while (connectionAttempts < 10 && pings.length < maxPings) { + + await new Promise(async (res) => { + const client = stp.connect({ + identity: this.identity, + ip: host, + port: parseInt(port) + }); + + client.on('error', _ => _); + + client.on('ready', async () => { + while (pings.length < maxPings) { + interactive.info(`[${pings.length + 1}/${maxPings}] Testing connection...`); + pings.push(await client.ping()); + // pings.push(10); + await new Promise(res => setTimeout(res, 100)); + } + const average = Math.round(pings.reduce((a, v) => a + v, 0) / maxPings); + interactive.success(`Test complete. Average Ping: ${average}`) + client.tcpSocket.destroy(); + res(); + }); + + client.on('close', () => { + res(); + }); + + }); + + } + }); + } +} + +class EndpointRecord { + + /** + * @param {Object|string} json string / object representation + * @returns {EndpointRecord} + */ + static fromJson(obj) { + if (typeof obj === 'string') + return EndpointRecord.fromJson(JSON.parse(obj)); + + return new EndpointRecord( + obj.host, + obj.port, + obj.lastPing ? new PingRecord( + obj.lastPing.average, + obj.lastPing.tests, + obj.lastPing.date + ) : null, + obj.status + ); + } + + constructor(host, port, lastPing, status) { + this.host = host; + this.port = port; + this.lastPing = lastPing; + this.status = status; + } +} + +class PingRecord { + constructor(average, tests, date) { + this.average = average; + this.tests = tests; + this.date = date; + } +} + +module.exports = Gateway \ No newline at end of file diff --git a/lib/Identity.js b/lib/Identity.js index 811f079..a4256d6 100644 --- a/lib/Identity.js +++ b/lib/Identity.js @@ -4,6 +4,7 @@ const { hri } = require('human-readable-ids'); const os = require('os'); const NodeRSA = require('node-rsa'); let log = require('signale').scope('Identity(null)'); +const appdata = require('./appdata'); module.exports.Identity = class Identity { kv; @@ -13,9 +14,10 @@ module.exports.Identity = class Identity { /// ASYNC CONSTRUCTOR constructor(module, id) { return new Promise(async (res, rej) => { + const kv = new Keyv({ store: new KeyvFile({ - filename: `${os.tmpdir()}/valnet/${module}/${id}.json` + filename: `${appdata}/valnet/${module}/${id}.json` }) }); @@ -67,6 +69,6 @@ module.exports.Identity = class Identity { } toString() { - return `[Identity(${this.name})]`; + return `[Identity ${this.name}]`; } } \ No newline at end of file diff --git a/lib/STP/index.js b/lib/STP/index.js index 52fda13..64bd6f2 100644 --- a/lib/STP/index.js +++ b/lib/STP/index.js @@ -1,12 +1,13 @@ const net = require('net'); const EventEmitter = require('events'); const NodeRSA = require('node-rsa'); -const log = require('signale').scope('stp'); +const log = require('signale').scope('_STP'); const { KeyExchangePacket, - AckPacket + AckPacket, + PingPacket, + PongPacket } = require('./packets'); -const { rejects } = require('assert'); module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) { const server = new Server(identity, port); @@ -37,7 +38,7 @@ class Server extends EventEmitter { } openServer() { - log.info(`opening STP server on ${this.port}`); + // log.info(`opening STP server on ${this.port}`); this.tcpServer = net.createServer(this.tcpConnectClient.bind(this)); this.tcpServer.on('error', e => { log.warn(e) @@ -56,11 +57,17 @@ class Server extends EventEmitter { class STPSocket extends EventEmitter { tcpSocket; - readyState = 0; buffer = ''; externalKey; identity; + CONNECTING = Symbol('connecting'); + EXCHANGE = Symbol('exchange'); + SECURED = Symbol('secured'); + readyState = this.CONNECTING; + + pingCallbacks = new Map(); + get loopback() { return this.identity.publicKey === this.externalKey.exportKey('pkcs8-public-pem'); @@ -113,24 +120,33 @@ class STPSocket extends EventEmitter { } processMessage(obj) { - switch(obj.cmd) { - case 'KEY': { - if(this.readyState === 0) { - this.externalKey = new NodeRSA(); - this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem'); - this.tcpSocket.write(new AckPacket().toBuffer()); - this.readyState = 1; - } - break; - } - case 'ACK': { - if(this.readyState === 1) { - this.readyState = 2; - this.emit('ready'); - } - break; - } + + if(this.readyState === this.CONNECTING && obj.cmd === 'KEY') { + this.externalKey = new NodeRSA(); + this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem'); + this.tcpSocket.write(new AckPacket().toBuffer()); + this.readyState = this.EXCHANGE; + return; } + + if(this.readyState === this.EXCHANGE && obj.cmd === 'ACK') { + this.readyState = this.SECURED; + this.emit('ready'); + return; + } + + if (this.readyState === this.SECURED && obj.cmd === 'PING') { + this.tcpSocket.write(new PongPacket(obj.data.id).toBuffer()); + return; + } + + if (this.readyState === this.SECURED && obj.cmd === 'PONG') { + if (this.pingCallbacks.has(obj.data.id)) { + this.pingCallbacks.get(obj.data.id)(); + } + return; + } + } handshake() { @@ -139,4 +155,17 @@ class STPSocket extends EventEmitter { const buffer = packet.toBuffer(); this.tcpSocket.write(buffer); } + + async ping() { + const startTime = new Date().getTime(); + return await new Promise(async (res) => { + const packet = new PingPacket(); + this.pingCallbacks.set(packet.data.id, _ => { + res(new Date().getTime() - startTime); + this.pingCallbacks.delete(packet.data.id); + }); + this.tcpSocket.write(packet.toBuffer()); + }) + + } } diff --git a/lib/STP/packets.js b/lib/STP/packets.js index 233ae89..58b1832 100644 --- a/lib/STP/packets.js +++ b/lib/STP/packets.js @@ -1,4 +1,6 @@ +const md5 = require('md5'); +// #region === [ private lib functions ] === class STPPacket { cmd = 'NOOP'; @@ -14,15 +16,6 @@ class STPPacket { } } -class KeyExchangePacket extends STPPacket { - constructor(key, type = 'pkcs8-pem') { - super(); - this.cmd = 'KEY'; - this.data.key = key; - this.meta.type = type; - } -} - function basicPacket(commandName) { return class extends STPPacket { constructor() { @@ -32,7 +25,87 @@ function basicPacket(commandName) { } } -module.exports.STPPacket = STPPacket; +// #endregion + +// #region === [ exotic packet classes ] === + +class KeyExchangePacket extends STPPacket { + constructor(key, type = 'pkcs8-pem') { + super(); + this.cmd = 'KEY'; + this.data.key = key; + this.meta.type = type; + } +} + +class ClientsPacket extends STPPacket { + constructor(clients) { + super(); + this.cmd = 'NODES' + this.data.clients = clients; + } +} + +class PingPacket extends STPPacket { + constructor() { + super(); + this.cmd = 'PING'; + this.data.id = md5(Date()); + } +} + +class PongPacket extends STPPacket { + constructor(id) { + super(); + this.cmd = 'PONG'; + this.data.id = id; + } +} + +// #endregion + +// #region === [ ordinary packet classes ] === + +const AckPacket = basicPacket('ACK'); +const GetClientsPacket = basicPacket('QNODES'); + +// #endregion + +// #region === [ public lib functions ] === + +function reconstructPacket(packet) { + + if(packet.startsWith('\02')) + return reconstructPacket(packet.substr(1)); + if(packet.endsWith('\x03')) + return reconstructPacket(packet.substr(0, packet.length - 1)); + + const obj = JSON.parse(packet); + + switch(obj.cmd) { + case 'KEY': return new KeyExchangePacket(obj.data.key, obj.meta.type); + case 'NODES': return new ClientsPacket(obj.data.clients); + case 'QNODES': return new GetClientsPacket(); + case 'ACK': return new AckPacket(); + + case 'NOOP': return new STPPacket(); + default: throw new TypeError(`Unknown command ${obj.cmd}`); + } + +} + +// #endregion + +// #region === [ exports ] === + module.exports.KeyExchangePacket = KeyExchangePacket; -module.exports.AckPacket = basicPacket('ACK') -module.exports.GetClientsPacket = basicPacket('NODES') +module.exports.ClientsPacket = ClientsPacket; +module.exports.PingPacket = PingPacket; +module.exports.PongPacket = PongPacket; + +module.exports.AckPacket = AckPacket; +module.exports.GetClientsPacket = GetClientsPacket; + +module.exports.reconstructPacket = reconstructPacket; + +// #endregion \ No newline at end of file diff --git a/lib/appdata.js b/lib/appdata.js new file mode 100644 index 0000000..cac3379 --- /dev/null +++ b/lib/appdata.js @@ -0,0 +1,3 @@ +const appdata = process.env.APPDATA || (process.platform == 'darwin' ? process.env.HOME + '/Library/Preferences' : process.env.HOME + "/.local/share"); + +module.exports = appdata; \ No newline at end of file diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..f4167dd --- /dev/null +++ b/lib/config.js @@ -0,0 +1,39 @@ +const pkg = require('./../package.json'); +const { readFileSync, writeFileSync } = require('fs'); +const { ensureDirSync } = require('fs-extra'); + +const appdata = require('./appdata'); +ensureDirSync(`${appdata}/valnet/relay`); +const filepath = `${appdata}/valnet/relay/config.json`; + +const configObject = {} + +module.exports.config = configObject; + +module.exports.write = write; + +function write() { + writeFileSync(filepath, JSON.stringify(configObject, null, 2)); +} + +function importFromPackage() { + loadObject(pkg.config); +} + +function loadObject(obj) { + for(const key in obj) { + configObject[key] = obj[key]; + } + + write(); +} + +try { + const json = readFileSync(filepath); + const data = JSON.parse(json); + + loadObject(data); + +} catch(e) { + importFromPackage(); +} \ No newline at end of file diff --git a/lib/node.js b/lib/node.js index 8b76499..233e1d7 100644 --- a/lib/node.js +++ b/lib/node.js @@ -1,11 +1,111 @@ const EventEmitter = require('events') - +const stp = require('./STP'); +const upnp = require('./upnp'); +const md5 = require('md5'); +const pkg = require('./../package.json'); +const { config, write } = require('./config.js'); +const log = require('signale').scope('NODE'); +const bonjour = require('bonjour')(); +const Gateway = require('./Gateway'); class Node extends EventEmitter { - constructor() { + clients = []; + hash = null; + name = null; + readyPromise = null; + port = null; + identity; + multicastAd = null; + multicastBrowser = null; + connected = false; + + constructor(identity) { + super(); + this.identity = identity; + this.hash = md5(identity.publicKey); + this.name = `valnet-node-${identity.name}`; + + this.readyPromise = this.negotiatePort() + .then(this.startServer.bind(this)) + .catch(this.serverStartupFailed.bind(this)) + .then(this.connectNetwork.bind(this)) + } + + async connectNetwork() { + const gateway = new Gateway(this.identity, config.endpoints); + } + + async serverStartupFailed(error) { + log.warn('Failed to set up Valet server on node.') + } + + async startServer() { + log.info('creating Valnet Node on port ' + this.port + '...'); + + stp.createServer({ + identity: this.identity, + port: this.port + }, (connection) => { + log.info('incomming connection from ' + connection.remoteAddress); + }); + log.info('advertising node on multicast...') + this.multicastAd = bonjour.publish({ + name: this.name, + type: 'STP', + port: this.port + }); + + this.multicastBrowser = bonjour.find({}); + + this.multicastBrowser.on('up', this.serviceUp.bind(this)); + this.multicastBrowser.on('down', this.serviceDown.bind(this)); + + // log.success('Node successfully registered!'); + } + + async serviceUp({name, address, port, protocol}) { + // log.debug(`Found ${name} @ ${address}:${port} using ${protocol}`); + } + + async serviceDown(service) { + log.debug('down', service); + } + + async negotiatePort() { + const mappings = await upnp.mappings(); + const matchingMappings = mappings.filter(mapping => { + return mapping.description === this.name + }); + const alreadyMapped = matchingMappings.length > 0; + const takenPorts = mappings.map(mapping => mapping.public.port); + + if(alreadyMapped) { + this.port = matchingMappings[0].public.port; + log.success(`upnp port ${this.port} already registered!`); + return; + } + + for(let port = config.ports.relay; port <= config.ports.relayEnd; port ++) { + if(takenPorts.indexOf(port) === -1) { + await upnp.mapIndefinite(port, this.name); + this.port = port; + log.success(`registered upnp port ${this.port}`); + return; + } + } + + // console.log(mappings, this.hash); + } + + static get Node() { + return Node; + } + + get ready() { + return this.readyPromise; } } -module.exports.Node = Node; \ No newline at end of file +module.exports = Node; \ No newline at end of file diff --git a/lib/packet.js b/lib/packet.js deleted file mode 100644 index e69de29..0000000 diff --git a/lib/upnp.js b/lib/upnp.js index 49ccfe3..918af49 100644 --- a/lib/upnp.js +++ b/lib/upnp.js @@ -1,31 +1,34 @@ const natUpnp = require('nat-upnp'); const client = natUpnp.createClient(); -module.exports.map = function(port) { + +module.exports.map = function(port, ttl = 10, name = 'upnp application') { return new Promise((res, rej) => { client.portMapping({ private: port, public: port, - ttl: 10, - description: 'valnet' + ttl, + description: name }, (err) => { if(err) rej(err); res(); }); }); -} -module.exports.mapIndefinite = function(port) { +}; + +module.exports.mapIndefinite = function(port, name = 'upnp application') { return new Promise((res, rej) => { client.portMapping({ private: port, public: port, ttl: 0, - description: 'valnet' + description: name }, (err) => { if(err) rej(err); res(); }); }); -} +}; + module.exports.unmap = function(port) { return new Promise((res, rej) => { client.portUnmapping({ @@ -36,7 +39,8 @@ module.exports.unmap = function(port) { res(); }); }); -} +}; + module.exports.mappings = function() { return new Promise((res, rej) => { client.getMappings((err, mappings) => { @@ -44,7 +48,7 @@ module.exports.mappings = function() { res(mappings); }); }); -} +}; /* diff --git a/lib/vns.js b/lib/vns.js deleted file mode 100644 index e69de29..0000000 diff --git a/name-server/index.js b/name-server/index.js deleted file mode 100644 index a146745..0000000 --- a/name-server/index.js +++ /dev/null @@ -1,27 +0,0 @@ -(async () => { -const { config } = require('./../package.json'); -const net = require('net'); -const dns = require('dns'); -const stp = require('../lib/STP'); -const os = require('os'); -const { title } = require('../lib/title'); -const { hri } = require('human-readable-ids'); -const log = require('signale'); -const Keyv = require('keyv'); -const { KeyvFile } = require('keyv-file'); -const kv = new Keyv({ - store: new KeyvFile({ - filename: `${os.tmpdir()}/valnet/name-server/data.json` - }) -}); -const { Identity } = require('./../lib/Identity'); -title('Name Server'); - -const identity = new Identity('name-server', 'default'); - - - - - - -})(); \ No newline at end of file diff --git a/package.json b/package.json index 8fe9e47..a2c18f0 100644 --- a/package.json +++ b/package.json @@ -6,29 +6,34 @@ "config": { "ports": { "relay": 5600, + "relayEnd": 5699, "http": 5700, "service": 5000 }, "addresses": { "relay": "valnet.xyz" - } + }, + "endpoints": [ + "valnet.xyz:5500" + ] }, "scripts": { - "name-server": "supervisor -w name-server,lib -n exit name-server/index.js", "relay": "supervisor -w relay,lib -n exit relay/index.js", "relay:service": "supervisor -- relay/service", - "client:a": "supervisor -w client,lib -n exit -- client/index.js --profile J2aV59rsIgcdd5k2", - "client:b": "supervisor -w client,lib -n exit -- client/index.js --profile LsE8OnVzr1iYrkT0" + "sloc": "find lib -type f | xargs wc -l" }, "dependencies": { + "bonjour": "^3.5.0", "express": "^4.17.1", "express-ws": "^4.0.0", "font-ascii": "^1.2.1", + "fs-extra": "^9.1.0", "gradient-string": "^1.2.0", "human-readable-ids": "^1.0.4", "ip": "^1.1.5", "keyv": "^4.0.3", "keyv-file": "^0.2.0", + "md5": "^2.3.0", "nat-upnp": "^1.1.1", "nedb": "^1.8.0", "node-rsa": "^1.1.1", diff --git a/relay/index.js b/relay/index.js index 05f9528..ac6016a 100644 --- a/relay/index.js +++ b/relay/index.js @@ -1,51 +1,16 @@ (async () => { const { title } = require('../lib/title'); -const net = require('net'); -const log = require('signale').scope('relay'); -const { config } = require('../package.json'); +const log = require('signale').scope('RLAY'); const { Identity } = require('../lib/Identity'); -const stp = require('../lib/STP'); title('relay', false); const identity = await new Identity('relay', 'default'); -const upnp = require('../lib/upnp'); +const Node = require('../lib/node'); +const { config } = require('../lib/config'); +const { ensureDirSync } = require('fs-extra'); +const appdata = require('../lib/appdata'); -const clients = []; - -// const client = stp.connect(identity, config.ports.relay, '127.0.0.1'); - -// upnp.mapIndefinite(5600); - -// ==================================== [STP SERVER] -stp.createServer({ - identity: identity, - port: config.ports.relay -}, socket => { - log.info('secured connection from ' + socket.remoteAddress); - clients.push(socket); -}); - -function connectNetwork(t = 1000) { - if(t > 60000) t /= 2; - - const client = stp.connect({ - identity, - port: config.ports.relay, - ip: config.addresses.relay - }); - client.on('ready', () => { - log.success('connectd to relay!'); - t = 500; - }) - client.on('error', e => { - }); - client.on('close', e => { - t *= 2; - setTimeout(connectNetwork.bind(global, t), t); - log.warn('disconnected from relay'); - log.warn('retrying connection... ' + (t/1000) + 's') - }); -} -connectNetwork(); +ensureDirSync(`${appdata}/valnet/relay`); +const node = new Node(identity); // ==================================== [EXPRESS] const express = require('express'); diff --git a/relay/service.js b/relay/service.js index b1f668c..5f6b3ff 100644 --- a/relay/service.js +++ b/relay/service.js @@ -1,5 +1,5 @@ (async () => { -const log = require('signale').scope('service'); +const log = require('signale').scope('SRVC'); const { execSync, spawn } = require('child_process'); const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); let proc; @@ -12,6 +12,12 @@ const { config } = require('../package.json'); const express = require('express'); const app = express(); +try { + appendLogs('yarn', execSync(`yarn`)); +} catch (e) { + appendLogs('failed to yarn install...') +} + logp('=================================='); logp('Starting Valnet Node as a Service!'); logp('Syncing to branch: ' + branch); @@ -130,14 +136,14 @@ ${docs.map(logItem => logItem.message).join('').replace(/\u001B\[.*?[A-Za-z]/g,





diff --git a/upnp.js b/upnp.js index 5d638a9..f1ae2fb 100644 --- a/upnp.js +++ b/upnp.js @@ -41,8 +41,6 @@ function searchGateway(timeout, callback) { } var onlistening = function() { - - console.log('listening?') socket.setBroadcast(socket.fd, true); // send a few packets just in case. diff --git a/yarn.lock b/yarn.lock index 5af0417..9145a6e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -52,6 +52,10 @@ array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" +array-flatten@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" + array-includes@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" @@ -95,6 +99,11 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -134,6 +143,17 @@ body-parser@1.19.0: raw-body "2.4.0" type-is "~1.6.17" +bonjour@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5" + dependencies: + array-flatten "^2.1.0" + deep-equal "^1.0.1" + dns-equal "^1.0.0" + dns-txt "^2.0.2" + multicast-dns "^6.0.1" + multicast-dns-service-types "^1.1.0" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -141,6 +161,10 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + bytes@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" @@ -152,6 +176,13 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.0" +call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" @@ -175,6 +206,10 @@ chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" +charenc@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" + cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -253,6 +288,10 @@ core-util-is@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" +crypt@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" + dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -271,6 +310,17 @@ debug@^4.1.1: dependencies: ms "2.1.2" +deep-equal@^1.0.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + dependencies: + is-arguments "^1.0.4" + is-date-object "^1.0.1" + is-regex "^1.0.4" + object-is "^1.0.1" + object-keys "^1.1.1" + regexp.prototype.flags "^1.2.0" + define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -289,6 +339,23 @@ destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" +dns-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" + +dns-packet@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a" + dependencies: + ip "^1.1.0" + safe-buffer "^5.0.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + dependencies: + buffer-indexof "^1.0.0" + doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -594,6 +661,16 @@ fs-extra@^4.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -610,6 +687,14 @@ get-intrinsic@^1.0.0: has "^1.0.3" has-symbols "^1.0.1" +get-intrinsic@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -620,6 +705,11 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.2.4" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" +graceful-fs@^4.2.0: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + gradient-string@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/gradient-string/-/gradient-string-1.2.0.tgz#93f39f2c7c8dcb095608c2ccf0aac24aa315fbac" @@ -734,7 +824,7 @@ inquirer@^7.0.0: strip-ansi "^6.0.0" through "^2.3.6" -ip@^1.1.4, ip@^1.1.5: +ip@^1.1.0, ip@^1.1.4, ip@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" @@ -742,10 +832,20 @@ ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" +is-arguments@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.0.tgz#62353031dfbee07ceb34656a6bde59efecae8dd9" + dependencies: + call-bind "^1.0.0" + is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" +is-buffer@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + is-callable@^1.1.4, is-callable@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" @@ -768,6 +868,13 @@ is-negative-zero@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" +is-regex@^1.0.4: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" + dependencies: + call-bind "^1.0.2" + has-symbols "^1.0.1" + is-regex@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" @@ -832,6 +939,15 @@ jsonfile@^4.0.0: optionalDependencies: graceful-fs "^4.1.6" +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -900,6 +1016,14 @@ lodash@^4.17.14, lodash@^4.17.19: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" +md5@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" + dependencies: + charenc "0.0.2" + crypt "0.0.2" + is-buffer "~1.1.6" + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -968,6 +1092,17 @@ ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" +multicast-dns-service-types@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901" + +multicast-dns@^6.0.1: + version "6.2.3" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229" + dependencies: + dns-packet "^1.3.1" + thunky "^1.0.2" + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -1018,6 +1153,13 @@ object-inspect@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" +object-is@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -1191,6 +1333,13 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" +regexp.prototype.flags@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz#7ef352ae8d159e758c0eadca6f8fcb4eef07be26" + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + regexpp@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" @@ -1407,6 +1556,10 @@ through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + tinycolor2@^1.0.0: version "1.4.2" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" @@ -1477,6 +1630,11 @@ universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"