diff --git a/RELEASES.md b/RELEASES.md index 5078ee5..63556dd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -3,6 +3,7 @@ ## Releases ## +- [v1.10.0](#1_10_0) - [v1.9.0](#1_9_0) - [v1.8.1](#1_8_1) - [v1.8.0](#1_8_0) @@ -16,6 +17,109 @@ - [v1.1.0](#1_1_0) + + +## Samourai Dojo v1.10.0 ## + + +### Notable changes ### + + +#### Performances optimization #### + +This release provides faster IBD, synchronization and rescans thanks to the optimization of multiple components of Dojo (Tracker, Importer, etc) + + +#### Export of XPUB activity #### + +The Maintenance Tool now allows to export the activity history of a XPUB in CSV format + + +#### Upgrade of bitcoind to v0.21.1 #### + +Upgrade to Bitcoin Core v0.21.1 + + +#### Upgrade of whirlpool to v0.10.11 #### + +Upgrade to whirlpool-cli 0.10.11 + + +#### Upgrade of explorer to v3.1.1 #### + +Upgrade to btc-rpc-explorer 3.1.1 + + +#### Upgrade of tor to v0.4.4.8 #### + +Upgrade to Tor v0.4.4.8 + + +#### Upgrade of indexer to v0.5.0 #### + +Upgrade to addrindexrs v0.5.0 + + + +### Change log ### + + +#### MyDojo #### + +- [#mr199](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/199) manage linux uids and gids as dojo system parameters +- [#mr200](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/200) manage ip addresses of containers as dojo system parameters +- [#mr201](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/201) disable rescan-lookahead field if data source is third_party_explorer +- [#mr202](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/202) reference db container by its ip address +- [#mr203](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/203) add export of xpub history in csv format +- [#mr204](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/204) upgrade whirlpool to whirlpool cli v0 10 10 +- [#mr206](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/206) add support of config profiles for mysql +- [#mr207](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/207) upgrade tor to tor 0.4.4.8 +- [#mr208](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/208) improve performances of blocks processing by the tracker +- [#mr209](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/209) improve performances of api +- [#mr210](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/210) better seriesCall +- [#mr211](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/211) add support of rest api provided by addrindexrs +- [#mr212](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/212) minor optimizations +- [#mr214](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/214) upgrade explorer to btc rpc explorer 3.0.0 +- [#mr215](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/215) handle Error in sendError method +- [#mr217](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/217) optimize tracker (parallel processing of blocks) +- [#mr218](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/218) optimize derivation of addresses +- [#mr219](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/219) optimize remote importer +- [#mr221](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/221) implement util.splitList() with slice() instead of splice() +- [#mr222](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/222) determine bitcoin network based on config file instead of cli argument +- [#mr223](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/223) upgrade bitcoind to bitcoin core 0.21.1 +- [#mr224](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/224) switch to buster-slim and alpine images +- [#mr226](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/226) upgrade btc-rpc-explorer to v3.1.1 +- [#mr227](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/227) switch from express to tiny-http +- [#mr228](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/228) set NODE_ENV to production for optimization purposes +- [#mr232](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/232) upgrade whirlpool to whirlpool-cli v0.10.11 + + +#### Bug fixes #### + +- [#mr220](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/220) switch tx isolation mode to read-committed + + +#### Security #### + +- [#mr216](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/216) upgrade node packages +- [#mr229](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/229) update node dependencies + + +#### Documentation #### + +- [#mr225](https://code.samourai.io/dojo/samourai-dojo/-/merge_requests/225) update docker_advanced_setups.md - fix typo + + +#### Credits ### + +- flatcloud0b3 +- kenshin-samourai +- LaurentMT +- MrHash +- pajasevi + + + ## Samourai Dojo v1.9.0 ## diff --git a/accounts/api-helper.js b/accounts/api-helper.js index 7ef0dcb..243b9d2 100644 --- a/accounts/api-helper.js +++ b/accounts/api-helper.js @@ -109,7 +109,7 @@ class ApiHelper { * Express middleware validating if entities params are well formed * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateEntitiesParams(req, res, next) { const params = this.checkEntitiesParams(req.query) ? req.query : req.body diff --git a/accounts/headers-rest-api.js b/accounts/headers-rest-api.js index 867801b..4312c1d 100644 --- a/accounts/headers-rest-api.js +++ b/accounts/headers-rest-api.js @@ -57,7 +57,7 @@ class HeadersRestApi { * Validate request arguments * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetHeader(req, res, next) { const isValidHash = validator.isHash(req.params.hash, 'sha256') diff --git a/accounts/index.js b/accounts/index.js index 8b3f65a..8f205ab 100644 --- a/accounts/index.js +++ b/accounts/index.js @@ -7,7 +7,7 @@ 'use strict' const Logger = require('../lib/logger') - const RpcClient = require('../lib/bitcoind-rpc/rpc-client') + const { waitForBitcoindRpcApi } = require('../lib/bitcoind-rpc/rpc-client') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] const db = require('../lib/db/mysql-db-wrapper') @@ -31,10 +31,10 @@ */ Logger.info('API : Process ID: ' + process.pid) Logger.info('API : Preparing the REST API') - + // Wait for Bitcoind RPC API // being ready to process requests - await RpcClient.waitForBitcoindRpcApi() + await waitForBitcoindRpcApi() // Initialize the db wrapper const dbConfig = { diff --git a/accounts/multiaddr-rest-api.js b/accounts/multiaddr-rest-api.js index 3bc7aaf..3855ded 100644 --- a/accounts/multiaddr-rest-api.js +++ b/accounts/multiaddr-rest-api.js @@ -79,7 +79,7 @@ class MultiaddrRestApi { } finally { if (debugApi) { - const strParams = + const strParams = `${req.query.active ? req.query.active : ''} \ ${req.query.new ? req.query.new : ''} \ ${req.query.pubkey ? req.query.pubkey : ''} \ @@ -120,7 +120,7 @@ class MultiaddrRestApi { } finally { if (debugApi) { - const strParams = + const strParams = `${req.body.active ? req.body.active : ''} \ ${req.body.new ? req.body.new : ''} \ ${req.body.pubkey ? req.body.pubkey : ''} \ diff --git a/accounts/support-rest-api.js b/accounts/support-rest-api.js index 5bd293d..42563cb 100644 --- a/accounts/support-rest-api.js +++ b/accounts/support-rest-api.js @@ -336,7 +336,7 @@ class SupportRestApi { * Validate arguments related to GET xpub info requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetXpubInfo(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.params.xpub) @@ -353,7 +353,7 @@ class SupportRestApi { * Validate arguments related to GET xpub rescan requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetXpubRescan(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.params.xpub) @@ -371,7 +371,7 @@ class SupportRestApi { * Validate arguments related to GET xpub delete requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetXpubDelete(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.params.xpub) @@ -388,7 +388,7 @@ class SupportRestApi { * Validate arguments related to addresses requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateAddress(req, res, next) { const isValidAddress = validator.isAlphanumeric(req.params.addr) diff --git a/accounts/transactions-rest-api.js b/accounts/transactions-rest-api.js index 5277e1b..546941a 100644 --- a/accounts/transactions-rest-api.js +++ b/accounts/transactions-rest-api.js @@ -83,8 +83,15 @@ class TransactionsRestApi { const active = apiHelper.parseEntities(req.query.active) const page = req.query.page != null ? parseInt(req.query.page) : 0 const count = req.query.count != null ? parseInt(req.query.count) : keys.multiaddr.transactions + const excludeNullXfer = req.query.excludeNullXfer != null const result = await walletService.getWalletTransactions(active, page, count) + if (excludeNullXfer) { + result.txs = result.txs.filter(tx => { + return tx['result'] != 0 + }) + } + const ret = JSON.stringify(result, null, 2) HttpServer.sendRawData(res, ret) @@ -105,7 +112,7 @@ class TransactionsRestApi { * Validate arguments of /tx requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetTransaction(req, res, next) { const isValidTxid = validator.isHash(req.params.txid, 'sha256') @@ -130,7 +137,7 @@ class TransactionsRestApi { * Validate arguments of /txs requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetTransactions(req, res, next) { const isValidPage = @@ -141,7 +148,11 @@ class TransactionsRestApi { !req.query.count || validator.isInt(req.query.count) - if (!(isValidPage && isValidCount)) { + const isValidExcludeNull = + !req.query.excludeNullXfer + || validator.isAlphanumeric(req.query.excludeNullXfer) + + if (!(isValidPage && isValidCount && isValidExcludeNull)) { HttpServer.sendError(res, errors.body.INVDATA) Logger.error( req.query, diff --git a/accounts/unspent-rest-api.js b/accounts/unspent-rest-api.js index baf1779..dfd378f 100644 --- a/accounts/unspent-rest-api.js +++ b/accounts/unspent-rest-api.js @@ -40,7 +40,7 @@ class UnspentRestApi { ) this.httpServer.app.post( - '/unspent', + '/unspent', urlencodedParser, authMgr.checkAuthentication.bind(authMgr), apiHelper.validateEntitiesParams.bind(apiHelper), @@ -79,7 +79,7 @@ class UnspentRestApi { } finally { if (debugApi) { - const strParams = + const strParams = `${req.query.active ? req.query.active : ''} \ ${req.query.new ? req.query.new : ''} \ ${req.query.pubkey ? req.query.pubkey : ''} \ @@ -120,7 +120,7 @@ class UnspentRestApi { } finally { if (debugApi) { - const strParams = + const strParams = `${req.body.active ? req.body.active : ''} \ ${req.body.new ? req.body.new : ''} \ ${req.body.pubkey ? req.body.pubkey : ''} \ @@ -134,4 +134,4 @@ class UnspentRestApi { } -module.exports = UnspentRestApi \ No newline at end of file +module.exports = UnspentRestApi diff --git a/accounts/wallet-rest-api.js b/accounts/wallet-rest-api.js index 96ab5e1..5301f6c 100644 --- a/accounts/wallet-rest-api.js +++ b/accounts/wallet-rest-api.js @@ -78,7 +78,7 @@ class WalletRestApi { } finally { if (debugApi) { - const strParams = + const strParams = `${req.query.active ? req.query.active : ''} \ ${req.query.new ? req.query.new : ''} \ ${req.query.pubkey ? req.query.pubkey : ''} \ @@ -119,7 +119,7 @@ class WalletRestApi { } finally { if (debugApi) { - const strParams = + const strParams = `${req.body.active ? req.body.active : ''} \ ${req.body.new ? req.body.new : ''} \ ${req.body.pubkey ? req.body.pubkey : ''} \ diff --git a/accounts/xpub-rest-api.js b/accounts/xpub-rest-api.js index cce81d8..18ace2d 100644 --- a/accounts/xpub-rest-api.js +++ b/accounts/xpub-rest-api.js @@ -9,16 +9,14 @@ const bodyParser = require('body-parser') const errors = require('../lib/errors') const network = require('../lib/bitcoin/network') const Logger = require('../lib/logger') -const db = require('../lib/db/mysql-db-wrapper') const hdaHelper = require('../lib/bitcoin/hd-accounts-helper') const hdaService = require('../lib/bitcoin/hd-accounts-service') -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') const HdAccountInfo = require('../lib/wallet/hd-account-info') const authMgr = require('../lib/auth/authorizations-manager') const HttpServer = require('../lib/http-server/http-server') const remoteImporter = require('../lib/remote-importer/remote-importer') -const debugApi = !!(process.argv.indexOf('api-debug') > -1) +const debugApi = process.argv.indexOf('api-debug') > -1 const gap = require('../keys/')[network.key].gap @@ -34,9 +32,6 @@ class XPubRestApi { constructor(httpServer) { this.httpServer = httpServer - // Initialize the rpc client - this.rpcClient = new RpcClient() - // Establish routes const urlencodedParser = bodyParser.urlencoded({ extended: true }) @@ -404,7 +399,7 @@ class XPubRestApi { * Validate arguments of postXpub requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsPostXpub(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.body.xpub) @@ -436,7 +431,7 @@ class XPubRestApi { * Validate arguments of getXpub requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsGetXpub(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.params.xpub) @@ -456,7 +451,7 @@ class XPubRestApi { * Validate arguments of postLockXpub requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsPostLockXpub(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.params.xpub) @@ -480,7 +475,7 @@ class XPubRestApi { * Validate arguments of deleteXpub requests * @param {object} req - http request object * @param {object} res - http response object - * @param {function} next - next express middleware + * @param {function} next - next tiny-http middleware */ validateArgsDeleteXpub(req, res, next) { const isValidXpub = validator.isAlphanumeric(req.params.xpub) diff --git a/doc/DOCKER_advanced_setups.md b/doc/DOCKER_advanced_setups.md index 2369eb9..89f8d55 100644 --- a/doc/DOCKER_advanced_setups.md +++ b/doc/DOCKER_advanced_setups.md @@ -11,7 +11,7 @@ A word of caution, though, the default values of these options try to maximize y - [Local Electrum server used as data source for imports/rescans](#local_electrum) - [Local Whirlpool client](#local_whirlpool) - [External Bitcoin full node](#external_bitcoind) -- [bitcoind RPC API ans ZMQ notifications exposed to external apps](#exposed_rpc_zmq) +- [bitcoind RPC API and ZMQ notifications exposed to external apps](#exposed_rpc_zmq) - [Static onion address for bitcoind hidden service](#static_onion) - [Configure Tor Bridges](#tor_bridges) - [Support of testnet](#testnet) @@ -282,7 +282,7 @@ Follow these steps if you want to speed up this operation by preloading an archi -## bitcoind RPC API ans ZMQ notifications exposed to external apps ## +## bitcoind RPC API and ZMQ notifications exposed to external apps ## By default, access to the RPC API of your bitcoind is restricted to Docker containers hosted on the "dojonet" network. diff --git a/doc/GET_txs.md b/doc/GET_txs.md index 8d1337b..adeabee 100644 --- a/doc/GET_txs.md +++ b/doc/GET_txs.md @@ -12,6 +12,7 @@ GET /txs?active=... * **active** - `string` - A pipe-separated list of extended public keys and/or loose addresses and/or pubkeys (`xpub1|address1|address2|pubkey1|...`) * **page** - `integer` - Index of the requested page (first page is index 0) * **count** - `integer` - Number of transactions returned per page +* **excludeNullXfer** - `boolean` - Boolean flag indicating if transactions that don't change the balance should be excluded from the result (default = false) * **at** - `string` (optional) - Access Token (json web token). Required if authentication is activated. Alternatively, the access token can be passed through the `Authorization` HTTP header (with the `Bearer` scheme). ### Examples diff --git a/docker/my-dojo/.env b/docker/my-dojo/.env index cd27eb6..e4dabae 100644 --- a/docker/my-dojo/.env +++ b/docker/my-dojo/.env @@ -10,15 +10,34 @@ COMPOSE_CONVERT_WINDOWS_PATHS=1 -DOJO_VERSION_TAG=1.9.0 -DOJO_DB_VERSION_TAG=1.2.0 -DOJO_BITCOIND_VERSION_TAG=1.11.0 -DOJO_NODEJS_VERSION_TAG=1.9.0 -DOJO_NGINX_VERSION_TAG=1.5.0 -DOJO_TOR_VERSION_TAG=1.7.0 -DOJO_EXPLORER_VERSION_TAG=1.4.0 -DOJO_INDEXER_VERSION_TAG=1.2.0 -DOJO_WHIRLPOOL_VERSION_TAG=1.3.0 +DOJO_VERSION_TAG=1.10.0 +DOJO_DB_VERSION_TAG=1.3.0 +DOJO_BITCOIND_VERSION_TAG=1.12.0 +DOJO_NODEJS_VERSION_TAG=1.10.0 +DOJO_NGINX_VERSION_TAG=1.6.0 +DOJO_TOR_VERSION_TAG=1.9.0 +DOJO_EXPLORER_VERSION_TAG=1.7.0 +DOJO_INDEXER_VERSION_TAG=1.3.0 +DOJO_WHIRLPOOL_VERSION_TAG=1.4.0 + + +######################################### +# NETWORKING +######################################### + +NET_DOJO_MYSQL_IPV4=172.28.1.1 +NET_DOJO_NODE_IPV4=172.28.1.2 +NET_DOJO_NGINX_IPV4=172.28.1.3 +NET_DOJO_TOR_IPV4=172.28.1.4 +NET_DOJO_BITCOIND_IPV4=172.28.1.5 +NET_DOJO_INDEXER_IPV4=172.28.1.6 +NET_DOJO_EXPLORER_IPV4=172.28.1.7 + +NET_DMZ_NGINX_IPV4=172.29.1.3 +NET_DMZ_TOR_IPV4=172.29.1.4 + +NET_WHIRL_NGINX_IPV4=172.30.1.3 +NET_WHIRL_WHIRLPOOL_IPV4=172.30.1.8 ######################################### @@ -32,6 +51,9 @@ MYSQL_DATABASE=samourai-main # BITCOIND ######################################### +BITCOIND_LINUX_UID=1105 +BITCOIND_LINUX_GID=1108 + BITCOIND_DNSSEED=0 BITCOIND_DNS=0 @@ -67,3 +89,35 @@ NODE_TRACKER_UNCONF_TXS_PERIOD=300000 ######################################### INDEXER_BATCH_SIZE=10 + + +######################################### +# TOR +######################################### + +TOR_LINUX_UID=1104 +TOR_LINUX_GID=1107 + + +######################################### +# WHIRLPOOL +######################################### + +WHIRLPOOL_LINUX_UID=1110 +WHIRLPOOL_LINUX_GID=1113 + + +######################################### +# INDEXER +######################################### + +INDEXER_LINUX_UID=1106 +INDEXER_LINUX_GID=1109 + + +######################################### +# SOROBAN +######################################### + +SOROBAN_LINUX_UID=1111 +SOROBAN_LINUX_GID=1114 diff --git a/docker/my-dojo/bitcoin/Dockerfile b/docker/my-dojo/bitcoin/Dockerfile index 160ea50..6c6a991 100644 --- a/docker/my-dojo/bitcoin/Dockerfile +++ b/docker/my-dojo/bitcoin/Dockerfile @@ -1,17 +1,22 @@ -FROM debian:buster +FROM debian:buster-slim ################################################################# # INSTALL BITCOIN ################################################################# ENV BITCOIN_HOME /home/bitcoin -ENV BITCOIN_VERSION 0.21.0 -ENV BITCOIN_URL https://bitcoincore.org/bin/bitcoin-core-0.21.0/bitcoin-0.21.0-x86_64-linux-gnu.tar.gz -ENV BITCOIN_SHA256 da7766775e3f9c98d7a9145429f2be8297c2672fe5b118fd3dc2411fb48e0032 +ENV BITCOIN_VERSION 0.21.1 +ENV BITCOIN_URL https://bitcoincore.org/bin/bitcoin-core-0.21.1/bitcoin-0.21.1-x86_64-linux-gnu.tar.gz +ENV BITCOIN_SHA256 366eb44a7a0aa5bd342deea215ec19a184a11f2ca22220304ebb20b9c8917e2b ENV BITCOIN_ASC_URL https://bitcoincore.org/bin/bitcoin-core-0.21.0/SHA256SUMS.asc ENV BITCOIN_PGP_KS_URI hkp://keyserver.ubuntu.com:80 ENV BITCOIN_PGP_KEY 01EA5486DE18A882D4C2684590C8019E36C2E964 +ARG BITCOIND_LINUX_UID +ARG BITCOIND_LINUX_GID +ARG TOR_LINUX_GID + + RUN set -ex && \ apt-get update && \ apt-get install -qq --no-install-recommends ca-certificates dirmngr gosu gpg gpg-agent wget && \ @@ -30,9 +35,9 @@ RUN set -ex && \ # Create groups bitcoin & tor # Create user bitcoin and add it to groups -RUN addgroup --system -gid 1108 bitcoin && \ - addgroup --system -gid 1107 tor && \ - adduser --system --ingroup bitcoin -uid 1105 bitcoin && \ +RUN addgroup --system -gid ${BITCOIND_LINUX_GID} bitcoin && \ + addgroup --system -gid ${TOR_LINUX_GID} tor && \ + adduser --system --ingroup bitcoin -uid ${BITCOIND_LINUX_UID} bitcoin && \ usermod -a -G tor bitcoin # Create data directory @@ -53,4 +58,4 @@ RUN chown bitcoin:bitcoin /wait-for-it.sh && \ EXPOSE 8333 9501 9502 28256 -USER bitcoin \ No newline at end of file +USER bitcoin diff --git a/docker/my-dojo/bitcoin/restart.sh b/docker/my-dojo/bitcoin/restart.sh index db14dd3..df3e9c1 100644 --- a/docker/my-dojo/bitcoin/restart.sh +++ b/docker/my-dojo/bitcoin/restart.sh @@ -15,9 +15,9 @@ bitcoind_options=( -mempoolexpiry=$BITCOIND_MEMPOOL_EXPIRY -minrelaytxfee=$BITCOIND_MIN_RELAY_TX_FEE -port=8333 - -proxy=172.28.1.4:9050 + -proxy=$NET_DOJO_TOR_IPV4:9050 -rpcallowip=0.0.0.0/0 - -rpcbind=172.28.1.5 + -rpcbind=$NET_DOJO_BITCOIND_IPV4 -rpcpassword=$BITCOIND_RPC_PASSWORD -rpcport=28256 -rpcthreads=$BITCOIND_RPC_THREADS @@ -31,7 +31,7 @@ bitcoind_options=( if [ "$BITCOIND_LISTEN_MODE" == "on" ]; then bitcoind_options+=(-listen=1) - bitcoind_options+=(-bind=172.28.1.5) + bitcoind_options+=(-bind="$NET_DOJO_BITCOIND_IPV4") bitcoind_options+=(-externalip=$(cat /var/lib/tor/hsv2bitcoind/hostname)) bitcoind_options+=(-externalip=$(cat /var/lib/tor/hsv3bitcoind/hostname)) fi diff --git a/docker/my-dojo/conf/docker-mysql.conf.tpl b/docker/my-dojo/conf/docker-mysql.conf.tpl index 8d84d95..cee4ffa 100644 --- a/docker/my-dojo/conf/docker-mysql.conf.tpl +++ b/docker/my-dojo/conf/docker-mysql.conf.tpl @@ -15,4 +15,10 @@ MYSQL_USER=samourai # Password of of user account # Warning: This option must not be modified after the first installation # Type: alphanumeric -MYSQL_PASSWORD=password \ No newline at end of file +MYSQL_PASSWORD=password + +# MySQL configuration profile +# default = default configuration parameters +# low_mem = configuration minimizing the RAM consumed by the database +# Values: default | low_mem +MYSQL_CONF_PROFILE=default \ No newline at end of file diff --git a/docker/my-dojo/docker-compose.yaml b/docker/my-dojo/docker-compose.yaml index 197ce65..5b2cda9 100644 --- a/docker/my-dojo/docker-compose.yaml +++ b/docker/my-dojo/docker-compose.yaml @@ -22,7 +22,7 @@ services: max-file: "10" networks: dojonet: - ipv4_address: 172.28.1.1 + ipv4_address: ${NET_DOJO_MYSQL_IPV4} node: image: "samouraiwallet/dojo-nodejs:${DOJO_NODEJS_VERSION_TAG}" @@ -30,6 +30,8 @@ services: build: context: ./../.. dockerfile: ./docker/my-dojo/node/Dockerfile + args: + TOR_LINUX_GID: ${TOR_LINUX_GID} env_file: - ./.env - ./conf/docker-common.conf @@ -55,7 +57,7 @@ services: - db networks: dojonet: - ipv4_address: 172.28.1.2 + ipv4_address: ${NET_DOJO_NODE_IPV4} nginx: image: "samouraiwallet/dojo-nginx:${DOJO_NGINX_VERSION_TAG}" @@ -79,17 +81,20 @@ services: - node networks: whirlnet: - ipv4_address: 172.30.1.3 + ipv4_address: ${NET_WHIRL_NGINX_IPV4} dmznet: - ipv4_address: 172.29.1.3 + ipv4_address: ${NET_DMZ_NGINX_IPV4} dojonet: - ipv4_address: 172.28.1.3 + ipv4_address: ${NET_DOJO_NGINX_IPV4} tor: image: "samouraiwallet/dojo-tor:${DOJO_TOR_VERSION_TAG}" container_name: tor build: context: ./tor + args: + TOR_LINUX_UID: ${TOR_LINUX_UID} + TOR_LINUX_GID: ${TOR_LINUX_GID} env_file: - ./.env - ./conf/docker-bitcoind.conf @@ -107,9 +112,9 @@ services: max-file: "10" networks: dmznet: - ipv4_address: 172.29.1.4 + ipv4_address: ${NET_DMZ_TOR_IPV4} dojonet: - ipv4_address: 172.28.1.4 + ipv4_address: ${NET_DOJO_TOR_IPV4} networks: dojonet: diff --git a/docker/my-dojo/explorer/Dockerfile b/docker/my-dojo/explorer/Dockerfile index c41c689..ba351e9 100644 --- a/docker/my-dojo/explorer/Dockerfile +++ b/docker/my-dojo/explorer/Dockerfile @@ -1,14 +1,15 @@ -FROM node:12-buster +FROM node:12-alpine + +ENV NODE_ENV production ENV APP_DIR /home/node/app ENV EXPLORER_URL https://github.com/janoside/btc-rpc-explorer/archive -ENV EXPLORER_VERSION 2.1.0 +ENV EXPLORER_VERSION 3.1.1 # Install netcat RUN set -ex && \ - apt-get update && \ - apt-get install -y netcat + apk --no-cache add bash gcc g++ make python3 git netcat-openbsd # Download the source code and install it RUN set -ex && \ @@ -29,4 +30,4 @@ RUN chown node:node "$APP_DIR/restart.sh" && \ EXPOSE 3002 -USER node \ No newline at end of file +USER node diff --git a/docker/my-dojo/explorer/restart.sh b/docker/my-dojo/explorer/restart.sh index 9d3722c..a1a7ae0 100644 --- a/docker/my-dojo/explorer/restart.sh +++ b/docker/my-dojo/explorer/restart.sh @@ -4,7 +4,7 @@ cd /home/node/app explorer_options=( --port 3002 - --host 172.28.1.7 + --host "$NET_DOJO_EXPLORER_IPV4" --basic-auth-password "$EXPLORER_KEY" --coin BTC --bitcoind-host "$BITCOIND_IP" diff --git a/docker/my-dojo/indexer/Dockerfile b/docker/my-dojo/indexer/Dockerfile index ea3b26a..5e6f81a 100644 --- a/docker/my-dojo/indexer/Dockerfile +++ b/docker/my-dojo/indexer/Dockerfile @@ -1,16 +1,19 @@ FROM rust:1.42.0-slim-buster ENV INDEXER_HOME /home/indexer -ENV INDEXER_VERSION 0.4.0 +ENV INDEXER_VERSION 0.5.0 ENV INDEXER_URL https://code.samourai.io/dojo/addrindexrs.git +ARG INDEXER_LINUX_GID +ARG INDEXER_LINUX_UID + RUN apt-get update && \ apt-get install -y clang cmake git && \ apt-get install -y libsnappy-dev # Create group and user indexer -RUN addgroup --system -gid 1109 indexer && \ - adduser --system --ingroup indexer -uid 1106 indexer +RUN addgroup --system -gid ${INDEXER_LINUX_GID} indexer && \ + adduser --system --ingroup indexer -uid ${INDEXER_LINUX_UID} indexer # Create data directory RUN mkdir "$INDEXER_HOME/addrindexrs" && \ @@ -39,5 +42,6 @@ RUN cd "$INDEXER_HOME/addrindexrs" && \ cargo install --locked --path . EXPOSE 50001 +EXPOSE 8080 STOPSIGNAL SIGINT diff --git a/docker/my-dojo/indexer/restart.sh b/docker/my-dojo/indexer/restart.sh index 0db33b1..b42770e 100644 --- a/docker/my-dojo/indexer/restart.sh +++ b/docker/my-dojo/indexer/restart.sh @@ -6,7 +6,8 @@ indexer_options=( --index-batch-size="$INDEXER_BATCH_SIZE" --jsonrpc-import --db-dir="/home/indexer/db" - --indexer-rpc-addr="172.28.1.6:50001" + --indexer-rpc-addr="$NET_DOJO_INDEXER_IPV4:50001" + --indexer-http-addr="$NET_DOJO_INDEXER_IPV4:8080" --daemon-rpc-addr="$BITCOIND_IP:$BITCOIND_RPC_PORT" --cookie="$BITCOIND_RPC_USER:$BITCOIND_RPC_PASSWORD" --txid-limit="$INDEXER_TXID_LIMIT" diff --git a/docker/my-dojo/install/install-scripts.sh b/docker/my-dojo/install/install-scripts.sh index c079d96..9bcb590 100755 --- a/docker/my-dojo/install/install-scripts.sh +++ b/docker/my-dojo/install/install-scripts.sh @@ -6,6 +6,12 @@ else source ./conf/docker-bitcoind.conf.tpl fi +if [ -f ./conf/docker-mysql.conf ]; then + source ./conf/docker-mysql.conf +else + source ./conf/docker-mysql.conf.tpl +fi + if [ -f ./conf/docker-explorer.conf ]; then source ./conf/docker-explorer.conf else @@ -66,10 +72,10 @@ init_config_files() { cp ./conf/docker-bitcoind.conf.tpl ./conf/docker-bitcoind.conf echo "Initialized docker-bitcoind.conf" - + cp ./conf/docker-mysql.conf.tpl ./conf/docker-mysql.conf echo "Initialized docker-mysql.conf" - + cp ./conf/docker-node.conf.tpl ./conf/docker-node.conf echo "Initialized docker-node.conf" @@ -99,7 +105,7 @@ init_config_files() { fi echo "Initialized dojo-whirlpool.conf (nginx)" - # Initialize config files for nginx and the maintenance tool + # Initialize config files for nginx and the maintenance tool if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then cp ./nginx/testnet.conf ./nginx/dojo.conf echo "Initialized dojo.conf (nginx)" @@ -111,4 +117,12 @@ init_config_files() { cp ../../static/admin/conf/index-mainnet.js ../../static/admin/conf/index.js echo "Initialized index.js (admin module)" fi + + # Initialize config files for mysql + if [ "$MYSQL_CONF_PROFILE" == "low_mem" ]; then + cp ./mysql/mysql-low_mem.cnf ./mysql/mysql-dojo.cnf + else + cp ./mysql/mysql-default.cnf ./mysql/mysql-dojo.cnf + fi + echo "Initialized mysql-dojo.cnf (mysql)" } diff --git a/docker/my-dojo/install/upgrade-scripts.sh b/docker/my-dojo/install/upgrade-scripts.sh index 9669cd1..b4a370a 100755 --- a/docker/my-dojo/install/upgrade-scripts.sh +++ b/docker/my-dojo/install/upgrade-scripts.sh @@ -6,6 +6,12 @@ else source ./conf/docker-common.conf.tpl fi +if [ -f ./conf/docker-mysql.conf ]; then + source ./conf/docker-mysql.conf +else + source ./conf/docker-mysql.conf.tpl +fi + if [ -f ./conf/docker-explorer.conf ]; then source ./conf/docker-explorer.conf else @@ -95,6 +101,14 @@ update_config_files() { cp ../../static/admin/conf/index-mainnet.js ../../static/admin/conf/index.js echo "Initialized index.js (admin module)" fi + + # Initialize config files for mysql + if [ "$MYSQL_CONF_PROFILE" == "low_mem" ]; then + cp ./mysql/mysql-low_mem.cnf ./mysql/mysql-dojo.cnf + else + cp ./mysql/mysql-default.cnf ./mysql/mysql-dojo.cnf + fi + echo "Initialized mysql-dojo.cnf (mysql)" } # Update a configuration file from template diff --git a/docker/my-dojo/mysql/mysql-default.cnf b/docker/my-dojo/mysql/mysql-default.cnf new file mode 100644 index 0000000..b9a1f1a --- /dev/null +++ b/docker/my-dojo/mysql/mysql-default.cnf @@ -0,0 +1,3 @@ +[mysqld] +sql_mode="NO_ENGINE_SUBSTITUTION" +transaction_isolation=READ-COMMITTED \ No newline at end of file diff --git a/docker/my-dojo/mysql/mysql-dojo.cnf b/docker/my-dojo/mysql/mysql-dojo.cnf deleted file mode 100644 index 1b697f5..0000000 --- a/docker/my-dojo/mysql/mysql-dojo.cnf +++ /dev/null @@ -1,2 +0,0 @@ -[mysqld] -sql_mode="NO_ENGINE_SUBSTITUTION" \ No newline at end of file diff --git a/docker/my-dojo/mysql/mysql-low_mem.cnf b/docker/my-dojo/mysql/mysql-low_mem.cnf new file mode 100644 index 0000000..9e47b12 --- /dev/null +++ b/docker/my-dojo/mysql/mysql-low_mem.cnf @@ -0,0 +1,11 @@ +[mysqld] +sql_mode="NO_ENGINE_SUBSTITUTION" +transaction_isolation=READ-COMMITTED +performance_schema=off +innodb_buffer_pool_size=128M +innodb_buffer_pool_chunk_size=16M +key_buffer_size=8M +tmp_table_size=1M +max_connections=80 +sort_buffer_size=1M +query_cache_size=8M \ No newline at end of file diff --git a/docker/my-dojo/node/Dockerfile b/docker/my-dojo/node/Dockerfile index db03868..47527c0 100644 --- a/docker/my-dojo/node/Dockerfile +++ b/docker/my-dojo/node/Dockerfile @@ -1,9 +1,15 @@ -FROM node:12-buster +FROM node:12-alpine -ENV APP_DIR /home/node/app +ENV NODE_ENV production + +ENV APP_DIR /home/node/app +ARG TOR_LINUX_GID + +RUN set -ex && \ + apk --no-cache add shadow bash gcc g++ make python3 # Add node user to tor group -RUN addgroup --system -gid 1107 tor && \ +RUN addgroup -S -g ${TOR_LINUX_GID} tor && \ usermod -a -G tor node # Install forever @@ -11,7 +17,7 @@ RUN npm install -g forever # Create app directory RUN mkdir "$APP_DIR" && \ - chown -R node:node "$APP_DIR" + chown -R node:node "$APP_DIR" # Copy app source files into APP_DIR COPY . "$APP_DIR" @@ -38,4 +44,4 @@ RUN chown node:node "$APP_DIR/wait-for-it.sh" && \ chmod u+x "$APP_DIR/wait-for-it.sh" && \ chmod g+x "$APP_DIR/wait-for-it.sh" -USER node \ No newline at end of file +USER node diff --git a/docker/my-dojo/node/keys.index.js b/docker/my-dojo/node/keys.index.js index e37a1f3..2131529 100644 --- a/docker/my-dojo/node/keys.index.js +++ b/docker/my-dojo/node/keys.index.js @@ -66,7 +66,7 @@ module.exports = { // Password pass: process.env.MYSQL_PASSWORD, // IP address - host: 'db', + host: process.env.NET_DOJO_MYSQL_IPV4, // TCP port port: 3306, // Db name @@ -190,7 +190,7 @@ module.exports = { }, // Use a SOCKS5 proxy for all communications with external services // Values: null if no socks5 proxy used, otherwise the url of the socks5 proxy - socks5Proxy: 'socks5h://172.28.1.4:9050', + socks5Proxy: `socks5h://${process.env.NET_DOJO_TOR_IPV4}:9050`, // OXT (mainnet) oxt: process.env.NODE_URL_OXT_API, // Esplora (testnet) @@ -223,10 +223,10 @@ module.exports = { minNbChildren: parseInt(process.env.NODE_ADDR_DERIVATION_MIN_CHILD), // Max number of child processes allowed maxNbChildren: parseInt(process.env.NODE_ADDR_DERIVATION_MAX_CHILD), - // Max duration + // Max duration acquireTimeoutMillis: 60000, // Parallel derivation threshold - // (use parallel derivation if number of addresses to be derived + // (use parallel derivation if number of addresses to be derived // is greater than thresholdParalleDerivation) thresholdParallelDerivation: parseInt(process.env.NODE_ADDR_DERIVATION_THRESHOLD), }, diff --git a/docker/my-dojo/node/restart.sh b/docker/my-dojo/node/restart.sh index 1c56a86..0442a1b 100644 --- a/docker/my-dojo/node/restart.sh +++ b/docker/my-dojo/node/restart.sh @@ -1,14 +1,14 @@ #!/bin/bash cd /home/node/app/accounts -forever start -a -l /dev/stdout -o /dev/null -e /dev/null index.js "$COMMON_BTC_NETWORK" +forever start -a -l /dev/stdout -o /dev/null -e /dev/null index.js cd /home/node/app/pushtx -forever start -a -l /dev/stdout -o /dev/null -e /dev/null index.js "$COMMON_BTC_NETWORK" -forever start -a -l /dev/stdout -o /dev/null -e /dev/null index-orchestrator.js "$COMMON_BTC_NETWORK" +forever start -a -l /dev/stdout -o /dev/null -e /dev/null index.js +forever start -a -l /dev/stdout -o /dev/null -e /dev/null index-orchestrator.js cd /home/node/app/tracker -forever start -a -l /dev/stdout -o /dev/null -e /dev/null index.js "$COMMON_BTC_NETWORK" +forever start -a -l /dev/stdout -o /dev/null -e /dev/null index.js # Keep the container up while true diff --git a/docker/my-dojo/node/wait-for-it.sh b/docker/my-dojo/node/wait-for-it.sh index 071c2be..d3a7092 100644 --- a/docker/my-dojo/node/wait-for-it.sh +++ b/docker/my-dojo/node/wait-for-it.sh @@ -146,7 +146,11 @@ WAITFORIT_TIMEOUT_PATH=$(type -p timeout) WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then WAITFORIT_ISBUSY=1 - WAITFORIT_BUSYTIMEFLAG="-t" + # Check if busybox timeout uses -t flag + # (recent Alpine versions don't support -t anymore) + if timeout &>/dev/stdout | grep -q -e '-t '; then + WAITFORIT_BUSYTIMEFLAG="-t" + fi else WAITFORIT_ISBUSY=0 diff --git a/docker/my-dojo/overrides/bitcoind.install.yaml b/docker/my-dojo/overrides/bitcoind.install.yaml index ab36e59..a0c9654 100644 --- a/docker/my-dojo/overrides/bitcoind.install.yaml +++ b/docker/my-dojo/overrides/bitcoind.install.yaml @@ -6,6 +6,10 @@ services: container_name: bitcoind build: context: ./bitcoin + args: + BITCOIND_LINUX_UID: ${BITCOIND_LINUX_UID} + BITCOIND_LINUX_GID: ${BITCOIND_LINUX_GID} + TOR_LINUX_GID: ${TOR_LINUX_GID} env_file: - ./.env - ./conf/docker-common.conf @@ -30,7 +34,7 @@ services: - tor networks: dojonet: - ipv4_address: 172.28.1.5 + ipv4_address: ${NET_DOJO_BITCOIND_IPV4} node: depends_on: diff --git a/docker/my-dojo/overrides/explorer.install.yaml b/docker/my-dojo/overrides/explorer.install.yaml index 079d18c..48a4e39 100644 --- a/docker/my-dojo/overrides/explorer.install.yaml +++ b/docker/my-dojo/overrides/explorer.install.yaml @@ -23,7 +23,7 @@ services: max-file: "10" networks: dojonet: - ipv4_address: 172.28.1.7 + ipv4_address: ${NET_DOJO_EXPLORER_IPV4} node: depends_on: diff --git a/docker/my-dojo/overrides/indexer.install.yaml b/docker/my-dojo/overrides/indexer.install.yaml index 462541f..e2f9a16 100644 --- a/docker/my-dojo/overrides/indexer.install.yaml +++ b/docker/my-dojo/overrides/indexer.install.yaml @@ -6,6 +6,9 @@ services: container_name: indexer build: context: ./indexer + args: + INDEXER_LINUX_UID: ${INDEXER_LINUX_UID} + INDEXER_LINUX_GID: ${INDEXER_LINUX_GID} env_file: - ./.env - ./conf/docker-common.conf @@ -15,6 +18,7 @@ services: command: "/wait-for-it.sh tor:9050 --timeout=360 --strict -- /restart.sh" expose: - "50001" + - "8080" volumes: - data-indexer:/home/indexer logging: @@ -26,7 +30,7 @@ services: - tor networks: dojonet: - ipv4_address: 172.28.1.6 + ipv4_address: ${NET_DOJO_INDEXER_IPV4} volumes: data-indexer: diff --git a/docker/my-dojo/overrides/whirlpool.install.yaml b/docker/my-dojo/overrides/whirlpool.install.yaml index 9d788b1..ced12af 100644 --- a/docker/my-dojo/overrides/whirlpool.install.yaml +++ b/docker/my-dojo/overrides/whirlpool.install.yaml @@ -6,6 +6,9 @@ services: container_name: whirlpool build: context: ./whirlpool + args: + WHIRLPOOL_LINUX_UID: ${WHIRLPOOL_LINUX_UID} + WHIRLPOOL_LINUX_GID: ${WHIRLPOOL_LINUX_GID} env_file: - ./.env - ./conf/docker-common.conf @@ -23,7 +26,7 @@ services: max-file: "10" networks: whirlnet: - ipv4_address: 172.30.1.8 + ipv4_address: ${NET_WHIRL_WHIRLPOOL_IPV4} volumes: data-whirlpool: diff --git a/docker/my-dojo/tor/Dockerfile b/docker/my-dojo/tor/Dockerfile index f21ce2c..1b57a53 100644 --- a/docker/my-dojo/tor/Dockerfile +++ b/docker/my-dojo/tor/Dockerfile @@ -1,9 +1,9 @@ -FROM debian:buster +FROM debian:buster-slim ENV TOR_HOME /var/lib/tor ENV TOR_URL https://dist.torproject.org ENV TOR_MIRROR_URL https://tor.eff.org/dist -ENV TOR_VERSION 0.4.4.7 +ENV TOR_VERSION 0.4.5.8 ENV TOR_GPG_KS_URI hkp://keyserver.ubuntu.com:80 ENV TOR_GPG_KEY1 0xEB5A896A28988BF5 ENV TOR_GPG_KEY2 0xC218525819F78451 @@ -11,17 +11,20 @@ ENV TOR_GPG_KEY3 0x21194EBB165733EA ENV TOR_GPG_KEY4 0x6AFEE6D49E92B601 ENV GOLANG_DL_URL https://dl.google.com/go -ENV GOLANG_ARCHIVE go1.11.13.linux-amd64.tar.gz -ENV GOLANG_SHA256 50fe8e13592f8cf22304b9c4adfc11849a2c3d281b1d7e09c924ae24874c6daa +ENV GOLANG_ARCHIVE go1.16.4.linux-amd64.tar.gz +ENV GOLANG_SHA256 7154e88f5a8047aad4b80ebace58a059e36e7e2e4eb3b383127a28c711b4ff59 ENV OBFS4_URL https://github.com/Yawning/obfs4.git ENV OBFS4_VERSION 0.0.11 +ARG TOR_LINUX_UID +ARG TOR_LINUX_GID + # Install Tor RUN set -ex && \ apt-get update && \ - apt-get install -y git libevent-dev zlib1g-dev libssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils gpg wget && \ + apt-get install -y git libevent-dev zlib1g-dev libssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils gpg wget python3 && \ mkdir -p /usr/local/src/ && \ cd /usr/local/src && \ res=0; \ @@ -68,8 +71,8 @@ RUN cd /usr/local/src && \ rm -rf obfs4proxy # Create group & user tor -RUN addgroup --system -gid 1107 tor && \ - adduser --system --ingroup tor -uid 1104 tor +RUN addgroup --system -gid ${TOR_LINUX_GID} tor && \ + adduser --system --ingroup tor -uid ${TOR_LINUX_UID} tor # Create /etc/tor directory RUN mkdir -p /etc/tor/ && \ diff --git a/docker/my-dojo/tor/restart.sh b/docker/my-dojo/tor/restart.sh index ef1392b..a7754b9 100644 --- a/docker/my-dojo/tor/restart.sh +++ b/docker/my-dojo/tor/restart.sh @@ -8,29 +8,29 @@ chmod 750 /var/lib/tor echo "## Start tor #############################" tor_options=( - --SocksPort 172.28.1.4:9050 + --SocksPort "$NET_DOJO_TOR_IPV4:9050" --SocksPolicy "accept 172.28.0.0/16" --SocksPolicy "reject *" --DataDirectory /var/lib/tor/.tor --DataDirectoryGroupReadable 1 --HiddenServiceDir /var/lib/tor/hsv2dojo --HiddenServiceVersion 2 - --HiddenServicePort "80 172.29.1.3:80" + --HiddenServicePort "80 $NET_DMZ_NGINX_IPV4:80" --HiddenServiceDir /var/lib/tor/hsv3dojo --HiddenServiceVersion 3 - --HiddenServicePort "80 172.29.1.3:80" + --HiddenServicePort "80 $NET_DMZ_NGINX_IPV4:80" ) if [ "$BITCOIND_INSTALL" == "on" ]; then if [ "$BITCOIND_LISTEN_MODE" == "on" ]; then tor_options+=(--HiddenServiceDir /var/lib/tor/hsv2bitcoind) tor_options+=(--HiddenServiceVersion 2) - tor_options+=(--HiddenServicePort "8333 172.28.1.5:8333") + tor_options+=(--HiddenServicePort "8333 $NET_DOJO_BITCOIND_IPV4:8333") tor_options+=(--HiddenServiceDirGroupReadable 1) tor_options+=(--HiddenServiceDir /var/lib/tor/hsv3bitcoind) tor_options+=(--HiddenServiceVersion 3) - tor_options+=(--HiddenServicePort "8333 172.28.1.5:8333") + tor_options+=(--HiddenServicePort "8333 $NET_DOJO_BITCOIND_IPV4:8333") tor_options+=(--HiddenServiceDirGroupReadable 1) fi fi @@ -38,24 +38,24 @@ fi if [ "$EXPLORER_INSTALL" == "on" ]; then tor_options+=(--HiddenServiceDir /var/lib/tor/hsv2explorer) tor_options+=(--HiddenServiceVersion 2) - tor_options+=(--HiddenServicePort "80 172.29.1.3:9080") + tor_options+=(--HiddenServicePort "80 $NET_DMZ_NGINX_IPV4:9080") tor_options+=(--HiddenServiceDirGroupReadable 1) tor_options+=(--HiddenServiceDir /var/lib/tor/hsv3explorer) tor_options+=(--HiddenServiceVersion 3) - tor_options+=(--HiddenServicePort "80 172.29.1.3:9080") + tor_options+=(--HiddenServicePort "80 $NET_DMZ_NGINX_IPV4:9080") tor_options+=(--HiddenServiceDirGroupReadable 1) fi if [ "$WHIRLPOOL_INSTALL" == "on" ]; then tor_options+=(--HiddenServiceDir /var/lib/tor/hsv2whirlpool) tor_options+=(--HiddenServiceVersion 2) - tor_options+=(--HiddenServicePort "80 172.29.1.3:8898") + tor_options+=(--HiddenServicePort "80 $NET_DMZ_NGINX_IPV4:8898") tor_options+=(--HiddenServiceDirGroupReadable 1) tor_options+=(--HiddenServiceDir /var/lib/tor/hsv3whirlpool) tor_options+=(--HiddenServiceVersion 3) - tor_options+=(--HiddenServicePort "80 172.29.1.3:8898") + tor_options+=(--HiddenServicePort "80 $NET_DMZ_NGINX_IPV4:8898") tor_options+=(--HiddenServiceDirGroupReadable 1) fi diff --git a/docker/my-dojo/whirlpool/Dockerfile b/docker/my-dojo/whirlpool/Dockerfile index 12e6c90..658e899 100644 --- a/docker/my-dojo/whirlpool/Dockerfile +++ b/docker/my-dojo/whirlpool/Dockerfile @@ -1,18 +1,24 @@ -FROM debian:buster +FROM debian:buster-slim ENV WHIRLPOOL_HOME /home/whirlpool ENV WHIRLPOOL_DIR /usr/local/whirlpool-cli +ARG WHIRLPOOL_LINUX_UID +ARG WHIRLPOOL_LINUX_GID # Install prerequisites # Create group & user whirlpool +# Create /usr/share/man/man1 directory # Create .whirlpool-cli subdirectory of WHIRLPOOL_HOME # Create /usr/local/src/whirlpool-cli directory + +RUN mkdir -p /usr/share/man/man1 + RUN set -ex && \ apt-get update && \ apt-get install -y libevent-dev zlib1g-dev libssl-dev gcc make automake ca-certificates autoconf musl-dev coreutils gpg wget default-jdk && \ - addgroup --system -gid 1113 whirlpool && \ - adduser --system --ingroup whirlpool -uid 1110 whirlpool && \ + addgroup --system -gid ${WHIRLPOOL_LINUX_GID} whirlpool && \ + adduser --system --ingroup whirlpool -uid ${WHIRLPOOL_LINUX_UID} whirlpool && \ mkdir -p "$WHIRLPOOL_HOME/.whirlpool-cli" && \ chown -Rv whirlpool:whirlpool "$WHIRLPOOL_HOME" && \ chmod -R 750 "$WHIRLPOOL_HOME" && \ @@ -21,7 +27,7 @@ RUN set -ex && \ # Install Tor ENV WHIRLPOOL_TOR_URL https://dist.torproject.org ENV WHIRLPOOL_TOR_MIRROR_URL https://tor.eff.org/dist -ENV WHIRLPOOL_TOR_VERSION 0.4.4.7 +ENV WHIRLPOOL_TOR_VERSION 0.4.4.8 ENV WHIRLPOOL_TOR_GPG_KS_URI hkp://keyserver.ubuntu.com:80 ENV WHIRLPOOL_TOR_GPG_KEY1 0xEB5A896A28988BF5 ENV WHIRLPOOL_TOR_GPG_KEY2 0xC218525819F78451 @@ -60,10 +66,11 @@ RUN set -ex && \ # Install whirlpool-cli ENV WHIRLPOOL_URL https://code.samourai.io/whirlpool/whirlpool-client-cli/uploads -ENV WHIRLPOOL_VERSION 0.10.9 -ENV WHIRLPOOL_VERSION_HASH 602666c59f95ce72f1466f72d9c853e3 +ENV WHIRLPOOL_VERSION 0.10.11 +ENV WHIRLPOOL_VERSION_HASH 21d25ed02cceb91f4aa95b6389b9da9c ENV WHIRLPOOL_JAR "whirlpool-client-cli-$WHIRLPOOL_VERSION-run.jar" -ENV WHIRLPOOL_SHA256 9de3ceaff6e8cc0849bde58bc9e17b9c602352df8659adc67ab95b39cf046e4c +ENV WHIRLPOOL_SHA256 09e574743851db2d5374bc7d4e66fd0c29f07b95b4e32b3d70c2187b724d5745 + RUN set -ex && \ cd "$WHIRLPOOL_DIR" && \ diff --git a/docker/my-dojo/whirlpool/restart.sh b/docker/my-dojo/whirlpool/restart.sh index 406ba3e..9781e63 100644 --- a/docker/my-dojo/whirlpool/restart.sh +++ b/docker/my-dojo/whirlpool/restart.sh @@ -11,15 +11,16 @@ whirlpool_options=( --cli.torConfig.coordinator.enabled=true --cli.torConfig.backend.enabled=false --cli.torConfig.backend.onion=false - --cli.mix.liquidityClient=false + --cli.mix.liquidityClient=true + --cli.mix.clientsPerPool=1 ) if [ "$COMMON_BTC_NETWORK" == "testnet" ]; then whirlpool_options+=(--cli.server="TESTNET") - whirlpool_options+=(--cli.dojo.url="http://172.30.1.3:80/test/v2/") + whirlpool_options+=(--cli.dojo.url="http://$NET_WHIRL_NGINX_IPV4:80/test/v2/") else whirlpool_options+=(--cli.server="MAINNET") - whirlpool_options+=(--cli.dojo.url="http://172.30.1.3:80/v2/") + whirlpool_options+=(--cli.dojo.url="http://$NET_WHIRL_NGINX_IPV4:80/v2/") fi if [ "$WHIRLPOOL_COORDINATOR_ONION" == "on" ]; then diff --git a/keys/index-example.js b/keys/index-example.js index 902b4ad..5c2af21 100644 --- a/keys/index-example.js +++ b/keys/index-example.js @@ -6,6 +6,7 @@ /** * Desired structure of /keys/index.js, which is ignored in the repository. + * index.js should store only one of the 2 sets of parameters (mainnet or testnet) */ module.exports = { /* @@ -15,7 +16,7 @@ module.exports = { /* * Dojo version */ - dojoVersion: '1.9.0', + dojoVersion: '1.10.0', /* * Bitcoind */ diff --git a/lib/bitcoin/addresses-helper.js b/lib/bitcoin/addresses-helper.js index 05039dd..e5d6495 100644 --- a/lib/bitcoin/addresses-helper.js +++ b/lib/bitcoin/addresses-helper.js @@ -7,7 +7,9 @@ const bitcoin = require('bitcoinjs-lib') const btcMessage = require('bitcoinjs-message') const activeNet = require('./network').network -const { p2pkh, p2sh, p2wpkh } = bitcoin.payments +const { p2pkh, p2sh, p2wpkh, p2wsh } = bitcoin.payments +const { OPS } = bitcoin.script + /** * A singleton providing Addresses helper functions @@ -106,6 +108,86 @@ class AddressesHelper { } } + /** + * Check if an output script is a P2PKH script + * @param {Buffer} scriptpubkey - scriptpubkey + * @returns {boolean} return true if output is a P2PKH script, otherwise return false + */ + isP2pkhScript(scriptpubkey) { + return scriptpubkey.length == 25 + && scriptpubkey[0] == OPS.OP_DUP + && scriptpubkey[1] == OPS.OP_HASH160 + && scriptpubkey[2] == 0x14 + && scriptpubkey[23] == OPS.OP_EQUALVERIFY + && scriptpubkey[24] == OPS.OP_CHECKSIG + } + + /** + * Check if an output script is a P2SH script + * @param {Buffer} scriptpubkey - scriptpubkey + * @returns {boolean} return true if output is a P2SH script, otherwise return false + */ + isP2shScript(scriptpubkey) { + return scriptpubkey.length == 23 + && scriptpubkey[0] == OPS.OP_HASH160 + && scriptpubkey[1] == 0x14 + && scriptpubkey[22] == OPS.OP_EQUAL + } + + /** + * Check if an output script is a P2WPKH script + * @param {Buffer} scriptpubkey - scriptpubkey + * @returns {boolean} return true if output is a P2WPKH script, otherwise return false + */ + isP2wpkhScript(scriptpubkey) { + return scriptpubkey.length == 22 + && scriptpubkey[0] == OPS.OP_0 + && scriptpubkey[1] == 0x14 + } + + /** + * Check if an output script is a P2WSH script + * @param {Buffer} scriptpubkey - scriptpubkey + * @returns {boolean} return true if output is a P2WSH script, otherwise return false + */ + isP2wshScript(scriptpubkey) { + return scriptpubkey.length == 34 + && scriptpubkey[0] == OPS.OP_0 + && scriptpubkey[1] == 0x20 + } + + /** + * Return the bitcoin address corresponding to an output script + * @param {Buffer} scriptpubkey - scriptpubkey + * @returns {string} bitcoin address + */ + outputScript2Address(scriptpubkey) { + if (this.isP2pkhScript(scriptpubkey)) + return p2pkh({ + output: scriptpubkey, + network: activeNet, + }).address + + if (this.isP2shScript(scriptpubkey)) + return p2sh({ + output: scriptpubkey, + network: activeNet, + }).address + + if (this.isP2wpkhScript(scriptpubkey)) + return p2wpkh({ + output: scriptpubkey, + network: activeNet, + }).address + + if (this.isP2wshScript(scriptpubkey)) + return p2wsh({ + output: scriptpubkey, + network: activeNet, + }).address + + throw 'unknown address format' + } } module.exports = new AddressesHelper() diff --git a/lib/bitcoin/hd-accounts-helper.js b/lib/bitcoin/hd-accounts-helper.js index 728196a..51dfe0f 100644 --- a/lib/bitcoin/hd-accounts-helper.js +++ b/lib/bitcoin/hd-accounts-helper.js @@ -4,14 +4,13 @@ */ 'use strict' -const cp = require('child_process') const LRU = require('lru-cache') +const workerPool = require('workerpool') const bitcoin = require('bitcoinjs-lib') const bs58check = require('bs58check') const bs58 = require('bs58') const errors = require('../errors') const Logger = require('../logger') -const ForkPool = require('../fork-pool') const network = require('./network') const activeNet = network.network const keys = require('../../keys/')[network.key] @@ -64,17 +63,16 @@ class HDAccountsHelper { // Pool of child processes used for derivation of addresses const poolKeys = keys.addrDerivationPool - this.derivationPool = new ForkPool( + this.derivationPool = workerPool.pool( `${__dirname}/parallel-address-derivation.js`, { - networkKey: network.key, - max: poolKeys.maxNbChildren, - min: poolKeys.minNbChildren, - acquireTimeoutMillis: poolKeys.acquireTimeoutMillis + maxWorkers: poolKeys.maxNbChildren, + minWorkers: poolKeys.minNbChildren, + workerType: 'thread' } ) - this.externalDerivationActivated = true + Logger.info(`Created ${poolKeys.minNbChildren} worker threads for addresses derivation (max = ${poolKeys.maxNbChildren})`) } /** @@ -374,7 +372,7 @@ class HDAccountsHelper { type: info.type } - const msg = await this.derivationPool.enqueue(data) + const msg = await this.derivationPool.exec('deriveAddresses', [data]) if (msg.status = 'ok') { resolve(msg.addresses) @@ -384,7 +382,7 @@ class HDAccountsHelper { } } catch(e) { - Logger.error(e, 'HdAccountsHelper : A problem was met during parallel addresses derivation') + Logger.error(null, 'HdAccountsHelper : A problem was met during parallel addresses derivation') reject(e) } }) diff --git a/lib/bitcoin/hd-accounts-service.js b/lib/bitcoin/hd-accounts-service.js index 63c3307..4de9787 100644 --- a/lib/bitcoin/hd-accounts-service.js +++ b/lib/bitcoin/hd-accounts-service.js @@ -144,10 +144,7 @@ class HDAccountsService { const externalPrm = hdaHelper.deriveAddresses(xpub, 0, _.range(gap.external), scheme) const internalPrm = hdaHelper.deriveAddresses(xpub, 1, _.range(gap.internal), scheme) - const external = await externalPrm - const internal = await internalPrm - - const addresses = _.flatten([external, internal]) + const addresses = _.flatten(await Promise.all([externalPrm, internalPrm])) return db.addAddressesToHDAccount(xpub, addresses) } diff --git a/lib/bitcoin/network.js b/lib/bitcoin/network.js index 6ce6022..829fc9d 100644 --- a/lib/bitcoin/network.js +++ b/lib/bitcoin/network.js @@ -5,8 +5,16 @@ 'use strict' const bitcoin = require('bitcoinjs-lib') +const keys = require('../../keys/') +/** + * A set of keywords encoding for mainnet + */ +const MAINNET_KEY = [ + 'bitcoin' +] + /** * A set of keywords encoding for testnet */ @@ -26,15 +34,20 @@ class Network { * Constructor */ constructor() { - this.key = 'bitcoin' - this.network = bitcoin.networks.bitcoin - + // Check if mainnet config is detected in index.js + for (let kw of MAINNET_KEY) { + if (kw in keys) { + this.key = 'bitcoin' + this.network = bitcoin.networks.bitcoin + return + } + } + // Check if testnet config is detected in index.js for (let kw of TESTNET_KEY) { - // Calling like 'node file.js arg1 arg2' - if (process.argv.indexOf(kw) > 1) { + if (kw in keys) { this.key = 'testnet' this.network = bitcoin.networks.testnet - break + return } } } diff --git a/lib/bitcoin/parallel-address-derivation.js b/lib/bitcoin/parallel-address-derivation.js index cae5240..38e1ce3 100644 --- a/lib/bitcoin/parallel-address-derivation.js +++ b/lib/bitcoin/parallel-address-derivation.js @@ -5,6 +5,7 @@ 'use strict' const bitcoin = require('bitcoinjs-lib') +const workerPool = require('workerpool') const errors = require('../errors') const activeNet = require('./network').network const addrHelper = require('./addresses-helper') @@ -26,7 +27,7 @@ const BIP84 = 2 * @param {int} type - type of derivation * @returns {Promise - object} returns an object {address: '...', chain: , index: } */ -const deriveAddress = async function(chain, chainNode, index, type) { +async function deriveAddress(chain, chainNode, index, type) { // Derive M/chain/index const indexNode = chainNode.derive(index) @@ -51,9 +52,11 @@ const deriveAddress = async function(chain, chainNode, index, type) { } /** - * Receive message from parent process + * Derives a set of addresses for an hd account + * @param {object} msg - parameters used for the derivation + * @returns {Promise - object[]} */ -process.on('message', async (msg) => { +async function deriveAddresses(msg) { try { const xpub = msg.xpub const chain = msg.chain @@ -76,17 +79,20 @@ process.on('message', async (msg) => { const addresses = await Promise.all(promises) // Send response to parent process - process.send({ + return { status: 'ok', addresses: addresses - }) + } } catch(e) { - process.send({ + return { status: 'error', addresses: [], - error: e - }) + error: JSON.stringify(e) + } } +} +workerPool.worker({ + deriveAddresses: deriveAddresses }) diff --git a/lib/bitcoind-rpc/fees.js b/lib/bitcoind-rpc/fees.js index fb4174d..ccd7c20 100644 --- a/lib/bitcoind-rpc/fees.js +++ b/lib/bitcoind-rpc/fees.js @@ -9,7 +9,7 @@ const errors = require('../errors') const Logger = require('../logger') const network = require('../bitcoin/network') const keys = require('../../keys')[network.key] -const RpcClient = require('./rpc-client') +const { createRpcClient } = require('./rpc-client') const latestBlock = require('./latest-block') @@ -27,7 +27,7 @@ class Fees { this.fees = {} this.feeType = keys.bitcoind.feeType - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() this.refresh() } @@ -53,16 +53,15 @@ class Fees { * @returns {Promise} */ async refresh() { - await util.seriesCall(this.targets, async tgt => { + await util.parallelCall(this.targets, async tgt => { try { - const level = await this.rpcClient.cmd('estimatesmartfee', tgt, this.feeType) + const level = await this.rpcClient.estimatesmartfee({ conf_target: tgt, estimate_mode: this.feeType }) this.fees[tgt] = (level.errors && level.errors.length > 0) ? 0 : Math.round(level.feerate * 1e5) } catch(e) { Logger.error(e, 'Bitcoind RPC : Fees.refresh()') this.fees[tgt] = 0 } }) - this.block = latestBlock.height } diff --git a/lib/bitcoind-rpc/headers.js b/lib/bitcoind-rpc/headers.js index 0464aec..eb6b965 100644 --- a/lib/bitcoind-rpc/headers.js +++ b/lib/bitcoind-rpc/headers.js @@ -6,11 +6,11 @@ const LRU = require('lru-cache') const errors = require('../errors') -const RpcClient = require('./rpc-client') +const { createRpcClient } = require('./rpc-client') /** - * A singleton providing information about block headers + * A singleton providing information about block headers */ class Headers { @@ -29,7 +29,7 @@ class Headers { }) // Initialize the rpc client - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() } /** @@ -40,9 +40,9 @@ class Headers { async getHeader(hash) { if (this.headers.has(hash)) return this.headers.get(hash) - + try { - const header = await this.rpcClient.getblockheader(hash, true) + const header = await this.rpcClient.getblockheader({ blockhash: hash, verbose: true }) const fmtHeader = JSON.stringify(header, null, 2) this.headers.set(hash, fmtHeader) return fmtHeader @@ -50,7 +50,7 @@ class Headers { return Promise.reject(errors.generic.GEN) } } - + } module.exports = new Headers() diff --git a/lib/bitcoind-rpc/latest-block.js b/lib/bitcoind-rpc/latest-block.js index 4a000cd..dfe659d 100644 --- a/lib/bitcoind-rpc/latest-block.js +++ b/lib/bitcoind-rpc/latest-block.js @@ -9,7 +9,7 @@ const Logger = require('../logger') const util = require('../util') const network = require('../bitcoin/network') const keys = require('../../keys')[network.key] -const RpcClient = require('./rpc-client') +const { createRpcClient } = require('./rpc-client') /** @@ -27,8 +27,8 @@ class LatestBlock { this.diff = null // Initialize the rpc client - this.rpcClient = new RpcClient() - + this.rpcClient = createRpcClient() + // Gets the latest block from bitcoind this.rpcClient.getbestblockhash().then(hash => this.onBlockHash(hash)) @@ -54,7 +54,7 @@ class LatestBlock { * @returns {Promise} */ async onBlockHash(hash) { - const header = await this.rpcClient.getblockheader(hash) + const header = await this.rpcClient.getblockheader({ blockhash: hash }) this.height = header.height this.hash = hash diff --git a/lib/bitcoind-rpc/rpc-client.js b/lib/bitcoind-rpc/rpc-client.js index f402d8d..2393bd5 100644 --- a/lib/bitcoind-rpc/rpc-client.js +++ b/lib/bitcoind-rpc/rpc-client.js @@ -4,7 +4,7 @@ */ 'use strict' -const rpc = require('bitcoind-rpc-client') +const {RPCClient} = require('rpc-bitcoin'); const network = require('../bitcoin/network') const keys = require('../../keys')[network.key] const util = require('../util') @@ -14,77 +14,51 @@ const Logger = require('../logger') /** * Wrapper for bitcoind rpc client */ -class RpcClient { - - /** - * Constructor - */ - constructor() { - // Initiliaze the rpc client - this.client = new rpc({ - host: keys.bitcoind.rpc.host, - port: keys.bitcoind.rpc.port - }) - - this.client.set('user', keys.bitcoind.rpc.user) - this.client.set('pass', keys.bitcoind.rpc.pass) - - // Initialize a proxy postprocessing api calls - return new Proxy(this, { - get: function(target, name, receiver) { - const origMethod = target.client[name] - - return async function(...args) { - const result = await origMethod.apply(target.client, args) - - if (Array.isArray(result)) { - return result - } else if (result.result) { - return result.result - } else if (result.error) { - throw result.error - } else { - throw 'A problem was met with a request sent to bitcoind RPC API' - } - } - } +const createRpcClient = () => { + return new RPCClient({ + url: `http://${keys.bitcoind.rpc.host}`, + port: keys.bitcoind.rpc.port, + user: keys.bitcoind.rpc.user, + pass: keys.bitcoind.rpc.pass }) - } +} - /** - * Check if an error returned by bitcoin-rpc-client - * is a connection error. - * @param {string} err - error message - * @returns {boolean} returns true if message related to a connection error - */ - static isConnectionError(err) { +/** + * Check if an error returned by bitcoin-rpc-client + * is a connection error. + * @param {string} err - error message + * @returns {boolean} returns true if message related to a connection error + */ +const isConnectionError = (err) => { if (typeof err != 'string') - return false + return false - const isTimeoutError = (err.indexOf('connect ETIMEDOUT') != -1) - const isConnRejected = (err.indexOf('Connection Rejected') != -1) + const isTimeoutError = (err.indexOf('connect ETIMEDOUT') !== -1) + const isConnRejected = (err.indexOf('Connection Rejected') !== -1) return (isTimeoutError || isConnRejected) - } +} - /** - * Check if the rpc api is ready to process requests - * @returns {Promise} - */ - static async waitForBitcoindRpcApi() { - let client = new RpcClient() +/** + * Check if the rpc api is ready to process requests + * @returns {Promise} + */ +const waitForBitcoindRpcApi = async () => { + let client = createRpcClient() try { - await client.getblockchaininfo() - } catch(e) { - client = null - Logger.info('Bitcoind RPC : API is still unreachable. New attempt in 20s.') - return util.delay(20000).then(() => { - return RpcClient.waitForBitcoindRpcApi() - }) + await client.getblockchaininfo() + } catch (e) { + client = null + Logger.info('Bitcoind RPC : API is still unreachable. New attempt in 20s.') + return util.delay(20000).then(() => { + return waitForBitcoindRpcApi() + }) } - } - } -module.exports = RpcClient +module.exports = { + createRpcClient, + isConnectionError, + waitForBitcoindRpcApi +} diff --git a/lib/bitcoind-rpc/transactions.js b/lib/bitcoind-rpc/transactions.js index 1aec6ac..f55d363 100644 --- a/lib/bitcoind-rpc/transactions.js +++ b/lib/bitcoind-rpc/transactions.js @@ -9,7 +9,7 @@ const LRU = require('lru-cache') const errors = require('../errors') const Logger = require('../logger') const util = require('../util') -const RpcClient = require('./rpc-client') +const { createRpcClient } = require('./rpc-client') const rpcLatestBlock = require('./latest-block') @@ -34,7 +34,7 @@ class Transactions { // Initialize the rpc client - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() } /** @@ -47,14 +47,17 @@ class Transactions { try { const rpcCalls = txids.map(txid => { return { - 'method': 'getrawtransaction', - 'params': [txid, true] + method: 'getrawtransaction', + params: { + txid, + verbose: true + } } }) const txs = await this.rpcClient.batch(rpcCalls) - return await util.seriesCall(txs, async tx => { + return await util.parallelCall(txs, async tx => { if (tx.result == null) { Logger.info(`Bitcoind RPC : got null for ${txids[tx.id]}`) return null @@ -77,7 +80,7 @@ class Transactions { */ async getTransaction(txid, fees) { try { - const tx = await this.rpcClient.getrawtransaction(txid, true) + const tx = await this.rpcClient.getrawtransaction({ txid, verbose: true }) return this._prepareTxResult(tx, fees) } catch(e) { Logger.error(e, 'Bitcoind RPC : Transaction.getTransaction()') @@ -177,7 +180,7 @@ class Transactions { if (this.prevCache.has(inTxid)) { ptx = this.prevCache.get(inTxid) } else { - ptx = await this.rpcClient.getrawtransaction(inTxid, true) + ptx = await this.rpcClient.getrawtransaction({ txid: inTxid, verbose: true }) this.prevCache.set(inTxid, ptx) } @@ -192,7 +195,7 @@ class Transactions { n++ } }) - + return inputs } diff --git a/lib/db/mysql-db-wrapper.js b/lib/db/mysql-db-wrapper.js index 5a64063..e704e63 100644 --- a/lib/db/mysql-db-wrapper.js +++ b/lib/db/mysql-db-wrapper.js @@ -5,14 +5,12 @@ 'use strict' const mysql = require('mysql') -const path = require('path') const Logger = require('../logger') const util = require('../util') const errors = require('../errors') const hdaHelper = require('../bitcoin/hd-accounts-helper') const network = require('../bitcoin/network') const keys = require('../../keys/')[network.key] -const keysDb = keys.db const debug = !!(process.argv.indexOf('db-debug') > -1) const queryDebug = !!(process.argv.indexOf('dbquery-debug') > -1) @@ -389,8 +387,8 @@ class MySqlDbWrapper { this.pool.query(query, null, async (err, result, fields) => { if (err) { // Retry the request on lock errors - if ((err.code == 'ER_LOCK_DEADLOCK' || - err.code == 'ER_LOCK_TIMEOUT' || + if ((err.code == 'ER_LOCK_DEADLOCK' || + err.code == 'ER_LOCK_TIMEOUT' || err.code == 'ER_LOCK_WAIT_TIMEOUT') && (retries > 0) ) { try { @@ -438,7 +436,7 @@ class MySqlDbWrapper { if (result.length > 0) return result[0].addrID - + throw errors.db.ERROR_NO_ADDRESS } @@ -455,7 +453,7 @@ class MySqlDbWrapper { if (result.length > 0) return result[0].addrID - + const sqlQuery2 = 'INSERT INTO `addresses` SET ?' const params2 = { addrAddress: address } const query2 = mysql.format(sqlQuery2, params2) @@ -521,7 +519,7 @@ class MySqlDbWrapper { async getAddressBalance(address) { if (address == null) return null - + const sqlQuery = 'SELECT SUM(`outputs`.`outAmount`) as balance \ FROM `addresses` \ INNER JOIN `outputs` ON `outputs`.`addrID` = `addresses`.`addrID` \ @@ -613,7 +611,7 @@ class MySqlDbWrapper { if (result.length > 0) return result[0].hdID - throw errors.db.ERROR_NO_HD_ACCOUNT + throw errors.db.ERROR_NO_HD_ACCOUNT } /** @@ -639,14 +637,14 @@ class MySqlDbWrapper { const sqlQuery2 = 'INSERT INTO `hd` SET ?' const params2 = { - hdXpub: xpub, + hdXpub: xpub, hdCreated: util.unix(), hdType: type, } const query2 = mysql.format(sqlQuery2, params2) const result2 = await this._query(query2) return result2.insertId - + } /** @@ -737,7 +735,7 @@ class MySqlDbWrapper { async addAddressesToHDAccount(xpub, addressData) { if (addressData.length == 0) return - + const addresses = addressData.map(d => d.address) const hdID = await this.getHDAccountId(xpub) @@ -801,10 +799,10 @@ class MySqlDbWrapper { * { * hd: { * [xpub]: { - * hdID: N, - * hdType: M, + * hdID: N, + * hdType: M, * addresses:[...] - * }, + * }, * ... * } * loose:[...] @@ -1050,7 +1048,7 @@ class MySqlDbWrapper { const sqlQuery = 'SELECT COUNT(DISTINCT `r`.`txnTxid`) AS nbTxs \ FROM (' + subQuery + ') AS `r`' - + let query = mysql.format(sqlQuery) const results = await this._query(query) @@ -1122,7 +1120,7 @@ class MySqlDbWrapper { if (txsIds.length == 0) return [] - // Prepares subqueries for + // Prepares subqueries for // the query retrieving utxos of interest let subQuery2 = '' let subQueries2 = [] @@ -1323,7 +1321,7 @@ class MySqlDbWrapper { async ensureTransactionId(txid) { const sqlQuery = 'INSERT IGNORE INTO `transactions` SET ?' const params = { - txnTxid: txid, + txnTxid: txid, txnCreated: util.unix() } const query = mysql.format(sqlQuery, params) @@ -1473,7 +1471,7 @@ class MySqlDbWrapper { tx.time = Math.min(tx.time, output.blockTime) tx.time = Math.min(tx.time, output.txnCreated) - + if (output.blockHeight != null) tx.block_height = output.blockHeight @@ -1532,7 +1530,7 @@ class MySqlDbWrapper { // Remove block height if null if (tx.block_height == null) delete tx.block_height - + return tx } @@ -1665,7 +1663,7 @@ class MySqlDbWrapper { /** * Get a list of outputs identified by their txid and index. - * The presence of spendingTxnID and spendingInID not null indicate that an + * The presence of spendingTxnID and spendingInID not null indicate that an * input spending the transaction output index is already in the database and * may indicate a DOUBLE SPEND. * @param {object[]} spends - array of {txid,index} @@ -1673,10 +1671,10 @@ class MySqlDbWrapper { * {addrAddress, outID, outAmount, txnTxid, outIndex, spendingTxnID/null, spendingInID/null} */ async getOutputSpends(spends) { - if (spends.length == 0) + if (spends.length == 0) return [] - const whereClauses = + const whereClauses = spends.map(s => '(`txnTxid`=' + this.pool.escape(s.txid) + ' AND `outIndex`=' + this.pool.escape(s.index) + ')') const whereClause = whereClauses.join(' OR ') @@ -1796,10 +1794,10 @@ class MySqlDbWrapper { const params2 = block.blockHash const query2 = mysql.format(sqlQuery2, params2) const result2 = await this._query(query2) - + if (result2.length > 0) - return result2[0].blockID - + return result2[0].blockID + throw 'Problem met while trying to insert a new block' } @@ -2009,7 +2007,7 @@ class MySqlDbWrapper { INNER JOIN `transactions` ON `outputs`.`txnID` = `transactions`.`txnID` \ WHERE `hd`.`hdCreated` > `transactions`.`txnCreated` \ GROUP BY `hd`.`hdID` LIMIT 100' - + return this._query(sqlQuery) } @@ -2022,7 +2020,7 @@ class MySqlDbWrapper { INNER JOIN `blocks` ON `transactions`.`blockID` = `blocks`.`blockID` \ WHERE `transactions`.`txnCreated` > `blocks`.`blockTime` \ LIMIT 100' - + return this._query(sqlQuery) } diff --git a/lib/fork-pool.js b/lib/fork-pool.js deleted file mode 100644 index 16df8e5..0000000 --- a/lib/fork-pool.js +++ /dev/null @@ -1,85 +0,0 @@ -/*! - * lib/fork-pool.js - * Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved. - */ -'use strict' - -const os = require('os') -const childProcess = require('child_process') -const genericPool = require('generic-pool') -const Logger = require('./logger') - - -/** - * A class managing a pool of child processes - * Inspired from fork-pool by Andrew Sliwinski - * https://github.com/thisandagain/fork-pool/ - */ -class ForkPool { - - /** - * Constructor - */ - constructor(path, options) { - if (!options) { - this._networkKey = '' - this._options = { - max: os.cpus().length / 2, - min: os.cpus().length / 2, - acquireTimeoutMillis: 60000 - } - } else { - this._networkKey = options.networkKey - this._options = options - } - - const factory = { - create: () => { - return childProcess.fork(path, [this._networkKey]) - }, - destroy: (cp) => { - cp.kill() - } - } - - this.pool = genericPool.createPool(factory, this._options) - Logger.info(`Created ${this._options.min} child processes for addresses derivation (max = ${this._options.max})`) - } - - /** - * Enqueue a new task to be processed by a child process - * @param {object} data - data to be passed to the child process - * @returns {Promise} - */ - async enqueue(data) { - let cp - const pool = this.pool - - return new Promise(async (resolve, reject) => { - try { - cp = await pool.acquire() - - cp.send(data) - - cp.once('message', async msg => { - pool.release(cp) - resolve(msg) - }) - - } catch(e) { - reject(e) - } - }) - } - - /** - * Drain the pool - */ - async drain() { - await this.pool.drain() - await this.pool.clear() - } - -} - -module.exports = ForkPool diff --git a/lib/http-server/http-server.js b/lib/http-server/http-server.js index d5e1600..9dba844 100644 --- a/lib/http-server/http-server.js +++ b/lib/http-server/http-server.js @@ -4,10 +4,11 @@ */ 'use strict' -const fs = require('fs') -const express = require('express') +const { App } = require('@tinyhttp/app') +const sirv = require('sirv') const helmet = require('helmet') const Logger = require('../logger') +const errors = require('../errors'); /** @@ -28,12 +29,12 @@ class HttpServer { // Listening server instance this.server = null - // Initialize the express app - this.app = express() + // Initialize the tiny-http app + this.app = new App(); this.app.set('trust proxy', 'loopback') // Middlewares for json responses and requests logging - this.app.use('/static', express.static('../static')); + this.app.use('/static', sirv('../static')); this.app.use(HttpServer.setJSONResponse) this.app.use(HttpServer.requestLogger) this.app.use(HttpServer.setCrossOrigin) @@ -117,12 +118,18 @@ class HttpServer { /** * Return an error response * @param {object} res - http response object - * @param {object} data - data object + * @param {string | Error} data - data object + * @param {number} [errorCode=400] - HTTP status code */ static sendError(res, data, errorCode) { if (errorCode == null) errorCode = 400 + if (data instanceof Error) { + Logger.error(data, 'API: Unhandled error') + data = errors.generic.GEN + } + const ret = { status: 'error', error: data diff --git a/lib/remote-importer/bitcoind-wrapper.js b/lib/remote-importer/bitcoind-wrapper.js index c66e52d..e3667b3 100644 --- a/lib/remote-importer/bitcoind-wrapper.js +++ b/lib/remote-importer/bitcoind-wrapper.js @@ -5,9 +5,10 @@ 'use strict' const bitcoin = require('bitcoinjs-lib') -const RpcClient = require('../bitcoind-rpc/rpc-client') +const { createRpcClient } = require('../bitcoind-rpc/rpc-client') const rpcLatestBlock = require('../bitcoind-rpc/latest-block') const Logger = require('../logger') +const addrHelper = require('../bitcoin/addresses-helper') const network = require('../bitcoin/network') const activeNet = network.network const keys = require('../../keys')[network.key] @@ -24,7 +25,7 @@ class BitcoindWrapper extends Wrapper { constructor() { super(null, null) // RPC client - this.client = new RpcClient() + this.client = createRpcClient() } /** @@ -34,7 +35,7 @@ class BitcoindWrapper extends Wrapper { * @returns {Promise} */ async _get(descriptors) { - return this.client.cmd('scantxoutset', 'start', descriptors) + return await this.client.scantxoutset({ action: 'start', scanobjects: descriptors }) } /** @@ -44,7 +45,7 @@ class BitcoindWrapper extends Wrapper { */ _xlatScriptPubKey(scriptPubKey) { const bScriptPubKey = Buffer.from(scriptPubKey, 'hex') - return bitcoin.address.fromOutputScript(bScriptPubKey, activeNet) + return addrHelper.outputScript2Address(bScriptPubKey) } /** diff --git a/lib/remote-importer/local-rest-indexer-wrapper.js b/lib/remote-importer/local-rest-indexer-wrapper.js new file mode 100644 index 0000000..0ec7677 --- /dev/null +++ b/lib/remote-importer/local-rest-indexer-wrapper.js @@ -0,0 +1,157 @@ +/*! + * lib/remote-importer/local-rest-indexer-wrapper.js + * Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved. + */ +'use strict' + +const axios = require('axios') +const bitcoin = require('bitcoinjs-lib') +const Logger = require('../logger') +const util = require('../util') +const network = require('../bitcoin/network') +const activeNet = network.network +const keys = require('../../keys')[network.key] +const Wrapper = require('./wrapper') + + +/** + * Wrapper for a local indexer + * providing a REST API + */ +class LocalRestIndexerWrapper extends Wrapper { + + /** + * Constructor + */ + constructor(url) { + super(url, null) + } + + /** + * Send a GET request to the API + * @param {string} route + * @returns {Promise} + */ + async _get(route) { + const params = { + url: `${this.base}${route}`, + method: 'GET', + responseType: 'json', + timeout: 15000, + headers: { + 'User-Agent': 'Dojo' + } + } + + const result = await axios(params) + return result.data + } + + /** + * Translate a bitcoin address into a script hash + * (@see https://electrumx.readthedocs.io/en/latest/protocol-basics.html#script-hashes) + * @param {string} address - bitcoin address + * @returns {string} returns the script hash associated to the address + */ + _getScriptHash(address) { + const bScriptPubKey = bitcoin.address.toOutputScript(address, activeNet) + const bScriptHash = bitcoin.crypto.sha256(bScriptPubKey) + return bScriptHash.reverse().toString('hex') + } + + /** + * Retrieve information for a given address + * @param {string} address - bitcoin address + * @param {boolean} filterAddr - True if an upper bound should be used + * for #transactions associated to the address, False otherwise + * @returns {Promise} returns an object + * { address: , txids: , ntx: } + */ + async getAddress(address, filterAddr) { + const ret = { + address: address, + ntx: 0, + txids: [] + } + + const scriptHash = this._getScriptHash(address) + const uri = `/blockchain/scripthash/${scriptHash}/history` + const results = await this._get(uri) + + for (let r of results) { + ret.txids.push(r.tx_hash) + ret.ntx++ + } + + if (filterAddr && ret.ntx > keys.addrFilterThreshold) { + Logger.info(`Importer : Import of ${address} rejected (too many transactions - ${ret.ntx})`) + return { + address: address, + ntx: 0, + txids: [] + } + } + + return ret + } + + /** + * Retrieve information for a given list of addresses + * @param {string} addresses - array of bitcoin addresses + * @param {boolean} filterAddr - True if an upper bound should be used + * for #transactions associated to the address, False otherwise + * @returns {Promise} returns an array of objects + * { address: , txids: , ntx: } + */ + async getAddresses(addresses, filterAddr) { + const ret = {} + const scriptHash2Address = {} + const scriptHashes = [] + + for (let a of addresses) { + const scriptHash = this._getScriptHash(a) + scriptHashes.push(scriptHash) + scriptHash2Address[scriptHash] = a + } + + const sScriptHashes = scriptHashes.join(',') + const uri = `/blockchain/scripthashes/history?scripthashes=${sScriptHashes}` + const results = await this._get(uri) + + for (let r of results) { + const a = scriptHash2Address[r.script_hash] + ret[a] = { + address: a, + ntx: r.txids.length, + txids: r.txids + } + } + + const aRet = Object.values(ret) + + for (let i in aRet) { + if (filterAddr && aRet[i].ntx > keys.addrFilterThreshold) { + Logger.info(`Importer : Import of ${aRet[i].address} rejected (too many transactions - ${aRet[i].ntx})`) + aRet.splice(i, 1) + } + } + + return aRet + } + + /** + * Retrieve the height of the chaintip for the remote source + * @returns {Promise} returns an object + * {chainTipHeight: } + */ + async getChainTipHeight() { + let chainTipHeight = null + const result = await this._get(`/blocks/tip`) + if (result != null && result['height'] != null) + chainTipHeight = parseInt(result['height']) + return {'chainTipHeight': chainTipHeight} + } + +} + +module.exports = LocalRestIndexerWrapper diff --git a/lib/remote-importer/remote-importer.js b/lib/remote-importer/remote-importer.js index a46aa7e..d56b319 100644 --- a/lib/remote-importer/remote-importer.js +++ b/lib/remote-importer/remote-importer.js @@ -60,79 +60,6 @@ class RemoteImporter { return this.importing[xpub] ? this.importing[xpub] : null } - /** - * Process the relations between a list of transactions - * @param {object[]} txs - array of transaction objects - * @returns {object} returns a object with 3 mappings - * {txMap: {], txChildren: {}, txParents: {}} - */ - _processTxsRelations(txs) { - const txMap = {} - const txChildren = {} - const txParents = {} - - for (let tx of txs) { - let txid = tx.txid - - // Populate txMap - txMap[txid] = tx - - // Create parent-child transaction associations - if (!txChildren[txid]) - txChildren[txid] = [] - - if (!txParents[txid]) - txParents[txid] = [] - - for (let i in tx.inputs) { - const input = tx.inputs[i] - let prev = input.outpoint.txid - if (!txMap[prev]) continue - - if (txParents[txid].indexOf(prev) == -1) - txParents[txid].push(prev) - - if (!txChildren[prev]) - txChildren[prev] = [] - - if (txChildren[prev].indexOf(txid) == -1) - txChildren[prev].push(txid) - } - } - - return { - txMap: txMap, - txChildren: txChildren, - txParents: txParents - } - } - - /** - * Import a list of transactions associated to a list of addresses - * @param {object[]} addresses - array of addresses objects - * @param {object[]} txns - array of transaction objects - * @returns {Promise} - */ - async _importTransactions(addresses, txns) { - const addrIdMap = await db.getAddressesIds(addresses) - - // The transactions array must be topologically ordered, such that - // entries earlier in the array MUST NOT depend upon any entry later - // in the array. - const txMaps = this._processTxsRelations(txns) - const txOrdered = util.topologicalOrdering(txMaps.txParents, txMaps.txChildren) - const aTxs = [] - - for (let txid of txOrdered) - if (txMaps.txMap[txid]) - aTxs.push(txMaps.txMap[txid]) - - // Store the transactions by batches of 200 transactions - const txsChunks = util.splitList(aTxs, 200) - for (let txsChunk of txsChunks) - await this.addTransactions(txsChunk, addrIdMap) - } - /** * Import an HD account from remote sources * @param {string} xpub - HD Account @@ -161,32 +88,22 @@ class RemoteImporter { const t0 = Date.now() const chains = [0,1] - let gaps = [gap.external, gap.internal] // Allow custom higher gap limits // for local scans relying on bitcoind or on a local indexer - if (gapLimit - && ((keys.indexer.active == 'local_bitcoind') - || (keys.indexer.active == 'local_indexer')) - ) { - gaps = [gapLimit, gapLimit] - } + const isLocal = ['local_bitcoind', 'local_indexer'].includes(keys.indexer.active) + const gaps = (gapLimit && isLocal) ? [gapLimit, gapLimit] : [gap.external, gap.internal] startIndex = (startIndex == null) ? -1 : startIndex - 1 - const addrIdMap = {} - let txns = [] - let addresses = [] - try { - const results = await util.seriesCall(chains, chain => { + const results = await util.parallelCall(chains, chain => { return this.xpubScan(xpub, chain, startIndex, startIndex, gaps[chain], type) }) // Accumulate addresses and transactions from all chains - for (let result of results) { - txns = txns.concat(result.transactions) - addresses = addresses.concat(result.addresses) - } + const txns = results.map(r => r.transactions).flat() + const addresses = results.map(r => r.addresses).flat() + const aAddresses = addresses.map(a => a.address) this.importing[xpub] = { 'status': this.STATUS_IMPORT, @@ -195,10 +112,13 @@ class RemoteImporter { // Store the hdaccount and the addresses into the database await db.ensureHDAccountId(xpub, type) - await db.addAddressesToHDAccount(xpub, addresses) + + const addrChunks = util.splitList(addresses, 1000) + await util.parallelCall(addrChunks, chunk => { + return db.addAddressesToHDAccount(xpub, chunk) + }) // Store the transaction into the database - const aAddresses = addresses.map(a => a.address) await this._importTransactions(aAddresses, txns) } catch(e) { @@ -256,62 +176,39 @@ class RemoteImporter { d = u + G Logger.info(`Importer : derived M/${c}/${A.join(',')}`) - const addrMap = {} - for (let a of ret.addresses) - addrMap[a.address] = a - + const addrMap = ret.addresses.reduce((m,a) => (m[a.address] = a, m), {}) const aAddresses = ret.addresses.map(a => a.address) try { const results = await this.sources.getAddresses(aAddresses) - - let gotTransactions = false - const scanTx = [] - - for (let r of results) { - if (r.ntx == 0) continue - - // Address is used. Update used parameter - u = Math.max(u, addrMap[r.address].index) - gotTransactions = true - // TODO: Handle pathological case of many address transactions - while (r.txids.length > 0) { - let txid = r.txids.pop() - if (!txids[txid]) - scanTx.push(txid) - } - } + const filteredResults = results.flat().filter(r => r.ntx > 0) + const gotTransactions = filteredResults.length > 0 + const scanTx = filteredResults.map(r => r.txids).flat().filter(t => !txids[t]) + u = filteredResults.reduce((m,r) => Math.max(m, addrMap[r.address].index), u) Logger.info(`Importer : Got ${scanTx.length} transactions`) // Retrieve the transactions by batches of 200 transactions - const txsChunks = util.splitList(scanTx, 200) try { - for (let txsChunk of txsChunks) { - const txs = await rpcTxns.getTransactions(txsChunk, false) - for (let tx of txs) { - if (tx != null) { - ret.transactions.push(tx) - txids[tx.txid] = true - } - } - } + const txsChunks = util.splitList(scanTx, 200) + const txs = await util.seriesCall(txsChunks, chunk => { + return rpcTxns.getTransactions(chunk, false) + }) + const filteredTxs = txs.flat().filter(tx => tx != null) + ret.transactions = ret.transactions.concat(filteredTxs) + txids = filteredTxs.reduce((m,tx) => (m[tx.txid] = true, m), txids) } catch(e) { Logger.error(e, `Importer : RemoteImporter.xpubScan() : getTransactions error`) } if (gotTransactions) { - if (c == 0) - this.importing[xpub]['txs_ext'] = Object.keys(txids).length - else - this.importing[xpub]['txs_int'] = Object.keys(txids).length + const keyStatus = (c == 0) ? 'txs_ext' : 'txs_int' + this.importing[xpub][keyStatus] = Object.keys(txids).length // We must go deeper const result = await this.xpubScan(xpub, c, d, u, G, type, txids) // Accumulate results from further down the rabbit hole - for (let a of result.addresses) - ret.addresses.push(a) - for (let t of result.transactions) - ret.transactions.push(t) + ret.addresses = ret.addresses.concat(result.addresses) + ret.transactions = ret.transactions.concat(result.transactions) } } catch(e) { @@ -329,50 +226,34 @@ class RemoteImporter { */ async importAddresses(candidates, filterAddr) { const t0 = Date.now() - const txns = [] - const addresses = [] - const imported = [] - - for (let address of candidates) { - if (!this.importing[address]) { - addresses.push(address) - this.importing[address] = true - } else { - Logger.info(`Importer : Import overlap for ${address}. Skipping`) - } - } - if (addresses.length == 0) - return true + // Check if some addresses are currently processed + const overlap = candidates.filter(c => this.importing[c]) + for (let a of overlap) + Logger.info(`Importer : Import overlap for ${a}. Skipping`) + + // List addresses that need to be processed + const addresses = candidates.filter(c => !this.importing[c]) + this.importing = addresses.reduce((m,a) => (m[a] = true, m), this.importing) + + if (addresses.length == 0) return true Logger.info(`Importer : Importing ${addresses.join(',')}`) try { - const scanTx = [] const results = await this.sources.getAddresses(addresses, filterAddr) - - for (let r of results) { - // Mark the address as imported - imported.push(r.address) - if (r.ntx == 0) continue - // TODO: Handle pathological case of many address transactions - while (r.txids.length > 0) { - let txid = r.txids.pop() - if (scanTx.indexOf(txid) == -1) - scanTx.push(txid) - } - } + const imported = results.map(r => r.address) + const filteredResults = results.filter(r => r.ntx > 0) + const scanTx = [...new Set(filteredResults.map(r => r.txids).flat())] Logger.info(`Importer : Got ${scanTx.length} transactions`) // Retrieve the transactions by batches of 100 transactions const txsChunks = util.splitList(scanTx, 100) - for (let txsChunk of txsChunks) { - const txs = await rpcTxns.getTransactions(txsChunk, false) - for (let tx of txs) - if (tx != null) - txns.push(tx) - } + const txs = await util.seriesCall(txsChunks, chunk => { + return rpcTxns.getTransactions(chunk, false) + }) + const txns = txs.flat().filter(tx => tx != null) // Import addresses and transactions into the database await db.addAddresses(imported) @@ -387,7 +268,7 @@ class RemoteImporter { const N = addresses.length if (N > 0) - Logger.info(`Importer : Imported ${N} addresses in ${ts}s (${(dt/N).toFixed(0)} ms/addr)`) + Logger.info(`Importer : Imported ${N} addresses in ${ts}s (${(dt/N).toFixed(0)} ms/addr)`) for (let address of addresses) delete this.importing[address] @@ -396,84 +277,116 @@ class RemoteImporter { } } + /** + * Import a list of transactions associated to a list of addresses + * @param {object[]} addresses - array of addresses objects + * @param {object[]} txs - array of transaction objects + * @returns {Promise} + */ + async _importTransactions(addresses, txs) { + const addrChunks = util.splitList(addresses, 1000) + const addrIdMaps = await util.parallelCall(addrChunks, chunk => { + return db.getAddressesIds(chunk) + }) + const addrIdMap = Object.assign({}, ...addrIdMaps) + + // Process the transactions by batches of 200 transactions + const txsChunks = util.splitList(txs, 200) + await util.parallelCall(txsChunks, chunk => { + return this._addTransactions(chunk) + }) + await util.parallelCall(txsChunks, chunk => { + return this._addOutputs(chunk, addrIdMap) + }) + await util.parallelCall(txsChunks, chunk => { + return this._addInputs(chunk) + }) + } + /** * Add a collection of transactions to the database. * @param {object[]} txs - array of transaction objects - * @params {object} addrIdMap - map address => addrId * @returns {Promise} */ - async addTransactions(txs, addrIdMap) { + async _addTransactions(txs) { try { // Store the transactions into the database await db.addTransactions(txs) // Confirm the transactions if needed - const blocksHashes = new Set() - for (let tx of txs) - if (tx.block) - blocksHashes.add(tx.block.hash) + const blocksHashes = txs.filter(tx => tx.block).map(tx => tx.block.hash) + const blocks = await db.getBlocksByHashes(blocksHashes) - const blocks = await db.getBlocksByHashes(Array.from(blocksHashes)) - - for (let block of blocks) { - // Filter the transactions by blockHash + return util.parallelCall(blocks, block => { const filteredTxs = txs.filter(tx => (tx.block && tx.block.hash == block.blockHash)) - if (filteredTxs.length > 0) { - const txids = filteredTxs.map(tx => tx.txid) - // Asynchronous confirmations - db.confirmTransactions(txids, block.blockID) - } - } + if (filteredTxs.length == 0) return + const txids = filteredTxs.map(tx => tx.txid) + return db.confirmTransactions(txids, block.blockID) + }) + } catch(e) { + Logger.error(e, `Importer : RemoteImporter.addTransactions() :`) + } + } - // Retrieve the database ids for the transactions + /** + * Add a collection of transaction outputs to the database. + * @param {object[]} txs - array of transaction objects + * @params {object} addrIdMap - map address => addrId + * @returns {Promise} + */ + async _addOutputs(txs, addrIdMap) { + try { const txids = txs.map(tx => tx.txid) const mapTxsIds = await db.getTransactionsIds(txids) - // Store the outputs in db - const outputs = [] - for (let tx of txs) { - for (let output of tx.outputs) { - if (addrIdMap[output.address]) { - outputs.push({ - txnID: mapTxsIds[tx.txid], - addrID: addrIdMap[output.address], - outIndex: output.n, - outAmount: output.value, - outScript: output.scriptpubkey, - }) - } - } - } - await db.addOutputs(outputs) + const outputs = txs + .map(tx => tx.outputs.map(o => (o.txnID = mapTxsIds[tx.txid], o))) + .flat() + .filter(o => addrIdMap[o.address]) + .map(o => { return { + txnID: o.txnID, + addrID: addrIdMap[o.address], + outIndex: o.n, + outAmount: o.value, + outScript: o.scriptpubkey, + }}) + + return db.addOutputs(outputs) + + } catch(e) { + Logger.error(e, `Importer : RemoteImporter._addOutputs() :`) + } + } - // Store the inputs in db - const inputs = [] - const spent = {} + /** + * Add a collection of transaction inputs to the database. + * @param {object[]} txs - array of transaction objects + * @returns {Promise} + */ + async _addInputs(txs) { + try { + // Retrieve the database ids for the transactions + const txids = txs.map(tx => tx.txid) + const mapTxsIds = await db.getTransactionsIds(txids) // Get any outputs spent by the inputs of this transaction, // add those database outIDs to the corresponding inputs, and store. - let outpoints = [] - for (let tx of txs) - outpoints = outpoints.concat(tx.inputs.map(input => input.outpoint)) - + const outpoints = txs.map(tx => tx.inputs).flat().map(input => input.outpoint) const res = await db.getOutputIds(outpoints) - for (let r of res) - spent[`${r.txnTxid}-${r.outIndex}`] = r.outID - - for (let tx of txs) { - for (let input of tx.inputs) { - const key = `${input.outpoint.txid}-${input.outpoint.vout}` - if (spent[key]) { - inputs.push({ - outID: spent[key], - txnID: mapTxsIds[tx.txid], - inIndex: input.n, - inSequence: input.seq - }) - } - } - } - await db.addInputs(inputs) + const spent = res.reduce((m,r) => (m[`${r.txnTxid}-${r.outIndex}`] = r.outID, m), {}) + + const inputs = txs + .map(tx => tx.inputs.map(i => (i.txnID = mapTxsIds[tx.txid], i))) + .flat() + .filter(i => spent[`${i.outpoint.txid}-${i.outpoint.vout}`]) + .map(i => { return { + outID: spent[`${i.outpoint.txid}-${i.outpoint.vout}`], + txnID: i.txnID, + inIndex: i.n, + inSequence: i.seq + }}) + + return db.addInputs(inputs) } catch(e) { Logger.error(e, `Importer : RemoteImporter.addTransactions() :`) diff --git a/lib/remote-importer/sources-mainnet.js b/lib/remote-importer/sources-mainnet.js index 6850b7f..48ce6a7 100644 --- a/lib/remote-importer/sources-mainnet.js +++ b/lib/remote-importer/sources-mainnet.js @@ -10,6 +10,7 @@ const keys = require('../../keys')[network.key] const Sources = require('./sources') const BitcoindWrapper = require('./bitcoind-wrapper') const LocalIndexerWrapper = require('./local-indexer-wrapper') +const LocalRestIndexerWrapper = require('./local-rest-indexer-wrapper') const OxtWrapper = require('./oxt-wrapper') @@ -40,6 +41,12 @@ class SourcesMainnet extends Sources { // we'll use the local indexer as our unique source this.source = new LocalIndexerWrapper() Logger.info('Importer : Activated local indexer as the data source for imports') + } else if (keys.indexer.active == 'local_rest_indexer') { + // If local rest indexer option is activated + // we'll use the local indexer as our unique source + const uri = `http://${keys.indexer.localIndexer.host}:${keys.indexer.localIndexer.port}` + this.source = new LocalRestIndexerWrapper(uri) + Logger.info('Importer : Activated local indexer (REST API) as the data source for imports') } else { // Otherwise, we'll use the rest api provided by OXT this.source = new OxtWrapper(keys.indexer.oxt) diff --git a/lib/remote-importer/sources-testnet.js b/lib/remote-importer/sources-testnet.js index 3efb3e6..3ee3907 100644 --- a/lib/remote-importer/sources-testnet.js +++ b/lib/remote-importer/sources-testnet.js @@ -11,6 +11,7 @@ const keys = require('../../keys')[network.key] const Sources = require('./sources') const BitcoindWrapper = require('./bitcoind-wrapper') const LocalIndexerWrapper = require('./local-indexer-wrapper') +const LocalRestIndexerWrapper = require('./local-rest-indexer-wrapper') const EsploraWrapper = require('./esplora-wrapper') @@ -41,6 +42,12 @@ class SourcesTestnet extends Sources { // we'll use the local indexer as our unique source this.source = new LocalIndexerWrapper() Logger.info('Importer : Activated local indexer as the data source for imports') + } else if (keys.indexer.active == 'local_rest_indexer') { + // If local rest indexer option is activated + // we'll use the local indexer as our unique source + const uri = `http://${keys.indexer.localIndexer.host}:${keys.indexer.localIndexer.port}` + this.source = new LocalRestIndexerWrapper(uri) + Logger.info('Importer : Activated local indexer (REST API) as the data source for imports') } else { // Otherwise, we'll use the rest api provided by Esplora this.source = new EsploraWrapper(keys.indexer.esplora) diff --git a/lib/util.js b/lib/util.js index eb81edb..0c96d04 100644 --- a/lib/util.js +++ b/lib/util.js @@ -15,77 +15,26 @@ class Util { constructor() {} /** - * Topological ordering of DAG - * https://en.wikipedia.org/wiki/Topological_sorting - * - * Kahn's algorithm - * - * L ← Empty list that will contain the sorted elements - * S ← Set of all nodes with no incoming edge - * while S is non-empty do - * remove a node n from S - * add n to tail of L - * for each node m with an edge e from n to m do - * remove edge e from the graph - * if m has no other incoming edges then - * insert m into S - * - * @param {object} parents - map of {[key]: [incoming edge keys]} - * @param {object} children - a map of {[key]: [outgoing edge keys]} - * @returns {object} - * if graph has edges then - * return error (graph has at least one cycle) - * else - * return L (a topologically sorted order) + * Serialize a series of asynchronous calls to a function + * over a list of objects */ - static topologicalOrdering(parents, children) { - const S = [] + static async seriesCall(list, fn) { + const results = [] - for (let node in parents) { - if (parents[node].length == 0) { - // Node has no parent (incoming edges) - S.push(node) - } + for (const item of list) { + results.push(await fn(item)); } - const L = [] - - while (S.length > 0) { - const node = S.pop() - L.push(node) - - // Loop over nodes that depend on node - for (let child of children[node]) { - let i = parents[child].indexOf(node) - if (i > -1) - parents[child].splice(i, 1) - - if (parents[child].length == 0) - S.push(child) - } - } - return L + return results; } /** - * Serialize a series of asynchronous calls to a function + * Execute parallel asynchronous calls to a function * over a list of objects - * ref: http://www.joezimjs.com/javascript/patterns-asynchronous-programming-promises/ */ - static seriesCall(list, fn) { - const results = [] - - return list.reduce((memo, item) => { - return memo.then(() => { - return fn(item) - }).then(result => { - results.push(result) - }) - }, - Promise.resolve() - ).then(function() { - return results - }) + static parallelCall(list, fn) { + const operations = list.map(item => { return fn(item) }) + return Promise.all(operations) } /** @@ -101,13 +50,9 @@ class Util { * Splits a list into a list of lists each with maximum length LIMIT */ static splitList(list, limit) { - if (list.length <= limit) - return [list] - const lists = [] - while (list.length) { - lists.push(list.splice(0, limit)) - } + for (let i=0; i < list.length; i += limit) + lists.push(list.slice(i, i+limit)) return lists } @@ -159,16 +104,16 @@ class Util { /** * Median of an array of values - */ + */ static median(arr, sorted) { if (arr.length == 0) return NaN if (arr.length == 1) return arr[0] if (!sorted) arr.sort(Util.cmpAsc) - + const midpoint = Math.floor(arr.length / 2) - + if (arr.length % 2) { // Odd-length array return arr[midpoint] @@ -252,10 +197,10 @@ class Util { // "Floor-x" const fx = Math.floor(x) - 1 - + // "Mod-x" const mx = x % 1 - + if (fx + 1 >= N) { return arr[fx] } else { @@ -340,7 +285,7 @@ class Util { const parts = [Util.pad10(h), Util.pad10(m), Util.pad10(s)] - if (d > 0) + if (d > 0) parts.splice(0, 0, Util.pad100(d)) const str = parts.join(':') diff --git a/lib/wallet/address-info.js b/lib/wallet/address-info.js index c5a22c2..194aba2 100644 --- a/lib/wallet/address-info.js +++ b/lib/wallet/address-info.js @@ -38,10 +38,19 @@ class AddressInfo { * @returns {Promise} */ async loadInfo() { + return Promise.all([ + this._loadBalance(), + this._loadNbTransactions() + ]) + } + + async _loadBalance() { const balance = await db.getAddressBalance(this.address) if (balance !== null) this.finalBalance = balance + } + async _loadNbTransactions() { const nbTxs = await db.getAddressNbTransactions(this.address) if (nbTxs !== null) this.nTx = nbTxs diff --git a/lib/wallet/hd-account-info.js b/lib/wallet/hd-account-info.js index 27df4cb..47a91eb 100644 --- a/lib/wallet/hd-account-info.js +++ b/lib/wallet/hd-account-info.js @@ -67,38 +67,50 @@ class HdAccountInfo { */ async loadInfo() { try { - const id = await db.getHDAccountId(this.xpub) - //if (id == null) return false - - const account = await db.getHDAccount(this.xpub) - this.created = account.hdCreated - this.derivation = hdaHelper.typeString(account.hdType) - this.tracked = true - - this.finalBalance = await db.getHDAccountBalance(this.xpub) - - const unusedIdx = await db.getHDAccountNextUnusedIndices(this.xpub) - this.accountIndex = unusedIdx[0] - this.changeIndex = unusedIdx[1] + await Promise.all([ + this._loadDerivationInfo(), + this._loadBalance(), + this._loadUnusedIndices(), + this._loadDerivedIndices(), + this._loadNbTransactions(), + ]) + return true + } catch(e) { + return false + } + } - const derivedIdx = await db.getHDAccountDerivedIndices(this.xpub) - this.accountDerivedIndex = derivedIdx[0] - this.changeDerivedIndex = derivedIdx[1] + async _loadDerivationInfo() { + const account = await db.getHDAccount(this.xpub) + this.created = account.hdCreated + this.derivation = hdaHelper.typeString(account.hdType) + this.tracked = true + const node = hdaHelper.getNode(this.xpub) + const index = node[2].index + const threshold = Math.pow(2,31) + const hardened = (index >= threshold) + this.account = hardened ? (index - threshold) : index + this.depth = node[2].depth + } - this.nTx = await db.getHDAccountNbTransactions(this.xpub) + async _loadBalance() { + this.finalBalance = await db.getHDAccountBalance(this.xpub) + } - const node = hdaHelper.getNode(this.xpub) - const index = node[2].index - const threshold = Math.pow(2,31) - const hardened = (index >= threshold) - this.account = hardened ? (index - threshold) : index - this.depth = node[2].depth + async _loadUnusedIndices() { + const unusedIdx = await db.getHDAccountNextUnusedIndices(this.xpub) + this.accountIndex = unusedIdx[0] + this.changeIndex = unusedIdx[1] + } - return true + async _loadDerivedIndices() { + const derivedIdx = await db.getHDAccountDerivedIndices(this.xpub) + this.accountDerivedIndex = derivedIdx[0] + this.changeDerivedIndex = derivedIdx[1] + } - } catch(e) { - return false - } + async _loadNbTransactions() { + this.nTx = await db.getHDAccountNbTransactions(this.xpub) } /** @@ -111,7 +123,7 @@ class HdAccountInfo { const utxos = await db.getHDAccountUnspentOutputs(this.xpub) for (let utxo of utxos) { - const conf = + const conf = (utxo.blockHeight == null) ? 0 : (rpcLatestBlock.height - utxo.blockHeight + 1) diff --git a/lib/wallet/wallet-info.js b/lib/wallet/wallet-info.js index f010461..3d09dfa 100644 --- a/lib/wallet/wallet-info.js +++ b/lib/wallet/wallet-info.js @@ -49,10 +49,10 @@ class WalletInfo { /** * Ensure hd accounts exist in database - * @returns {Promise} + * @returns {Promise} */ async ensureHdAccounts() { - return util.seriesCall(this.entities.xpubs, async xpub => { + return util.parallelCall(this.entities.xpubs, async xpub => { const hdaInfo = new HdAccountInfo(xpub) return hdaInfo.ensureHdAccount() }) @@ -63,7 +63,7 @@ class WalletInfo { * @returns {Promise} */ async loadHdAccountsInfo() { - return util.seriesCall(this.entities.xpubs, async xpub => { + return util.parallelCall(this.entities.xpubs, async xpub => { const hdaInfo = new HdAccountInfo(xpub) await hdaInfo.loadInfo() this.wallet.finalBalance += hdaInfo.finalBalance @@ -77,7 +77,7 @@ class WalletInfo { */ async ensureAddresses() { const importAddrs = [] - + const addrIdMap = await db.getAddressesIds(this.entities.addrs) for (let addr of this.entities.addrs) { @@ -113,7 +113,7 @@ class WalletInfo { * @returns {Promise} */ async loadAddressesInfo() { - return util.seriesCall(this.entities.addrs, async address => { + return util.parallelCall(this.entities.addrs, async address => { const addrInfo = new AddressInfo(address) await addrInfo.loadInfo() this.wallet.finalBalance += addrInfo.finalBalance @@ -125,7 +125,7 @@ class WalletInfo { * Loads a partial list of transactions for this wallet * @param {integer} page - page index * @param {integer} count - number of transactions per page - * @param {boolean} txBalance - True if past wallet balance + * @param {boolean} txBalance - True if past wallet balance * should be computed for each transaction * @returns {Promise} */ @@ -166,7 +166,7 @@ class WalletInfo { * @returns {Promise} */ async loadFeesInfo() { - this.info.fees = await rpcFees.getFees() + this.info.fees = await rpcFees.getFees() } /** @@ -175,7 +175,7 @@ class WalletInfo { */ async loadUtxos() { // Load the utxos for the hd accounts - await util.seriesCall(this.entities.xpubs, async xpub => { + await util.parallelCall(this.entities.xpubs, async xpub => { const hdaInfo = new HdAccountInfo(xpub) const utxos = await hdaInfo.loadUtxos() for (let utxo of utxos) diff --git a/lib/wallet/wallet-service.js b/lib/wallet/wallet-service.js index d77adbc..08cb7ad 100644 --- a/lib/wallet/wallet-service.js +++ b/lib/wallet/wallet-service.js @@ -51,37 +51,53 @@ class WalletService { const walletInfo = new WalletInfo(active) try { - // Add the new xpubs - await util.seriesCall(legacy.xpubs, this._newBIP44) - await util.seriesCall(bip49.xpubs, this._newBIP49) - await util.seriesCall(bip84.xpubs, this._newBIP84) - // Load hd accounts info - await walletInfo.ensureHdAccounts() - await walletInfo.loadHdAccountsInfo() - // Add the new addresses - await db.addAddresses(legacy.addrs) - await db.addAddresses(bip49.addrs) - await db.addAddresses(bip84.addrs) - await db.addAddresses(pubkeys.addrs) - // Ensure addresses exist - await walletInfo.ensureAddresses() + await Promise.all([ + + // Add the new xpubs + util.parallelCall(legacy.xpubs, this._newBIP44), + util.parallelCall(bip49.xpubs, this._newBIP49), + util.parallelCall(bip84.xpubs, this._newBIP84), + // Add the new addresses + db.addAddresses(legacy.addrs), + db.addAddresses(bip49.addrs), + db.addAddresses(bip84.addrs), + db.addAddresses(pubkeys.addrs), + ]) + + // Ensure hd accounts and addresses exist + await Promise.all([ + walletInfo.ensureHdAccounts(), + walletInfo.ensureAddresses(), + ]) + // Force import of addresses associated to paynyms // if dojo relies on a local index if (keys.indexer.active != 'third_party_explorer') await this._forceEnsureAddressesForActivePubkeys(active) + // Filter the addresses await walletInfo.filterAddresses() - // Load the utxos - await walletInfo.loadUtxos() - // Load the addresses - await walletInfo.loadAddressesInfo() - // Load the most recent transactions - await walletInfo.loadTransactions(0, null, true) - // Load feerates - await walletInfo.loadFeesInfo() + + // Load wallet information + await Promise.all([ + // Load the hd accounts, + walletInfo.loadHdAccountsInfo(), + // Load the utxos + walletInfo.loadUtxos(), + // Load the addresses + walletInfo.loadAddressesInfo(), + // Load the most recent transactions + walletInfo.loadTransactions(0, null, true), + // Load feerates + walletInfo.loadFeesInfo(), + ]) + // Postprocessing - await walletInfo.postProcessAddresses() - await walletInfo.postProcessHdAccounts() + await Promise.all([ + walletInfo.postProcessAddresses(), + walletInfo.postProcessHdAccounts(), + ]) + // Format the result return this._formatGetFullWalletInfoResult(walletInfo) @@ -250,7 +266,7 @@ class WalletService { return ret } catch(e) { - Logger.error(e, 'WalletService.getWalletUtxos()') + Logger.error(e, 'WalletService.getWalletUtxos()') return Promise.reject({status: 'error', error: 'internal server error'}) } } @@ -280,20 +296,25 @@ class WalletService { try { // Filter the addresses await walletInfo.filterAddresses() - // Load the number of transactions - await walletInfo.loadNbTransactions() - // Load the requested page of transactions - await walletInfo.loadTransactions(page, count, false) + + await Promise.all([ + // Load the number of transactions + walletInfo.loadNbTransactions(), + // Load the requested page of transactions + walletInfo.loadTransactions(page, count, false), + ]) + // Postprocessing await walletInfo.postProcessAddresses() await walletInfo.postProcessHdAccounts() + // Format the result ret.n_tx = walletInfo.nTx ret.txs = walletInfo.txs return ret } catch(e) { - Logger.error(e, 'WalletService.getWalletTransactions()') + Logger.error(e, 'WalletService.getWalletTransactions()') return Promise.reject({status:'error', error:'internal server error'}) } } @@ -344,10 +365,7 @@ class WalletService { */ _mergeEntities(active, legacy, bip49, bip84, pubkeys) { // Put all xpub into active.xpubs - active.xpubs = active.xpubs - .concat(legacy.xpubs) - .concat(bip49.xpubs) - .concat(bip84.xpubs) + active.xpubs = active.xpubs.concat(legacy.xpubs, bip49.xpubs, bip84.xpubs) // Put addresses and pubkeys into active // but avoid duplicates diff --git a/package-lock.json b/package-lock.json index a7451db..b86c465 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,29 +1,3873 @@ { "name": "samourai-dojo", - "version": "1.9.0", - "lockfileVersion": 1, + "version": "1.10.0", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "version": "1.10.0", + "license": "AGPL-3.0-only", + "dependencies": { + "@tinyhttp/app": "1.3.3", + "async-sema": "2.1.2", + "axios": "0.21.1", + "bip39": "2.4.0", + "bitcoinjs-lib": "5.2.0", + "bitcoinjs-message": "1.0.1", + "body-parser": "1.19.0", + "helmet": "3.23.3", + "jsonwebtoken": "8.5.1", + "lodash": "4.17.21", + "lru-cache": "4.0.2", + "make-concurrent": "5.3.0", + "minimist": "1.2.5", + "mysql": "2.18.1", + "passport": "0.4.1", + "passport-localapikey-update": "0.6.0", + "rpc-bitcoin": "2.0.0", + "sirv": "1.0.11", + "socks-proxy-agent": "4.0.1", + "validator": "10.8.0", + "websocket": "1.0.34", + "workerpool": "6.1.4", + "zeromq": "4.2.0" + }, + "devDependencies": { + "mocha": "^7.1.1" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.12", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz", + "integrity": "sha512-6RglhutqrGFMO1MNUXp95RBuYIuc8wTnMAV5MUhLmjTOy78ncwOw7RgeQ/HeymkKXRhZd0s2DNrM1rL7unk3MQ==" + }, + "node_modules/@tinyhttp/accepts": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/accepts/-/accepts-1.3.0.tgz", + "integrity": "sha512-YaJ4EMgVUI6JHzWO14lr6vn/BLJEoFN4Sqd20l0/oBcLLENkP8gnPtX1jB7OhIu0AE40VCweAqvSP+0/pgzB1g==", + "dependencies": { + "es-mime-types": "^0.0.16", + "negotiator": "^0.6.2" + }, + "engines": { + "node": ">=12.4.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/talentlessguy/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/app": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@tinyhttp/app/-/app-1.3.3.tgz", + "integrity": "sha512-PhE3En3AMWNcdrm0hVTcawz5UIWUlzHo5Zl+JunOXR2hhXJ9afvm6OCXg0GX/bgNZ1vW/Prwp10+KrGWygthnQ==", + "dependencies": { + "@tinyhttp/cookie": "1.3.0", + "@tinyhttp/proxy-addr": "1.3.0", + "@tinyhttp/req": "1.3.0", + "@tinyhttp/res": "1.3.0", + "@tinyhttp/router": "1.3.1", + "regexparam": "^1.3.0" + }, + "engines": { + "node": ">=12.x" + }, + "funding": { + "type": "individual", + "url": "https://github.com/talentlessguy/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/content-disposition": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/content-disposition/-/content-disposition-1.3.0.tgz", + "integrity": "sha512-sSj7YDVz7NcHDn6/O/I3WjtC8ZWJKKIGULoV+pgrLvJvtXK5WroE1Fm8rHRQewh2d9NMajh/7NX6NuSlF8LUaQ==", + "engines": { + "node": ">=12.4.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/talentlessguy/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/cookie": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/cookie/-/cookie-1.3.0.tgz", + "integrity": "sha512-4ZVfP8WApV9ZRchv/1i0QiKdP0wxWTUNv4ZsMQrqK0p1KXA0/SvpYUTS6bp1E6Yo0dNxcKte4wJ4FCWFDcShhQ==", + "engines": { + "node": ">=12.4.0" + }, + "funding": { + "type": "individual", + "url": "https://github.com/talentlessguy/tinyhttp?sponsor=1" + } + }, + "node_modules/@tinyhttp/cookie-signature": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/cookie-signature/-/cookie-signature-1.3.0.tgz", + "integrity": "sha512-xCQZyCT1S/Rn2Z3SX2gp4IDAwW9AUnjky6hKvqzmMaQqEbIk7e2GCOXW5yjndbfGNTJAxj0tuLNMF4G8aLkfMw==", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/encode-url": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/encode-url/-/encode-url-0.3.0.tgz", + "integrity": "sha512-QM5j5t0GLucBuBePoOilcz1/zDpqX+LtUdtkPn7IvoHTNJYNxEfSUmIMPUPhyVY7mvbwvafPUCK8u1Byx0+NfQ==", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/etag": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/etag/-/etag-1.3.0.tgz", + "integrity": "sha512-aWnDb4NuMf/UTm1H88rZgqu32E6t3iDHSHtAppiQCH4M7jRfTUEpiZjz//S+giDnOxAuYttLrXQ1+HGpgzyYUQ==", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/forwarded": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/forwarded/-/forwarded-1.3.0.tgz", + "integrity": "sha512-U2FPtOH+DoFtd98edMRyqiquRaiuEl5I2PMUWdKaBSpiAIR96buyanQ7hScenz1MihK0AVid7wLAviaJU+Xlyg==", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/proxy-addr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/proxy-addr/-/proxy-addr-1.3.0.tgz", + "integrity": "sha512-7Kv6YIC/PlhUwyqAGXhg4DoQDOzbYlcGPkNv/KZAMFj9fZ6IEZyneyaClnD21hMT8qa7g3Z/66hxLa/WxiPAYA==", + "dependencies": { + "@tinyhttp/forwarded": "^1.3.0", + "ipaddr.js": "^2.0.0" + }, + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/req": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/req/-/req-1.3.0.tgz", + "integrity": "sha512-zIbtJA7Hp2p4MqszP2jOBi2NWi8fTGd4lso+0CjwJa+WTE+lgXVAy6mN12rTAxjXweAyRvQpRIJ5W2r8OLuEXQ==", + "dependencies": { + "@tinyhttp/accepts": "1.3.0", + "@tinyhttp/type-is": "1.3.0", + "@tinyhttp/url": "1.3.0", + "es-fresh": "^0.0.8", + "range-parser": "^1.2.1" + }, + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/res": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/res/-/res-1.3.0.tgz", + "integrity": "sha512-ez6fCpGsYoU6HUBq0e+m4l6Cffu2FeucK+m5Z6a8sBGqLR7/teB1pFufCOPwrdwzdNrLNarGJpsNQpvQqDMWaA==", + "dependencies": { + "@tinyhttp/content-disposition": "1.3.0", + "@tinyhttp/cookie": "1.3.0", + "@tinyhttp/cookie-signature": "1.3.0", + "@tinyhttp/encode-url": "0.3.0", + "@tinyhttp/req": "1.3.0", + "@tinyhttp/send": "1.3.0", + "es-mime-types": "^0.0.16", + "es-vary": "^0.0.8", + "escape-html": "^1.0.3" + }, + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/router": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@tinyhttp/router/-/router-1.3.1.tgz", + "integrity": "sha512-r+VTBrRVxCgkTUVOzR2Awzaqa8DCQKQg/BLIpKEHNGp/OVuxSvVGVIEKiZZY9Z5E3HR6FYZL0TMO7r6QvzP1Jg==", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/send": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/send/-/send-1.3.0.tgz", + "integrity": "sha512-3Tn8NaLhNdcIJQqc/3ZBFV0hX6jCaFNDX5/vWxoPubDrh8HOpn2foPXL7ZIRk8GDkaB/M3cSzKIlKpnTKmh0Nw==", + "dependencies": { + "@tinyhttp/etag": "1.3.0", + "es-content-type": "^0.0.10", + "es-mime-types": "^0.0.16" + }, + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/type-is": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/type-is/-/type-is-1.3.0.tgz", + "integrity": "sha512-3NClOYPNJst9vVLcb793epRI+ZuRwl6IjxSq9LkGN8TEBbtNgv2vTmXZRWcUs2zY9Ju+NQIYecWcsG0Kx23E+g==", + "dependencies": { + "es-content-type": "^0.0.10", + "es-mime-types": "^0.0.16" + }, + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@tinyhttp/url": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/url/-/url-1.3.0.tgz", + "integrity": "sha512-GgdKez5AaQRIm0kFNp7BZnxFQ2F7LZ7g3rOQ/v11oYZR3jhH7JPGM+7hZQjYqFXD/5TK/of7hepu418K2fghvg==", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, + "node_modules/@types/node": { + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" + }, + "node_modules/@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", + "dependencies": { + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" + } + }, + "node_modules/@types/request-promise-native": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/request-promise-native/-/request-promise-native-1.0.17.tgz", + "integrity": "sha512-05/d0WbmuwjtGMYEdHIBZ0tqMJJQ2AD9LG2F6rKNBGX1SSFR27XveajH//2N/XYtual8T9Axwl+4v7oBtPUZqg==", + "dependencies": { + "@types/request": "*" + } + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, + "node_modules/agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/are-we-there-yet/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async-sema": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-2.1.2.tgz", + "integrity": "sha512-7Wxs4QBLL9XklTVaRKH16ws/YJBZ7wouqnSu84jILDqZZObsrhDfsVELhQE7U53b2qkFtsAX5ED1ZMvrWzv1Yg==", + "dependencies": { + "double-ended-queue": "2.1.0-0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base-x": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", + "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bip174": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz", + "integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bip32": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.5.tgz", + "integrity": "sha512-zVY4VvJV+b2fS0/dcap/5XLlpqtgwyN8oRkuGgAS1uLOeEp0Yo6Tw2yUTozTtlrMJO3G8n4g/KX/XGFHW6Pq3g==", + "dependencies": { + "@types/node": "10.12.18", + "bs58check": "^2.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "tiny-secp256k1": "^1.1.3", + "typeforce": "^1.11.5", + "wif": "^2.0.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bip39": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.4.0.tgz", + "integrity": "sha512-1++HywqIyPtWDo7gm4v0ylYbwkLvHkuwVSKbBlZBbTCP/mnkyrlARBny906VLAwxJbC5xw9EvuJasHFIZaIFMQ==", + "dependencies": { + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1", + "safe-buffer": "^5.0.1", + "unorm": "^1.3.3" + } + }, + "node_modules/bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bitcoin-ops": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz", + "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==" + }, + "node_modules/bitcoinjs-lib": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-5.2.0.tgz", + "integrity": "sha512-5DcLxGUDejgNBYcieMIUfjORtUeNWl828VWLHJGVKZCb4zIS1oOySTUr0LGmcqJBQgTBz3bGbRQla4FgrdQEIQ==", + "dependencies": { + "bech32": "^1.1.2", + "bip174": "^2.0.1", + "bip32": "^2.0.4", + "bip66": "^1.1.0", + "bitcoin-ops": "^1.4.0", + "bs58check": "^2.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.3", + "merkle-lib": "^2.0.10", + "pushdata-bitcoin": "^1.0.1", + "randombytes": "^2.0.1", + "tiny-secp256k1": "^1.1.1", + "typeforce": "^1.11.3", + "varuint-bitcoin": "^1.0.4", + "wif": "^2.0.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bitcoinjs-message": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bitcoinjs-message/-/bitcoinjs-message-1.0.1.tgz", + "integrity": "sha1-P8xfHYX53TCsYNERlIyxs7T+nMU=", + "dependencies": { + "bs58check": "^1.0.8", + "buffer-equals": "^1.0.3", + "create-hash": "^1.1.2", + "secp256k1": "^3.0.1", + "varuint-bitcoin": "^1.0.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/bitcoinjs-message/node_modules/base-x": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-1.1.0.tgz", + "integrity": "sha1-QtPXF0dPnqAiB/bRqh9CaRPut6w=" + }, + "node_modules/bitcoinjs-message/node_modules/bs58": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-3.1.0.tgz", + "integrity": "sha1-1MJjiL9IBMrHFBQbGUWqR+XrJI4=", + "dependencies": { + "base-x": "^1.1.0" + } + }, + "node_modules/bitcoinjs-message/node_modules/bs58check": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-1.3.4.tgz", + "integrity": "sha1-xSVABzdJEXcU+gQsMEfrj5FRy/g=", + "dependencies": { + "bs58": "^3.1.0", + "create-hash": "^1.1.0" + } + }, + "node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/bl/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/bl/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/body-parser/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/body-parser/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/body-parser/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/bowser": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", + "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/buffer-equals": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/buffer-equals/-/buffer-equals-1.0.4.tgz", + "integrity": "sha1-A1O1T9B/2VZBcGca5vZrnPENJ/U=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "node_modules/bufferutil": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz", + "integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.2.0" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + }, + "engines": { + "node": ">= 8.10.0" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "node_modules/content-security-policy-builder": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", + "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dasherize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", + "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg=" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dont-sniff-mimetype": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz", + "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + }, + "node_modules/drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", + "dependencies": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-content-type": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/es-content-type/-/es-content-type-0.0.10.tgz", + "integrity": "sha512-yCgcv1M2IuFUoGZ3zE4OR2INGmZOwEuyaE5WX4MOKGpJcO8JXgVOIcXVicwnTqlxvx6qs9IJGl/Rr1+YtCkRgg==", + "engines": { + "node": ">=12.x" + } + }, + "node_modules/es-fresh": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/es-fresh/-/es-fresh-0.0.8.tgz", + "integrity": "sha512-ZM+K/T/zHJVuOhaz19iymidACazB1fl2uihBtSfRie8YzN1YM+KldVmNaU+GSmVvTOPSO2utKOhxcOinr5tKjw==", + "engines": { + "node": ">=12.x" + } + }, + "node_modules/es-mime-types": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/es-mime-types/-/es-mime-types-0.0.16.tgz", + "integrity": "sha512-84QoSLeA7cdTeHpALFNl3ZOstXfvLt426/kaOgmSxmNUOhi4GesKVkhJgIfnsqGNziYezVA8rvZUsXj7oWX2qQ==", + "dependencies": { + "mime-db": "^1.44.0" + }, + "engines": { + "node": ">=12.x" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-vary": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/es-vary/-/es-vary-0.0.8.tgz", + "integrity": "sha512-fiERjQiCHrXUAToNRT/sh7MtXnfei9n7cF9oVQRUEp9L5BGXsTKSPaXq8L+4v0c/ezfvuTWd/f0JSl5IBRUvSg==", + "engines": { + "node": ">=12.x" + } + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expand-template": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", + "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==" + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/feature-policy": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", + "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "dependencies": { + "is-buffer": "~2.0.3" + }, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=" + }, + "node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/helmet": { + "version": "3.23.3", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.3.tgz", + "integrity": "sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==", + "dependencies": { + "depd": "2.0.0", + "dont-sniff-mimetype": "1.1.0", + "feature-policy": "0.3.0", + "helmet-crossdomain": "0.4.0", + "helmet-csp": "2.10.0", + "hide-powered-by": "1.1.0", + "hpkp": "2.0.0", + "hsts": "2.2.0", + "nocache": "2.1.0", + "referrer-policy": "1.2.0", + "x-xss-protection": "1.3.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/helmet-crossdomain": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz", + "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/helmet-csp": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.10.0.tgz", + "integrity": "sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==", + "dependencies": { + "bowser": "2.9.0", + "camelize": "1.0.0", + "content-security-policy-builder": "2.1.0", + "dasherize": "2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/helmet/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/hide-powered-by": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz", + "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hpkp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", + "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI=" + }, + "node_modules/hsts": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz", + "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==", + "dependencies": { + "depd": "2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/hsts/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, + "node_modules/ipaddr.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.0.tgz", + "integrity": "sha512-S54H9mIj0rbxRIyrDMEuuER86LdlgUg9FSeZ8duQb6CUG2iRrA36MYVQBSprTF/ZeAwvyQ5mDGuNvIPM0BIl3w==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", + "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.0.tgz", + "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/make-concurrent": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/make-concurrent/-/make-concurrent-5.3.0.tgz", + "integrity": "sha512-8si1KzXm7DiUXSbeOPliY9MrNVFGaEEgKZNctxz9FM3Ztx/cb5qiUazD/8WurKCJL05/zizZHBXYdjXRNAvtFA==", + "engines": { + "node": ">=7.6.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merkle-lib": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", + "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" + }, + "node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "dependencies": { + "mime-db": "1.47.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.2.0.tgz", + "integrity": "sha512-O9CIypScywTVpNaRrCAgoUnJgozpIofjKUYmJhiCIJMiuYnLI6otcb1/kpW9/n/tJODHGZ7i8aLQoDVsMtOKQQ==", + "dev": true, + "dependencies": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.5", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 8.10.0" + } + }, + "node_modules/mocha/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/mysql/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/mysql/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/nan": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", + "integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node_modules/nocache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", + "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/node-abi": { + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.18.0.tgz", + "integrity": "sha512-yi05ZoiuNNEbyT/xXfSySZE+yVnQW6fxPZuFbLyS1s6b5Kw3HzV2PHOM4XR+nsjzkHxByK+2Wg+yCQbe35l8dw==", + "dependencies": { + "semver": "^5.4.1" + } + }, + "node_modules/node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "dependencies": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-localapikey-update": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/passport-localapikey-update/-/passport-localapikey-update-0.6.0.tgz", + "integrity": "sha512-NklCLY68AdepFID+HQ9CVPqRKKYIPw+fGQBsQoP/WZ2ovVfmJ0Qx7eoBpUtpta0vyav2TPDoHSAKoHTjO+LPcw==", + "dependencies": { + "passport-strategy": "1.x.x", + "pkginfo": "0.2.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, + "node_modules/pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/pkginfo": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", + "integrity": "sha1-cjnEKl72wwuPMoQ52bn/cQQkkPg=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/prebuild-install": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.3.tgz", + "integrity": "sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g==", + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^1.0.2", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "node-abi": "^2.2.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.1.6", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "prebuild-install": "bin.js" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pushdata-bitcoin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", + "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=", + "dependencies": { + "bitcoin-ops": "^1.3.0" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/raw-body/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/raw-body/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/referrer-policy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", + "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/regexparam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-1.3.0.tgz", + "integrity": "sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "dependencies": { + "lodash": "^4.17.19" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dependencies": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rpc-bitcoin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rpc-bitcoin/-/rpc-bitcoin-2.0.0.tgz", + "integrity": "sha512-o+DJHCuuuTJIJgWD1De3fGWd/ulpHb/Nn87qSh0Zn6+ur1pvyJU6TzvIlYAW6EWtCCyZdwbEXL3+Jpmh3/7EvQ==", + "dependencies": { + "rpc-request": "^4.0.9" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "type": "Coinbase Commerce", + "url": "https://commerce.coinbase.com/checkout/89a70363-3d1f-4aa0-8d2a-1424ed9e87ee" + } + }, + "node_modules/rpc-request": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/rpc-request/-/rpc-request-4.0.10.tgz", + "integrity": "sha512-VQIogs0wYpRBxmliXxOK6sDj+BCS/AFwPjroffwg7l5Dxur0l1YkljtB/pdYj0p31U0seEiwKeYr0j7xTY0Clg==", + "dependencies": { + "@types/request-promise-native": "^1.0.17", + "request": "^2.88.2", + "request-promise-native": "^1.0.9" + }, + "engines": { + "node": ">=10.18.1" + }, + "funding": { + "type": "Coinbase Commerce", + "url": "https://commerce.coinbase.com/checkout/32948818-f4bb-4087-ae5e-1d29ecb86e64" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/secp256k1": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.8.0.tgz", + "integrity": "sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw==", + "dependencies": { + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.5.2", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "node_modules/simple-get": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", + "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sirv": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.11.tgz", + "integrity": "sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg==", + "dependencies": { + "@polka/url": "^1.0.0-next.9", + "mime": "^2.3.1", + "totalist": "^1.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "engines": { + "node": ">= 4.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.3.tgz", + "integrity": "sha512-+2r83WaRT3PXYoO/1z+RDEBE7Z2f9YcdQnJ0K/ncXXbV5gJ6wYfNAebYFYiiUjM6E4JyXnPY8cimwyvFYHVUUA==", + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + }, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", + "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", + "dependencies": { + "agent-base": "~4.2.0", + "socks": "~2.2.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "dependencies": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + } + }, + "node_modules/tar-fs/node_modules/pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/tar-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/tar-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tiny-secp256k1": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.5.tgz", + "integrity": "sha512-duE2hSLSQIpHGzmK48OgRrGTi+4OTkXLC6aa86uOYQ6LLCYZSarVKIAvEtY7MoXjoL6bOXMSerEGMzrvW4SkDw==", + "dependencies": { + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + }, + "node_modules/unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.5.tgz", + "integrity": "sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.2.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validator": { + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.8.0.tgz", + "integrity": "sha512-mXqMxfCh5NLsVgYVKl9WvnHNDPCcbNppHSPPowu0VjtSsGWVY+z8hJF44edLR1nbLNzi3jYoYsIl8KZpioIk6g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/varuint-bitcoin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", + "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "dependencies": { + "safe-buffer": "^5.1.1" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/websocket": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/which-pm-runs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", + "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=" + }, + "node_modules/wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dependencies": { + "string-width": "^1.0.2 || 2" + } + }, + "node_modules/wif": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", + "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", + "dependencies": { + "bs58check": "<3.0.0" + } + }, + "node_modules/workerpool": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.4.tgz", + "integrity": "sha512-jGWPzsUqzkow8HoAvqaPWTUPCrlPJaJ5tY8Iz7n1uCz3tTp6s3CDG0FF1NsX42WNlkRSW6Mr+CDZGnNoSsKa7g==" + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/x-xss-protection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz", + "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/yaeti": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz", + "integrity": "sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc=", + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "dependencies": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/zeromq": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-4.2.0.tgz", + "integrity": "sha1-4RMzBd9zyE+MffBgqOKzA7THLX8=", + "dependencies": { + "nan": "^2.4.0", + "prebuild-install": "^2.1.1" + }, + "engines": { + "node": ">=0.10" + } + } + }, "dependencies": { + "@polka/url": { + "version": "1.0.0-next.12", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.12.tgz", + "integrity": "sha512-6RglhutqrGFMO1MNUXp95RBuYIuc8wTnMAV5MUhLmjTOy78ncwOw7RgeQ/HeymkKXRhZd0s2DNrM1rL7unk3MQ==" + }, + "@tinyhttp/accepts": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/accepts/-/accepts-1.3.0.tgz", + "integrity": "sha512-YaJ4EMgVUI6JHzWO14lr6vn/BLJEoFN4Sqd20l0/oBcLLENkP8gnPtX1jB7OhIu0AE40VCweAqvSP+0/pgzB1g==", + "requires": { + "es-mime-types": "^0.0.16", + "negotiator": "^0.6.2" + } + }, + "@tinyhttp/app": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@tinyhttp/app/-/app-1.3.3.tgz", + "integrity": "sha512-PhE3En3AMWNcdrm0hVTcawz5UIWUlzHo5Zl+JunOXR2hhXJ9afvm6OCXg0GX/bgNZ1vW/Prwp10+KrGWygthnQ==", + "requires": { + "@tinyhttp/cookie": "1.3.0", + "@tinyhttp/proxy-addr": "1.3.0", + "@tinyhttp/req": "1.3.0", + "@tinyhttp/res": "1.3.0", + "@tinyhttp/router": "1.3.1", + "regexparam": "^1.3.0" + } + }, + "@tinyhttp/content-disposition": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/content-disposition/-/content-disposition-1.3.0.tgz", + "integrity": "sha512-sSj7YDVz7NcHDn6/O/I3WjtC8ZWJKKIGULoV+pgrLvJvtXK5WroE1Fm8rHRQewh2d9NMajh/7NX6NuSlF8LUaQ==" + }, + "@tinyhttp/cookie": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/cookie/-/cookie-1.3.0.tgz", + "integrity": "sha512-4ZVfP8WApV9ZRchv/1i0QiKdP0wxWTUNv4ZsMQrqK0p1KXA0/SvpYUTS6bp1E6Yo0dNxcKte4wJ4FCWFDcShhQ==" + }, + "@tinyhttp/cookie-signature": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/cookie-signature/-/cookie-signature-1.3.0.tgz", + "integrity": "sha512-xCQZyCT1S/Rn2Z3SX2gp4IDAwW9AUnjky6hKvqzmMaQqEbIk7e2GCOXW5yjndbfGNTJAxj0tuLNMF4G8aLkfMw==" + }, + "@tinyhttp/encode-url": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/encode-url/-/encode-url-0.3.0.tgz", + "integrity": "sha512-QM5j5t0GLucBuBePoOilcz1/zDpqX+LtUdtkPn7IvoHTNJYNxEfSUmIMPUPhyVY7mvbwvafPUCK8u1Byx0+NfQ==" + }, + "@tinyhttp/etag": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/etag/-/etag-1.3.0.tgz", + "integrity": "sha512-aWnDb4NuMf/UTm1H88rZgqu32E6t3iDHSHtAppiQCH4M7jRfTUEpiZjz//S+giDnOxAuYttLrXQ1+HGpgzyYUQ==" + }, + "@tinyhttp/forwarded": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/forwarded/-/forwarded-1.3.0.tgz", + "integrity": "sha512-U2FPtOH+DoFtd98edMRyqiquRaiuEl5I2PMUWdKaBSpiAIR96buyanQ7hScenz1MihK0AVid7wLAviaJU+Xlyg==" + }, + "@tinyhttp/proxy-addr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/proxy-addr/-/proxy-addr-1.3.0.tgz", + "integrity": "sha512-7Kv6YIC/PlhUwyqAGXhg4DoQDOzbYlcGPkNv/KZAMFj9fZ6IEZyneyaClnD21hMT8qa7g3Z/66hxLa/WxiPAYA==", + "requires": { + "@tinyhttp/forwarded": "^1.3.0", + "ipaddr.js": "^2.0.0" + } + }, + "@tinyhttp/req": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/req/-/req-1.3.0.tgz", + "integrity": "sha512-zIbtJA7Hp2p4MqszP2jOBi2NWi8fTGd4lso+0CjwJa+WTE+lgXVAy6mN12rTAxjXweAyRvQpRIJ5W2r8OLuEXQ==", + "requires": { + "@tinyhttp/accepts": "1.3.0", + "@tinyhttp/type-is": "1.3.0", + "@tinyhttp/url": "1.3.0", + "es-fresh": "^0.0.8", + "range-parser": "^1.2.1" + } + }, + "@tinyhttp/res": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/res/-/res-1.3.0.tgz", + "integrity": "sha512-ez6fCpGsYoU6HUBq0e+m4l6Cffu2FeucK+m5Z6a8sBGqLR7/teB1pFufCOPwrdwzdNrLNarGJpsNQpvQqDMWaA==", + "requires": { + "@tinyhttp/content-disposition": "1.3.0", + "@tinyhttp/cookie": "1.3.0", + "@tinyhttp/cookie-signature": "1.3.0", + "@tinyhttp/encode-url": "0.3.0", + "@tinyhttp/req": "1.3.0", + "@tinyhttp/send": "1.3.0", + "es-mime-types": "^0.0.16", + "es-vary": "^0.0.8", + "escape-html": "^1.0.3" + } + }, + "@tinyhttp/router": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@tinyhttp/router/-/router-1.3.1.tgz", + "integrity": "sha512-r+VTBrRVxCgkTUVOzR2Awzaqa8DCQKQg/BLIpKEHNGp/OVuxSvVGVIEKiZZY9Z5E3HR6FYZL0TMO7r6QvzP1Jg==" + }, + "@tinyhttp/send": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/send/-/send-1.3.0.tgz", + "integrity": "sha512-3Tn8NaLhNdcIJQqc/3ZBFV0hX6jCaFNDX5/vWxoPubDrh8HOpn2foPXL7ZIRk8GDkaB/M3cSzKIlKpnTKmh0Nw==", + "requires": { + "@tinyhttp/etag": "1.3.0", + "es-content-type": "^0.0.10", + "es-mime-types": "^0.0.16" + } + }, + "@tinyhttp/type-is": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/type-is/-/type-is-1.3.0.tgz", + "integrity": "sha512-3NClOYPNJst9vVLcb793epRI+ZuRwl6IjxSq9LkGN8TEBbtNgv2vTmXZRWcUs2zY9Ju+NQIYecWcsG0Kx23E+g==", + "requires": { + "es-content-type": "^0.0.10", + "es-mime-types": "^0.0.16" + } + }, + "@tinyhttp/url": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@tinyhttp/url/-/url-1.3.0.tgz", + "integrity": "sha512-GgdKez5AaQRIm0kFNp7BZnxFQ2F7LZ7g3rOQ/v11oYZR3jhH7JPGM+7hZQjYqFXD/5TK/of7hepu418K2fghvg==" + }, + "@types/caseless": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", + "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" + }, "@types/node": { "version": "10.12.18", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "@types/request": { + "version": "2.48.5", + "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", + "integrity": "sha512-/LO7xRVnL3DxJ1WkPGDQrp4VTV1reX9RkC85mJ+Qzykj2Bdw+mG15aAfDahc76HtknjzE16SX/Yddn6MxVbmGQ==", "requires": { - "mime-types": "2.1.27", - "negotiator": "0.6.2" + "@types/caseless": "*", + "@types/node": "*", + "@types/tough-cookie": "*", + "form-data": "^2.5.0" } }, + "@types/request-promise-native": { + "version": "1.0.17", + "resolved": "https://registry.npmjs.org/@types/request-promise-native/-/request-promise-native-1.0.17.tgz", + "integrity": "sha512-05/d0WbmuwjtGMYEdHIBZ0tqMJJQ2AD9LG2F6rKNBGX1SSFR27XveajH//2N/XYtual8T9Axwl+4v7oBtPUZqg==", + "requires": { + "@types/request": "*" + } + }, + "@types/tough-cookie": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A==" + }, "agent-base": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "requires": { - "es6-promisify": "5.0.0" + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, "ansi-colors": { @@ -43,7 +3887,7 @@ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "requires": { - "color-convert": "1.9.3" + "color-convert": "^1.9.0" } }, "anymatch": { @@ -52,8 +3896,8 @@ "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", "dev": true, "requires": { - "normalize-path": "3.0.0", - "picomatch": "2.2.2" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "aproba": { @@ -66,8 +3910,8 @@ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.7" + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" }, "dependencies": { "readable-stream": { @@ -75,13 +3919,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -94,7 +3938,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -105,18 +3949,21 @@ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "requires": { - "sprintf-js": "1.0.3" + "sprintf-js": "~1.0.2" } }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } }, - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "async-sema": { "version": "2.1.2", @@ -126,20 +3973,27 @@ "double-ended-queue": "2.1.0-0" } }, - "axios": { - "version": "0.20.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz", - "integrity": "sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA==", - "requires": { - "follow-redirects": "1.13.0" - } + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, - "babel-runtime": { - "version": "5.8.38", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz", - "integrity": "sha1-HAsC62MxL18If/IEUIJ7QlydTBk=", + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "axios": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", "requires": { - "core-js": "1.2.7" + "follow-redirects": "^1.10.0" } }, "balanced-match": { @@ -153,7 +4007,15 @@ "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz", "integrity": "sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA==", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.0.1" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" } }, "bech32": { @@ -162,9 +4024,9 @@ "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" }, "bignumber.js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz", - "integrity": "sha512-eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==" + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" }, "binary-extensions": { "version": "2.1.0", @@ -181,9 +4043,9 @@ } }, "bip174": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bip174/-/bip174-1.0.1.tgz", - "integrity": "sha512-Mq2aFs1TdMfxBpYPg7uzjhsiXbAtoVq44TNjEWtvuZBiBgc3m7+n55orYMtTAxdg7jWbL4DtH0MKocJER4xERQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.0.1.tgz", + "integrity": "sha512-i3X26uKJOkDTAalYAp0Er+qGMDhrbbh2o93/xiPyAN2s25KrClSpe3VXo/7mNJoqA5qfko8rLS2l3RWZgYmjKQ==" }, "bip32": { "version": "2.0.5", @@ -191,12 +4053,12 @@ "integrity": "sha512-zVY4VvJV+b2fS0/dcap/5XLlpqtgwyN8oRkuGgAS1uLOeEp0Yo6Tw2yUTozTtlrMJO3G8n4g/KX/XGFHW6Pq3g==", "requires": { "@types/node": "10.12.18", - "bs58check": "2.1.2", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "tiny-secp256k1": "1.1.5", - "typeforce": "1.18.0", - "wif": "2.0.6" + "bs58check": "^2.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "tiny-secp256k1": "^1.1.3", + "typeforce": "^1.11.5", + "wif": "^2.0.6" } }, "bip39": { @@ -204,11 +4066,11 @@ "resolved": "https://registry.npmjs.org/bip39/-/bip39-2.4.0.tgz", "integrity": "sha512-1++HywqIyPtWDo7gm4v0ylYbwkLvHkuwVSKbBlZBbTCP/mnkyrlARBny906VLAwxJbC5xw9EvuJasHFIZaIFMQ==", "requires": { - "create-hash": "1.2.0", - "pbkdf2": "3.1.1", - "randombytes": "2.1.0", - "safe-buffer": "5.2.1", - "unorm": "1.6.0" + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1", + "safe-buffer": "^5.0.1", + "unorm": "^1.3.3" } }, "bip66": { @@ -216,7 +4078,7 @@ "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.0.1" } }, "bitcoin-ops": { @@ -224,37 +4086,26 @@ "resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz", "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==" }, - "bitcoind-rpc-client": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/bitcoind-rpc-client/-/bitcoind-rpc-client-0.3.1.tgz", - "integrity": "sha1-bKiVn5H/f+O9I7f7XTAqnAKu/o0=", - "requires": { - "babel-runtime": "5.8.38", - "make-concurrent": "1.2.0", - "promise-useful-utils": "0.2.1" - } - }, "bitcoinjs-lib": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-5.1.4.tgz", - "integrity": "sha512-tSgxnXC3xEXw5DxKGIHNkzz+pxYzsSViT/XfQVIn8vM/b5kXtg3BJuFg6T1h2zhgG+iClzDf+5S/5wxFIddzWg==", - "requires": { - "@types/node": "10.12.18", - "bech32": "1.1.4", - "bip174": "1.0.1", - "bip32": "2.0.5", - "bip66": "1.1.5", - "bitcoin-ops": "1.4.1", - "bs58check": "2.1.2", - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "merkle-lib": "2.0.10", - "pushdata-bitcoin": "1.0.1", - "randombytes": "2.1.0", - "tiny-secp256k1": "1.1.5", - "typeforce": "1.18.0", - "varuint-bitcoin": "1.1.2", - "wif": "2.0.6" + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-5.2.0.tgz", + "integrity": "sha512-5DcLxGUDejgNBYcieMIUfjORtUeNWl828VWLHJGVKZCb4zIS1oOySTUr0LGmcqJBQgTBz3bGbRQla4FgrdQEIQ==", + "requires": { + "bech32": "^1.1.2", + "bip174": "^2.0.1", + "bip32": "^2.0.4", + "bip66": "^1.1.0", + "bitcoin-ops": "^1.4.0", + "bs58check": "^2.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.3", + "merkle-lib": "^2.0.10", + "pushdata-bitcoin": "^1.0.1", + "randombytes": "^2.0.1", + "tiny-secp256k1": "^1.1.1", + "typeforce": "^1.11.3", + "varuint-bitcoin": "^1.0.4", + "wif": "^2.0.1" } }, "bitcoinjs-message": { @@ -262,11 +4113,11 @@ "resolved": "https://registry.npmjs.org/bitcoinjs-message/-/bitcoinjs-message-1.0.1.tgz", "integrity": "sha1-P8xfHYX53TCsYNERlIyxs7T+nMU=", "requires": { - "bs58check": "1.3.4", - "buffer-equals": "1.0.4", - "create-hash": "1.2.0", - "secp256k1": "3.8.0", - "varuint-bitcoin": "1.1.2" + "bs58check": "^1.0.8", + "buffer-equals": "^1.0.3", + "create-hash": "^1.1.2", + "secp256k1": "^3.0.1", + "varuint-bitcoin": "^1.0.1" }, "dependencies": { "base-x": { @@ -279,7 +4130,7 @@ "resolved": "https://registry.npmjs.org/bs58/-/bs58-3.1.0.tgz", "integrity": "sha1-1MJjiL9IBMrHFBQbGUWqR+XrJI4=", "requires": { - "base-x": "1.1.0" + "base-x": "^1.1.0" } }, "bs58check": { @@ -287,19 +4138,19 @@ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-1.3.4.tgz", "integrity": "sha1-xSVABzdJEXcU+gQsMEfrj5FRy/g=", "requires": { - "bs58": "3.1.0", - "create-hash": "1.2.0" + "bs58": "^3.1.0", + "create-hash": "^1.1.0" } } } }, "bl": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", "requires": { - "readable-stream": "2.3.7", - "safe-buffer": "5.2.1" + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" }, "dependencies": { "readable-stream": { @@ -307,13 +4158,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" }, "dependencies": { "safe-buffer": { @@ -328,7 +4179,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" }, "dependencies": { "safe-buffer": { @@ -346,20 +4197,54 @@ "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==" }, "body-parser": { - "version": "1.18.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", - "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", "requires": { - "bytes": "3.0.0", - "content-type": "1.0.4", + "bytes": "3.1.0", + "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "on-finished": "2.3.0", - "qs": "6.5.2", - "raw-body": "2.3.3", - "type-is": "1.6.18" + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } } }, "bowser": { @@ -373,7 +4258,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -383,7 +4268,7 @@ "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "requires": { - "fill-range": "7.0.1" + "fill-range": "^7.0.1" } }, "brorand": { @@ -402,12 +4287,12 @@ "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "evp_bytestokey": "1.0.3", - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "bs58": { @@ -415,7 +4300,7 @@ "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha1-vhYedsNU9veIrkBx9j806MTwpCo=", "requires": { - "base-x": "3.0.8" + "base-x": "^3.0.2" } }, "bs58check": { @@ -423,9 +4308,9 @@ "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", "requires": { - "bs58": "4.0.1", - "create-hash": "1.2.0", - "safe-buffer": "5.2.1" + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" } }, "buffer-alloc": { @@ -433,8 +4318,8 @@ "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", "requires": { - "buffer-alloc-unsafe": "1.1.0", - "buffer-fill": "1.0.0" + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" } }, "buffer-alloc-unsafe": { @@ -462,10 +4347,13 @@ "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "bufferutil": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz", + "integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==", + "requires": { + "node-gyp-build": "^4.2.0" + } }, "camelcase": { "version": "5.3.1", @@ -478,15 +4366,20 @@ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs=" }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.5.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "dependencies": { "supports-color": { @@ -495,7 +4388,7 @@ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } } } @@ -506,14 +4399,13 @@ "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", "dev": true, "requires": { - "anymatch": "3.1.1", - "braces": "3.0.2", - "fsevents": "2.1.3", - "glob-parent": "5.1.1", - "is-binary-path": "2.1.0", - "is-glob": "4.0.1", - "normalize-path": "3.0.0", - "readdirp": "3.2.0" + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" } }, "chownr": { @@ -526,8 +4418,8 @@ "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", "requires": { - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "cliui": { @@ -536,9 +4428,9 @@ "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "dev": true, "requires": { - "string-width": "3.1.0", - "strip-ansi": "5.2.0", - "wrap-ansi": "5.1.0" + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" }, "dependencies": { "ansi-regex": { @@ -559,9 +4451,9 @@ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { @@ -570,7 +4462,7 @@ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "4.1.0" + "ansi-regex": "^4.1.0" } } } @@ -595,6 +4487,14 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -606,11 +4506,6 @@ "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, "content-security-policy-builder": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", @@ -621,21 +4516,6 @@ "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -646,11 +4526,11 @@ "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.4", - "md5.js": "1.3.5", - "ripemd160": "2.0.2", - "sha.js": "2.4.11" + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" } }, "create-hmac": { @@ -658,12 +4538,29 @@ "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.2.0", - "inherits": "2.0.4", - "ripemd160": "2.0.2", - "safe-buffer": "5.2.1", - "sha.js": "2.4.11" + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" } }, "dasherize": { @@ -690,7 +4587,7 @@ "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", "requires": { - "mimic-response": "1.0.1" + "mimic-response": "^1.0.0" } }, "deep-extend": { @@ -704,9 +4601,14 @@ "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "dev": true, "requires": { - "object-keys": "1.1.1" + "object-keys": "^1.0.12" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", @@ -717,11 +4619,6 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, "detect-libc": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", @@ -748,9 +4645,18 @@ "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", "integrity": "sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs=", "requires": { - "browserify-aes": "1.2.0", - "create-hash": "1.2.0", - "create-hmac": "1.1.7" + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "ecdsa-sig-formatter": { @@ -758,7 +4664,7 @@ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.0.1" } }, "ee-first": { @@ -767,17 +4673,17 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "elliptic": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz", - "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", "requires": { - "bn.js": "4.11.9", - "brorand": "1.1.0", - "hash.js": "1.1.7", - "hmac-drbg": "1.0.1", - "inherits": "2.0.4", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, "emoji-regex": { @@ -786,25 +4692,12 @@ "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "dev": true }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, "end-of-stream": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "requires": { - "once": "1.4.0" - } - }, - "error-system": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/error-system/-/error-system-1.0.1.tgz", - "integrity": "sha1-BxU79HecB5Dnpg7QXvn0fRMYagI=", - "requires": { - "inherits": "2.0.4" + "once": "^1.4.0" } }, "es-abstract": { @@ -813,17 +4706,35 @@ "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", "dev": true, "requires": { - "es-to-primitive": "1.2.1", - "function-bind": "1.1.1", - "has": "1.0.3", - "has-symbols": "1.0.1", - "is-callable": "1.2.0", - "is-regex": "1.1.0", - "object-inspect": "1.8.0", - "object-keys": "1.1.1", - "object.assign": "4.1.0", - "string.prototype.trimend": "1.0.1", - "string.prototype.trimstart": "1.0.1" + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-content-type": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/es-content-type/-/es-content-type-0.0.10.tgz", + "integrity": "sha512-yCgcv1M2IuFUoGZ3zE4OR2INGmZOwEuyaE5WX4MOKGpJcO8JXgVOIcXVicwnTqlxvx6qs9IJGl/Rr1+YtCkRgg==" + }, + "es-fresh": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/es-fresh/-/es-fresh-0.0.8.tgz", + "integrity": "sha512-ZM+K/T/zHJVuOhaz19iymidACazB1fl2uihBtSfRie8YzN1YM+KldVmNaU+GSmVvTOPSO2utKOhxcOinr5tKjw==" + }, + "es-mime-types": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/es-mime-types/-/es-mime-types-0.0.16.tgz", + "integrity": "sha512-84QoSLeA7cdTeHpALFNl3ZOstXfvLt426/kaOgmSxmNUOhi4GesKVkhJgIfnsqGNziYezVA8rvZUsXj7oWX2qQ==", + "requires": { + "mime-db": "^1.44.0" } }, "es-to-primitive": { @@ -832,9 +4743,34 @@ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", "dev": true, "requires": { - "is-callable": "1.2.0", - "is-date-object": "1.0.2", - "is-symbol": "1.0.3" + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es-vary": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/es-vary/-/es-vary-0.0.8.tgz", + "integrity": "sha512-fiERjQiCHrXUAToNRT/sh7MtXnfei9n7cF9oVQRUEp9L5BGXsTKSPaXq8L+4v0c/ezfvuTWd/f0JSl5IBRUvSg==" + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" } }, "es6-promise": { @@ -847,7 +4783,16 @@ "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { - "es6-promise": "4.2.8" + "es6-promise": "^4.0.3" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" } }, "escape-html": { @@ -867,18 +4812,13 @@ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", "requires": { - "md5.js": "1.3.5", - "safe-buffer": "5.2.1" + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" } }, "expand-template": { @@ -886,136 +4826,40 @@ "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-1.1.1.tgz", "integrity": "sha512-cebqLtV8KOZfw0UI8TEFWxtczxxC1jvyUvx6H4fyp1K1FN7A4Q+uggVUlOsI1K8AGU0rwOGqP8nCapdrw8CYQg==" }, - "express": { - "version": "4.16.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", - "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", - "requires": { - "accepts": "1.3.7", - "array-flatten": "1.1.1", - "body-parser": "1.18.2", - "content-disposition": "0.5.2", - "content-type": "1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "1.1.2", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", - "finalhandler": "1.1.1", - "fresh": "0.5.2", - "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "2.0.6", - "qs": "6.5.1", - "range-parser": "1.2.1", - "safe-buffer": "5.1.1", - "send": "0.16.2", - "serve-static": "1.13.2", - "setprototypeof": "1.1.0", - "statuses": "1.4.0", - "type-is": "1.6.18", - "utils-merge": "1.0.1", - "vary": "1.1.2" - }, - "dependencies": { - "body-parser": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", - "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", - "requires": { - "bytes": "3.0.0", - "content-type": "1.0.4", - "debug": "2.6.9", - "depd": "1.1.2", - "http-errors": "1.6.3", - "iconv-lite": "0.4.19", - "on-finished": "2.3.0", - "qs": "6.5.1", - "raw-body": "2.3.2", - "type-is": "1.6.18" - } - }, - "iconv-lite": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" - }, - "raw-body": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", - "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.2", - "iconv-lite": "0.4.19", - "unpipe": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": "1.4.0" - } - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - } - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==" } } }, - "express-jwt": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/express-jwt/-/express-jwt-5.3.1.tgz", - "integrity": "sha512-1C9RNq0wMp/JvsH/qZMlg3SIPvKu14YkZ4YYv7gJQ1Vq+Dv8LH9tLKenS5vMNth45gTlEUGx+ycp9IHIlaHP/g==", - "requires": { - "async": "1.5.2", - "express-unless": "0.3.1", - "jsonwebtoken": "8.5.1", - "lodash.set": "4.3.2" - } + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, - "express-unless": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/express-unless/-/express-unless-0.3.1.tgz", - "integrity": "sha1-JVfBRudb65A+LSR/m1ugFFJpbiA=" + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "feature-policy": { "version": "0.3.0", @@ -1033,28 +4877,7 @@ "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "to-regex-range": "5.0.1" - } - }, - "finalhandler": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", - "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.3", - "statuses": "1.4.0", - "unpipe": "1.0.0" - }, - "dependencies": { - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } + "to-regex-range": "^5.0.1" } }, "find-up": { @@ -1063,7 +4886,7 @@ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "locate-path": "3.0.0" + "locate-path": "^3.0.0" } }, "flat": { @@ -1072,23 +4895,28 @@ "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", "dev": true, "requires": { - "is-buffer": "2.0.4" + "is-buffer": "~2.0.3" } }, "follow-redirects": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", - "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==" + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz", + "integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==" }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "form-data": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } }, "fs-constants": { "version": "1.0.0", @@ -1101,13 +4929,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", - "dev": true, - "optional": true - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -1119,27 +4940,30 @@ "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.3", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.3" + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" } }, - "generic-pool": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.4.2.tgz", - "integrity": "sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==" - }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -1151,12 +4975,12 @@ "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.4", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, "glob-parent": { @@ -1165,7 +4989,7 @@ "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", "dev": true, "requires": { - "is-glob": "4.0.1" + "is-glob": "^4.0.1" } }, "growl": { @@ -1174,13 +4998,27 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, "requires": { - "function-bind": "1.1.1" + "function-bind": "^1.1.1" } }, "has-flag": { @@ -1205,9 +5043,9 @@ "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", "requires": { - "inherits": "2.0.4", - "readable-stream": "3.6.0", - "safe-buffer": "5.2.1" + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" } }, "hash.js": { @@ -1215,8 +5053,8 @@ "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", "requires": { - "inherits": "2.0.4", - "minimalistic-assert": "1.0.1" + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, "he": { @@ -1276,9 +5114,9 @@ "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", "requires": { - "hash.js": "1.1.7", - "minimalistic-assert": "1.0.1", - "minimalistic-crypto-utils": "1.0.1" + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, "hpkp": { @@ -1301,30 +5139,22 @@ } } }, - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "depd": "1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": "1.5.0" - }, - "dependencies": { - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - } + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { - "safer-buffer": "2.1.2" + "safer-buffer": ">= 2.1.2 < 3" } }, "inflight": { @@ -1333,8 +5163,8 @@ "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -1343,9 +5173,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "ip": { "version": "1.1.5", @@ -1353,9 +5183,9 @@ "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.0.tgz", + "integrity": "sha512-S54H9mIj0rbxRIyrDMEuuER86LdlgUg9FSeZ8duQb6CUG2iRrA36MYVQBSprTF/ZeAwvyQ5mDGuNvIPM0BIl3w==" }, "is-binary-path": { "version": "2.1.0", @@ -1363,7 +5193,7 @@ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "requires": { - "binary-extensions": "2.1.0" + "binary-extensions": "^2.0.0" } }, "is-buffer": { @@ -1395,7 +5225,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "1.0.1" + "number-is-nan": "^1.0.0" } }, "is-glob": { @@ -1404,7 +5234,7 @@ "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", "dev": true, "requires": { - "is-extglob": "2.1.1" + "is-extglob": "^2.1.1" } }, "is-number": { @@ -1419,7 +5249,7 @@ "integrity": "sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw==", "dev": true, "requires": { - "has-symbols": "1.0.1" + "has-symbols": "^1.0.1" } }, "is-symbol": { @@ -1428,7 +5258,7 @@ "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", "dev": true, "requires": { - "has-symbols": "1.0.1" + "has-symbols": "^1.0.1" } }, "is-typedarray": { @@ -1447,40 +5277,76 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, "js-yaml": { "version": "3.13.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "requires": { - "argparse": "1.0.10", - "esprima": "4.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, "jsonwebtoken": { "version": "8.5.1", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "requires": { - "jws": "3.2.2", - "lodash.includes": "4.3.0", - "lodash.isboolean": "3.0.3", - "lodash.isinteger": "4.0.4", - "lodash.isnumber": "3.0.3", - "lodash.isplainobject": "4.0.6", - "lodash.isstring": "4.0.1", - "lodash.once": "4.1.1", - "ms": "2.1.2", - "semver": "5.7.1" + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" }, "dependencies": { "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -1488,7 +5354,7 @@ "requires": { "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "5.2.1" + "safe-buffer": "^5.0.1" } }, "jws": { @@ -1496,8 +5362,8 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", "requires": { - "jwa": "1.4.1", - "safe-buffer": "5.2.1" + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" } }, "locate-path": { @@ -1506,14 +5372,14 @@ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "p-locate": "3.0.0", - "path-exists": "3.0.0" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "lodash.includes": { "version": "4.3.0", @@ -1550,18 +5416,13 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=" - }, "log-symbols": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", "dev": true, "requires": { - "chalk": "2.4.2" + "chalk": "^2.4.2" } }, "lru-cache": { @@ -1569,26 +5430,23 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" } }, "make-concurrent": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/make-concurrent/-/make-concurrent-1.2.0.tgz", - "integrity": "sha1-2XfixWy4hXfCyDlONAzZ7rJc80Y=", - "requires": { - "babel-runtime": "5.8.38" - } + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/make-concurrent/-/make-concurrent-5.3.0.tgz", + "integrity": "sha512-8si1KzXm7DiUXSbeOPliY9MrNVFGaEEgKZNctxz9FM3Ztx/cb5qiUazD/8WurKCJL05/zizZHBXYdjXRNAvtFA==" }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", "requires": { - "hash-base": "3.1.0", - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" } }, "media-typer": { @@ -1596,37 +5454,27 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, "merkle-lib": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz", "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY=" }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==" }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==" }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", "requires": { - "mime-db": "1.44.0" + "mime-db": "1.47.0" } }, "mimic-response": { @@ -1650,27 +5498,20 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.3.tgz", - "integrity": "sha512-+bMdgqjMN/Z77a6NlY/I3U5LlRDbnmaAk6lDveAPKwSpcPM4tKAuYsvYF8xjhOPXhOYGe/73vVLVez5PW+jqhw==" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mkdirp": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "requires": { - "minimist": "1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - } + "minimist": "^1.2.5" } }, "mocha": { @@ -1711,7 +5552,7 @@ "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", "dev": true, "requires": { - "ms": "2.1.1" + "ms": "^2.1.1" } }, "ms": { @@ -1728,28 +5569,28 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, "mysql": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.16.0.tgz", - "integrity": "sha512-dPbN2LHonQp7D5ja5DJXNbCLe/HRdu+f3v61aguzNRQIrmZLOeRoymBYyeThrR6ug+FqzDL95Gc9maqZUJS+Gw==", + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", "requires": { - "bignumber.js": "4.1.0", - "readable-stream": "2.3.6", + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" }, "dependencies": { "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -1762,7 +5603,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -1777,6 +5618,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, "nocache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", @@ -1787,7 +5633,7 @@ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.18.0.tgz", "integrity": "sha512-yi05ZoiuNNEbyT/xXfSySZE+yVnQW6fxPZuFbLyS1s6b5Kw3HzV2PHOM4XR+nsjzkHxByK+2Wg+yCQbe35l8dw==", "requires": { - "semver": "5.7.1" + "semver": "^5.4.1" } }, "node-environment-flags": { @@ -1796,10 +5642,15 @@ "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", "dev": true, "requires": { - "object.getownpropertydescriptors": "2.1.0", - "semver": "5.7.1" + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" } }, + "node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==" + }, "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", @@ -1816,10 +5667,10 @@ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { - "are-we-there-yet": "1.1.5", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" } }, "number-is-nan": { @@ -1827,6 +5678,11 @@ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1850,10 +5706,10 @@ "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", "dev": true, "requires": { - "define-properties": "1.1.3", - "function-bind": "1.1.1", - "has-symbols": "1.0.1", - "object-keys": "1.1.1" + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" } }, "object.getownpropertydescriptors": { @@ -1862,8 +5718,8 @@ "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.17.6" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" } }, "on-finished": { @@ -1879,7 +5735,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { - "wrappy": "1.0.2" + "wrappy": "1" } }, "os-homedir": { @@ -1893,7 +5749,7 @@ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { - "p-try": "2.2.0" + "p-try": "^2.0.0" } }, "p-locate": { @@ -1902,7 +5758,7 @@ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "dev": true, "requires": { - "p-limit": "2.3.0" + "p-limit": "^2.0.0" } }, "p-try": { @@ -1911,17 +5767,12 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, "passport": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", - "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", "requires": { - "passport-strategy": "1.0.0", + "passport-strategy": "1.x.x", "pause": "0.0.1" } }, @@ -1930,8 +5781,8 @@ "resolved": "https://registry.npmjs.org/passport-localapikey-update/-/passport-localapikey-update-0.6.0.tgz", "integrity": "sha512-NklCLY68AdepFID+HQ9CVPqRKKYIPw+fGQBsQoP/WZ2ovVfmJ0Qx7eoBpUtpta0vyav2TPDoHSAKoHTjO+LPcw==", "requires": { - "passport-strategy": "1.0.0", - "pkginfo": "0.2.3" + "passport-strategy": "1.x.x", + "pkginfo": "0.2.x" } }, "passport-strategy": { @@ -1951,11 +5802,6 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, "pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", @@ -1966,13 +5812,18 @@ "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", "requires": { - "create-hash": "1.2.0", - "create-hmac": "1.1.7", - "ripemd160": "2.0.2", - "safe-buffer": "5.2.1", - "sha.js": "2.4.11" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -1989,21 +5840,21 @@ "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-2.5.3.tgz", "integrity": "sha512-/rI36cN2g7vDQnKWN8Uzupi++KjyqS9iS+/fpwG4Ea8d0Pip0PQ5bshUNzVwt+/D2MRfhVAplYMMvWLqWrCF/g==", "requires": { - "detect-libc": "1.0.3", - "expand-template": "1.1.1", + "detect-libc": "^1.0.3", + "expand-template": "^1.0.2", "github-from-package": "0.0.0", - "minimist": "1.2.3", - "mkdirp": "0.5.5", - "node-abi": "2.18.0", - "noop-logger": "0.1.1", - "npmlog": "4.1.2", - "os-homedir": "1.0.2", - "pump": "2.0.1", - "rc": "1.2.8", - "simple-get": "2.8.1", - "tar-fs": "1.16.3", - "tunnel-agent": "0.6.0", - "which-pm-runs": "1.0.0" + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "node-abi": "^2.2.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.1.6", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" } }, "process-nextick-args": { @@ -2011,57 +5862,49 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, - "promise-useful-utils": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/promise-useful-utils/-/promise-useful-utils-0.2.1.tgz", - "integrity": "sha1-pDgNGJnia/2kNB1hD4LKCOQmLqw=", - "requires": { - "babel-runtime": "5.8.38", - "error-system": "1.0.1" - } - }, - "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", - "requires": { - "forwarded": "0.1.2", - "ipaddr.js": "1.9.1" - } - }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, "pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { - "end-of-stream": "1.4.4", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, "pushdata-bitcoin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz", "integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=", "requires": { - "bitcoin-ops": "1.4.1" + "bitcoin-ops": "^1.3.0" } }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.1.0" } }, "range-parser": { @@ -2070,14 +5913,48 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + } } }, "rc": { @@ -2085,10 +5962,10 @@ "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { - "deep-extend": "0.6.0", - "ini": "1.3.5", - "minimist": "1.2.3", - "strip-json-comments": "2.0.1" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, "readable-stream": { @@ -2096,9 +5973,9 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { - "inherits": "2.0.4", - "string_decoder": "1.3.0", - "util-deprecate": "1.0.2" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, "readdirp": { @@ -2107,7 +5984,7 @@ "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", "dev": true, "requires": { - "picomatch": "2.2.2" + "picomatch": "^2.0.4" } }, "referrer-policy": { @@ -2115,6 +5992,73 @@ "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==" }, + "regexparam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-1.3.0.tgz", + "integrity": "sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g==" + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "request-promise-core": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", + "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", + "requires": { + "lodash": "^4.17.19" + } + }, + "request-promise-native": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", + "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", + "requires": { + "request-promise-core": "1.1.4", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2132,8 +6076,26 @@ "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "requires": { - "hash-base": "3.1.0", - "inherits": "2.0.4" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rpc-bitcoin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/rpc-bitcoin/-/rpc-bitcoin-2.0.0.tgz", + "integrity": "sha512-o+DJHCuuuTJIJgWD1De3fGWd/ulpHb/Nn87qSh0Zn6+ur1pvyJU6TzvIlYAW6EWtCCyZdwbEXL3+Jpmh3/7EvQ==", + "requires": { + "rpc-request": "^4.0.9" + } + }, + "rpc-request": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/rpc-request/-/rpc-request-4.0.10.tgz", + "integrity": "sha512-VQIogs0wYpRBxmliXxOK6sDj+BCS/AFwPjroffwg7l5Dxur0l1YkljtB/pdYj0p31U0seEiwKeYr0j7xTY0Clg==", + "requires": { + "@types/request-promise-native": "^1.0.17", + "request": "^2.88.2", + "request-promise-native": "^1.0.9" } }, "safe-buffer": { @@ -2151,14 +6113,14 @@ "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.8.0.tgz", "integrity": "sha512-k5ke5avRZbtl9Tqx/SA7CbY3NF6Ro+Sj9cZxezFzuBlLDmyqPiL8hJJ+EmzD8Ig4LUDByHJ3/iPOVoRixs/hmw==", "requires": { - "bindings": "1.5.0", - "bip66": "1.1.5", - "bn.js": "4.11.9", - "create-hash": "1.2.0", - "drbg.js": "1.0.1", - "elliptic": "6.5.3", - "nan": "2.14.1", - "safe-buffer": "5.2.1" + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.5.2", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" } }, "semver": { @@ -2166,61 +6128,18 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, - "send": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", - "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", - "requires": { - "debug": "2.6.9", - "depd": "1.1.2", - "destroy": "1.0.4", - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "etag": "1.8.1", - "fresh": "0.5.2", - "http-errors": "1.6.3", - "mime": "1.4.1", - "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.1", - "statuses": "1.4.0" - }, - "dependencies": { - "statuses": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", - "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" - } - } - }, - "serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", - "requires": { - "encodeurl": "1.0.2", - "escape-html": "1.0.3", - "parseurl": "1.3.3", - "send": "0.16.2" - } - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "requires": { - "inherits": "2.0.4", - "safe-buffer": "5.2.1" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, "signal-exit": { @@ -2238,9 +6157,19 @@ "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.1.tgz", "integrity": "sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw==", "requires": { - "decompress-response": "3.3.0", - "once": "1.4.0", - "simple-concat": "1.0.1" + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "sirv": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.11.tgz", + "integrity": "sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg==", + "requires": { + "@polka/url": "^1.0.0-next.9", + "mime": "^2.3.1", + "totalist": "^1.0.0" } }, "smart-buffer": { @@ -2253,7 +6182,7 @@ "resolved": "https://registry.npmjs.org/socks/-/socks-2.2.3.tgz", "integrity": "sha512-+2r83WaRT3PXYoO/1z+RDEBE7Z2f9YcdQnJ0K/ncXXbV5gJ6wYfNAebYFYiiUjM6E4JyXnPY8cimwyvFYHVUUA==", "requires": { - "ip": "1.1.5", + "ip": "^1.1.5", "smart-buffer": "4.0.2" } }, @@ -2262,8 +6191,8 @@ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz", "integrity": "sha512-Kezx6/VBguXOsEe5oU3lXYyKMi4+gva72TwJ7pQY5JfqUx2nMk7NXA6z/mpNqIlfQjWYVfeuNvQjexiTaTn6Nw==", "requires": { - "agent-base": "4.2.1", - "socks": "2.2.3" + "agent-base": "~4.2.0", + "socks": "~2.2.0" } }, "sprintf-js": { @@ -2277,19 +6206,43 @@ "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", "integrity": "sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A=" }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string.prototype.trimend": { @@ -2298,8 +6251,8 @@ "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.17.6" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, "string.prototype.trimstart": { @@ -2308,16 +6261,8 @@ "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", "dev": true, "requires": { - "define-properties": "1.1.3", - "es-abstract": "1.17.6" - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "5.2.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" } }, "strip-ansi": { @@ -2325,7 +6270,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.1.1" + "ansi-regex": "^2.0.0" } }, "strip-json-comments": { @@ -2339,7 +6284,7 @@ "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", "dev": true, "requires": { - "has-flag": "3.0.0" + "has-flag": "^3.0.0" } }, "tar-fs": { @@ -2347,10 +6292,10 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", "requires": { - "chownr": "1.1.4", - "mkdirp": "0.5.5", - "pump": "1.0.3", - "tar-stream": "1.6.2" + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" }, "dependencies": { "pump": { @@ -2358,8 +6303,8 @@ "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", "requires": { - "end-of-stream": "1.4.4", - "once": "1.4.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } } } @@ -2369,13 +6314,13 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", "requires": { - "bl": "1.2.2", - "buffer-alloc": "1.2.0", - "end-of-stream": "1.4.4", - "fs-constants": "1.0.0", - "readable-stream": "2.3.7", - "to-buffer": "1.1.1", - "xtend": "4.0.2" + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" }, "dependencies": { "readable-stream": { @@ -2383,13 +6328,13 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.4", - "isarray": "1.0.0", - "process-nextick-args": "2.0.1", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, "safe-buffer": { @@ -2402,7 +6347,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "~5.1.0" } } } @@ -2412,11 +6357,11 @@ "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.5.tgz", "integrity": "sha512-duE2hSLSQIpHGzmK48OgRrGTi+4OTkXLC6aa86uOYQ6LLCYZSarVKIAvEtY7MoXjoL6bOXMSerEGMzrvW4SkDw==", "requires": { - "bindings": "1.5.0", - "bn.js": "4.11.9", - "create-hmac": "1.1.7", - "elliptic": "6.5.3", - "nan": "2.14.1" + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" } }, "to-buffer": { @@ -2430,7 +6375,26 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "7.0.0" + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "totalist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", + "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "tunnel-agent": { @@ -2438,16 +6402,26 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.0.1" } }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "requires": { "media-typer": "0.3.0", - "mime-types": "2.1.27" + "mime-types": "~2.1.24" } }, "typedarray-to-buffer": { @@ -2455,7 +6429,7 @@ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "requires": { - "is-typedarray": "1.0.0" + "is-typedarray": "^1.0.0" } }, "typeforce": { @@ -2473,15 +6447,31 @@ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "utf-8-validate": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.5.tgz", + "integrity": "sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ==", + "requires": { + "node-gyp-build": "^4.2.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" }, "validator": { "version": "10.8.0", @@ -2493,23 +6483,30 @@ "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", "requires": { - "safe-buffer": "5.2.1" + "safe-buffer": "^5.1.1" } }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } }, "websocket": { - "version": "1.0.28", - "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.28.tgz", - "integrity": "sha512-00y/20/80P7H4bCYkzuuvvfDvh+dgtXi5kzDf3UcZwN6boTYaKvsrtZ5lIYm1Gsg48siMErd9M4zjSYfYFHTrA==", + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz", + "integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==", "requires": { - "debug": "2.6.9", - "nan": "2.14.1", - "typedarray-to-buffer": "3.1.5", - "yaeti": "0.0.6" + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.50", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" } }, "which": { @@ -2518,7 +6515,7 @@ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "which-module": { @@ -2537,7 +6534,7 @@ "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", "requires": { - "string-width": "1.0.2" + "string-width": "^1.0.2 || 2" } }, "wif": { @@ -2545,18 +6542,23 @@ "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", "integrity": "sha1-CNP1IFbGZnkplyb63g1DKudLRwQ=", "requires": { - "bs58check": "2.1.2" + "bs58check": "<3.0.0" } }, + "workerpool": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.4.tgz", + "integrity": "sha512-jGWPzsUqzkow8HoAvqaPWTUPCrlPJaJ5tY8Iz7n1uCz3tTp6s3CDG0FF1NsX42WNlkRSW6Mr+CDZGnNoSsKa7g==" + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "dev": true, "requires": { - "ansi-styles": "3.2.1", - "string-width": "3.1.0", - "strip-ansi": "5.2.0" + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" }, "dependencies": { "ansi-regex": { @@ -2577,9 +6579,9 @@ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { @@ -2588,7 +6590,7 @@ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "4.1.0" + "ansi-regex": "^4.1.0" } } } @@ -2609,9 +6611,9 @@ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yaeti": { @@ -2630,16 +6632,16 @@ "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", "dev": true, "requires": { - "cliui": "5.0.0", - "find-up": "3.0.0", - "get-caller-file": "2.0.5", - "require-directory": "2.1.1", - "require-main-filename": "2.0.0", - "set-blocking": "2.0.0", - "string-width": "3.1.0", - "which-module": "2.0.0", - "y18n": "4.0.0", - "yargs-parser": "13.1.2" + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" }, "dependencies": { "ansi-regex": { @@ -2660,9 +6662,9 @@ "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "dev": true, "requires": { - "emoji-regex": "7.0.3", - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "5.2.0" + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" } }, "strip-ansi": { @@ -2671,7 +6673,7 @@ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "dev": true, "requires": { - "ansi-regex": "4.1.0" + "ansi-regex": "^4.1.0" } } } @@ -2682,8 +6684,8 @@ "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", "dev": true, "requires": { - "camelcase": "5.3.1", - "decamelize": "1.2.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" } }, "yargs-unparser": { @@ -2692,9 +6694,9 @@ "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", "dev": true, "requires": { - "flat": "4.1.0", - "lodash": "4.17.19", - "yargs": "13.3.2" + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" } }, "zeromq": { @@ -2702,8 +6704,8 @@ "resolved": "https://registry.npmjs.org/zeromq/-/zeromq-4.2.0.tgz", "integrity": "sha1-4RMzBd9zyE+MffBgqOKzA7THLX8=", "requires": { - "nan": "2.14.1", - "prebuild-install": "2.5.3" + "nan": "^2.4.0", + "prebuild-install": "^2.1.1" } } } diff --git a/package.json b/package.json index 4f6aa28..9d547f5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "samourai-dojo", - "version": "1.9.0", + "version": "1.10.0", "description": "Backend server for Samourai Wallet", "main": "accounts/index.js", "scripts": { @@ -14,26 +14,28 @@ "license": "AGPL-3.0-only", "homepage": "https://code.samourai.io/dojo/samourai-dojo", "dependencies": { + "@tinyhttp/app": "1.3.3", "async-sema": "2.1.2", - "axios": "0.20.0", + "axios": "0.21.1", "bip39": "2.4.0", - "bitcoind-rpc-client": "0.3.1", - "bitcoinjs-lib": "5.1.4", + "bitcoinjs-lib": "5.2.0", "bitcoinjs-message": "1.0.1", - "body-parser": "1.18.3", - "express": "4.16.3", - "express-jwt": "5.3.1", - "generic-pool": "3.4.2", + "body-parser": "1.19.0", "helmet": "3.23.3", - "lodash": "4.17.19", + "jsonwebtoken": "8.5.1", + "lodash": "4.17.21", "lru-cache": "4.0.2", - "minimist": "1.2.3", - "mysql": "2.16.0", - "passport": "0.4.0", + "make-concurrent": "5.3.0", + "minimist": "1.2.5", + "mysql": "2.18.1", + "passport": "0.4.1", "passport-localapikey-update": "0.6.0", + "rpc-bitcoin": "2.0.0", + "sirv": "1.0.11", "socks-proxy-agent": "4.0.1", "validator": "10.8.0", - "websocket": "1.0.28", + "websocket": "1.0.34", + "workerpool": "6.1.4", "zeromq": "4.2.0" }, "devDependencies": { diff --git a/pushtx/index-orchestrator.js b/pushtx/index-orchestrator.js index 15b0f85..ef581f7 100644 --- a/pushtx/index-orchestrator.js +++ b/pushtx/index-orchestrator.js @@ -8,7 +8,7 @@ const Logger = require('../lib/logger') const db = require('../lib/db/mysql-db-wrapper') - const RpcClient = require('../lib/bitcoind-rpc/rpc-client') + const { waitForBitcoindRpcApi } = require('../lib/bitcoind-rpc/rpc-client') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] const Orchestrator = require('./orchestrator') @@ -23,7 +23,7 @@ // Wait for Bitcoind RPC API // being ready to process requests - await RpcClient.waitForBitcoindRpcApi() + await waitForBitcoindRpcApi() // Initialize the db wrapper const dbConfig = { diff --git a/pushtx/index.js b/pushtx/index.js index 022e882..e8fa5f3 100644 --- a/pushtx/index.js +++ b/pushtx/index.js @@ -8,7 +8,7 @@ const Logger = require('../lib/logger') const db = require('../lib/db/mysql-db-wrapper') - const RpcClient = require('../lib/bitcoind-rpc/rpc-client') + const { waitForBitcoindRpcApi } = require('../lib/bitcoind-rpc/rpc-client') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] const HttpServer = require('../lib/http-server/http-server') @@ -24,7 +24,7 @@ // Wait for Bitcoind RPC API // being ready to process requests - await RpcClient.waitForBitcoindRpcApi() + await waitForBitcoindRpcApi() // Initialize the db wrapper const dbConfig = { diff --git a/pushtx/orchestrator.js b/pushtx/orchestrator.js index 8b4f54a..8c87931 100644 --- a/pushtx/orchestrator.js +++ b/pushtx/orchestrator.js @@ -8,7 +8,7 @@ const zmq = require('zeromq') const Sema = require('async-sema') const Logger = require('../lib/logger') const db = require('../lib/db/mysql-db-wrapper') -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') +const { createRpcClient, isConnectionError } = require('../lib/bitcoind-rpc/rpc-client') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] const pushTxProcessor = require('./pushtx-processor') @@ -24,7 +24,7 @@ class Orchestrator { */ constructor() { // RPC client - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() // ZeroMQ socket for bitcoind blocks messages this.blkSock = null // Initialize a semaphor protecting the onBlockHash() method @@ -77,7 +77,7 @@ class Orchestrator { // Retrieve the block height const blockHash = buf.toString('hex') - const header = await this.rpcClient.getblockheader(blockHash, true) + const header = await this.rpcClient.getblockheader({ blockhash: blockHash, verbose: true }) const height = header.height Logger.info(`Orchestrator : Block ${height} ${blockHash}`) @@ -100,7 +100,7 @@ class Orchestrator { // Check if previous transaction has been confirmed if (hasParentTx) { try { - parentTx = await this.rpcClient.getrawtransaction(tx.schParentTxid, true) + parentTx = await this.rpcClient.getrawtransaction({ txid: tx.schParentTxid, verbose: true }) } catch(e) { Logger.error(e, 'Orchestrator : Transaction.getTransaction()') } @@ -116,7 +116,7 @@ class Orchestrator { Logger.error(e, `Orchestrator : Orchestrator.onBlockHash() : ${msg}`) // Check if it's an issue with the connection to the RPC API // (=> immediately stop the loop) - if (RpcClient.isConnectionError(e)) { + if (isConnectionError(e)) { Logger.info('Orchestrator : Connection issue') rpcConnOk = false break diff --git a/pushtx/pushtx-processor.js b/pushtx/pushtx-processor.js index 0ba6d4c..11766e6 100644 --- a/pushtx/pushtx-processor.js +++ b/pushtx/pushtx-processor.js @@ -9,7 +9,8 @@ const zmq = require('zeromq') const Logger = require('../lib/logger') const errors = require('../lib/errors') const db = require('../lib/db/mysql-db-wrapper') -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') +const addrHelper = require('../lib/bitcoin/addresses-helper') const network = require('../lib/bitcoin/network') const activeNet = network.network const keys = require('../keys')[network.key] @@ -24,7 +25,7 @@ if (network.key == 'bitcoin') { /** - * A singleton providing a wrapper + * A singleton providing a wrapper * for pushing transactions with the local bitcoind */ class PushTxProcessor { @@ -36,7 +37,7 @@ class PushTxProcessor { this.notifSock = null this.sources = new Sources() // Initialize the rpc client - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() } /** @@ -52,7 +53,7 @@ class PushTxProcessor { * Enforce a strict verification mode on a list of outputs * @param {string} rawtx - raw bitcoin transaction in hex format * @param {array} vouts - output indices (integer) - * @returns {array} returns the indices of the faulty outputs + * @returns {array} returns the indices of the faulty outputs */ async enforceStrictModeVouts(rawtx, vouts) { const faultyOutputs = [] @@ -63,12 +64,12 @@ class PushTxProcessor { } catch(e) { throw errors.tx.PARSE } - // Check in db if addresses are known and have been used + // Check in db if addresses are known and have been used for (let vout of vouts) { if (vout >= tx.outs.length) throw errors.txout.VOUT const output = tx.outs[vout] - const address = bitcoin.address.fromOutputScript(output.script, activeNet) + const address = addrHelper.outputScript2Address(output.script) const nbTxs = await db.getAddressNbTransactions(address) if (nbTxs == null || nbTxs > 0) faultyOutputs.push(vout) @@ -108,7 +109,7 @@ class PushTxProcessor { // At this point, the raw hex parses as a legitimate transaction. // Attempt to send via RPC to the bitcoind instance try { - const txid = await this.rpcClient.sendrawtransaction(rawtx) + const txid = await this.rpcClient.sendrawtransaction({ hexstring: rawtx }) Logger.info('PushTx : Pushed!') // Update the stats status.updateStats(value) diff --git a/pushtx/status.js b/pushtx/status.js index 918bfb0..7a1aa40 100644 --- a/pushtx/status.js +++ b/pushtx/status.js @@ -10,7 +10,7 @@ const Logger = require('../lib/logger') const db = require('../lib/db/mysql-db-wrapper') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') /** @@ -49,7 +49,7 @@ class Status { amount: 0, count: 0 } - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() } /** @@ -75,8 +75,7 @@ class Status { this.status.push.count = this.stats.count try { - await this._refreshNetworkInfo() - await this._refreshBlockchainInfo() + await Promise.all([this._refreshNetworkInfo(), this._refreshBlockchainInfo()]) } catch (e) { Logger.error(e, 'PushTx : Status.getCurrent() : Error') } finally { @@ -107,7 +106,7 @@ class Status { * Refresh network info */ async _refreshNetworkInfo() { - const info = await this.rpcClient.getNetworkInfo() + const info = await this.rpcClient.getnetworkinfo() this.status.bitcoind.conn = info.connections this.status.bitcoind.version = info.version this.status.bitcoind.protocolversion = info.protocolversion @@ -118,9 +117,9 @@ class Status { * Refresh blockchain info */ async _refreshBlockchainInfo() { - const info = await this.rpcClient.getBlockchainInfo() + const info = await this.rpcClient.getblockchaininfo() this.status.bitcoind.blocks = info.blocks - this.status.bitcoind.testnet = (info.chain != 'main') + this.status.bitcoind.testnet = (info.chain !== 'main') this.status.bitcoind.up = true } diff --git a/pushtx/transactions-scheduler.js b/pushtx/transactions-scheduler.js index 11f085c..00b845c 100644 --- a/pushtx/transactions-scheduler.js +++ b/pushtx/transactions-scheduler.js @@ -10,7 +10,7 @@ const errors = require('../lib/errors') const db = require('../lib/db/mysql-db-wrapper') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') const pushTxProcessor = require('./pushtx-processor') @@ -23,7 +23,7 @@ class TransactionsScheduler { * Constructor */ constructor() { - this.rpcClient = new RpcClient() + this.rpcClient = createRpcClient() } /** @@ -41,7 +41,7 @@ class TransactionsScheduler { script.sort((a,b) => a.hop - b.hop || a.nlocktime - b.nlocktime) // Get the height of last block seen - const info = await this.rpcClient.getBlockchainInfo() + const info = await this.rpcClient.getblockchaininfo() const lastHeight = info.blocks // Get the nLockTime associated to the first transaction diff --git a/scripts/create-first-blocks.js b/scripts/create-first-blocks.js index e103420..bed335d 100644 --- a/scripts/create-first-blocks.js +++ b/scripts/create-first-blocks.js @@ -9,7 +9,7 @@ const Logger = require('../lib/logger') const util = require('../lib/util') const db = require('../lib/db/mysql-db-wrapper') const network = require('../lib/bitcoin/network') -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') const keys = require('../keys')[network.key] @@ -19,7 +19,7 @@ const keys = require('../keys')[network.key] */ // RPC Client requests data from bitcoind -let client = new RpcClient() +let client = createRpcClient() // Database id of the previous block let prevID = null; @@ -28,10 +28,10 @@ let prevID = null; async function processBlock(height) { Logger.info('Start processing block ' + height) - const blockHash = await client.getblockhash(height) + const blockHash = await client.getblockhash({ height }) if (blockHash) { - const header = await client.getblockheader(blockHash, true) + const header = await client.getblockheader({ blockhash: blockHash, verbose: true }) if (header) { const dbBlock = { diff --git a/static/admin/css/style.css b/static/admin/css/style.css index a1da6e6..b4ac1e5 100644 --- a/static/admin/css/style.css +++ b/static/admin/css/style.css @@ -27,6 +27,12 @@ input[type="checkbox"]{ -webkit-transform: scale(1.3); } +input:disabled, select:disabled { + border: 1px solid #8f8f8f; + color: #8f8f8f; + background-color: #3a3d3f; +} + a, a:visited { color: #a1a1a1; } @@ -545,6 +551,17 @@ button { display: inline-block; } +#xpubs-export-actions span { + display: inline; +} + +#xpubs-export-actions select { + width: 240px; + margin-left: 5px; + margin-right: 5px; + display: inline-block; +} + #xpubs-tool-details #xpub-value { overflow: hidden; } diff --git a/static/admin/dmt/status/status.js b/static/admin/dmt/status/status.js index f427e6c..1075172 100644 --- a/static/admin/dmt/status/status.js +++ b/static/admin/dmt/status/status.js @@ -55,8 +55,10 @@ const statusScript = { this.setStatusIndicator('#indexer-status-ind', 'ko') } const indexerType = apiStatus['indexer']['type'] - if (indexerType) + if (indexerType) { + sessionStorage.setItem('indexerType', indexerType) $('#indexer-type').text(indexerType.replace(/_/g, ' ')) + } const indexerUrl = apiStatus['indexer']['url'] if (indexerUrl) $('#indexer-url').text(indexerUrl) diff --git a/static/admin/dmt/xpubs-tools/xpubs-tools.html b/static/admin/dmt/xpubs-tools/xpubs-tools.html index fd7017e..8524c4d 100644 --- a/static/admin/dmt/xpubs-tools/xpubs-tools.html +++ b/static/admin/dmt/xpubs-tools/xpubs-tools.html @@ -59,16 +59,17 @@
- - - + + + +
- Rescan this xpub starting at index + Rescan this XPUB starting at index with a lookahead of @@ -80,12 +81,25 @@
- Do you want to delete this xpub? + Do you want to delete this XPUB?
+
+
+ Do you want to export a list of + + of this XPUB? + + +
+
+
diff --git a/static/admin/dmt/xpubs-tools/xpubs-tools.js b/static/admin/dmt/xpubs-tools/xpubs-tools.js index 2ada7e5..20d93cc 100644 --- a/static/admin/dmt/xpubs-tools/xpubs-tools.js +++ b/static/admin/dmt/xpubs-tools/xpubs-tools.js @@ -12,10 +12,13 @@ const screenXpubsToolsScript = { $('#btn-xpub-details-reset').click(() => {this.showSearchForm()}) $('#btn-xpub-details-rescan').click(() => {this.showRescanForm()}) $('#btn-xpub-details-delete').click(() => {this.showDeletionForm()}) + $('#btn-xpub-details-export').click(() => {this.showExportForm()}) $('#btn-xpub-rescan-go').click(() => {this.rescanXpub()}) $('#btn-xpub-rescan-cancel').click(() => {this.hideRescanForm()}) $('#btn-xpub-delete-go').click(() => {this.deleteXpub()}) $('#btn-xpub-delete-cancel').click(() => {this.hideDeletionForm()}) + $('#btn-xpub-export-go').click(() => {this.exportXpubHistory()}) + $('#btn-xpub-export-cancel').click(() => {this.hideExportForm()}) $('#btn-xpub-import-go').click(() => {this.importXpub()}) $('#btn-xpub-details-retype').click(() => {this.showImportForm(true)}) $('#btn-xpub-import-cancel').click(() => {this.hideImportForm(this.isReimport)}) @@ -27,8 +30,15 @@ const screenXpubsToolsScript = { }, preparePage: function() { + // Disable custom lookahead if data source is a third party explorer + const isTPE = sessionStorage.getItem('indexerType') == 'third_party_explorer' + const isLRI = sessionStorage.getItem('indexerType') == 'local_rest_indexer' + const disableLookahead = isTPE || isLRI + $('#rescan-lookahead').prop('disabled', disableLookahead) + this.hideRescanForm() this.hideDeletionForm() + this.hideExportForm() this.showSearchForm() $("#xpub").focus() }, @@ -144,6 +154,35 @@ const screenXpubsToolsScript = { }) }, + exportXpubHistory: function() { + lib_msg.displayMessage('Exporting the transactional history of this xpub. Please wait...') + + const args = { + 'active': this.currentXpub, + 'page': 0, + 'count': 1000000000 + } + + if ($('#export-type').val() == 'notNull') + args['excludeNullXfer'] = 1 + + return lib_api.getTransactions(args) + .then(result => { + if (result['txs'] && result['txs'].length > 0) { + let content = 'data:text/csv;charset=utf-8,' + content += 'height,txid,date,flow\n' + for (let tx of result['txs']) + content += `${tx['block_height']},${tx['hash']},${new Date(tx['time']*1000).toString()},${tx['result']/100000000}\n` + const encodedURI = encodeURI(content) + window.open(encodedURI) + } + this.hideExportForm() + lib_msg.displayInfo('Transactional history successfully exported.') + }).catch(e => { + lib_errors.processError(e) + }) + }, + checkRescanStatus: function(callback) { this.rescanStatusTimerId = setTimeout(() => { lib_api.getXpubRescanStatus(this.currentXpub) @@ -308,6 +347,17 @@ const screenXpubsToolsScript = { $('#xpubs-tool-actions').show() }, + showExportForm: function() { + $('#xpubs-tool-actions').hide() + $('#xpubs-export-actions').show() + lib_msg.cleanMessagesUi() + }, + + hideExportForm: function() { + $('#xpubs-export-actions').hide() + $('#xpubs-tool-actions').show() + }, + } screenScripts.set('#screen-xpubs-tools', screenXpubsToolsScript) diff --git a/static/admin/lib/api-wrapper.js b/static/admin/lib/api-wrapper.js index 2fdae1d..6dfbcb3 100644 --- a/static/admin/lib/api-wrapper.js +++ b/static/admin/lib/api-wrapper.js @@ -156,6 +156,14 @@ const lib_api = { ) }, + /** + * Transactions + */ + getTransactions: function(arguments) { + let uri = this.baseUri + '/txs' + return this.sendGetUriEncoded(uri, arguments) + }, + /** * Rescans a range of blocks */ diff --git a/static/admin/lib/auth-utils.js b/static/admin/lib/auth-utils.js index 656a3d7..e17557b 100644 --- a/static/admin/lib/auth-utils.js +++ b/static/admin/lib/auth-utils.js @@ -139,6 +139,7 @@ const lib_auth = { this.setRefreshToken(null) this.setAccessToken(null) sessionStorage.setItem('activeTab', '') + sessionStorage.setItem('indexerType', '') lib_cmn.goToHomePage() } diff --git a/tracker/abstract-processor.js b/tracker/abstract-processor.js deleted file mode 100644 index 3f46325..0000000 --- a/tracker/abstract-processor.js +++ /dev/null @@ -1,50 +0,0 @@ -/*! - * tracker/abstract-processor.js - * Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved. - */ -'use strict' - -const RpcClient = require('../lib/bitcoind-rpc/rpc-client') - - -/** - * An abstract class for tracker processors - */ -class AbstractProcessor { - - /** - * Constructor - * @param {object} notifSock - ZMQ socket used for notifications - */ - constructor(notifSock) { - // RPC client - this.client = new RpcClient() - // ZeroMQ socket for notifications sent to others components - this.notifSock = notifSock - } - - /** - * Notify a new transaction - * @param {object} tx - bitcoin transaction - */ - notifyTx(tx) { - // Real-time client updates for this transaction. - // Any address input or output present in transaction - // is a potential client to notify. - if (this.notifSock) - this.notifSock.send(['transaction', JSON.stringify(tx)]) - } - - /** - * Notify a new block - * @param {string} header - block header - */ - notifyBlock(header) { - // Notify clients of the block - if (this.notifSock) - this.notifSock.send(['block', JSON.stringify(header)]) - } - -} - -module.exports = AbstractProcessor diff --git a/tracker/block-worker.js b/tracker/block-worker.js new file mode 100644 index 0000000..f19a2ef --- /dev/null +++ b/tracker/block-worker.js @@ -0,0 +1,173 @@ +/*! + * tracker/block-worker.js + * Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved. + */ +'use strict' + +const { isMainThread, parentPort } = require('worker_threads') +const network = require('../lib/bitcoin/network') +const keys = require('../keys')[network.key] +const db = require('../lib/db/mysql-db-wrapper') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') +const Block = require('./block') + + +/** + * STATUS + */ +const IDLE = 0 +module.exports.IDLE = IDLE + +const INITIALIZED = 1 +module.exports.INITIALIZED = INITIALIZED + +const OUTPUTS_PROCESSED = 2 +module.exports.OUTPUTS_PROCESSED = OUTPUTS_PROCESSED + +const INPUTS_PROCESSED = 3 +module.exports.INPUTS_PROCESSED = INPUTS_PROCESSED + +const TXS_CONFIRMED = 4 +module.exports.TXS_CONFIRMED = TXS_CONFIRMED + +/** + * OPS + */ +const OP_INIT = 0 +module.exports.OP_INIT = OP_INIT + +const OP_PROCESS_OUTPUTS = 1 +module.exports.OP_PROCESS_OUTPUTS = OP_PROCESS_OUTPUTS + +const OP_PROCESS_INPUTS = 2 +module.exports.OP_PROCESS_INPUTS = OP_PROCESS_INPUTS + +const OP_CONFIRM = 3 +module.exports.OP_CONFIRM = OP_CONFIRM + +const OP_RESET = 4 +module.exports.OP_RESET = OP_RESET + + + +/** + * Process message received by the worker + * @param {object} msg - message received by the worker + */ +async function processMessage(msg) { + let res = null + let success = true + + try { + switch(msg.op) { + case OP_INIT: + if (status != IDLE) + throw 'Operation not allowed' + res = await initBlock(msg.header) + break + case OP_PROCESS_OUTPUTS: + if (status != INITIALIZED) + throw 'Operation not allowed' + res = await processOutputs() + break + case OP_PROCESS_INPUTS: + if (status != OUTPUTS_PROCESSED) + throw 'Operation not allowed' + res = await processInputs() + break + case OP_CONFIRM: + if (status != INPUTS_PROCESSED) + throw 'Operation not allowed' + res = await confirmTransactions(msg.blockId) + break + case OP_RESET: + res = await reset() + break + default: + throw 'Invalid Operation' + } + } catch (e) { + success = false + res = e + } finally { + parentPort.postMessage({ + 'op': msg.op, + 'status': success, + 'res': res + }) + } +} + +/** + * Initialize the block + * @param {object} header - block header + */ +async function initBlock(header) { + status = INITIALIZED + const hex = await rpcClient.getblock({ blockhash: header.hash, verbosity: 0 }) + block = new Block(hex, header) + return true +} + +/** + * Process the transactions outputs + */ +async function processOutputs() { + status = OUTPUTS_PROCESSED + txsForBroadcast = await block.processOutputs() + return true +} + +/** + * Process the transactions inputs + */ +async function processInputs() { + status = INPUTS_PROCESSED + const txs = await block.processInputs() + txsForBroadcast = txsForBroadcast.concat(txs) + return true +} + +/** + * Confirm the transactions + * @param {integer} blockId - id of the block in db + */ +async function confirmTransactions(blockId) { + status = TXS_CONFIRMED + const aTxsForBroadcast = [...new Set(txsForBroadcast)] + await block.confirmTransactions(aTxsForBroadcast, blockId) + return aTxsForBroadcast +} + +/** + * Reset + */ +function reset() { + status = IDLE + block = null + txsForBroadcast = [] + return true +} + + +/** + * MAIN + */ +const rpcClient = createRpcClient() +let block = null +let txsForBroadcast = [] +let status = IDLE + +if (!isMainThread) { + db.connect({ + connectionLimit: keys.db.connectionLimitTracker, + acquireTimeout: keys.db.acquireTimeout, + host: keys.db.host, + user: keys.db.user, + password: keys.db.pass, + database: keys.db.database + }) + + reset() + parentPort.on('message', processMessage) +} diff --git a/tracker/block.js b/tracker/block.js index b8cfe91..55161e2 100644 --- a/tracker/block.js +++ b/tracker/block.js @@ -26,44 +26,92 @@ class Block extends TransactionsBundle { super() this.hex = hex this.header = header + + try { + if (hex != null) { + const block = bitcoin.Block.fromHex(hex) + this.transactions = block.transactions + } + } catch (e) { + Logger.error(e, 'Tracker : Block()') + Logger.error(null, header) + return Promise.reject(e) + } } /** * Register the block and transactions of interest in db + * @dev This method isn't used anymore. + * It has been replaced by a parallel processing of blocks. + * (see blocks-processor and block-worker) * @returns {Promise - object[]} returns an array of transactions to be broadcast */ - async checkBlock() { + async processBlock() { Logger.info('Tracker : Beginning to process new block.') - let block - const txsForBroadcast = [] - - try { - block = bitcoin.Block.fromHex(this.hex) - this.transactions = block.transactions - } catch (e) { - Logger.error(e, 'Tracker : Block.checkBlock()') - Logger.error(null, this.header) - return Promise.reject(e) - } - const t0 = Date.now() - let ntx = 0 - - // Filter transactions - const filteredTxs = await this.prefilterTransactions() - - // Check filtered transactions - // and broadcast notifications - await util.seriesCall(filteredTxs, async tx => { - const filteredTx = new Transaction(tx) - const txCheck = await filteredTx.checkTransaction() - if (txCheck && txCheck.broadcast) - txsForBroadcast.push(txCheck.tx) + + const txsForBroadcast = new Map() + + const txsForBroadcast1 = await this.processOutputs() + txsForBroadcast1.map(tx => {txsForBroadcast.set(tx.getId(), tx)}) + + const txsForBroadcast2 = await this.processInputs() + txsForBroadcast2.map(tx => {txsForBroadcast.set(tx.getId(), tx)}) + + const aTxsForBroadcast = [...txsForBroadcast.values()] + + const blockId = await this.registerBlock() + + await this.confirmTransactions(aTxsForBroadcast, blockId) + + // Logs and result returned + const ntx = this.transactions.length + const dt = ((Date.now()-t0)/1000).toFixed(1) + const per = ((Date.now()-t0)/ntx).toFixed(0) + Logger.info(`Tracker : Finished block ${this.header.height}, ${dt}s, ${ntx} tx, ${per}ms/tx`) + + return aTxsForBroadcast + } + + + /** + * Process the transaction outputs + * @returns {Promise - object[]} returns an array of transactions to be broadcast + */ + async processOutputs() { + const txsForBroadcast = new Set() + const filteredTxs = await this.prefilterByOutputs() + await util.parallelCall(filteredTxs, async filteredTx => { + const tx = new Transaction(filteredTx) + await tx.processOutputs() + if (tx.doBroadcast) + txsForBroadcast.add(tx.tx) + }) + return [...txsForBroadcast] + } + + /** + * Process the transaction inputs + * @returns {Promise - object[]} returns an array of transactions to be broadcast + */ + async processInputs() { + const txsForBroadcast = new Set() + const filteredTxs = await this.prefilterByInputs() + await util.parallelCall(filteredTxs, async filteredTx => { + const tx = new Transaction(filteredTx) + await tx.processInputs() + if (tx.doBroadcast) + txsForBroadcast.add(tx.tx) }) + return [...txsForBroadcast] + } - // Retrieve the previous block - // and store the new block into the database + /** + * Store the block in db + * @returns {Promise - int} returns the id of the block + */ + async registerBlock() { const prevBlock = await db.getBlockByHash(this.header.previousblockhash) const prevID = (prevBlock && prevBlock.blockID) ? prevBlock.blockID : null @@ -76,18 +124,19 @@ class Block extends TransactionsBundle { Logger.info(`Tracker : Added block ${this.header.height} (id=${blockId})`) - // Confirms the transactions - const txids = this.transactions.map(t => t.getId()) - ntx = txids.length - const txidLists = util.splitList(txids, 100) - await util.seriesCall(txidLists, list => db.confirmTransactions(list, blockId)) - - // Logs and result returned - const dt = ((Date.now()-t0)/1000).toFixed(1) - const per = ((Date.now()-t0)/ntx).toFixed(0) - Logger.info(`Tracker : Finished block ${this.header.height}, ${dt}s, ${ntx} tx, ${per}ms/tx`) + return blockId + } - return txsForBroadcast + /** + * Confirm the transactions in db + * @param {Set} txs - set of transactions stored in db + * @param {int} blockId - id of the block + * r@returns {Promise} + */ + async confirmTransactions(txs, blockId) { + const txids = txs.map(t => t.getId()) + const txidLists = util.splitList(txids, 100) + return util.parallelCall(txidLists, list => db.confirmTransactions(list, blockId)) } /** diff --git a/tracker/blockchain-processor.js b/tracker/blockchain-processor.js index f0ee571..15185de 100644 --- a/tracker/blockchain-processor.js +++ b/tracker/blockchain-processor.js @@ -11,29 +11,34 @@ const util = require('../lib/util') const Logger = require('../lib/logger') const db = require('../lib/db/mysql-db-wrapper') const network = require('../lib/bitcoin/network') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') const keys = require('../keys')[network.key] -const AbstractProcessor = require('./abstract-processor') const Block = require('./block') -const TransactionsBundle = require('./transactions-bundle') +const blocksProcessor = require('./blocks-processor') /** * A class allowing to process the blockchain */ -class BlockchainProcessor extends AbstractProcessor { +class BlockchainProcessor { /** * Constructor * @param {object} notifSock - ZMQ socket used for notifications */ constructor(notifSock) { - super(notifSock) + // RPC client + this.client = createRpcClient() // ZeroMQ socket for bitcoind blocks messages this.blkSock = null // Initialize a semaphor protecting the onBlockHash() method this._onBlockHashSemaphor = new Sema(1, { capacity: 50 }) + // Array of worker threads used for parallel processing of blocks + this.blockWorkers = [] // Flag tracking Initial Block Download Mode this.isIBD = true + // Initialize the blocks processor + blocksProcessor.init(notifSock) } /** @@ -55,8 +60,7 @@ class BlockchainProcessor extends AbstractProcessor { * @returns {Promise} */ async catchup() { - const highest = await db.getHighestBlock() - const info = await this.client.getblockchaininfo() + const [highest, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()]) const daemonNbHeaders = info.headers // Consider that we are in IBD mode if Dojo is far in the past (> 13,000 blocks) @@ -80,12 +84,11 @@ class BlockchainProcessor extends AbstractProcessor { try { Logger.info('Tracker : Tracker Startup (IBD mode)') - const info = await this.client.getblockchaininfo() + // Get highest block processed by the tracker + const [highest, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()]) const daemonNbBlocks = info.blocks const daemonNbHeaders = info.headers - // Get highest block processed by the tracker - const highest = await db.getHighestBlock() const dbMaxHeight = highest.blockHeight let prevBlockId = highest.blockID @@ -114,8 +117,8 @@ class BlockchainProcessor extends AbstractProcessor { await util.seriesCall(blockRange, async height => { try { - const blockHash = await this.client.getblockhash(height) - const header = await this.client.getblockheader(blockHash, true) + const blockHash = await this.client.getblockhash({ height }) + const header = await this.client.getblockheader({ blockhash: blockHash, verbose: true }) prevBlockId = await this.processBlockHeader(header, prevBlockId) } catch(e) { Logger.error(e, 'Tracker : BlockchainProcessor.catchupIBDMode()') @@ -151,30 +154,23 @@ class BlockchainProcessor extends AbstractProcessor { try { Logger.info('Tracker : Tracker Startup (normal mode)') - const info = await this.client.getblockchaininfo() + // Get highest block processed by the tracker + const [highest, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()]) const daemonNbBlocks = info.blocks - // Get highest block processed by the tracker - const highest = await db.getHighestBlock() if (highest == null) return null if (daemonNbBlocks == highest.blockHeight) return null - // Compute blocks range to be processed const blockRange = _.range(highest.blockHeight, daemonNbBlocks + 1) Logger.info(`Tracker : Sync ${blockRange.length} blocks`) - // Process the blocks - return util.seriesCall(blockRange, async height => { - try { - const hash = await this.client.getblockhash(height) - const header = await this.client.getblockheader(hash) - return this.processBlock(header) - } catch(e) { - Logger.error(e, 'Tracker : BlockchainProcessor.catchupNormalMode()') - process.exit() - } - }, 'Tracker syncing', true) + try { + return this.processBlockRange(blockRange) + } catch(e) { + Logger.error(e, 'Tracker : BlockchainProcessor.catchupNormalMode()') + process.exit() + } } catch(e) { Logger.error(e, 'Tracker : BlockchainProcessor.catchupNormalMode()') @@ -240,7 +236,7 @@ class BlockchainProcessor extends AbstractProcessor { let headers = null try { - const header = await this.client.getblockheader(blockHash, true) + const header = await this.client.getblockheader({ blockhash: blockHash, verbose: true }) Logger.info(`Tracker : Block #${header.height} ${blockHash}`) // Grab all headers between this block and last known headers = await this.chainBacktrace([header]) @@ -262,9 +258,7 @@ class BlockchainProcessor extends AbstractProcessor { await this.rewind(knownHeight) // Process the blocks - return await util.seriesCall(headers, header => { - return this.processBlock(header) - }) + return await this.processBlocks(headers) } catch(e) { Logger.error(e, 'Tracker : BlockchainProcessor.onBlockHash()') @@ -292,7 +286,7 @@ class BlockchainProcessor extends AbstractProcessor { if (block == null) { // Previous block does not exist in database. Grab from bitcoind - const header = await this.client.getblockheader(deepest.previousblockhash, true) + const header = await this.client.getblockheader({ blockhash: deepest.previousblockhash, verbose: true }) headers.push(header) return this.chainBacktrace(headers) } else { @@ -318,8 +312,6 @@ class BlockchainProcessor extends AbstractProcessor { await db.unconfirmTransactions(txids) } - // TODO: get accounts and notify of deletion ? - await db.deleteBlocksAfterHeight(height) } @@ -342,45 +334,40 @@ class BlockchainProcessor extends AbstractProcessor { Logger.info(`Blocks Rescan : starting a rescan for ${blockRange.length} blocks`) - // Process the blocks - return util.seriesCall(blockRange, async height => { - try { - Logger.info(`Tracker : Rescanning block ${height}`) - const hash = await this.client.getblockhash(height) - const header = await this.client.getblockheader(hash) - return this.processBlock(header) - } catch(e) { - Logger.error(e, 'Tracker : BlockchainProcessor.rescan()') - throw e - } - }, 'Tracker rescan', true) + try { + return this.processBlockRange(blockRange) + } catch(e) { + Logger.error(e, 'Tracker : BlockchainProcessor.rescan()') + throw e + } } /** - * Process a block - * @param {object} header - block header - * @returns {Promise} + * Process a list of blocks + * @param {object[]} headers - array of block headers */ - async processBlock(header) { - try { - // Get raw block hex string from bitcoind - const hex = await this.client.getblock(header.hash, false) - - const block = new Block(hex, header) - - const txsForBroadcast = await block.checkBlock() + async processBlocks(headers) { + const chunks = util.splitList(headers, blocksProcessor.nbWorkers) - // Send notifications - for (let tx of txsForBroadcast) - this.notifyTx(tx) + await util.seriesCall(chunks, async chunk => { + return blocksProcessor.processChunk(chunk) + }) + } - this.notifyBlock(header) + /** + * Process a range of blocks + * @param {int[]} heights - a range of block heights + */ + async processBlockRange(heights) { + const chunks = util.splitList(heights, blocksProcessor.nbWorkers) - } catch(e) { - // The show must go on. - // TODO: further notification that this block did not check out - Logger.error(e, 'Tracker : BlockchainProcessor.processBlock()') - } + return util.seriesCall(chunks, async chunk => { + const headers = await util.parallelCall(chunk, async height => { + const hash = await this.client.getblockhash({ height }) + return await this.client.getblockheader({ blockhash: hash }) + }) + return this.processBlocks(headers) + }) } /** diff --git a/tracker/blocks-processor.js b/tracker/blocks-processor.js new file mode 100644 index 0000000..c5c9f99 --- /dev/null +++ b/tracker/blocks-processor.js @@ -0,0 +1,222 @@ +/*! + * tracker/blocks-processor.js + * Copyright © 2019 – Katana Cryptographic Ltd. All Rights Reserved. + */ +'use strict' + +const os = require('os') +const Sema = require('async-sema') +const { Worker } = require('worker_threads') +const Logger = require('../lib/logger') +const util = require('../lib/util') +const dbProcessor = require('../lib/db/mysql-db-wrapper') +const blockWorker = require('./block-worker') + + +let notifSock = null +let blockWorkers = [] +let headersChunk = [] +let txsForBroadcast = [] +let t0 = null +let currentOp = null +let nbTasksEnqueued = 0 +let nbTasksCompleted = 0 + +// Semaphor protecting the processBloks() method +const _processBlocksSemaphor = new Sema(1) + +// Number of worker threads processing the blocks in parallel +const nbWorkers = os.cpus().length //- 1 +module.exports.nbWorkers = nbWorkers + + +/** + * Initialize the processor + * @param {object} notifSock - ZMQ socket used for notifications + */ +function init(notifSock) { + notifSock = notifSock + + for (let i = 0; i < nbWorkers; i++) { + const worker = new Worker( + `${__dirname}/block-worker.js`, + { workerData: null } + ) + worker.on('error', processWorkerError) + worker.on('message', processWorkerMessage) + blockWorkers.push(worker) + } +} +module.exports.init = init + +/** + * Process a chunk of block headers + * @param {object[]} chunk - array of block headers + */ +async function processChunk(chunk) { + // Acquire the semaphor (wait for previous chunk) + await _processBlocksSemaphor.acquire() + + t0 = Date.now() + const sBlockRange = `${chunk[0].height}-${chunk[chunk.length-1].height}` + Logger.info(`Tracker : Beginning to process blocks ${sBlockRange}`) + + // Process the chunk + chunk.sort((a,b) => a.height - b.height) + headersChunk = chunk + txsForBroadcast = [] + processTask(blockWorker.OP_INIT) +} +module.exports.processChunk = processChunk + +/** + * Process an error returned by a worker thread + * @param {object} e - error + */ +async function processWorkerError(e) { + return processWorkerMessage({ + 'op': currentOp, + 'status': false, + 'res': e + }) +} + +/** + * Process a message returned by a worker thread + * @param {object} msg - message sent by the worker thread + */ +async function processWorkerMessage(msg) { + nbTasksCompleted++ + + if (!msg.status) { + Logger.error(msg.res, 'Tracker : processWorkerMessage()') + } else if (msg.op == blockWorker.OP_CONFIRM) { + txsForBroadcast = txsForBroadcast.concat(msg.res) + } + + if (nbTasksCompleted == nbTasksEnqueued) { + switch (msg.op) { + case blockWorker.OP_INIT: + // Process the transaction outputs + processTask(blockWorker.OP_PROCESS_OUTPUTS) + break + case blockWorker.OP_PROCESS_OUTPUTS: + // Process the transaction inputs + processTask(blockWorker.OP_PROCESS_INPUTS) + break + case blockWorker.OP_PROCESS_INPUTS: + // Store the blocks in db and get their id + const blockIds = await util.seriesCall(headersChunk, async header => { + return registerBlock(header) + }) + // Confirm the transactions + processTask(blockWorker.OP_CONFIRM, blockIds) + break + case blockWorker.OP_CONFIRM: + // Notify new transactions and blocks + await Promise.all([ + util.parallelCall(txsForBroadcast, async tx => { + notifyTx(tx) + }), + util.parallelCall(headersChunk, async header => { + notifyBlock(header) + }) + ]) + // Process complete. Reset the workers + processTask(blockWorker.OP_RESET) + break + case blockWorker.OP_RESET: + const dt = ((Date.now()-t0)/1000).toFixed(1) + const per = ((Date.now()-t0)/headersChunk.length).toFixed(0) + const sBlockRange = `${headersChunk[0].height}-${headersChunk[headersChunk.length-1].height}` + Logger.info(`Tracker : Finished processing blocks ${sBlockRange}, ${dt}s, ${per}ms/block`) + // Release the semaphor + await _processBlocksSemaphor.release() + break + } + } +} + +/** + * Execute an operation processing a block + * @param {integer} op - operation + * @param {*} args + */ +function processTask(op, args) { + currentOp = op + nbTasksEnqueued = 0 + nbTasksCompleted = 0 + + switch (op) { + case blockWorker.OP_INIT: + for (let i = 0; i < headersChunk.length; i++) { + blockWorkers[i].postMessage({ + 'op': op, + 'header': headersChunk[i] + }) + nbTasksEnqueued++ + } + break + case blockWorker.OP_PROCESS_OUTPUTS: + case blockWorker.OP_PROCESS_INPUTS: + case blockWorker.OP_RESET: + for (let i = 0; i < headersChunk.length; i++) { + blockWorkers[i].postMessage({'op': op}) + nbTasksEnqueued++ + } + break + case blockWorker.OP_CONFIRM: + for (let i = 0; i < headersChunk.length; i++) { + blockWorkers[i].postMessage({ + 'op': op, + 'blockId': args[i] + }) + nbTasksEnqueued++ + } + break + default: + Logger.error(null, 'Tracker : processTask() : Unknown operation') + } +} + +/** + * Notify a new transaction + * @param {object} tx - bitcoin transaction + */ +function notifyTx(tx) { + // Real-time client updates for this transaction. + // Any address input or output present in transaction + // is a potential client to notify. + if (notifSock) + notifSock.send(['transaction', JSON.stringify(tx)]) +} + +/** + * Notify a new block + * @param {string} header - block header + */ +function notifyBlock(header) { + // Notify clients of the block + if (notifSock) + notifSock.send(['block', JSON.stringify(header)]) +} + +/** + * Store a block in db + * @param {object} header - block header + * @returns {Promise - int} returns the id of the block + */ +async function registerBlock(header) { + const prevBlock = await dbProcessor.getBlockByHash(header.previousblockhash) + const prevID = (prevBlock && prevBlock.blockID) ? prevBlock.blockID : null + + const blockId = await dbProcessor.addBlock({ + blockHeight: header.height, + blockHash: header.hash, + blockTime: header.time, + blockParent: prevID + }) + + Logger.info(`Tracker : Added block ${header.height} (id=${blockId})`) + return blockId +} diff --git a/tracker/index.js b/tracker/index.js index bbbed6a..b08887c 100644 --- a/tracker/index.js +++ b/tracker/index.js @@ -6,7 +6,7 @@ 'use strict' - const RpcClient = require('../lib/bitcoind-rpc/rpc-client') + const { waitForBitcoindRpcApi } = require('../lib/bitcoind-rpc/rpc-client') const network = require('../lib/bitcoin/network') const keys = require('../keys')[network.key] const db = require('../lib/db/mysql-db-wrapper') @@ -21,7 +21,7 @@ // Wait for Bitcoind RPC API // being ready to process requests - await RpcClient.waitForBitcoindRpcApi() + await waitForBitcoindRpcApi() // Initialize the db wrapper const dbConfig = { diff --git a/tracker/mempool-processor.js b/tracker/mempool-processor.js index a9f4563..bd30ef3 100644 --- a/tracker/mempool-processor.js +++ b/tracker/mempool-processor.js @@ -11,8 +11,8 @@ const util = require('../lib/util') const Logger = require('../lib/logger') const db = require('../lib/db/mysql-db-wrapper') const network = require('../lib/bitcoin/network') +const { createRpcClient } = require('../lib/bitcoind-rpc/rpc-client') const keys = require('../keys')[network.key] -const AbstractProcessor = require('./abstract-processor') const Transaction = require('./transaction') const TransactionsBundle = require('./transactions-bundle') @@ -20,14 +20,17 @@ const TransactionsBundle = require('./transactions-bundle') /** * A class managing a buffer for the mempool */ -class MempoolProcessor extends AbstractProcessor { +class MempoolProcessor { /** * Constructor * @param {object} notifSock - ZMQ socket used for notifications */ constructor(notifSock) { - super(notifSock) + // RPC client + this.client = createRpcClient() + // ZeroMQ socket for notifications sent to others components + this.notifSock = notifSock // Mempool buffer this.mempoolBuffer = new TransactionsBundle() // ZeroMQ socket for bitcoind Txs messages @@ -69,15 +72,17 @@ class MempoolProcessor extends AbstractProcessor { /** * Stop processing - */ + */ async stop() { clearInterval(this.checkUnconfirmedId) clearInterval(this.processMempoolId) //clearInterval(this.displayStatsId) - resolve(this.txSock.disconnect(keys.bitcoind.zmqTx).close()) - resolve(this.pushTxSock.disconnect(keys.ports.notifpushtx).close()) - resolve(this.orchestratorSock.disconnect(keys.ports.orchestrator).close()) + this.txSock.disconnect(keys.bitcoind.zmqTx).close() + this.pushTxSock.disconnect(keys.ports.notifpushtx).close() + this.orchestratorSock.disconnect(keys.ports.orchestrator).close() + + return Promise.resolve(); } /** @@ -150,14 +155,27 @@ class MempoolProcessor extends AbstractProcessor { let currentMempool = new TransactionsBundle(this.mempoolBuffer.toArray()) this.mempoolBuffer.clear() - const filteredTxs = await currentMempool.prefilterTransactions() + const txsForBroadcast = new Map() + + let filteredTxs = await currentMempool.prefilterByOutputs() + await util.parallelCall(filteredTxs, async filteredTx => { + const tx = new Transaction(filteredTx) + await tx.processOutputs() + if (tx.doBroadcast) + txsForBroadcast[tx.txid] = tx.tx + }) - return util.seriesCall(filteredTxs, async filteredTx => { + filteredTxs = await currentMempool.prefilterByInputs() + await util.parallelCall(filteredTxs, async filteredTx => { const tx = new Transaction(filteredTx) - const txCheck = await tx.checkTransaction() - if (txCheck && txCheck.broadcast) - this.notifyTx(txCheck.tx) + await tx.processInputs() + if (tx.doBroadcast) + txsForBroadcast[tx.txid] = tx.tx }) + + // Send the notifications + for (let tx of txsForBroadcast.values()) + this.notifyTx(tx) } /** @@ -206,6 +224,29 @@ class MempoolProcessor extends AbstractProcessor { } } + /** + * Notify a new transaction + * @param {object} tx - bitcoin transaction + */ + notifyTx(tx) { + // Real-time client updates for this transaction. + // Any address input or output present in transaction + // is a potential client to notify. + if (this.notifSock) + this.notifSock.send(['transaction', JSON.stringify(tx)]) + } + + /** + * Notify a new block + * @param {string} header - block header + */ + notifyBlock(header) { + // Notify clients of the block + if (this.notifSock) + this.notifSock.send(['block', JSON.stringify(header)]) + } + + /** * Check unconfirmed transactions * @returns {Promise} @@ -218,11 +259,11 @@ class MempoolProcessor extends AbstractProcessor { const unconfirmedTxs = await db.getUnconfirmedTransactions() if (unconfirmedTxs.length > 0) { - await util.seriesCall(unconfirmedTxs, tx => { + await util.parallelCall(unconfirmedTxs, tx => { try { - return this.client.getrawtransaction(tx.txnTxid, true) + return this.client.getrawtransaction( { txid: tx.txnTxid, verbose: true }) .then(async rtx => { - if (!rtx.blockhash) return null + if (!rtx.blockhash) return null // Transaction is confirmed const block = await db.getBlockByHash(rtx.blockhash) if (block && block.blockID) { @@ -247,7 +288,7 @@ class MempoolProcessor extends AbstractProcessor { const ntx = unconfirmedTxs.length const dt = ((Date.now() - t0) / 1000).toFixed(1) const per = (ntx == 0) ? 0 : ((Date.now() - t0) / ntx).toFixed(0) - Logger.info(`Tracker : Finished processing unconfirmed transactions ${dt}s, ${ntx} tx, ${per}ms/tx`) + Logger.info(`Tracker : Finished processing unconfirmed transactions ${dt}s, ${ntx} tx, ${per}ms/tx`) } /** @@ -255,11 +296,10 @@ class MempoolProcessor extends AbstractProcessor { */ async _refreshActiveStatus() { // Get highest header in the blockchain - const info = await this.client.getblockchaininfo() + // Get highest block processed by the tracker + const [highestBlock, info] = await Promise.all([db.getHighestBlock(), this.client.getblockchaininfo()]) const highestHeader = info.headers - // Get highest block processed by the tracker - const highestBlock = await db.getHighestBlock() if (highestBlock == null || highestBlock.blockHeight == 0) { this.isActive = false return diff --git a/tracker/tracker-rest-api.js b/tracker/tracker-rest-api.js index 85d7c5f..5fc43cc 100644 --- a/tracker/tracker-rest-api.js +++ b/tracker/tracker-rest-api.js @@ -4,10 +4,7 @@ */ 'use strict' -const qs = require('querystring') const validator = require('validator') -const bodyParser = require('body-parser') -const Logger = require('../lib/logger') const errors = require('../lib/errors') const authMgr = require('../lib/auth/authorizations-manager') const HttpServer = require('../lib/http-server/http-server') @@ -29,8 +26,6 @@ class TrackerRestApi { this.httpServer = httpServer this.tracker = tracker - const urlencodedParser = bodyParser.urlencoded({ extended: true }) - // Establish routes. Proxy server strips /pushtx this.httpServer.app.get( `/${keys.prefixes.support}/rescan`, diff --git a/tracker/transaction.js b/tracker/transaction.js index f81d0b8..037e774 100644 --- a/tracker/transaction.js +++ b/tracker/transaction.js @@ -8,6 +8,7 @@ const _ = require('lodash') const bitcoin = require('bitcoinjs-lib') const util = require('../lib/util') const Logger = require('../lib/logger') +const addrHelper = require('../lib/bitcoin/addresses-helper') const hdaHelper = require('../lib/bitcoin/hd-accounts-helper') const db = require('../lib/db/mysql-db-wrapper') const network = require('../lib/bitcoin/network') @@ -28,9 +29,9 @@ class Transaction { */ constructor(tx) { this.tx = tx - this.txid = this.tx.getId() + this.txid = this.tx.getId() // Id of transaction stored in db - this.storedTxnID = null + this.storedTxnID = null // Should this transaction be broadcast out to connected clients? this.doBroadcast = false } @@ -46,10 +47,10 @@ class Transaction { async checkTransaction() { try { // Process transaction inputs - await this._processInputs() + await this.processInputs() // Process transaction outputs - await this._processOutputs() + await this.processOutputs() // If this point reached with no errors, // store the fact that this transaction was checked. @@ -72,7 +73,7 @@ class Transaction { * Process transaction inputs * @returns {Promise} */ - async _processInputs() { + async processInputs() { // Array of inputs spent const spends = [] // Store input indices, keyed by `txid-outindex` for easy retrieval @@ -80,7 +81,7 @@ class Transaction { // Store database ids of double spend transactions const doubleSpentTxnIDs = [] // Store inputs of interest - const inputs = [] + const inputs = [] // Extracts inputs information let index = 0 @@ -150,16 +151,16 @@ class Transaction { * Process transaction outputs * @returns {Promise} */ - async _processOutputs() { + async processOutputs() { // Store outputs, keyed by address. Values are arrays of outputs const indexedOutputs = {} - + // Extracts outputs information let index = 0 for (let output of this.tx.outs) { try { - const address = bitcoin.address.fromOutputScript(output.script, activeNet) + const address = addrHelper.outputScript2Address(output.script) if (!indexedOutputs[address]) indexedOutputs[address] = [] @@ -174,7 +175,7 @@ class Transaction { // Array of addresses receiving tx outputs const addresses = _.keys(indexedOutputs) - + // Store a list of known addresses that received funds let fundedAddresses = [] @@ -203,7 +204,7 @@ class Transaction { for (let a of fundedAddresses) { outputs.push({ - txnID: this.storedTxnID, + txnID: this.storedTxnID, addrID: a.addrID, outIndex: a.outIndex, outAmount: a.outAmount, @@ -253,9 +254,9 @@ class Transaction { // Store a list of known addresses that received funds const fundedAddresses = [] const xpubList = _.keys(hdAccounts) - + if (xpubList.length > 0) { - await util.seriesCall(xpubList, async xpub => { + await util.parallelCall(xpubList, async xpub => { const usedNewAddresses = await this._deriveNewAddresses( xpub, hdAccounts[xpub], @@ -281,7 +282,7 @@ class Transaction { } }) } - + return fundedAddresses } @@ -290,7 +291,7 @@ class Transaction { * Check if tx addresses are at or beyond the next unused * index for the HD chain. Derive additional addresses * to replace the gap limit and add those addresses to - * the database. Make sure to account for tx sending to + * the database. Make sure to account for tx sending to * newly-derived addresses. * * @param {string} xpub @@ -389,7 +390,7 @@ class Transaction { await db.addAddressesToHDAccount(xpub, newAddresses) return _.keys(usedNewAddresses) } - + /** * Store the transaction in database @@ -405,7 +406,7 @@ class Transaction { locktime: this.tx.locktime, }) - Logger.info(`Tracker : Storing transaction ${this.txid}`) + Logger.info(`Tracker : Storing transaction ${this.txid}`) } } diff --git a/tracker/transactions-bundle.js b/tracker/transactions-bundle.js index 081eca7..a769e44 100644 --- a/tracker/transactions-bundle.js +++ b/tracker/transactions-bundle.js @@ -6,12 +6,9 @@ const _ = require('lodash') const LRU = require('lru-cache') -const bitcoin = require('bitcoinjs-lib') const util = require('../lib/util') const db = require('../lib/db/mysql-db-wrapper') -const network = require('../lib/bitcoin/network') -const keys = require('../keys')[network.key] -const activeNet = network.network +const addrHelper = require('../lib/bitcoin/addresses-helper') /** @@ -63,64 +60,54 @@ class TransactionsBundle { /** * Find the transactions of interest + * based on theirs inputs * @returns {object[]} returns an array of transactions objects */ - async prefilterTransactions() { + async prefilterByInputs() { // Process transactions by slices of 5000 transactions const MAX_NB_TXS = 5000 const lists = util.splitList(this.transactions, MAX_NB_TXS) - - const results = await util.seriesCall(lists, list => { - return this._prefilterTransactions(list) - }) - + const results = await util.parallelCall(lists, txs => this._prefilterByInputs(txs)) return _.flatten(results) } /** - * Find the transactions of interest (internal implementation) - * @params {object[]} transactions - array of transactions objects + * Find the transactions of interest + * based on theirs outputs * @returns {object[]} returns an array of transactions objects */ - async _prefilterTransactions(transactions) { - let inputs = [] - let outputs = [] + async prefilterByOutputs() { + // Process transactions by slices of 5000 transactions + const MAX_NB_TXS = 5000 + const lists = util.splitList(this.transactions, MAX_NB_TXS) + const results = await util.parallelCall(lists, txs => this._prefilterByOutputs(txs)) + return _.flatten(results) + } - // Store indices of txs to be processed + /** + * Find the transactions of interest + * based on theirs outputs (internal implementation) + * @params {object[]} txs - array of transactions objects + * @returns {object[]} returns an array of transactions objects + */ + async _prefilterByOutputs(txs) { + let addresses = [] let filteredIdxTxs = [] - - // Store txs indices, keyed by `txid-outindex`. - // Values are arrays of txs indices (for double spends) - let indexedInputs = {} - - // Store txs indices, keyed by address. - // Values are arrays of txs indices let indexedOutputs = {} - // Stores txs indices, keyed by txids - let indexedTxs = {} - - // - // Prefilter against the outputs - // - // Index the transaction outputs - for (const i in transactions) { - const tx = transactions[i] + for (const i in txs) { + const tx = txs[i] const txid = tx.getId() - indexedTxs[txid] = i - - // If we already checked this tx if (TransactionsBundle.cache.has(txid)) - continue + continue for (const j in tx.outs) { try { const script = tx.outs[j].script - const address = bitcoin.address.fromOutputScript(script, activeNet) - outputs.push(address) - // Index the output + const address = addrHelper.outputScript2Address(script) + addresses.push(address) if (!indexedOutputs[address]) indexedOutputs[address] = [] indexedOutputs[address].push(i) @@ -129,8 +116,7 @@ class TransactionsBundle { } // Prefilter - const outRes = await db.getUngroupedHDAccountsByAddresses(outputs) - + const outRes = await db.getUngroupedHDAccountsByAddresses(addresses) for (const i in outRes) { const key = outRes[i].addrAddress const idxTxs = indexedOutputs[key] @@ -141,41 +127,43 @@ class TransactionsBundle { } } - // - // Prefilter against the inputs - // + return filteredIdxTxs.map(x => txs[x]) + } - // Index the transaction inputs - for (const i in transactions) { - const tx = transactions[i] + /** + * Find the transactions of interest + * based on theirs inputs (internal implementation) + * @params {object[]} txs - array of transactions objects + * @returns {object[]} returns an array of transactions objects + */ + async _prefilterByInputs(txs) { + let inputs = [] + let filteredIdxTxs = [] + let indexedInputs = {} + + for (const i in txs) { + const tx = txs[i] const txid = tx.getId() - // If we already checked this tx if (TransactionsBundle.cache.has(txid)) continue for (const j in tx.ins) { const spendHash = tx.ins[j].hash const spendTxid = Buffer.from(spendHash).reverse().toString('hex') - // Check if this input consumes an output - // generated by a transaction from this block - if (filteredIdxTxs.indexOf(indexedTxs[spendTxid]) > -1 && filteredIdxTxs.indexOf(i) == -1) { - filteredIdxTxs.push(i) - } else { - const spendIdx = tx.ins[j].index - inputs.push({txid: spendTxid, index: spendIdx}) - // Index the input - const key = spendTxid + '-' + spendIdx - if (!indexedInputs[key]) - indexedInputs[key] = [] - indexedInputs[key].push(i) - } + const spendIdx = tx.ins[j].index + inputs.push({txid: spendTxid, index: spendIdx}) + const key = spendTxid + '-' + spendIdx + if (!indexedInputs[key]) + indexedInputs[key] = [] + indexedInputs[key].push(i) } } // Prefilter - const inRes = await db.getOutputSpends(inputs) - + const lists = util.splitList(inputs, 1000) + const results = await util.parallelCall(lists, list => db.getOutputSpends(list)) + const inRes = _.flatten(results) for (const i in inRes) { const key = inRes[i].txnTxid + '-' + inRes[i].outIndex const idxTxs = indexedInputs[key] @@ -186,11 +174,7 @@ class TransactionsBundle { } } - // - // Returns the matching transactions - // - filteredIdxTxs.sort((a, b) => a - b); - return filteredIdxTxs.map(x => transactions[x]) + return filteredIdxTxs.map(x => txs[x]) } }