serviceable
parent
c9fb26009c
commit
c19c4c2fec
56
package.json
56
package.json
|
|
@ -1,4 +1,15 @@
|
||||||
{
|
{
|
||||||
|
"config": {
|
||||||
|
"ports": {
|
||||||
|
"relay": 5600,
|
||||||
|
"relayEnd": 5699,
|
||||||
|
"http": 5700,
|
||||||
|
"service": 5000
|
||||||
|
},
|
||||||
|
"endpoints": [
|
||||||
|
"valnet.xyz:5500"
|
||||||
|
]
|
||||||
|
},
|
||||||
"name": "electron-react-boilerplate",
|
"name": "electron-react-boilerplate",
|
||||||
"productName": "ElectronReact",
|
"productName": "ElectronReact",
|
||||||
"description": "Electron application boilerplate based on React, React Router, Webpack, React Fast Refresh for rapid application development",
|
"description": "Electron application boilerplate based on React, React Router, Webpack, React Fast Refresh for rapid application development",
|
||||||
|
|
@ -15,20 +26,6 @@
|
||||||
"start:renderer": "cross-env NODE_ENV=development webpack serve --config ./.erb/configs/webpack.config.renderer.dev.babel.js",
|
"start:renderer": "cross-env NODE_ENV=development webpack serve --config ./.erb/configs/webpack.config.renderer.dev.babel.js",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"lint-staged": {
|
|
||||||
"*.{js,jsx,ts,tsx}": [
|
|
||||||
"cross-env NODE_ENV=development eslint --cache"
|
|
||||||
],
|
|
||||||
"{*.json,.{babelrc,eslintrc,prettierrc}}": [
|
|
||||||
"prettier --ignore-path .eslintignore --parser json --write"
|
|
||||||
],
|
|
||||||
"*.{css,scss}": [
|
|
||||||
"prettier --ignore-path .eslintignore --single-quote --write"
|
|
||||||
],
|
|
||||||
"*.{html,md,yml}": [
|
|
||||||
"prettier --ignore-path .eslintignore --single-quote --write"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"build": {
|
"build": {
|
||||||
"productName": "ElectronReact",
|
"productName": "ElectronReact",
|
||||||
"appId": "org.erb.ElectronReact",
|
"appId": "org.erb.ElectronReact",
|
||||||
|
|
@ -213,13 +210,11 @@
|
||||||
"eslint-config-airbnb": "^18.2.0",
|
"eslint-config-airbnb": "^18.2.0",
|
||||||
"eslint-config-airbnb-typescript": "^12.0.0",
|
"eslint-config-airbnb-typescript": "^12.0.0",
|
||||||
"eslint-config-erb": "^2.0.0",
|
"eslint-config-erb": "^2.0.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
|
||||||
"eslint-import-resolver-webpack": "^0.13.0",
|
"eslint-import-resolver-webpack": "^0.13.0",
|
||||||
"eslint-plugin-compat": "^3.8.0",
|
"eslint-plugin-compat": "^3.8.0",
|
||||||
"eslint-plugin-import": "^2.22.0",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"eslint-plugin-jest": "^24.1.3",
|
"eslint-plugin-jest": "^24.1.3",
|
||||||
"eslint-plugin-jsx-a11y": "6.4.1",
|
"eslint-plugin-jsx-a11y": "6.4.1",
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
"eslint-plugin-react": "^7.20.6",
|
"eslint-plugin-react": "^7.20.6",
|
||||||
"eslint-plugin-react-hooks": "^4.0.8",
|
"eslint-plugin-react-hooks": "^4.0.8",
|
||||||
|
|
@ -231,7 +226,6 @@
|
||||||
"mini-css-extract-plugin": "^1.3.1",
|
"mini-css-extract-plugin": "^1.3.1",
|
||||||
"node-sass": "^5.0.0",
|
"node-sass": "^5.0.0",
|
||||||
"opencollective-postinstall": "^2.0.3",
|
"opencollective-postinstall": "^2.0.3",
|
||||||
"prettier": "^2.0.5",
|
|
||||||
"react-refresh": "^0.9.0",
|
"react-refresh": "^0.9.0",
|
||||||
"react-test-renderer": "^17.0.1",
|
"react-test-renderer": "^17.0.1",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.0",
|
||||||
|
|
@ -248,15 +242,23 @@
|
||||||
"yarn-deduplicate": "^3.1.0"
|
"yarn-deduplicate": "^3.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"bonjour": "^3.5.0",
|
||||||
"electron-debug": "^3.1.0",
|
"electron-debug": "^3.1.0",
|
||||||
"electron-log": "^4.2.4",
|
"electron-log": "^4.2.4",
|
||||||
"electron-updater": "^4.3.4",
|
"electron-updater": "^4.3.4",
|
||||||
"history": "^5.0.0",
|
"history": "^5.0.0",
|
||||||
|
"human-readable-ids": "^1.0.4",
|
||||||
|
"keyv": "^4.0.3",
|
||||||
|
"keyv-file": "^0.2.0",
|
||||||
|
"md5": "^2.3.0",
|
||||||
"menubar": "^9.0.3",
|
"menubar": "^9.0.3",
|
||||||
|
"nat-upnp": "^1.1.1",
|
||||||
|
"node-rsa": "^1.1.1",
|
||||||
"react": "^17.0.1",
|
"react": "^17.0.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"regenerator-runtime": "^0.13.5",
|
"regenerator-runtime": "^0.13.5",
|
||||||
|
"signale": "^1.4.0",
|
||||||
"source-map-support": "^0.5.19"
|
"source-map-support": "^0.5.19"
|
||||||
},
|
},
|
||||||
"devEngines": {
|
"devEngines": {
|
||||||
|
|
@ -268,21 +270,6 @@
|
||||||
"url": "https://opencollective.com/electron-react-boilerplate-594"
|
"url": "https://opencollective.com/electron-react-boilerplate-594"
|
||||||
},
|
},
|
||||||
"browserslist": [],
|
"browserslist": [],
|
||||||
"prettier": {
|
|
||||||
"overrides": [
|
|
||||||
{
|
|
||||||
"files": [
|
|
||||||
".prettierrc",
|
|
||||||
".babelrc",
|
|
||||||
".eslintrc"
|
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"parser": "json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"singleQuote": true
|
|
||||||
},
|
|
||||||
"renovate": {
|
"renovate": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"bliss"
|
"bliss"
|
||||||
|
|
@ -290,10 +277,5 @@
|
||||||
"baseBranches": [
|
"baseBranches": [
|
||||||
"next"
|
"next"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"husky": {
|
|
||||||
"hooks": {
|
|
||||||
"pre-commit": "lint-staged"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,13 @@ const { title } = require('../lib/title');
|
||||||
const log = require('signale').scope('RLAY');
|
const log = require('signale').scope('RLAY');
|
||||||
const { Identity } = require('../lib/Identity');
|
const { Identity } = require('../lib/Identity');
|
||||||
title('relay', false);
|
title('relay', false);
|
||||||
const identity = await new Identity('relay', 'default');
|
|
||||||
const Node = require('../lib/node');
|
const Node = require('../lib/node');
|
||||||
const { config } = require('../lib/config');
|
const { config } = require('../lib/config');
|
||||||
const { ensureDirSync } = require('fs-extra');
|
const { ensureDirSync } = require('fs-extra');
|
||||||
const appdata = require('../lib/appdata');
|
const appdata = require('../lib/appdata');
|
||||||
|
|
||||||
ensureDirSync(`${appdata}/valnet/relay`);
|
ensureDirSync(`${appdata}/valnet/relay`);
|
||||||
const node = new Node(identity);
|
const node = new Node();
|
||||||
|
|
||||||
// ==================================== [EXPRESS]
|
// ==================================== [EXPRESS]
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
|
|
|
||||||
|
|
@ -1,163 +1,163 @@
|
||||||
const { config } = require('./config');
|
const { config } = require('./config');
|
||||||
const Keyv = require('keyv');
|
const Keyv = require('keyv');
|
||||||
const { KeyvFile } = require('keyv-file');
|
const { KeyvFile } = require('keyv-file');
|
||||||
const { Signale } = require('signale');
|
const { Signale } = require('signale');
|
||||||
const log = new Signale().scope('GTWY');
|
const log = new Signale().scope('GTWY');
|
||||||
const stp = require('./STP');
|
const stp = require('./STP');
|
||||||
const appdata = require('./appdata');
|
const appdata = require('./appdata');
|
||||||
|
|
||||||
class Gateway {
|
class Gateway {
|
||||||
constructor(identity, endpoints) {
|
constructor(identity, endpoints) {
|
||||||
this.identity = identity;
|
this.identity = identity;
|
||||||
|
|
||||||
this.endpoints = new Keyv({
|
this.endpoints = new Keyv({
|
||||||
store: new KeyvFile({
|
store: new KeyvFile({
|
||||||
filename: `${appdata}/valnet/relay/${this.identity.name}-endpoints.json`
|
filename: `${appdata}/valnet/relay/${this.identity.name}-endpoints.json`
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
this.ready = this.insertEndpoints(endpoints)
|
this.ready = this.insertEndpoints(endpoints)
|
||||||
.then(this.networkTest.bind(this));
|
.then(this.networkTest.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
async insertEndpoints(endpoints) {
|
async insertEndpoints(endpoints) {
|
||||||
for (const endpoint of endpoints) {
|
for (const endpoint of endpoints) {
|
||||||
const storeValue = await this.endpoints.get(endpoint);
|
const storeValue = await this.endpoints.get(endpoint);
|
||||||
if (storeValue) continue;
|
if (storeValue) continue;
|
||||||
|
|
||||||
const [host, port] = endpoint.split(':');
|
const [host, port] = endpoint.split(':');
|
||||||
const record = new EndpointRecord(host, port, null, 'unknown');
|
const record = new EndpointRecord(host, port, null, 'unknown');
|
||||||
const currentEnpoints = await this.endpoints.get('cache') || [];
|
const currentEnpoints = await this.endpoints.get('cache') || [];
|
||||||
|
|
||||||
if (currentEnpoints.indexOf(endpoint) === -1) {
|
if (currentEnpoints.indexOf(endpoint) === -1) {
|
||||||
currentEnpoints.push(endpoint);
|
currentEnpoints.push(endpoint);
|
||||||
await this.endpoints.set('cache', currentEnpoints);
|
await this.endpoints.set('cache', currentEnpoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.endpoints.set(endpoint, record);
|
await this.endpoints.set(endpoint, record);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('gateway endpoints:');
|
log.info('gateway endpoints:');
|
||||||
for(const endpoint of (await this.endpoints.get('cache'))) {
|
for(const endpoint of (await this.endpoints.get('cache'))) {
|
||||||
log.info(`\t${endpoint}`);
|
log.info(`\t${endpoint}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async networkTest() {
|
async networkTest() {
|
||||||
const endpoints = (await Promise.all(
|
const endpoints = (await Promise.all(
|
||||||
(await this.endpoints.get('cache'))
|
(await this.endpoints.get('cache'))
|
||||||
.map(endpoint => this.endpoints.get(endpoint))
|
.map(endpoint => this.endpoints.get(endpoint))
|
||||||
)).map(EndpointRecord.fromJson);
|
)).map(EndpointRecord.fromJson);
|
||||||
|
|
||||||
|
|
||||||
for (const endpoint of endpoints) {
|
for (const endpoint of endpoints) {
|
||||||
await this.testEndpoint(endpoint.host, endpoint.port);
|
await this.testEndpoint(endpoint.host, endpoint.port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async testEndpoint(host, port) {
|
async testEndpoint(host, port) {
|
||||||
const log = new Signale({ scope: `${host}:${port}` });
|
const log = new Signale({ scope: `${host}:${port}` });
|
||||||
const interactive = new Signale({ interactive: true, scope: `${host}:${port}` });
|
const interactive = new Signale({ interactive: true, scope: `${host}:${port}` });
|
||||||
|
|
||||||
await new Promise(async (res, rej) => {
|
await new Promise(async (res, rej) => {
|
||||||
let pings = [];
|
let pings = [];
|
||||||
let maxPings = 1;
|
let maxPings = 1;
|
||||||
let connectionAttempts = 0;
|
let connectionAttempts = 0;
|
||||||
let wasConnected = false;
|
let wasConnected = false;
|
||||||
|
|
||||||
const done = _ => connectionAttempts === 2 || pings.length === maxPings
|
const done = _ => connectionAttempts === 2 || pings.length === maxPings
|
||||||
|
|
||||||
log.info('Starting connection test...');
|
log.info('Starting connection test...');
|
||||||
|
|
||||||
while (!done()) {
|
while (!done()) {
|
||||||
|
|
||||||
await new Promise(async (res) => {
|
await new Promise(async (res) => {
|
||||||
const client = stp.connect({
|
const client = stp.connect({
|
||||||
identity: this.identity,
|
identity: this.identity,
|
||||||
ip: host,
|
ip: host,
|
||||||
port: parseInt(port)
|
port: parseInt(port)
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('error', _ => _);
|
client.on('error', _ => _);
|
||||||
|
|
||||||
client.on('ready', async () => {
|
client.on('ready', async () => {
|
||||||
wasConnected = true;
|
wasConnected = true;
|
||||||
|
|
||||||
while (pings.length < maxPings) {
|
while (pings.length < maxPings) {
|
||||||
log.info(`[${pings.length + 1}/${maxPings}] Testing connection`);
|
log.info(`[${pings.length + 1}/${maxPings}] Testing connection`);
|
||||||
pings.push(await client.ping());
|
pings.push(await client.ping());
|
||||||
// await new Promise(res => setTimeout(res, 1000));
|
// await new Promise(res => setTimeout(res, 1000));
|
||||||
}
|
}
|
||||||
client.tcpSocket.destroy();
|
client.tcpSocket.destroy();
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
|
|
||||||
client.on('close', () => {
|
client.on('close', () => {
|
||||||
connectionAttempts ++;
|
connectionAttempts ++;
|
||||||
if(!done() && wasConnected) {
|
if(!done() && wasConnected) {
|
||||||
log.warn(`Lost connection, Retrying...`);
|
log.warn(`Lost connection, Retrying...`);
|
||||||
}
|
}
|
||||||
wasConnected = false;
|
wasConnected = false;
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pings.length === maxPings) {
|
if (pings.length === maxPings) {
|
||||||
const average = Math.round(pings.reduce((a, v) => a + v, 0) / maxPings);
|
const average = Math.round(pings.reduce((a, v) => a + v, 0) / maxPings);
|
||||||
const pingRecord = new PingRecord(average, pings.length, new Date().getTime());
|
const pingRecord = new PingRecord(average, pings.length, new Date().getTime());
|
||||||
const endpointRecord = new EndpointRecord(host, port, pingRecord, 'online');
|
const endpointRecord = new EndpointRecord(host, port, pingRecord, 'online');
|
||||||
|
|
||||||
await this.endpoints.set(`${host}:${port}`, endpointRecord);
|
await this.endpoints.set(`${host}:${port}`, endpointRecord);
|
||||||
|
|
||||||
log.success(`Test complete. Average Ping: ${average}ms`);
|
log.success(`Test complete. Average Ping: ${average}ms`);
|
||||||
} else {
|
} else {
|
||||||
log.error(`Could not complete connection test`)
|
log.error(`Could not complete connection test`)
|
||||||
}
|
}
|
||||||
|
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EndpointRecord {
|
class EndpointRecord {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Object|string} json string / object representation
|
* @param {Object|string} json string / object representation
|
||||||
* @returns {EndpointRecord}
|
* @returns {EndpointRecord}
|
||||||
*/
|
*/
|
||||||
static fromJson(obj) {
|
static fromJson(obj) {
|
||||||
if (typeof obj === 'string')
|
if (typeof obj === 'string')
|
||||||
return EndpointRecord.fromJson(JSON.parse(obj));
|
return EndpointRecord.fromJson(JSON.parse(obj));
|
||||||
|
|
||||||
return new EndpointRecord(
|
return new EndpointRecord(
|
||||||
obj.host,
|
obj.host,
|
||||||
obj.port,
|
obj.port,
|
||||||
obj.lastPing ? new PingRecord(
|
obj.lastPing ? new PingRecord(
|
||||||
obj.lastPing.average,
|
obj.lastPing.average,
|
||||||
obj.lastPing.tests,
|
obj.lastPing.tests,
|
||||||
obj.lastPing.date
|
obj.lastPing.date
|
||||||
) : null,
|
) : null,
|
||||||
obj.status
|
obj.status
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(host, port, lastPing, status) {
|
constructor(host, port, lastPing, status) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.lastPing = lastPing;
|
this.lastPing = lastPing;
|
||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PingRecord {
|
class PingRecord {
|
||||||
constructor(average, tests, date) {
|
constructor(average, tests, date) {
|
||||||
this.average = average;
|
this.average = average;
|
||||||
this.tests = tests;
|
this.tests = tests;
|
||||||
this.date = date;
|
this.date = date;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Gateway
|
module.exports = Gateway
|
||||||
|
|
@ -1,187 +1,187 @@
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const NodeRSA = require('node-rsa');
|
const NodeRSA = require('node-rsa');
|
||||||
const log = require('signale').scope('_STP');
|
const log = require('signale').scope('_STP');
|
||||||
const debug = require('debug')('xyz:valnet:stp');
|
const debug = require('debug')('xyz:valnet:stp');
|
||||||
const {
|
const {
|
||||||
KeyExchangePacket,
|
KeyExchangePacket,
|
||||||
AckPacket,
|
AckPacket,
|
||||||
PingPacket,
|
PingPacket,
|
||||||
PongPacket
|
PongPacket
|
||||||
} = require('./packets');
|
} = require('./packets');
|
||||||
|
|
||||||
module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) {
|
module.exports.createServer = function({identity = {}, port = 5000} = {}, cb = _ => _) {
|
||||||
const server = new Server(identity, port);
|
const server = new Server(identity, port);
|
||||||
server.on('connection', connection => {
|
server.on('connection', connection => {
|
||||||
cb(connection);
|
cb(connection);
|
||||||
});
|
});
|
||||||
// return 5;
|
// return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.connect = function({
|
module.exports.connect = function({
|
||||||
identity,
|
identity,
|
||||||
port,
|
port,
|
||||||
ip
|
ip
|
||||||
}) {
|
}) {
|
||||||
return new STPSocket(net.connect(port, ip), identity);
|
return new STPSocket(net.connect(port, ip), identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
class Server extends EventEmitter {
|
class Server extends EventEmitter {
|
||||||
tcpServer;
|
tcpServer;
|
||||||
identity;
|
identity;
|
||||||
port;
|
port;
|
||||||
|
|
||||||
constructor(identity, port) {
|
constructor(identity, port) {
|
||||||
super();
|
super();
|
||||||
this.identity = identity;
|
this.identity = identity;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.openServer();
|
this.openServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
openServer() {
|
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 = net.createServer(this.tcpConnectClient.bind(this));
|
||||||
this.tcpServer.on('error', e => {
|
this.tcpServer.on('error', e => {
|
||||||
log.warn(e)
|
log.warn(e)
|
||||||
setTimeout(this.openServer.bind(this), 5000);
|
setTimeout(this.openServer.bind(this), 5000);
|
||||||
})
|
})
|
||||||
this.tcpServer.listen(this.port);
|
this.tcpServer.listen(this.port);
|
||||||
}
|
}
|
||||||
|
|
||||||
tcpConnectClient(tcpSocket) {
|
tcpConnectClient(tcpSocket) {
|
||||||
const socket = new STPSocket(tcpSocket, this.identity);
|
const socket = new STPSocket(tcpSocket, this.identity);
|
||||||
socket.on('ready', () => {
|
socket.on('ready', () => {
|
||||||
this.emit('connection', socket);
|
this.emit('connection', socket);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class STPSocket extends EventEmitter {
|
class STPSocket extends EventEmitter {
|
||||||
tcpSocket;
|
tcpSocket;
|
||||||
buffer = '';
|
buffer = '';
|
||||||
externalKey;
|
externalKey;
|
||||||
identity;
|
identity;
|
||||||
externalName;
|
externalName;
|
||||||
|
|
||||||
CONNECTING = Symbol('connecting');
|
CONNECTING = Symbol('connecting');
|
||||||
EXCHANGE = Symbol('exchange');
|
EXCHANGE = Symbol('exchange');
|
||||||
SECURED = Symbol('secured');
|
SECURED = Symbol('secured');
|
||||||
readyState = this.CONNECTING;
|
readyState = this.CONNECTING;
|
||||||
|
|
||||||
pingCallbacks = new Map();
|
pingCallbacks = new Map();
|
||||||
|
|
||||||
get loopback() {
|
get loopback() {
|
||||||
return this.identity.publicKey ===
|
return this.identity.publicKey ===
|
||||||
this.externalKey.exportKey('pkcs8-public-pem');
|
this.externalKey.exportKey('pkcs8-public-pem');
|
||||||
}
|
}
|
||||||
|
|
||||||
get remoteAddress() {
|
get remoteAddress() {
|
||||||
return this.tcpSocket.remoteAddress;
|
return this.tcpSocket.remoteAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
get remoteName() {
|
get remoteName() {
|
||||||
return this.externalName;
|
return this.externalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
get remoteIdentity() {
|
get remoteIdentity() {
|
||||||
return this.externalKey.exportKey('pkcs8-public-pem');
|
return this.externalKey.exportKey('pkcs8-public-pem');
|
||||||
}
|
}
|
||||||
|
|
||||||
get open() {
|
get open() {
|
||||||
return this.tcpSocket.readyState === 'open';
|
return this.tcpSocket.readyState === 'open';
|
||||||
}
|
}
|
||||||
|
|
||||||
get secured() {
|
get secured() {
|
||||||
return this.readyState;
|
return this.readyState;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(tcpSocket, identity) {
|
constructor(tcpSocket, identity) {
|
||||||
super();
|
super();
|
||||||
this.tcpSocket = tcpSocket;
|
this.tcpSocket = tcpSocket;
|
||||||
this.identity = identity;
|
this.identity = identity;
|
||||||
if(this.open) this.handshake();
|
if(this.open) this.handshake();
|
||||||
else this.tcpSocket.on('connect', this.handshake.bind(this));
|
else this.tcpSocket.on('connect', this.handshake.bind(this));
|
||||||
|
|
||||||
this.tcpSocket.on('data', this.data.bind(this));
|
this.tcpSocket.on('data', this.data.bind(this));
|
||||||
this.tcpSocket.on('error', (...args) => this.emit('error', ...args));
|
this.tcpSocket.on('error', (...args) => this.emit('error', ...args));
|
||||||
this.tcpSocket.on('close', (...args) => this.emit('close', ...args));
|
this.tcpSocket.on('close', (...args) => this.emit('close', ...args));
|
||||||
}
|
}
|
||||||
|
|
||||||
data(evt) {
|
data(evt) {
|
||||||
this.buffer += evt.toString();
|
this.buffer += evt.toString();
|
||||||
this.processBuffer();
|
this.processBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
processBuffer() {
|
processBuffer() {
|
||||||
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
|
const parts = this.buffer.split(/(\x02[^\x02\x03]*\x03)/g);
|
||||||
this.buffer = '';
|
this.buffer = '';
|
||||||
|
|
||||||
for(const message of parts) {
|
for(const message of parts) {
|
||||||
if(message.endsWith('\x03')) {
|
if(message.endsWith('\x03')) {
|
||||||
const obj = JSON.parse(message.substr(1, message.length - 2));
|
const obj = JSON.parse(message.substr(1, message.length - 2));
|
||||||
this.processMessage(obj);
|
this.processMessage(obj);
|
||||||
} else {
|
} else {
|
||||||
this.buffer += message;
|
this.buffer += message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
processMessage(obj) {
|
processMessage(obj) {
|
||||||
|
|
||||||
if(this.readyState === this.CONNECTING && obj.cmd === 'KEY') {
|
if(this.readyState === this.CONNECTING && obj.cmd === 'KEY') {
|
||||||
debug('received remote public key...');
|
debug('received remote public key...');
|
||||||
this.externalKey = new NodeRSA();
|
this.externalKey = new NodeRSA();
|
||||||
this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem');
|
this.externalKey.importKey(obj.data.key, 'pkcs8-public-pem');
|
||||||
this.externalName = obj.meta.name;
|
this.externalName = obj.meta.name;
|
||||||
this.tcpSocket.write(new AckPacket().toBuffer());
|
this.tcpSocket.write(new AckPacket().toBuffer());
|
||||||
this.readyState = this.EXCHANGE;
|
this.readyState = this.EXCHANGE;
|
||||||
debug('sent acknowledgement...');
|
debug('sent acknowledgement...');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.readyState === this.EXCHANGE && obj.cmd === 'ACK') {
|
if(this.readyState === this.EXCHANGE && obj.cmd === 'ACK') {
|
||||||
debug('received acknowledgement...');
|
debug('received acknowledgement...');
|
||||||
this.readyState = this.SECURED;
|
this.readyState = this.SECURED;
|
||||||
this.emit('ready');
|
this.emit('ready');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.readyState === this.SECURED && obj.cmd === 'PING') {
|
if (this.readyState === this.SECURED && obj.cmd === 'PING') {
|
||||||
this.tcpSocket.write(new PongPacket(obj.data.id).toBuffer());
|
this.tcpSocket.write(new PongPacket(obj.data.id).toBuffer());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.readyState === this.SECURED && obj.cmd === 'PONG') {
|
if (this.readyState === this.SECURED && obj.cmd === 'PONG') {
|
||||||
if (this.pingCallbacks.has(obj.data.id)) {
|
if (this.pingCallbacks.has(obj.data.id)) {
|
||||||
this.pingCallbacks.get(obj.data.id)();
|
this.pingCallbacks.get(obj.data.id)();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handshake() {
|
handshake() {
|
||||||
debug('connected')
|
debug('connected')
|
||||||
const pk = this.identity.publicKey;
|
const pk = this.identity.publicKey;
|
||||||
const packet = new KeyExchangePacket(pk, {
|
const packet = new KeyExchangePacket(pk, {
|
||||||
name: this.identity.name
|
name: this.identity.name
|
||||||
});
|
});
|
||||||
const buffer = packet.toBuffer();
|
const buffer = packet.toBuffer();
|
||||||
this.tcpSocket.write(buffer);
|
this.tcpSocket.write(buffer);
|
||||||
debug('sent public key...')
|
debug('sent public key...')
|
||||||
}
|
}
|
||||||
|
|
||||||
async ping() {
|
async ping() {
|
||||||
const startTime = new Date().getTime();
|
const startTime = new Date().getTime();
|
||||||
return await new Promise(async (res) => {
|
return await new Promise(async (res) => {
|
||||||
const packet = new PingPacket();
|
const packet = new PingPacket();
|
||||||
this.pingCallbacks.set(packet.data.id, _ => {
|
this.pingCallbacks.set(packet.data.id, _ => {
|
||||||
res(new Date().getTime() - startTime);
|
res(new Date().getTime() - startTime);
|
||||||
this.pingCallbacks.delete(packet.data.id);
|
this.pingCallbacks.delete(packet.data.id);
|
||||||
});
|
});
|
||||||
this.tcpSocket.write(packet.toBuffer());
|
this.tcpSocket.write(packet.toBuffer());
|
||||||
debug('ping sent...');
|
debug('ping sent...');
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,115 +1,115 @@
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
|
|
||||||
// #region === [ private lib functions ] ===
|
// #region === [ private lib functions ] ===
|
||||||
|
|
||||||
class STPPacket {
|
class STPPacket {
|
||||||
cmd = 'NOOP';
|
cmd = 'NOOP';
|
||||||
data = {};
|
data = {};
|
||||||
meta = {};
|
meta = {};
|
||||||
|
|
||||||
toBuffer() {
|
toBuffer() {
|
||||||
return Buffer.from(`\x02${JSON.stringify({
|
return Buffer.from(`\x02${JSON.stringify({
|
||||||
cmd: this.cmd,
|
cmd: this.cmd,
|
||||||
data: this.data,
|
data: this.data,
|
||||||
meta: this.meta
|
meta: this.meta
|
||||||
})}\x03`);
|
})}\x03`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function basicPacket(commandName) {
|
function basicPacket(commandName) {
|
||||||
return class extends STPPacket {
|
return class extends STPPacket {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.cmd = commandName;
|
this.cmd = commandName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region === [ exotic packet classes ] ===
|
// #region === [ exotic packet classes ] ===
|
||||||
|
|
||||||
class KeyExchangePacket extends STPPacket {
|
class KeyExchangePacket extends STPPacket {
|
||||||
constructor(key, {
|
constructor(key, {
|
||||||
type = 'pkcs8-pem',
|
type = 'pkcs8-pem',
|
||||||
name = 'anonymous'
|
name = 'anonymous'
|
||||||
} = {}) {
|
} = {}) {
|
||||||
super();
|
super();
|
||||||
this.cmd = 'KEY';
|
this.cmd = 'KEY';
|
||||||
this.data.key = key;
|
this.data.key = key;
|
||||||
this.meta.name = name;
|
this.meta.name = name;
|
||||||
this.meta.type = type;
|
this.meta.type = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClientsPacket extends STPPacket {
|
class ClientsPacket extends STPPacket {
|
||||||
constructor(clients) {
|
constructor(clients) {
|
||||||
super();
|
super();
|
||||||
this.cmd = 'NODES'
|
this.cmd = 'NODES'
|
||||||
this.data.clients = clients;
|
this.data.clients = clients;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PingPacket extends STPPacket {
|
class PingPacket extends STPPacket {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.cmd = 'PING';
|
this.cmd = 'PING';
|
||||||
this.data.id = md5(Date());
|
this.data.id = md5(Date());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PongPacket extends STPPacket {
|
class PongPacket extends STPPacket {
|
||||||
constructor(id) {
|
constructor(id) {
|
||||||
super();
|
super();
|
||||||
this.cmd = 'PONG';
|
this.cmd = 'PONG';
|
||||||
this.data.id = id;
|
this.data.id = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region === [ ordinary packet classes ] ===
|
// #region === [ ordinary packet classes ] ===
|
||||||
|
|
||||||
const AckPacket = basicPacket('ACK');
|
const AckPacket = basicPacket('ACK');
|
||||||
const GetClientsPacket = basicPacket('QNODES');
|
const GetClientsPacket = basicPacket('QNODES');
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region === [ public lib functions ] ===
|
// #region === [ public lib functions ] ===
|
||||||
|
|
||||||
function reconstructPacket(packet) {
|
function reconstructPacket(packet) {
|
||||||
|
|
||||||
if(packet.startsWith('\02'))
|
if(packet.startsWith('\x02'))
|
||||||
return reconstructPacket(packet.substr(1));
|
return reconstructPacket(packet.substr(1));
|
||||||
if(packet.endsWith('\x03'))
|
if(packet.endsWith('\x03'))
|
||||||
return reconstructPacket(packet.substr(0, packet.length - 1));
|
return reconstructPacket(packet.substr(0, packet.length - 1));
|
||||||
|
|
||||||
const obj = JSON.parse(packet);
|
const obj = JSON.parse(packet);
|
||||||
|
|
||||||
switch(obj.cmd) {
|
switch(obj.cmd) {
|
||||||
case 'KEY': return new KeyExchangePacket(obj.data.key, obj.meta);
|
case 'KEY': return new KeyExchangePacket(obj.data.key, obj.meta);
|
||||||
case 'NODES': return new ClientsPacket(obj.data.clients);
|
case 'NODES': return new ClientsPacket(obj.data.clients);
|
||||||
case 'QNODES': return new GetClientsPacket();
|
case 'QNODES': return new GetClientsPacket();
|
||||||
case 'ACK': return new AckPacket();
|
case 'ACK': return new AckPacket();
|
||||||
|
|
||||||
case 'NOOP': return new STPPacket();
|
case 'NOOP': return new STPPacket();
|
||||||
default: throw new TypeError(`Unknown command ${obj.cmd}`);
|
default: throw new TypeError(`Unknown command ${obj.cmd}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
||||||
// #region === [ exports ] ===
|
// #region === [ exports ] ===
|
||||||
|
|
||||||
module.exports.KeyExchangePacket = KeyExchangePacket;
|
module.exports.KeyExchangePacket = KeyExchangePacket;
|
||||||
module.exports.ClientsPacket = ClientsPacket;
|
module.exports.ClientsPacket = ClientsPacket;
|
||||||
module.exports.PingPacket = PingPacket;
|
module.exports.PingPacket = PingPacket;
|
||||||
module.exports.PongPacket = PongPacket;
|
module.exports.PongPacket = PongPacket;
|
||||||
|
|
||||||
module.exports.AckPacket = AckPacket;
|
module.exports.AckPacket = AckPacket;
|
||||||
module.exports.GetClientsPacket = GetClientsPacket;
|
module.exports.GetClientsPacket = GetClientsPacket;
|
||||||
|
|
||||||
module.exports.reconstructPacket = reconstructPacket;
|
module.exports.reconstructPacket = reconstructPacket;
|
||||||
|
|
||||||
// #endregion
|
// #endregion
|
||||||
|
|
@ -1,35 +1,34 @@
|
||||||
const pkg = require('./../package.json');
|
const { readFileSync, writeFileSync, existsSync } = require('fs');
|
||||||
const { readFileSync, writeFileSync, existsSync } = require('fs');
|
const { ensureDirSync } = require('fs-extra');
|
||||||
const { ensureDirSync } = require('fs-extra');
|
const { config } = require('../../package.json');
|
||||||
const { config } = require('../package.json');
|
const deepmerge = require('deepmerge');
|
||||||
const deepmerge = require('deepmerge');
|
|
||||||
|
const appdata = require('./appdata');
|
||||||
const appdata = require('./appdata');
|
ensureDirSync(`${appdata}/valnet/relay`);
|
||||||
ensureDirSync(`${appdata}/valnet/relay`);
|
const filepath = `${appdata}/valnet/relay/config.json`;
|
||||||
const filepath = `${appdata}/valnet/relay/config.json`;
|
|
||||||
|
const configObject = {};
|
||||||
const configObject = {};
|
|
||||||
|
module.exports.config = configObject;
|
||||||
module.exports.config = configObject;
|
|
||||||
|
function loadObject(obj) {
|
||||||
function loadObject(obj) {
|
for(const key in obj) {
|
||||||
for(const key in obj) {
|
configObject[key] = obj[key];
|
||||||
configObject[key] = obj[key];
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
try {
|
||||||
try {
|
if(!existsSync(filepath))
|
||||||
if(!existsSync(filepath))
|
writeFileSync(filepath, JSON.stringify({}, null, 2));
|
||||||
writeFileSync(filepath, JSON.stringify({}, null, 2));
|
|
||||||
|
const json = readFileSync(filepath);
|
||||||
const json = readFileSync(filepath);
|
const data = JSON.parse(json);
|
||||||
const data = JSON.parse(json);
|
|
||||||
|
|
||||||
|
loadObject(deepmerge(config, data, {
|
||||||
loadObject(deepmerge(config, data, {
|
arrayMerge: (_, sourceArray, __) => sourceArray
|
||||||
arrayMerge: (_, sourceArray, __) => sourceArray
|
}));
|
||||||
}));
|
|
||||||
|
} catch(e) {
|
||||||
} catch(e) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,122 +1,128 @@
|
||||||
const EventEmitter = require('events')
|
const EventEmitter = require('events')
|
||||||
const stp = require('./STP');
|
const stp = require('./STP');
|
||||||
const upnp = require('./upnp');
|
const upnp = require('./upnp');
|
||||||
const md5 = require('md5');
|
const md5 = require('md5');
|
||||||
const pkg = require('./../package.json');
|
const pkg = require('./../package.json');
|
||||||
const { config, write } = require('./config.js');
|
const { config, write } = require('./config.js');
|
||||||
const log = require('signale').scope('NODE');
|
const log = require('signale').scope('NODE');
|
||||||
const bonjour = require('bonjour')();
|
const bonjour = require('bonjour')();
|
||||||
const Gateway = require('./Gateway');
|
const Gateway = require('./Gateway');
|
||||||
|
const { Identity } = require('./Identity');
|
||||||
class Node extends EventEmitter {
|
|
||||||
clients = [];
|
class Node extends EventEmitter {
|
||||||
hash = null;
|
clients = [];
|
||||||
name = null;
|
hash = null;
|
||||||
readyPromise = null;
|
name = null;
|
||||||
port = null;
|
readyPromise = null;
|
||||||
identity;
|
port = null;
|
||||||
multicastAd = null;
|
identity;
|
||||||
multicastBrowser = null;
|
multicastAd = null;
|
||||||
connected = false;
|
multicastBrowser = null;
|
||||||
multicastDevices = [];
|
connected = false;
|
||||||
upnpEnabled = false;
|
multicastDevices = [];
|
||||||
|
upnpEnabled = false;
|
||||||
constructor(identity) {
|
|
||||||
super();
|
constructor() {
|
||||||
this.identity = identity;
|
super();
|
||||||
this.hash = md5(identity.publicKey);
|
|
||||||
this.name = `valnet-node-${identity.name}`;
|
this.readyPromise = this.setupIdentity()
|
||||||
|
.then(this.negotiatePort.bind(this))
|
||||||
this.readyPromise = this.negotiatePort()
|
.catch(this.serverStartupFailed.bind(this))
|
||||||
.catch(this.serverStartupFailed.bind(this))
|
.then(this.startServer.bind(this))
|
||||||
.then(this.startServer.bind(this))
|
.then(this.connectNetwork.bind(this))
|
||||||
.then(this.connectNetwork.bind(this))
|
}
|
||||||
}
|
|
||||||
|
async setupIdentity() {
|
||||||
async connectNetwork() {
|
const identity = await new Identity('relay', 'default');
|
||||||
const gateway = new Gateway(this.identity, config.endpoints);
|
this.identity = identity;
|
||||||
}
|
this.hash = md5(identity.publicKey);
|
||||||
|
this.name = `valnet-node-${identity.name}`;
|
||||||
async serverStartupFailed(error) {
|
}
|
||||||
log.warn('port negotiation failed, using config port: ' + config.ports.relay);
|
|
||||||
log.warn('If This is meant to be a server, you\'ll');
|
async connectNetwork() {
|
||||||
log.warn('need to manually forward the port.');
|
const gateway = new Gateway(this.identity, config.endpoints);
|
||||||
log.warn('elsewise, this warning is safe to ignore.');
|
}
|
||||||
}
|
|
||||||
|
async serverStartupFailed(error) {
|
||||||
async startServer() {
|
log.warn('port negotiation failed, using config port: ' + config.ports.relay);
|
||||||
log.info('creating Valnet Node on port ' + this.port + '...');
|
log.warn('If This is meant to be a server, you\'ll');
|
||||||
|
log.warn('need to manually forward the port.');
|
||||||
stp.createServer({
|
log.warn('elsewise, this warning is safe to ignore.');
|
||||||
identity: this.identity,
|
}
|
||||||
port: this.port
|
|
||||||
}, (connection) => {
|
async startServer() {
|
||||||
log.info('incomming connection from ' + connection.remoteName);
|
log.info('creating Valnet Node on port ' + this.port + '...');
|
||||||
});
|
|
||||||
|
stp.createServer({
|
||||||
log.info('advertising node on multicast...')
|
identity: this.identity,
|
||||||
this.multicastAd = bonjour.publish({
|
port: this.port
|
||||||
name: this.name,
|
}, (connection) => {
|
||||||
type: 'stp',
|
log.info('incomming connection from ' + connection.remoteName);
|
||||||
port: this.port,
|
});
|
||||||
protocol: 'tcp'
|
|
||||||
});
|
log.info('advertising node on multicast...')
|
||||||
|
this.multicastAd = bonjour.publish({
|
||||||
this.multicastBrowser = bonjour.find({type: 'stp'});
|
name: this.name,
|
||||||
|
type: 'stp',
|
||||||
this.multicastBrowser.on('up', this.serviceUp.bind(this));
|
port: this.port,
|
||||||
this.multicastBrowser.on('down', this.serviceDown.bind(this));
|
protocol: 'tcp'
|
||||||
|
});
|
||||||
// log.success('Node successfully registered!');
|
|
||||||
}
|
this.multicastBrowser = bonjour.find({type: 'stp'});
|
||||||
|
|
||||||
async serviceUp(device) {
|
this.multicastBrowser.on('up', this.serviceUp.bind(this));
|
||||||
this.multicastDevices.push(device);
|
this.multicastBrowser.on('down', this.serviceDown.bind(this));
|
||||||
}
|
|
||||||
|
// log.success('Node successfully registered!');
|
||||||
async serviceDown(device) {
|
}
|
||||||
this.multicastDevices = this.multicastDevices.filter(testDevice => {
|
|
||||||
return testDevice.host !== device.host
|
async serviceUp(device) {
|
||||||
|| testDevice.port !== device.port
|
this.multicastDevices.push(device);
|
||||||
})
|
}
|
||||||
}
|
|
||||||
|
async serviceDown(device) {
|
||||||
async negotiatePort() {
|
this.multicastDevices = this.multicastDevices.filter(testDevice => {
|
||||||
const mappings = await upnp.mappings();
|
return testDevice.host !== device.host
|
||||||
const matchingMappings = mappings.filter(mapping => {
|
|| testDevice.port !== device.port
|
||||||
return mapping.description === this.name
|
})
|
||||||
});
|
}
|
||||||
const alreadyMapped = matchingMappings.length > 0;
|
|
||||||
const takenPorts = mappings.map(mapping => mapping.public.port);
|
async negotiatePort() {
|
||||||
|
const mappings = await upnp.mappings();
|
||||||
if(alreadyMapped) {
|
const matchingMappings = mappings.filter(mapping => {
|
||||||
this.port = matchingMappings[0].public.port;
|
return mapping.description === this.name
|
||||||
this.upnpEnabled = true;
|
});
|
||||||
log.success(`upnp port ${this.port} already registered!`);
|
const alreadyMapped = matchingMappings.length > 0;
|
||||||
return;
|
const takenPorts = mappings.map(mapping => mapping.public.port);
|
||||||
}
|
|
||||||
|
if(alreadyMapped) {
|
||||||
for(let port = config.ports.relay; port <= config.ports.relayEnd; port ++) {
|
this.port = matchingMappings[0].public.port;
|
||||||
if(takenPorts.indexOf(port) === -1) {
|
this.upnpEnabled = true;
|
||||||
await upnp.mapIndefinite(port, this.name);
|
log.success(`upnp port ${this.port} already registered!`);
|
||||||
this.port = port;
|
return;
|
||||||
this.upnpEnabled = true;
|
}
|
||||||
log.success(`registered upnp port ${this.port}`);
|
|
||||||
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;
|
||||||
// console.log(mappings, this.hash);
|
this.upnpEnabled = true;
|
||||||
}
|
log.success(`registered upnp port ${this.port}`);
|
||||||
|
return;
|
||||||
static get Node() {
|
}
|
||||||
return Node;
|
}
|
||||||
}
|
|
||||||
|
// console.log(mappings, this.hash);
|
||||||
get ready() {
|
}
|
||||||
return this.readyPromise;
|
|
||||||
}
|
static get Node() {
|
||||||
}
|
return Node;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ready() {
|
||||||
|
return this.readyPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = Node;
|
module.exports = Node;
|
||||||
|
|
@ -1,67 +1,67 @@
|
||||||
const natUpnp = require('nat-upnp');
|
const natUpnp = require('nat-upnp');
|
||||||
const client = natUpnp.createClient();
|
const client = natUpnp.createClient();
|
||||||
|
|
||||||
module.exports.map = function(port, ttl = 10, name = 'upnp application') {
|
module.exports.map = function(port, ttl = 10, name = 'upnp application') {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
client.portMapping({
|
client.portMapping({
|
||||||
private: port,
|
private: port,
|
||||||
public: port,
|
public: port,
|
||||||
ttl,
|
ttl,
|
||||||
description: name
|
description: name
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if(err) rej(err);
|
if(err) rej(err);
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.mapIndefinite = function(port, name = 'upnp application') {
|
module.exports.mapIndefinite = function(port, name = 'upnp application') {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
client.portMapping({
|
client.portMapping({
|
||||||
private: port,
|
private: port,
|
||||||
public: port,
|
public: port,
|
||||||
ttl: 0,
|
ttl: 0,
|
||||||
description: name
|
description: name
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if(err) rej(err);
|
if(err) rej(err);
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.unmap = function(port) {
|
module.exports.unmap = function(port) {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
client.portUnmapping({
|
client.portUnmapping({
|
||||||
private: port,
|
private: port,
|
||||||
public: port
|
public: port
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
if(err) rej(err);
|
if(err) rej(err);
|
||||||
res();
|
res();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.mappings = function() {
|
module.exports.mappings = function() {
|
||||||
return new Promise((res, rej) => {
|
return new Promise((res, rej) => {
|
||||||
client.getMappings((err, mappings) => {
|
client.getMappings((err, mappings) => {
|
||||||
if(err) rej(err);
|
if(err) rej(err);
|
||||||
res(mappings);
|
res(mappings);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
(async () => {
|
(async () => {
|
||||||
try {
|
try {
|
||||||
log.debug('first upnp mapping attempt...');
|
log.debug('first upnp mapping attempt...');
|
||||||
await client.map(this.port);
|
await client.map(this.port);
|
||||||
this.openServer();
|
this.openServer();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.warn(`Could not open upnp port ${this.port}`);
|
log.warn(`Could not open upnp port ${this.port}`);
|
||||||
log.warn('Check your router is configured to allow upnp.');
|
log.warn('Check your router is configured to allow upnp.');
|
||||||
log.warn('Valnet will continue to operate, but incomming')
|
log.warn('Valnet will continue to operate, but incomming')
|
||||||
log.warn('peer connections will not be possible.')
|
log.warn('peer connections will not be possible.')
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
*/
|
*/
|
||||||
|
|
@ -132,3 +132,7 @@ app.on('activate', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// === [ VALNET NODE ] ===
|
// === [ VALNET NODE ] ===
|
||||||
|
|
||||||
|
const { Node } = require('./lib/node');
|
||||||
|
|
||||||
|
const node = new Node();
|
||||||
|
|
|
||||||
158
yarn.lock
158
yarn.lock
|
|
@ -2426,7 +2426,7 @@ asn1.js@^5.2.0:
|
||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
safer-buffer "^2.1.0"
|
safer-buffer "^2.1.0"
|
||||||
|
|
||||||
asn1@~0.2.3:
|
asn1@^0.2.4, asn1@~0.2.3:
|
||||||
version "0.2.4"
|
version "0.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
|
||||||
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
|
||||||
|
|
@ -2496,7 +2496,7 @@ async@0.9.x:
|
||||||
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
|
resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d"
|
||||||
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
|
integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=
|
||||||
|
|
||||||
async@^2.6.2:
|
async@^2.1.5, async@^2.6.2:
|
||||||
version "2.6.3"
|
version "2.6.3"
|
||||||
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
|
||||||
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
|
integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==
|
||||||
|
|
@ -3128,7 +3128,7 @@ chalk@^1.1.1:
|
||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
supports-color "^2.0.0"
|
supports-color "^2.0.0"
|
||||||
|
|
||||||
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
|
chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||||
|
|
@ -3158,6 +3158,11 @@ char-regex@^1.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
|
||||||
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
|
integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
|
||||||
|
|
||||||
|
charenc@0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
|
||||||
|
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
|
||||||
|
|
||||||
cheerio@^1.0.0-rc.3:
|
cheerio@^1.0.0-rc.3:
|
||||||
version "1.0.0-rc.3"
|
version "1.0.0-rc.3"
|
||||||
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
|
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
|
||||||
|
|
@ -3677,6 +3682,11 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
|
||||||
shebang-command "^2.0.0"
|
shebang-command "^2.0.0"
|
||||||
which "^2.0.1"
|
which "^2.0.1"
|
||||||
|
|
||||||
|
crypt@0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
|
||||||
|
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
|
||||||
|
|
||||||
crypto-browserify@^3.11.0:
|
crypto-browserify@^3.11.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
|
||||||
|
|
@ -4807,13 +4817,6 @@ eslint-config-erb@^2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
babel-eslint "^10.1.0"
|
babel-eslint "^10.1.0"
|
||||||
|
|
||||||
eslint-config-prettier@^6.11.0:
|
|
||||||
version "6.15.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9"
|
|
||||||
integrity sha512-a1+kOYLR8wMGustcgAjdydMsQ2A/2ipRPwRKUmfYaSxc9ZPcrku080Ctl6zrZzZNs/U82MjSv+qKREkoq3bJaw==
|
|
||||||
dependencies:
|
|
||||||
get-stdin "^6.0.0"
|
|
||||||
|
|
||||||
eslint-import-resolver-node@^0.3.4:
|
eslint-import-resolver-node@^0.3.4:
|
||||||
version "0.3.4"
|
version "0.3.4"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
|
||||||
|
|
@ -4903,13 +4906,6 @@ eslint-plugin-jsx-a11y@6.4.1:
|
||||||
jsx-ast-utils "^3.1.0"
|
jsx-ast-utils "^3.1.0"
|
||||||
language-tags "^1.0.5"
|
language-tags "^1.0.5"
|
||||||
|
|
||||||
eslint-plugin-prettier@^3.1.4:
|
|
||||||
version "3.1.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2"
|
|
||||||
integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg==
|
|
||||||
dependencies:
|
|
||||||
prettier-linter-helpers "^1.0.0"
|
|
||||||
|
|
||||||
eslint-plugin-promise@^4.2.1:
|
eslint-plugin-promise@^4.2.1:
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
|
||||||
|
|
@ -5236,11 +5232,6 @@ fast-deep-equal@^3.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||||
|
|
||||||
fast-diff@^1.1.2:
|
|
||||||
version "1.2.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
|
|
||||||
integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
|
|
||||||
|
|
||||||
fast-glob@^3.1.1:
|
fast-glob@^3.1.1:
|
||||||
version "3.2.4"
|
version "3.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
|
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
|
||||||
|
|
@ -5298,6 +5289,13 @@ fd-slicer@~1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
pend "~1.2.0"
|
pend "~1.2.0"
|
||||||
|
|
||||||
|
figures@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
|
||||||
|
integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp "^1.0.5"
|
||||||
|
|
||||||
figures@^3.2.0:
|
figures@^3.2.0:
|
||||||
version "3.2.0"
|
version "3.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
|
||||||
|
|
@ -5482,6 +5480,15 @@ fresh@0.5.2:
|
||||||
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
|
||||||
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||||
|
|
||||||
|
fs-extra@^4.0.1:
|
||||||
|
version "4.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
|
||||||
|
integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==
|
||||||
|
dependencies:
|
||||||
|
graceful-fs "^4.1.2"
|
||||||
|
jsonfile "^4.0.0"
|
||||||
|
universalify "^0.1.0"
|
||||||
|
|
||||||
fs-extra@^8.1.0:
|
fs-extra@^8.1.0:
|
||||||
version "8.1.0"
|
version "8.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
|
||||||
|
|
@ -5612,11 +5619,6 @@ get-stdin@^4.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
|
||||||
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
|
integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
|
||||||
|
|
||||||
get-stdin@^6.0.0:
|
|
||||||
version "6.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
|
|
||||||
integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==
|
|
||||||
|
|
||||||
get-stream@^4.0.0, get-stream@^4.1.0:
|
get-stream@^4.0.0, get-stream@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
|
||||||
|
|
@ -6119,6 +6121,13 @@ https-browserify@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||||
|
|
||||||
|
human-readable-ids@^1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/human-readable-ids/-/human-readable-ids-1.0.4.tgz#41b3a2a6966636e104e41e0673b984b36dfde202"
|
||||||
|
integrity sha512-h1zwThTims8A/SpqFGWyTx+jG1+WRMJaEeZgbtPGrIpj2AZjsOgy8Y+iNzJ0yAyN669Q6F02EK66WMWcst+2FA==
|
||||||
|
dependencies:
|
||||||
|
knuth-shuffle "^1.0.0"
|
||||||
|
|
||||||
human-signals@^1.1.1:
|
human-signals@^1.1.1:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
|
||||||
|
|
@ -6317,7 +6326,7 @@ ip-regex@^2.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
|
||||||
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
|
integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
|
||||||
|
|
||||||
ip@^1.1.0, ip@^1.1.5:
|
ip@^1.1.0, ip@^1.1.4, ip@^1.1.5:
|
||||||
version "1.1.5"
|
version "1.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
|
resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
|
||||||
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
|
integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
|
||||||
|
|
@ -6378,7 +6387,7 @@ is-boolean-object@^1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e"
|
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.1.tgz#10edc0900dd127697a92f6f9807c7617d68ac48e"
|
||||||
integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==
|
integrity sha512-TqZuVwa/sppcrhUCAYkGBk7w0yxfQQnxq28fjkO53tnK9FQXmdwz2JS5+GjsWQ6RByES1K40nI+yDic5c9/aAQ==
|
||||||
|
|
||||||
is-buffer@^1.1.5:
|
is-buffer@^1.1.5, is-buffer@~1.1.6:
|
||||||
version "1.1.6"
|
version "1.1.6"
|
||||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||||
|
|
@ -7327,6 +7336,15 @@ keyboardevents-areequal@^0.2.1:
|
||||||
resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
|
resolved "https://registry.yarnpkg.com/keyboardevents-areequal/-/keyboardevents-areequal-0.2.2.tgz#88191ec738ce9f7591c25e9056de928b40277194"
|
||||||
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
|
integrity sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==
|
||||||
|
|
||||||
|
keyv-file@^0.2.0:
|
||||||
|
version "0.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/keyv-file/-/keyv-file-0.2.0.tgz#3442b07a00c1d7bd0242f4a91bcf498afbd6ea6a"
|
||||||
|
integrity sha512-zUQ11eZRmilEUpV1gJSj8mBAHjyXpleQo1iCS0khb+GFRhiPfwavWgn4eDUKNlOyMZzmExnISl8HE1hNbim0gw==
|
||||||
|
dependencies:
|
||||||
|
debug "^4.1.1"
|
||||||
|
fs-extra "^4.0.1"
|
||||||
|
tslib "^1.9.3"
|
||||||
|
|
||||||
keyv@^3.0.0:
|
keyv@^3.0.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
|
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
|
||||||
|
|
@ -7334,7 +7352,7 @@ keyv@^3.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer "3.0.0"
|
json-buffer "3.0.0"
|
||||||
|
|
||||||
keyv@^4.0.0:
|
keyv@^4.0.0, keyv@^4.0.3:
|
||||||
version "4.0.3"
|
version "4.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254"
|
resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.0.3.tgz#4f3aa98de254803cafcd2896734108daa35e4254"
|
||||||
integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==
|
integrity sha512-zdGa2TOpSZPq5mU6iowDARnMBZgtCqJ11dJROFi6tg6kTn4nuUdU09lFyLFSaHrWqpIJ+EBq4E8/Dc0Vx5vLdA==
|
||||||
|
|
@ -7380,6 +7398,11 @@ klona@^2.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
|
resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.4.tgz#7bb1e3affb0cb8624547ef7e8f6708ea2e39dfc0"
|
||||||
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
|
integrity sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==
|
||||||
|
|
||||||
|
knuth-shuffle@^1.0.0:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/knuth-shuffle/-/knuth-shuffle-1.0.8.tgz#929a467b0efd8d297bdcf318ca988a9f1037f80d"
|
||||||
|
integrity sha512-IdC4Hpp+mx53zTt6VAGsAtbGM0g4BV9fP8tTcviCosSwocHcRDw9uG5Rnv6wLWckF4r72qeXFoK9NkvV1gUJCQ==
|
||||||
|
|
||||||
language-subtag-registry@~0.3.2:
|
language-subtag-registry@~0.3.2:
|
||||||
version "0.3.21"
|
version "0.3.21"
|
||||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
||||||
|
|
@ -7501,6 +7524,16 @@ load-json-file@^2.0.0:
|
||||||
pify "^2.0.0"
|
pify "^2.0.0"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
|
load-json-file@^4.0.0:
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b"
|
||||||
|
integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs=
|
||||||
|
dependencies:
|
||||||
|
graceful-fs "^4.1.2"
|
||||||
|
parse-json "^4.0.0"
|
||||||
|
pify "^3.0.0"
|
||||||
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
loader-runner@^4.1.0:
|
loader-runner@^4.1.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.1.0.tgz#f70bc0c29edbabdf2043e7ee73ccc3fe1c96b42d"
|
resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.1.0.tgz#f70bc0c29edbabdf2043e7ee73ccc3fe1c96b42d"
|
||||||
|
|
@ -7715,6 +7748,15 @@ md5.js@^1.3.4:
|
||||||
inherits "^2.0.1"
|
inherits "^2.0.1"
|
||||||
safe-buffer "^5.1.2"
|
safe-buffer "^5.1.2"
|
||||||
|
|
||||||
|
md5@^2.3.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f"
|
||||||
|
integrity sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==
|
||||||
|
dependencies:
|
||||||
|
charenc "0.0.2"
|
||||||
|
crypt "0.0.2"
|
||||||
|
is-buffer "~1.1.6"
|
||||||
|
|
||||||
mdn-browser-compat-data@^1.0.28:
|
mdn-browser-compat-data@^1.0.28:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/mdn-browser-compat-data/-/mdn-browser-compat-data-1.1.2.tgz#90d2a25ce731b34a14329396887dadfd657ea7b2"
|
resolved "https://registry.yarnpkg.com/mdn-browser-compat-data/-/mdn-browser-compat-data-1.1.2.tgz#90d2a25ce731b34a14329396887dadfd657ea7b2"
|
||||||
|
|
@ -8050,6 +8092,16 @@ nanomatch@^1.2.9:
|
||||||
snapdragon "^0.8.1"
|
snapdragon "^0.8.1"
|
||||||
to-regex "^3.0.1"
|
to-regex "^3.0.1"
|
||||||
|
|
||||||
|
nat-upnp@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/nat-upnp/-/nat-upnp-1.1.1.tgz#b18365e4faf44652549bb593c69e6b690df22043"
|
||||||
|
integrity sha512-b1Q+sf9fHGCXhlWErNgTTEto8A02MnNysw3vx3kD1657+/Ae23vPEAB6QBh+9RqLL4+xw/LmjVTiLy6A7Cx0xw==
|
||||||
|
dependencies:
|
||||||
|
async "^2.1.5"
|
||||||
|
ip "^1.1.4"
|
||||||
|
request "^2.79.0"
|
||||||
|
xml2js "~0.1.14"
|
||||||
|
|
||||||
native-url@^0.2.6:
|
native-url@^0.2.6:
|
||||||
version "0.2.6"
|
version "0.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae"
|
resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae"
|
||||||
|
|
@ -8202,6 +8254,13 @@ node-releases@^1.1.66:
|
||||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12"
|
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.67.tgz#28ebfcccd0baa6aad8e8d4d8fe4cbc49ae239c12"
|
||||||
integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==
|
integrity sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==
|
||||||
|
|
||||||
|
node-rsa@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-rsa/-/node-rsa-1.1.1.tgz#efd9ad382097782f506153398496f79e4464434d"
|
||||||
|
integrity sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==
|
||||||
|
dependencies:
|
||||||
|
asn1 "^0.2.4"
|
||||||
|
|
||||||
node-sass@^5.0.0:
|
node-sass@^5.0.0:
|
||||||
version "5.0.0"
|
version "5.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-5.0.0.tgz#4e8f39fbef3bac8d2dc72ebe3b539711883a78d2"
|
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-5.0.0.tgz#4e8f39fbef3bac8d2dc72ebe3b539711883a78d2"
|
||||||
|
|
@ -8871,6 +8930,14 @@ pirates@^4.0.0, pirates@^4.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
node-modules-regexp "^1.0.0"
|
node-modules-regexp "^1.0.0"
|
||||||
|
|
||||||
|
pkg-conf@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058"
|
||||||
|
integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=
|
||||||
|
dependencies:
|
||||||
|
find-up "^2.0.0"
|
||||||
|
load-json-file "^4.0.0"
|
||||||
|
|
||||||
pkg-dir@^2.0.0:
|
pkg-dir@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
|
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
|
||||||
|
|
@ -9251,14 +9318,7 @@ prepend-http@^2.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
|
||||||
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
|
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
|
||||||
|
|
||||||
prettier-linter-helpers@^1.0.0:
|
prettier@*:
|
||||||
version "1.0.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
|
|
||||||
integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
|
|
||||||
dependencies:
|
|
||||||
fast-diff "^1.1.2"
|
|
||||||
|
|
||||||
prettier@*, prettier@^2.0.5:
|
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.0.5.tgz#d6d56282455243f2f92cc1716692c08aa31522d4"
|
||||||
integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
|
integrity sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==
|
||||||
|
|
@ -9826,7 +9886,7 @@ request-promise-native@^1.0.8:
|
||||||
stealthy-require "^1.1.1"
|
stealthy-require "^1.1.1"
|
||||||
tough-cookie "^2.3.3"
|
tough-cookie "^2.3.3"
|
||||||
|
|
||||||
request@^2.88.0, request@^2.88.2:
|
request@^2.79.0, request@^2.88.0, request@^2.88.2:
|
||||||
version "2.88.2"
|
version "2.88.2"
|
||||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||||
|
|
@ -10097,7 +10157,7 @@ sass-loader@^10.1.0:
|
||||||
schema-utils "^3.0.0"
|
schema-utils "^3.0.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
sax@^1.2.4, sax@~1.2.4:
|
sax@>=0.1.1, sax@^1.2.4, sax@~1.2.4:
|
||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||||
|
|
@ -10357,6 +10417,15 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
|
||||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
|
||||||
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
|
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
|
||||||
|
|
||||||
|
signale@^1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1"
|
||||||
|
integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==
|
||||||
|
dependencies:
|
||||||
|
chalk "^2.3.2"
|
||||||
|
figures "^2.0.0"
|
||||||
|
pkg-conf "^2.1.0"
|
||||||
|
|
||||||
simple-swizzle@^0.2.2:
|
simple-swizzle@^0.2.2:
|
||||||
version "0.2.2"
|
version "0.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
||||||
|
|
@ -11201,7 +11270,7 @@ tsconfig-paths@^3.9.0:
|
||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
tslib@^1.8.1, tslib@^1.9.0:
|
tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||||
|
|
@ -11961,6 +12030,13 @@ xml-name-validator@^3.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||||
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
|
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
|
||||||
|
|
||||||
|
xml2js@~0.1.14:
|
||||||
|
version "0.1.14"
|
||||||
|
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c"
|
||||||
|
integrity sha1-UnTmf1pkxfkpdM2FE54DMq3GuQw=
|
||||||
|
dependencies:
|
||||||
|
sax ">=0.1.1"
|
||||||
|
|
||||||
xmlchars@^2.2.0:
|
xmlchars@^2.2.0:
|
||||||
version "2.2.0"
|
version "2.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
|
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
|
||||||
|
|
|
||||||
Reference in New Issue