From 1c4192069d256bcb7909ed1a6bbeb059e64f4359 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Mon, 12 Jun 2023 19:54:34 -0400 Subject: [PATCH 01/64] WIP --- .dockerignore | 4 + dist/Tezos.js | 4 +- dist/api.js | 124 +++++++- package-lock.json | 719 ++++++++++++++++++++++++++++++++++++++++------ package.json | 10 +- src/Tezos.ts | 2 +- src/api.ts | 303 ++++++++++++------- 7 files changed, 959 insertions(+), 207 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..03952b9 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +.gitignore +LICENSE.md +node_modules +README.md diff --git a/dist/Tezos.js b/dist/Tezos.js index 5dc6987..fc90a77 100644 --- a/dist/Tezos.js +++ b/dist/Tezos.js @@ -15,6 +15,7 @@ const taquito_1 = require("@taquito/taquito"); const defaultMaxBalance = 6000; const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () { console.log(`Send ${amount} xtz to ${address}`); + return ""; // Connect to RPC endpoint const rpcUrl = process.env.RPC_URL; if (!rpcUrl) { @@ -25,7 +26,8 @@ const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () let Tezos = new taquito_1.TezosToolkit(rpcUrl); // Check max balance const userBalance = (yield Tezos.tz.getBalance(address)).toNumber(); - if (userBalance > defaultMaxBalance * 1000000) { + const maxBalance = process.env.MAX_BALANCE || defaultMaxBalance; + if (userBalance > maxBalance * 1000000) { console.log(`User balance too high (${userBalance / 1000000}), don't send`); throw new Error("You have already enough ꜩ"); } diff --git a/dist/api.js b/dist/api.js index 47162cb..238fe60 100644 --- a/dist/api.js +++ b/dist/api.js @@ -14,10 +14,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) { Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = __importDefault(require("express")); const body_parser_1 = __importDefault(require("body-parser")); +const morgan_1 = __importDefault(require("morgan")); const dotenv_1 = __importDefault(require("dotenv")); +const vdf_1 = __importDefault(require("@subspace/vdf")); const Types_1 = require("./Types"); const Captcha_1 = require("./Captcha"); const Tezos_1 = require("./Tezos"); +const crypto_1 = require("crypto"); dotenv_1.default.config(); const defaultPort = 3000; const defaultUserAmount = 1; @@ -25,43 +28,61 @@ const defaultBakerAmount = 6000; const app = (0, express_1.default)(); app.use(body_parser_1.default.json()); app.use(body_parser_1.default.urlencoded({ extended: true })); +app.use((0, morgan_1.default)("dev")); app.use((req, res, next) => { - const cors = process.env.AUTHORIZED_HOST || '*'; + const cors = process.env.AUTHORIZED_HOST || "*"; res.setHeader("Access-Control-Allow-Origin", cors); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); - res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); + res.setHeader("Access-Control-Allow-Methods", "GET, POST"); + res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); -app.get('/info', (_, res) => { - console.log('Get info'); +// createVdf().then((vdfInstance: any) => { +// const iterations = 3 +// const challenge = Buffer.from("aa", "hex") +// const intSizeBits = 2048 +// // const intSizeBits = 100; +// const isPietrzak = false +// const res = vdfInstance.generate( +// iterations, +// challenge, +// intSizeBits, +// isPietrzak +// ) +// // console.log(res) +// console.log(Buffer.from(res).toString("hex")) +// console.log(vdfInstance.verify(3, challenge, res, intSizeBits, isPietrzak)) +// }) +app.get("/info", (_, res) => { + console.log("Get info"); let profiles = { user: { profile: Types_1.Profile.USER, amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, - currency: "tez" + currency: "tez", }, baker: { profile: Types_1.Profile.BAKER, amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, - currency: "tez" - } + currency: "tez", + }, }; let info = { faucetAddress: process.env.FAUCET_ADDRESS, captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), profiles: profiles, - maxBalance: process.env.MAX_BALANCE + maxBalance: process.env.MAX_BALANCE, }; res.status(200); res.send(info); }); -app.post('/send', (req, res) => __awaiter(void 0, void 0, void 0, function* () { +app.post("/send", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const body = req.body; - const { captchaToken: captchaToken, address: address, profile: profile } = body; - let responseBody = { - status: '', + const { captchaToken, address, profile } = body; + const responseBody = { + status: "", message: undefined, - txHash: undefined + txHash: undefined, + vdfChallenge: "", }; let amount = 0; switch (profile) { @@ -79,7 +100,24 @@ app.post('/send', (req, res) => __awaiter(void 0, void 0, void 0, function* () { res.send(responseBody); return; } - console.log(`Try to send ${amount} xtz to ${address}, with captcha token ${captchaToken}`); + // console.log( + // `Try to send ${amount} xtz to ${address}, with captcha token ${captchaToken}` + // ) + const discriminant_challenge = (0, crypto_1.randomBytes)(10); + console.log({ + discriminant_challenge: Buffer.from(discriminant_challenge).toString("hex"), + }); + responseBody.status = "SUCCESS"; + responseBody.vdfChallenge = { + challenge: discriminant_challenge, + // challenge: "adfdafaafas329084dfadf", + iterations: 10000, + // size: 512, + size: 2048, + }; + res.status(200); + res.send(responseBody); + return; if (yield (0, Captcha_1.checkCaptcha)(captchaToken)) { try { responseBody.txHash = yield (0, Tezos_1.send)(amount, address); @@ -99,6 +137,62 @@ app.post('/send', (req, res) => __awaiter(void 0, void 0, void 0, function* () { } res.send(responseBody); })); +const vdf = (0, vdf_1.default)(); +app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { + const body = req.body; + // const body: VerificationRequestBody = req.body + const { challenge, iterations, size, solution, profile, address } = body; + // console.log({ solution: Buffer.from(solution, "hex") }) + let responseBody = { + status: "", + message: undefined, + txHash: undefined, + }; + // Verify the solution (use the VDF library's verify method) + const v = yield vdf; + // console.log({ v }) + let solutionBuffer = Buffer.from(solution, "base64"); + // console.log({ bufferFromSolution: Buffer.from(solution) }) + // let uint8Array = new Uint8Array(buffer) + console.log({ solutionBuffer, challenge, size, iterations }); + console.log(solutionBuffer.toString("hex")); + const isValid = v.verify(iterations, challenge, solutionBuffer, size, false); + console.log({ isValid }); + if (isValid) { + let amount = 0; + switch (profile) { + case Types_1.Profile.USER: + amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount; + break; + case Types_1.Profile.BAKER: + amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount; + break; + default: + console.log(`Unknown profile ${profile}`); + responseBody.status = "ERROR"; + responseBody.message = `Unknown profile`; + res.status(400); + res.send(responseBody); + return; + } + try { + responseBody.txHash = yield (0, Tezos_1.send)(amount, address); + responseBody.status = "SUCCESS"; + res.status(200); + } + catch (error) { + responseBody.message = `${error}`; + responseBody.status = "ERROR"; + res.status(500); + } + } + else { + responseBody.status = "ERROR"; + responseBody.message = `Invalid solution`; + res.status(400); + } + res.send(responseBody); +})); const port = process.env.API_PORT || defaultPort; app.listen(port, () => { console.log(`Start API on port ${port}.`); diff --git a/package-lock.json b/package-lock.json index ef0552f..2f596b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,25 +1,28 @@ { "name": "tezos-testnet-faucet-backend", - "version": "0.0.1", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "tezos-testnet-faucet-backend", - "version": "0.0.1", + "version": "1.0.0", "license": "ISC", "dependencies": { "@netlify/functions": "^1.0.0", + "@subspace/vdf": "^0.1.0", "@taquito/signer": "^12.1.1", "@taquito/taquito": "^12.1.1", "axios": "^0.26.1", "body-parser": "^1.20.0", "dotenv": "^16.0.1", - "express": "^4.18.1" + "express": "^4.18.1", + "morgan": "^1.10.0" }, "devDependencies": { "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/morgan": "^1.9.4", "@types/node": "^17.0.36", "nodemon": "^2.0.16", "npm": "^8.17.0", @@ -177,6 +180,19 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@subspace/vdf": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subspace/vdf/-/vdf-0.1.0.tgz", + "integrity": "sha512-iKYdYOcAtALmxxgreWqnHphT7m8HIyBsAYLrPSRvOJM9hTY+Rfg+EsLiqXLgHoIXyy980dQhoE4yIwu8xXDmvg==", + "dependencies": { + "@types/node": "^11.13.4" + } + }, + "node_modules/@subspace/vdf/node_modules/@types/node": { + "version": "11.15.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.54.tgz", + "integrity": "sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==" + }, "node_modules/@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -402,6 +418,15 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "node_modules/@types/morgan": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", + "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "17.0.36", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", @@ -539,6 +564,22 @@ } ] }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/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/bignumber.js": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", @@ -1776,6 +1817,32 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2027,6 +2094,7 @@ }, "node_modules/npm/node_modules/@colors/colors": { "version": "1.5.0", + "dev": true, "inBundle": true, "license": "MIT", "optional": true, @@ -2036,16 +2104,19 @@ }, "node_modules/npm/node_modules/@gar/promisify": { "version": "1.1.3", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { "version": "5.5.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2095,6 +2166,7 @@ }, "node_modules/npm/node_modules/@npmcli/ci-detect": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -2103,6 +2175,7 @@ }, "node_modules/npm/node_modules/@npmcli/config": { "version": "4.2.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2121,6 +2194,7 @@ }, "node_modules/npm/node_modules/@npmcli/disparity-colors": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2132,6 +2206,7 @@ }, "node_modules/npm/node_modules/@npmcli/fs": { "version": "2.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2144,6 +2219,7 @@ }, "node_modules/npm/node_modules/@npmcli/git": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2163,6 +2239,7 @@ }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { "version": "1.0.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2178,6 +2255,7 @@ }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { "version": "2.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2192,6 +2270,7 @@ }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { "version": "3.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2206,6 +2285,7 @@ }, "node_modules/npm/node_modules/@npmcli/move-file": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2218,11 +2298,13 @@ }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/node-gyp": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -2231,6 +2313,7 @@ }, "node_modules/npm/node_modules/@npmcli/package-json": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2242,6 +2325,7 @@ }, "node_modules/npm/node_modules/@npmcli/promise-spawn": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2253,6 +2337,7 @@ }, "node_modules/npm/node_modules/@npmcli/query": { "version": "1.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2266,6 +2351,7 @@ }, "node_modules/npm/node_modules/@npmcli/run-script": { "version": "4.2.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2281,6 +2367,7 @@ }, "node_modules/npm/node_modules/@tootallnate/once": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2289,11 +2376,13 @@ }, "node_modules/npm/node_modules/abbrev": { "version": "1.1.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/agent-base": { "version": "6.0.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2305,6 +2394,7 @@ }, "node_modules/npm/node_modules/agentkeepalive": { "version": "4.2.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2318,6 +2408,7 @@ }, "node_modules/npm/node_modules/aggregate-error": { "version": "3.1.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2330,6 +2421,7 @@ }, "node_modules/npm/node_modules/ansi-regex": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2338,6 +2430,7 @@ }, "node_modules/npm/node_modules/ansi-styles": { "version": "4.3.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2352,16 +2445,19 @@ }, "node_modules/npm/node_modules/aproba": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/archy": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/are-we-there-yet": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2374,16 +2470,19 @@ }, "node_modules/npm/node_modules/asap": { "version": "2.0.6", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/bin-links": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2400,6 +2499,7 @@ }, "node_modules/npm/node_modules/binary-extensions": { "version": "2.2.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2408,6 +2508,7 @@ }, "node_modules/npm/node_modules/brace-expansion": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2416,6 +2517,7 @@ }, "node_modules/npm/node_modules/builtins": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2424,6 +2526,7 @@ }, "node_modules/npm/node_modules/cacache": { "version": "16.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2452,6 +2555,7 @@ }, "node_modules/npm/node_modules/chalk": { "version": "4.1.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2467,6 +2571,7 @@ }, "node_modules/npm/node_modules/chownr": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -2475,6 +2580,7 @@ }, "node_modules/npm/node_modules/cidr-regex": { "version": "3.1.1", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -2486,6 +2592,7 @@ }, "node_modules/npm/node_modules/clean-stack": { "version": "2.2.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2494,6 +2601,7 @@ }, "node_modules/npm/node_modules/cli-columns": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2506,6 +2614,7 @@ }, "node_modules/npm/node_modules/cli-table3": { "version": "0.6.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2520,6 +2629,7 @@ }, "node_modules/npm/node_modules/clone": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2528,6 +2638,7 @@ }, "node_modules/npm/node_modules/cmd-shim": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2539,6 +2650,7 @@ }, "node_modules/npm/node_modules/color-convert": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2550,11 +2662,13 @@ }, "node_modules/npm/node_modules/color-name": { "version": "1.1.4", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/color-support": { "version": "1.1.3", + "dev": true, "inBundle": true, "license": "ISC", "bin": { @@ -2563,6 +2677,7 @@ }, "node_modules/npm/node_modules/columnify": { "version": "1.6.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2575,21 +2690,25 @@ }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/concat-map": { "version": "0.0.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/console-control-strings": { "version": "1.1.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/cssesc": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "MIT", "bin": { @@ -2601,6 +2720,7 @@ }, "node_modules/npm/node_modules/debug": { "version": "4.3.4", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2617,11 +2737,13 @@ }, "node_modules/npm/node_modules/debug/node_modules/ms": { "version": "2.1.2", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/debuglog": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2630,6 +2752,7 @@ }, "node_modules/npm/node_modules/defaults": { "version": "1.0.3", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2638,11 +2761,13 @@ }, "node_modules/npm/node_modules/delegates": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/depd": { "version": "1.1.2", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2651,6 +2776,7 @@ }, "node_modules/npm/node_modules/dezalgo": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2660,6 +2786,7 @@ }, "node_modules/npm/node_modules/diff": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "BSD-3-Clause", "engines": { @@ -2668,11 +2795,13 @@ }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/encoding": { "version": "0.1.13", + "dev": true, "inBundle": true, "license": "MIT", "optional": true, @@ -2682,6 +2811,7 @@ }, "node_modules/npm/node_modules/env-paths": { "version": "2.2.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2690,16 +2820,19 @@ }, "node_modules/npm/node_modules/err-code": { "version": "2.0.3", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/fastest-levenshtein": { "version": "1.0.12", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/fs-minipass": { "version": "2.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2711,16 +2844,19 @@ }, "node_modules/npm/node_modules/fs.realpath": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/function-bind": { "version": "1.1.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/gauge": { "version": "4.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2739,6 +2875,7 @@ }, "node_modules/npm/node_modules/glob": { "version": "8.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2757,11 +2894,13 @@ }, "node_modules/npm/node_modules/graceful-fs": { "version": "4.2.10", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/has": { "version": "1.0.3", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2773,6 +2912,7 @@ }, "node_modules/npm/node_modules/has-flag": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2781,11 +2921,13 @@ }, "node_modules/npm/node_modules/has-unicode": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/hosted-git-info": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2797,11 +2939,13 @@ }, "node_modules/npm/node_modules/http-cache-semantics": { "version": "4.1.0", + "dev": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/http-proxy-agent": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2815,6 +2959,7 @@ }, "node_modules/npm/node_modules/https-proxy-agent": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2827,6 +2972,7 @@ }, "node_modules/npm/node_modules/humanize-ms": { "version": "1.2.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2835,6 +2981,7 @@ }, "node_modules/npm/node_modules/iconv-lite": { "version": "0.6.3", + "dev": true, "inBundle": true, "license": "MIT", "optional": true, @@ -2847,6 +2994,7 @@ }, "node_modules/npm/node_modules/ignore-walk": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2858,6 +3006,7 @@ }, "node_modules/npm/node_modules/imurmurhash": { "version": "0.1.4", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2866,6 +3015,7 @@ }, "node_modules/npm/node_modules/indent-string": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2874,11 +3024,13 @@ }, "node_modules/npm/node_modules/infer-owner": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/inflight": { "version": "1.0.6", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2888,11 +3040,13 @@ }, "node_modules/npm/node_modules/inherits": { "version": "2.0.4", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/ini": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -2901,6 +3055,7 @@ }, "node_modules/npm/node_modules/init-package-json": { "version": "3.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -2918,11 +3073,13 @@ }, "node_modules/npm/node_modules/ip": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/ip-regex": { "version": "4.3.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2931,6 +3088,7 @@ }, "node_modules/npm/node_modules/is-cidr": { "version": "4.0.2", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -2942,6 +3100,7 @@ }, "node_modules/npm/node_modules/is-core-module": { "version": "2.10.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -2953,6 +3112,7 @@ }, "node_modules/npm/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -2961,21 +3121,25 @@ }, "node_modules/npm/node_modules/is-lambda": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/isexe": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/json-parse-even-better-errors": { "version": "2.3.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/json-stringify-nice": { "version": "1.1.4", + "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -2984,6 +3148,7 @@ }, "node_modules/npm/node_modules/jsonparse": { "version": "1.3.1", + "dev": true, "engines": [ "node >= 0.2.0" ], @@ -2992,16 +3157,19 @@ }, "node_modules/npm/node_modules/just-diff": { "version": "5.1.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/just-diff-apply": { "version": "5.4.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { "version": "6.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3016,6 +3184,7 @@ }, "node_modules/npm/node_modules/libnpmdiff": { "version": "4.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3034,6 +3203,7 @@ }, "node_modules/npm/node_modules/libnpmexec": { "version": "4.0.10", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3058,6 +3228,7 @@ }, "node_modules/npm/node_modules/libnpmfund": { "version": "3.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3069,6 +3240,7 @@ }, "node_modules/npm/node_modules/libnpmhook": { "version": "8.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3081,6 +3253,7 @@ }, "node_modules/npm/node_modules/libnpmorg": { "version": "4.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3093,6 +3266,7 @@ }, "node_modules/npm/node_modules/libnpmpack": { "version": "4.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3106,6 +3280,7 @@ }, "node_modules/npm/node_modules/libnpmpublish": { "version": "6.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3121,6 +3296,7 @@ }, "node_modules/npm/node_modules/libnpmsearch": { "version": "5.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3132,6 +3308,7 @@ }, "node_modules/npm/node_modules/libnpmteam": { "version": "4.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3144,6 +3321,7 @@ }, "node_modules/npm/node_modules/libnpmversion": { "version": "3.0.6", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3159,6 +3337,7 @@ }, "node_modules/npm/node_modules/lru-cache": { "version": "7.13.2", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -3167,6 +3346,7 @@ }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "10.2.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3193,6 +3373,7 @@ }, "node_modules/npm/node_modules/minimatch": { "version": "5.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3204,6 +3385,7 @@ }, "node_modules/npm/node_modules/minipass": { "version": "3.3.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3215,6 +3397,7 @@ }, "node_modules/npm/node_modules/minipass-collect": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3226,6 +3409,7 @@ }, "node_modules/npm/node_modules/minipass-fetch": { "version": "2.1.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3242,6 +3426,7 @@ }, "node_modules/npm/node_modules/minipass-flush": { "version": "1.0.5", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3253,6 +3438,7 @@ }, "node_modules/npm/node_modules/minipass-json-stream": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3262,6 +3448,7 @@ }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3273,6 +3460,7 @@ }, "node_modules/npm/node_modules/minipass-sized": { "version": "1.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3284,6 +3472,7 @@ }, "node_modules/npm/node_modules/minizlib": { "version": "2.1.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3296,6 +3485,7 @@ }, "node_modules/npm/node_modules/mkdirp": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "MIT", "bin": { @@ -3307,6 +3497,7 @@ }, "node_modules/npm/node_modules/mkdirp-infer-owner": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3320,16 +3511,19 @@ }, "node_modules/npm/node_modules/ms": { "version": "2.1.3", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/mute-stream": { "version": "0.0.8", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/negotiator": { "version": "0.6.3", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -3338,6 +3532,7 @@ }, "node_modules/npm/node_modules/node-gyp": { "version": "9.1.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3361,6 +3556,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3370,6 +3566,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/glob": { "version": "7.2.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3389,6 +3586,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { "version": "3.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3400,6 +3598,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3414,6 +3613,7 @@ }, "node_modules/npm/node_modules/nopt": { "version": "6.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3428,6 +3628,7 @@ }, "node_modules/npm/node_modules/normalize-package-data": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -3442,6 +3643,7 @@ }, "node_modules/npm/node_modules/npm-audit-report": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3453,6 +3655,7 @@ }, "node_modules/npm/node_modules/npm-bundled": { "version": "1.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3461,6 +3664,7 @@ }, "node_modules/npm/node_modules/npm-install-checks": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -3472,11 +3676,13 @@ }, "node_modules/npm/node_modules/npm-normalize-package-bin": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/npm-package-arg": { "version": "9.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3491,6 +3697,7 @@ }, "node_modules/npm/node_modules/npm-packlist": { "version": "5.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3508,6 +3715,7 @@ }, "node_modules/npm/node_modules/npm-pick-manifest": { "version": "7.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3522,6 +3730,7 @@ }, "node_modules/npm/node_modules/npm-profile": { "version": "6.2.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3534,6 +3743,7 @@ }, "node_modules/npm/node_modules/npm-registry-fetch": { "version": "13.3.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3551,11 +3761,13 @@ }, "node_modules/npm/node_modules/npm-user-validate": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/npmlog": { "version": "6.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3570,6 +3782,7 @@ }, "node_modules/npm/node_modules/once": { "version": "1.4.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3578,6 +3791,7 @@ }, "node_modules/npm/node_modules/opener": { "version": "1.5.2", + "dev": true, "inBundle": true, "license": "(WTFPL OR MIT)", "bin": { @@ -3586,6 +3800,7 @@ }, "node_modules/npm/node_modules/p-map": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3600,6 +3815,7 @@ }, "node_modules/npm/node_modules/pacote": { "version": "13.6.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3634,6 +3850,7 @@ }, "node_modules/npm/node_modules/parse-conflict-json": { "version": "2.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3647,6 +3864,7 @@ }, "node_modules/npm/node_modules/path-is-absolute": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -3655,6 +3873,7 @@ }, "node_modules/npm/node_modules/postcss-selector-parser": { "version": "6.0.10", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3667,6 +3886,7 @@ }, "node_modules/npm/node_modules/proc-log": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -3675,6 +3895,7 @@ }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -3683,6 +3904,7 @@ }, "node_modules/npm/node_modules/promise-call-limit": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -3691,11 +3913,13 @@ }, "node_modules/npm/node_modules/promise-inflight": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3708,6 +3932,7 @@ }, "node_modules/npm/node_modules/promzard": { "version": "0.3.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3716,6 +3941,7 @@ }, "node_modules/npm/node_modules/qrcode-terminal": { "version": "0.12.0", + "dev": true, "inBundle": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" @@ -3723,6 +3949,7 @@ }, "node_modules/npm/node_modules/read": { "version": "1.0.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3734,6 +3961,7 @@ }, "node_modules/npm/node_modules/read-cmd-shim": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -3742,6 +3970,7 @@ }, "node_modules/npm/node_modules/read-package-json": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3756,6 +3985,7 @@ }, "node_modules/npm/node_modules/read-package-json-fast": { "version": "2.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3768,6 +3998,7 @@ }, "node_modules/npm/node_modules/readable-stream": { "version": "3.6.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3781,6 +4012,7 @@ }, "node_modules/npm/node_modules/readdir-scoped-modules": { "version": "1.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3792,6 +4024,7 @@ }, "node_modules/npm/node_modules/retry": { "version": "0.12.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -3800,6 +4033,7 @@ }, "node_modules/npm/node_modules/rimraf": { "version": "3.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3814,6 +4048,7 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3823,6 +4058,7 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/glob": { "version": "7.2.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3842,6 +4078,7 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3853,6 +4090,7 @@ }, "node_modules/npm/node_modules/safe-buffer": { "version": "5.2.1", + "dev": true, "funding": [ { "type": "github", @@ -3872,12 +4110,14 @@ }, "node_modules/npm/node_modules/safer-buffer": { "version": "2.1.2", + "dev": true, "inBundle": true, "license": "MIT", "optional": true }, "node_modules/npm/node_modules/semver": { "version": "7.3.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3892,6 +4132,7 @@ }, "node_modules/npm/node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3903,16 +4144,19 @@ }, "node_modules/npm/node_modules/set-blocking": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/signal-exit": { "version": "3.0.7", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/smart-buffer": { "version": "4.2.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -3922,6 +4166,7 @@ }, "node_modules/npm/node_modules/socks": { "version": "2.7.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3935,6 +4180,7 @@ }, "node_modules/npm/node_modules/socks-proxy-agent": { "version": "7.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3948,6 +4194,7 @@ }, "node_modules/npm/node_modules/spdx-correct": { "version": "3.1.1", + "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -3957,11 +4204,13 @@ }, "node_modules/npm/node_modules/spdx-exceptions": { "version": "2.3.0", + "dev": true, "inBundle": true, "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3971,11 +4220,13 @@ }, "node_modules/npm/node_modules/spdx-license-ids": { "version": "3.0.11", + "dev": true, "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { "version": "9.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -3987,6 +4238,7 @@ }, "node_modules/npm/node_modules/string_decoder": { "version": "1.3.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -3995,6 +4247,7 @@ }, "node_modules/npm/node_modules/string-width": { "version": "4.2.3", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -4008,6 +4261,7 @@ }, "node_modules/npm/node_modules/strip-ansi": { "version": "6.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -4019,6 +4273,7 @@ }, "node_modules/npm/node_modules/supports-color": { "version": "7.2.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -4030,6 +4285,7 @@ }, "node_modules/npm/node_modules/tar": { "version": "6.1.11", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4046,16 +4302,19 @@ }, "node_modules/npm/node_modules/text-table": { "version": "0.2.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/tiny-relative-date": { "version": "1.3.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/treeverse": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -4064,6 +4323,7 @@ }, "node_modules/npm/node_modules/unique-filename": { "version": "1.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4072,6 +4332,7 @@ }, "node_modules/npm/node_modules/unique-slug": { "version": "2.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4080,11 +4341,13 @@ }, "node_modules/npm/node_modules/util-deprecate": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/validate-npm-package-license": { "version": "3.0.4", + "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -4094,6 +4357,7 @@ }, "node_modules/npm/node_modules/validate-npm-package-name": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4105,11 +4369,13 @@ }, "node_modules/npm/node_modules/walk-up-path": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/wcwidth": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -4118,6 +4384,7 @@ }, "node_modules/npm/node_modules/which": { "version": "2.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4132,6 +4399,7 @@ }, "node_modules/npm/node_modules/wide-align": { "version": "1.1.5", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4140,11 +4408,13 @@ }, "node_modules/npm/node_modules/wrappy": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/write-file-atomic": { "version": "4.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -4157,6 +4427,7 @@ }, "node_modules/npm/node_modules/yallist": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, @@ -4179,6 +4450,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5043,6 +5322,21 @@ "@stablelib/wipe": "^1.0.1" } }, + "@subspace/vdf": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@subspace/vdf/-/vdf-0.1.0.tgz", + "integrity": "sha512-iKYdYOcAtALmxxgreWqnHphT7m8HIyBsAYLrPSRvOJM9hTY+Rfg+EsLiqXLgHoIXyy980dQhoE4yIwu8xXDmvg==", + "requires": { + "@types/node": "^11.13.4" + }, + "dependencies": { + "@types/node": { + "version": "11.15.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.54.tgz", + "integrity": "sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==" + } + } + }, "@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -5216,6 +5510,15 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, + "@types/morgan": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", + "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/node": { "version": "17.0.36", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", @@ -5324,7 +5627,22 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, - "bignumber.js": { + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + }, + "dependencies": { + "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==" + } + } + }, + "bignumber.js": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" @@ -6253,6 +6571,28 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "requires": { + "ee-first": "1.1.1" + } + } + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6401,19 +6741,23 @@ "@colors/colors": { "version": "1.5.0", "bundled": true, + "dev": true, "optional": true }, "@gar/promisify": { "version": "1.1.3", - "bundled": true + "bundled": true, + "dev": true }, "@isaacs/string-locale-compare": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/arborist": { "version": "5.5.0", "bundled": true, + "dev": true, "requires": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -6455,11 +6799,13 @@ }, "@npmcli/ci-detect": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/config": { "version": "4.2.1", "bundled": true, + "dev": true, "requires": { "@npmcli/map-workspaces": "^2.0.2", "ini": "^3.0.0", @@ -6474,6 +6820,7 @@ "@npmcli/disparity-colors": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "ansi-styles": "^4.3.0" } @@ -6481,6 +6828,7 @@ "@npmcli/fs": { "version": "2.1.1", "bundled": true, + "dev": true, "requires": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" @@ -6489,6 +6837,7 @@ "@npmcli/git": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "@npmcli/promise-spawn": "^3.0.0", "lru-cache": "^7.4.4", @@ -6504,6 +6853,7 @@ "@npmcli/installed-package-contents": { "version": "1.0.7", "bundled": true, + "dev": true, "requires": { "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" @@ -6512,6 +6862,7 @@ "@npmcli/map-workspaces": { "version": "2.0.4", "bundled": true, + "dev": true, "requires": { "@npmcli/name-from-folder": "^1.0.1", "glob": "^8.0.1", @@ -6522,6 +6873,7 @@ "@npmcli/metavuln-calculator": { "version": "3.1.1", "bundled": true, + "dev": true, "requires": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", @@ -6532,6 +6884,7 @@ "@npmcli/move-file": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -6539,15 +6892,18 @@ }, "@npmcli/name-from-folder": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/node-gyp": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/package-json": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.1" } @@ -6555,6 +6911,7 @@ "@npmcli/promise-spawn": { "version": "3.0.0", "bundled": true, + "dev": true, "requires": { "infer-owner": "^1.0.4" } @@ -6562,6 +6919,7 @@ "@npmcli/query": { "version": "1.1.1", "bundled": true, + "dev": true, "requires": { "npm-package-arg": "^9.1.0", "postcss-selector-parser": "^6.0.10", @@ -6571,6 +6929,7 @@ "@npmcli/run-script": { "version": "4.2.1", "bundled": true, + "dev": true, "requires": { "@npmcli/node-gyp": "^2.0.0", "@npmcli/promise-spawn": "^3.0.0", @@ -6581,15 +6940,18 @@ }, "@tootallnate/once": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "abbrev": { "version": "1.1.1", - "bundled": true + "bundled": true, + "dev": true }, "agent-base": { "version": "6.0.2", "bundled": true, + "dev": true, "requires": { "debug": "4" } @@ -6597,6 +6959,7 @@ "agentkeepalive": { "version": "4.2.1", "bundled": true, + "dev": true, "requires": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -6606,6 +6969,7 @@ "aggregate-error": { "version": "3.1.0", "bundled": true, + "dev": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -6613,26 +6977,31 @@ }, "ansi-regex": { "version": "5.0.1", - "bundled": true + "bundled": true, + "dev": true }, "ansi-styles": { "version": "4.3.0", "bundled": true, + "dev": true, "requires": { "color-convert": "^2.0.1" } }, "aproba": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "archy": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "are-we-there-yet": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -6640,15 +7009,18 @@ }, "asap": { "version": "2.0.6", - "bundled": true + "bundled": true, + "dev": true }, "balanced-match": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "bin-links": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "cmd-shim": "^5.0.0", "mkdirp-infer-owner": "^2.0.0", @@ -6660,11 +7032,13 @@ }, "binary-extensions": { "version": "2.2.0", - "bundled": true + "bundled": true, + "dev": true }, "brace-expansion": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0" } @@ -6672,6 +7046,7 @@ "builtins": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "semver": "^7.0.0" } @@ -6679,6 +7054,7 @@ "cacache": { "version": "16.1.1", "bundled": true, + "dev": true, "requires": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", @@ -6703,6 +7079,7 @@ "chalk": { "version": "4.1.2", "bundled": true, + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6710,22 +7087,26 @@ }, "chownr": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "cidr-regex": { "version": "3.1.1", "bundled": true, + "dev": true, "requires": { "ip-regex": "^4.1.0" } }, "clean-stack": { "version": "2.2.0", - "bundled": true + "bundled": true, + "dev": true }, "cli-columns": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "string-width": "^4.2.3", "strip-ansi": "^6.0.1" @@ -6734,6 +7115,7 @@ "cli-table3": { "version": "0.6.2", "bundled": true, + "dev": true, "requires": { "@colors/colors": "1.5.0", "string-width": "^4.2.0" @@ -6741,11 +7123,13 @@ }, "clone": { "version": "1.0.4", - "bundled": true + "bundled": true, + "dev": true }, "cmd-shim": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "mkdirp-infer-owner": "^2.0.0" } @@ -6753,21 +7137,25 @@ "color-convert": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", - "bundled": true + "bundled": true, + "dev": true }, "color-support": { "version": "1.1.3", - "bundled": true + "bundled": true, + "dev": true }, "columnify": { "version": "1.6.0", "bundled": true, + "dev": true, "requires": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" @@ -6775,55 +7163,66 @@ }, "common-ancestor-path": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "cssesc": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "debug": { "version": "4.3.4", "bundled": true, + "dev": true, "requires": { "ms": "2.1.2" }, "dependencies": { "ms": { "version": "2.1.2", - "bundled": true + "bundled": true, + "dev": true } } }, "debuglog": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "defaults": { "version": "1.0.3", "bundled": true, + "dev": true, "requires": { "clone": "^1.0.2" } }, "delegates": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "depd": { "version": "1.1.2", - "bundled": true + "bundled": true, + "dev": true }, "dezalgo": { "version": "1.0.4", "bundled": true, + "dev": true, "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -6831,15 +7230,18 @@ }, "diff": { "version": "5.0.0", - "bundled": true + "bundled": true, + "dev": true }, "emoji-regex": { "version": "8.0.0", - "bundled": true + "bundled": true, + "dev": true }, "encoding": { "version": "0.1.13", "bundled": true, + "dev": true, "optional": true, "requires": { "iconv-lite": "^0.6.2" @@ -6847,34 +7249,41 @@ }, "env-paths": { "version": "2.2.1", - "bundled": true + "bundled": true, + "dev": true }, "err-code": { "version": "2.0.3", - "bundled": true + "bundled": true, + "dev": true }, "fastest-levenshtein": { "version": "1.0.12", - "bundled": true + "bundled": true, + "dev": true }, "fs-minipass": { "version": "2.1.0", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } }, "fs.realpath": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "function-bind": { "version": "1.1.1", - "bundled": true + "bundled": true, + "dev": true }, "gauge": { "version": "4.0.4", "bundled": true, + "dev": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -6889,6 +7298,7 @@ "glob": { "version": "8.0.3", "bundled": true, + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -6899,37 +7309,44 @@ }, "graceful-fs": { "version": "4.2.10", - "bundled": true + "bundled": true, + "dev": true }, "has": { "version": "1.0.3", "bundled": true, + "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "4.0.0", - "bundled": true + "bundled": true, + "dev": true }, "has-unicode": { "version": "2.0.1", - "bundled": true + "bundled": true, + "dev": true }, "hosted-git-info": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "lru-cache": "^7.5.1" } }, "http-cache-semantics": { "version": "4.1.0", - "bundled": true + "bundled": true, + "dev": true }, "http-proxy-agent": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "@tootallnate/once": "2", "agent-base": "6", @@ -6939,6 +7356,7 @@ "https-proxy-agent": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -6947,6 +7365,7 @@ "humanize-ms": { "version": "1.2.1", "bundled": true, + "dev": true, "requires": { "ms": "^2.0.0" } @@ -6954,6 +7373,7 @@ "iconv-lite": { "version": "0.6.3", "bundled": true, + "dev": true, "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -6962,25 +7382,30 @@ "ignore-walk": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "minimatch": "^5.0.1" } }, "imurmurhash": { "version": "0.1.4", - "bundled": true + "bundled": true, + "dev": true }, "indent-string": { "version": "4.0.0", - "bundled": true + "bundled": true, + "dev": true }, "infer-owner": { "version": "1.0.4", - "bundled": true + "bundled": true, + "dev": true }, "inflight": { "version": "1.0.6", "bundled": true, + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -6988,15 +7413,18 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "dev": true }, "ini": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "init-package-json": { "version": "3.0.2", "bundled": true, + "dev": true, "requires": { "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", @@ -7009,15 +7437,18 @@ }, "ip": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "ip-regex": { "version": "4.3.0", - "bundled": true + "bundled": true, + "dev": true }, "is-cidr": { "version": "4.0.2", "bundled": true, + "dev": true, "requires": { "cidr-regex": "^3.1.1" } @@ -7025,45 +7456,55 @@ "is-core-module": { "version": "2.10.0", "bundled": true, + "dev": true, "requires": { "has": "^1.0.3" } }, "is-fullwidth-code-point": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "is-lambda": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "isexe": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "json-parse-even-better-errors": { "version": "2.3.1", - "bundled": true + "bundled": true, + "dev": true }, "json-stringify-nice": { "version": "1.1.4", - "bundled": true + "bundled": true, + "dev": true }, "jsonparse": { "version": "1.3.1", - "bundled": true + "bundled": true, + "dev": true }, "just-diff": { "version": "5.1.1", - "bundled": true + "bundled": true, + "dev": true }, "just-diff-apply": { "version": "5.4.1", - "bundled": true + "bundled": true, + "dev": true }, "libnpmaccess": { "version": "6.0.3", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "minipass": "^3.1.1", @@ -7074,6 +7515,7 @@ "libnpmdiff": { "version": "4.0.4", "bundled": true, + "dev": true, "requires": { "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -7088,6 +7530,7 @@ "libnpmexec": { "version": "4.0.10", "bundled": true, + "dev": true, "requires": { "@npmcli/arborist": "^5.0.0", "@npmcli/ci-detect": "^2.0.0", @@ -7108,6 +7551,7 @@ "libnpmfund": { "version": "3.0.2", "bundled": true, + "dev": true, "requires": { "@npmcli/arborist": "^5.0.0" } @@ -7115,6 +7559,7 @@ "libnpmhook": { "version": "8.0.3", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -7123,6 +7568,7 @@ "libnpmorg": { "version": "4.0.3", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -7131,6 +7577,7 @@ "libnpmpack": { "version": "4.1.2", "bundled": true, + "dev": true, "requires": { "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", @@ -7140,6 +7587,7 @@ "libnpmpublish": { "version": "6.0.4", "bundled": true, + "dev": true, "requires": { "normalize-package-data": "^4.0.0", "npm-package-arg": "^9.0.1", @@ -7151,6 +7599,7 @@ "libnpmsearch": { "version": "5.0.3", "bundled": true, + "dev": true, "requires": { "npm-registry-fetch": "^13.0.0" } @@ -7158,6 +7607,7 @@ "libnpmteam": { "version": "4.0.3", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -7166,6 +7616,7 @@ "libnpmversion": { "version": "3.0.6", "bundled": true, + "dev": true, "requires": { "@npmcli/git": "^3.0.0", "@npmcli/run-script": "^4.1.3", @@ -7176,11 +7627,13 @@ }, "lru-cache": { "version": "7.13.2", - "bundled": true + "bundled": true, + "dev": true }, "make-fetch-happen": { "version": "10.2.0", "bundled": true, + "dev": true, "requires": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -7203,6 +7656,7 @@ "minimatch": { "version": "5.1.0", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^2.0.1" } @@ -7210,6 +7664,7 @@ "minipass": { "version": "3.3.4", "bundled": true, + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -7217,6 +7672,7 @@ "minipass-collect": { "version": "1.0.2", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -7224,6 +7680,7 @@ "minipass-fetch": { "version": "2.1.0", "bundled": true, + "dev": true, "requires": { "encoding": "^0.1.13", "minipass": "^3.1.6", @@ -7234,6 +7691,7 @@ "minipass-flush": { "version": "1.0.5", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -7241,6 +7699,7 @@ "minipass-json-stream": { "version": "1.0.1", "bundled": true, + "dev": true, "requires": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -7249,6 +7708,7 @@ "minipass-pipeline": { "version": "1.2.4", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -7256,6 +7716,7 @@ "minipass-sized": { "version": "1.0.3", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -7263,6 +7724,7 @@ "minizlib": { "version": "2.1.2", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -7270,11 +7732,13 @@ }, "mkdirp": { "version": "1.0.4", - "bundled": true + "bundled": true, + "dev": true }, "mkdirp-infer-owner": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "chownr": "^2.0.0", "infer-owner": "^1.0.4", @@ -7283,19 +7747,23 @@ }, "ms": { "version": "2.1.3", - "bundled": true + "bundled": true, + "dev": true }, "mute-stream": { "version": "0.0.8", - "bundled": true + "bundled": true, + "dev": true }, "negotiator": { "version": "0.6.3", - "bundled": true + "bundled": true, + "dev": true }, "node-gyp": { "version": "9.1.0", "bundled": true, + "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -7312,6 +7780,7 @@ "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7320,6 +7789,7 @@ "glob": { "version": "7.2.3", "bundled": true, + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7332,6 +7802,7 @@ "minimatch": { "version": "3.1.2", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7339,6 +7810,7 @@ "nopt": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "abbrev": "1" } @@ -7348,6 +7820,7 @@ "nopt": { "version": "6.0.0", "bundled": true, + "dev": true, "requires": { "abbrev": "^1.0.0" } @@ -7355,6 +7828,7 @@ "normalize-package-data": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -7365,6 +7839,7 @@ "npm-audit-report": { "version": "3.0.0", "bundled": true, + "dev": true, "requires": { "chalk": "^4.0.0" } @@ -7372,6 +7847,7 @@ "npm-bundled": { "version": "1.1.2", "bundled": true, + "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -7379,17 +7855,20 @@ "npm-install-checks": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "semver": "^7.1.1" } }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "npm-package-arg": { "version": "9.1.0", "bundled": true, + "dev": true, "requires": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -7400,6 +7879,7 @@ "npm-packlist": { "version": "5.1.1", "bundled": true, + "dev": true, "requires": { "glob": "^8.0.1", "ignore-walk": "^5.0.1", @@ -7410,6 +7890,7 @@ "npm-pick-manifest": { "version": "7.0.1", "bundled": true, + "dev": true, "requires": { "npm-install-checks": "^5.0.0", "npm-normalize-package-bin": "^1.0.1", @@ -7420,6 +7901,7 @@ "npm-profile": { "version": "6.2.1", "bundled": true, + "dev": true, "requires": { "npm-registry-fetch": "^13.0.1", "proc-log": "^2.0.0" @@ -7428,6 +7910,7 @@ "npm-registry-fetch": { "version": "13.3.0", "bundled": true, + "dev": true, "requires": { "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", @@ -7440,11 +7923,13 @@ }, "npm-user-validate": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "npmlog": { "version": "6.0.2", "bundled": true, + "dev": true, "requires": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -7455,17 +7940,20 @@ "once": { "version": "1.4.0", "bundled": true, + "dev": true, "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.2", - "bundled": true + "bundled": true, + "dev": true }, "p-map": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "aggregate-error": "^3.0.0" } @@ -7473,6 +7961,7 @@ "pacote": { "version": "13.6.1", "bundled": true, + "dev": true, "requires": { "@npmcli/git": "^3.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -7500,6 +7989,7 @@ "parse-conflict-json": { "version": "2.0.2", "bundled": true, + "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.1", "just-diff": "^5.0.1", @@ -7508,11 +7998,13 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "postcss-selector-parser": { "version": "6.0.10", "bundled": true, + "dev": true, "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7520,23 +8012,28 @@ }, "proc-log": { "version": "2.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-all-reject-late": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-call-limit": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-inflight": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-retry": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -7545,28 +8042,33 @@ "promzard": { "version": "0.3.0", "bundled": true, + "dev": true, "requires": { "read": "1" } }, "qrcode-terminal": { "version": "0.12.0", - "bundled": true + "bundled": true, + "dev": true }, "read": { "version": "1.0.7", "bundled": true, + "dev": true, "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "read-package-json": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "glob": "^8.0.1", "json-parse-even-better-errors": "^2.3.1", @@ -7577,6 +8079,7 @@ "read-package-json-fast": { "version": "2.0.3", "bundled": true, + "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" @@ -7585,6 +8088,7 @@ "readable-stream": { "version": "3.6.0", "bundled": true, + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -7594,6 +8098,7 @@ "readdir-scoped-modules": { "version": "1.1.0", "bundled": true, + "dev": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -7603,11 +8108,13 @@ }, "retry": { "version": "0.12.0", - "bundled": true + "bundled": true, + "dev": true }, "rimraf": { "version": "3.0.2", "bundled": true, + "dev": true, "requires": { "glob": "^7.1.3" }, @@ -7615,6 +8122,7 @@ "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7623,6 +8131,7 @@ "glob": { "version": "7.2.3", "bundled": true, + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -7635,6 +8144,7 @@ "minimatch": { "version": "3.1.2", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -7643,16 +8153,19 @@ }, "safe-buffer": { "version": "5.2.1", - "bundled": true + "bundled": true, + "dev": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, + "dev": true, "optional": true }, "semver": { "version": "7.3.7", "bundled": true, + "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -7660,6 +8173,7 @@ "lru-cache": { "version": "6.0.0", "bundled": true, + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -7668,19 +8182,23 @@ }, "set-blocking": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "signal-exit": { "version": "3.0.7", - "bundled": true + "bundled": true, + "dev": true }, "smart-buffer": { "version": "4.2.0", - "bundled": true + "bundled": true, + "dev": true }, "socks": { "version": "2.7.0", "bundled": true, + "dev": true, "requires": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -7689,6 +8207,7 @@ "socks-proxy-agent": { "version": "7.0.0", "bundled": true, + "dev": true, "requires": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -7698,6 +8217,7 @@ "spdx-correct": { "version": "3.1.1", "bundled": true, + "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -7705,11 +8225,13 @@ }, "spdx-exceptions": { "version": "2.3.0", - "bundled": true + "bundled": true, + "dev": true }, "spdx-expression-parse": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -7717,11 +8239,13 @@ }, "spdx-license-ids": { "version": "3.0.11", - "bundled": true + "bundled": true, + "dev": true }, "ssri": { "version": "9.0.1", "bundled": true, + "dev": true, "requires": { "minipass": "^3.1.1" } @@ -7729,6 +8253,7 @@ "string_decoder": { "version": "1.3.0", "bundled": true, + "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -7736,6 +8261,7 @@ "string-width": { "version": "4.2.3", "bundled": true, + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -7745,6 +8271,7 @@ "strip-ansi": { "version": "6.0.1", "bundled": true, + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -7752,6 +8279,7 @@ "supports-color": { "version": "7.2.0", "bundled": true, + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -7759,6 +8287,7 @@ "tar": { "version": "6.1.11", "bundled": true, + "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -7770,19 +8299,23 @@ }, "text-table": { "version": "0.2.0", - "bundled": true + "bundled": true, + "dev": true }, "tiny-relative-date": { "version": "1.3.0", - "bundled": true + "bundled": true, + "dev": true }, "treeverse": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "unique-filename": { "version": "1.1.1", "bundled": true, + "dev": true, "requires": { "unique-slug": "^2.0.0" } @@ -7790,17 +8323,20 @@ "unique-slug": { "version": "2.0.2", "bundled": true, + "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, "util-deprecate": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "validate-npm-package-license": { "version": "3.0.4", "bundled": true, + "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -7809,17 +8345,20 @@ "validate-npm-package-name": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "builtins": "^5.0.0" } }, "walk-up-path": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "wcwidth": { "version": "1.0.1", "bundled": true, + "dev": true, "requires": { "defaults": "^1.0.3" } @@ -7827,6 +8366,7 @@ "which": { "version": "2.0.2", "bundled": true, + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -7834,17 +8374,20 @@ "wide-align": { "version": "1.1.5", "bundled": true, + "dev": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "write-file-atomic": { "version": "4.0.1", "bundled": true, + "dev": true, "requires": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -7852,7 +8395,8 @@ }, "yallist": { "version": "4.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, @@ -7869,6 +8413,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", diff --git a/package.json b/package.json index 68b6c81..c8f7b56 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,9 @@ "main": "dist/api.js", "scripts": { "build": "npx tsc", - "test": "echo \"Error: no test specified\" && exit 1", - "serve": "nodemon dist/api.js" + "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run serve\"", + "serve": "node --experimental-modules --experimental-wasm-modules dist/api.js", + "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", @@ -20,16 +21,19 @@ "homepage": "https://github.com/oxheadalpha/tezos-testnet-faucet-backend#readme", "dependencies": { "@netlify/functions": "^1.0.0", + "@subspace/vdf": "^0.1.0", "@taquito/signer": "^12.1.1", "@taquito/taquito": "^12.1.1", "axios": "^0.26.1", "body-parser": "^1.20.0", "dotenv": "^16.0.1", - "express": "^4.18.1" + "express": "^4.18.1", + "morgan": "^1.10.0" }, "devDependencies": { "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/morgan": "^1.9.4", "@types/node": "^17.0.36", "nodemon": "^2.0.16", "npm": "^8.17.0", diff --git a/src/Tezos.ts b/src/Tezos.ts index 59aec2b..0ce2700 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -5,7 +5,7 @@ const defaultMaxBalance: number = 6000; const send = async (amount: number, address: string): Promise => { console.log(`Send ${amount} xtz to ${address}`); - + return "" // Connect to RPC endpoint const rpcUrl: string = process.env.RPC_URL; diff --git a/src/api.ts b/src/api.ts index a17d29b..2682147 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,116 +1,215 @@ -import express, { Express, Request, Response } from 'express'; -import bodyParser from 'body-parser'; -import dotenv from 'dotenv'; +import express, { Express, Request, Response } from "express" +import bodyParser from "body-parser" +import morgan from "morgan" +import dotenv from "dotenv" +import createVdf from "@subspace/vdf" -import { Profile, RequestBody, ResponseBody, InfoResponseBody } from './Types'; -import { checkCaptcha } from './Captcha'; -import { send } from './Tezos'; +import { Profile, RequestBody, ResponseBody, InfoResponseBody } from "./Types" +import { checkCaptcha } from "./Captcha" +import { send } from "./Tezos" +import { randomBytes } from "crypto" +import { log } from "console" -dotenv.config(); +dotenv.config() -const defaultPort: number = 3000; -const defaultUserAmount: number = 1; -const defaultBakerAmount: number = 6000; - -const app: Express = express(); -app.use(bodyParser.json()); -app.use(bodyParser.urlencoded({ extended: true })); +const defaultPort: number = 3000 +const defaultUserAmount: number = 1 +const defaultBakerAmount: number = 6000 +const app: Express = express() +app.use(bodyParser.json()) +app.use(bodyParser.urlencoded({ extended: true })) +app.use(morgan("dev")) app.use((req: Request, res: Response, next) => { - - const cors: string = process.env.AUTHORIZED_HOST || '*'; - res.setHeader("Access-Control-Allow-Origin", cors); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST'); - res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); - - next(); -}); - -app.get('/info', (_, res: Response) => { - - console.log('Get info'); - - let profiles: any = { - user: { - profile: Profile.USER, - amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, - currency: "tez" - }, - baker: { - profile: Profile.BAKER, - amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, - currency: "tez" - } - }; - - let info: InfoResponseBody = { - faucetAddress: process.env.FAUCET_ADDRESS, - captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), - profiles: profiles, - maxBalance: process.env.MAX_BALANCE - }; - - res.status(200); - res.send(info); -}); - -app.post('/send', async (req: Request, res: Response) => { - - const body: RequestBody = req.body; - - const { captchaToken: captchaToken, address: address, profile: profile } = body; - - let responseBody: ResponseBody = { - status: '', - message: undefined, - txHash: undefined - }; - - let amount: number = 0; - - switch (profile) { - case Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount; - break; - case Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount; - break; - default: - console.log(`Unknown profile ${profile}`); - responseBody.status = "ERROR"; - responseBody.message = `Unknown profile`; - res.status(400); - res.send(responseBody); - return; + const cors: string = process.env.AUTHORIZED_HOST || "*" + res.setHeader("Access-Control-Allow-Origin", cors) + res.setHeader("Access-Control-Allow-Methods", "GET, POST") + res.setHeader( + "Access-Control-Allow-Headers", + "Origin, X-Requested-With, Content-Type, Accept" + ) + + next() +}) + +// createVdf().then((vdfInstance: any) => { +// const iterations = 3 +// const challenge = Buffer.from("aa", "hex") +// const intSizeBits = 2048 +// // const intSizeBits = 100; +// const isPietrzak = false +// const res = vdfInstance.generate( +// iterations, +// challenge, +// intSizeBits, +// isPietrzak +// ) +// // console.log(res) +// console.log(Buffer.from(res).toString("hex")) +// console.log(vdfInstance.verify(3, challenge, res, intSizeBits, isPietrzak)) +// }) + + +app.get("/info", (_, res: Response) => { + console.log("Get info") + + let profiles: any = { + user: { + profile: Profile.USER, + amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, + currency: "tez", + }, + baker: { + profile: Profile.BAKER, + amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, + currency: "tez", + }, + } + + let info: InfoResponseBody = { + faucetAddress: process.env.FAUCET_ADDRESS, + captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), + profiles: profiles, + maxBalance: process.env.MAX_BALANCE, + } + + res.status(200) + res.send(info) +}) + +app.post("/send", async (req: Request, res: Response) => { + const body: RequestBody = req.body + + const { captchaToken, address, profile } = body + + const responseBody: any = { + status: "", + message: undefined, + txHash: undefined, + vdfChallenge: "", + } + + let amount: number = 0 + + switch (profile) { + case Profile.USER: + amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount + break + case Profile.BAKER: + amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount + break + default: + console.log(`Unknown profile ${profile}`) + responseBody.status = "ERROR" + responseBody.message = `Unknown profile` + res.status(400) + res.send(responseBody) + return + } + + // console.log( + // `Try to send ${amount} xtz to ${address}, with captcha token ${captchaToken}` + // ) + + const discriminant_challenge = randomBytes(10) + console.log({ + discriminant_challenge: Buffer.from(discriminant_challenge).toString("hex"), + }) + + responseBody.status = "SUCCESS" + responseBody.vdfChallenge = { + challenge: discriminant_challenge, + // challenge: "adfdafaafas329084dfadf", + iterations: 10000, + // size: 512, + size: 2048, + } + res.status(200) + res.send(responseBody) + return + + if (await checkCaptcha(captchaToken)) { + try { + responseBody.txHash = await send(amount, address) + responseBody.status = "SUCCESS" + res.status(200) + } catch (error) { + responseBody.message = `${error}` + responseBody.status = "ERROR" + res.status(500) } + } else { + responseBody.status = "ERROR" + responseBody.message = `Captcha error` + res.status(400) + } + + res.send(responseBody) +}) + +const vdf = createVdf() + +app.post("/verify", async (req: Request, res: Response) => { + const body: any = req.body + // const body: VerificationRequestBody = req.body + + const { challenge, iterations, size, solution, profile, address } = body + // console.log({ solution: Buffer.from(solution, "hex") }) + let responseBody: ResponseBody = { + status: "", + message: undefined, + txHash: undefined, + } + + // Verify the solution (use the VDF library's verify method) + const v = await vdf + // console.log({ v }) + let solutionBuffer = Buffer.from(solution, "base64") + // console.log({ bufferFromSolution: Buffer.from(solution) }) + // let uint8Array = new Uint8Array(buffer) + console.log({ solutionBuffer, challenge, size, iterations }) + console.log(solutionBuffer.toString("hex")) + const isValid = v.verify(iterations, challenge, solutionBuffer, size, false) + console.log({isValid}) + if (isValid) { + let amount: number = 0 - console.log(`Try to send ${amount} xtz to ${address}, with captcha token ${captchaToken}`); - - if (await checkCaptcha(captchaToken)) { - - try { - responseBody.txHash = await send(amount, address); - responseBody.status = "SUCCESS"; - res.status(200); - } - catch (error) { - responseBody.message = `${error}`; - responseBody.status = "ERROR"; - res.status(500); - } + switch (profile) { + case Profile.USER: + amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount + break + case Profile.BAKER: + amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount + break + default: + console.log(`Unknown profile ${profile}`) + responseBody.status = "ERROR" + responseBody.message = `Unknown profile` + res.status(400) + res.send(responseBody) + return } - else { - responseBody.status = "ERROR"; - responseBody.message = `Captcha error`; - res.status(400); + try { + responseBody.txHash = await send(amount, address) + responseBody.status = "SUCCESS" + res.status(200) + } catch (error) { + responseBody.message = `${error}` + responseBody.status = "ERROR" + res.status(500) } + } else { + responseBody.status = "ERROR" + responseBody.message = `Invalid solution` + res.status(400) + } - res.send(responseBody); -}); + res.send(responseBody) +}) -const port: number = process.env.API_PORT || defaultPort; +const port: number = process.env.API_PORT || defaultPort app.listen(port, () => { - console.log(`Start API on port ${port}.`); -}); \ No newline at end of file + console.log(`Start API on port ${port}.`) +}) From ff151129b4188965f20f48a80013a4132143d2b5 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 23 Jun 2023 16:14:57 -0400 Subject: [PATCH 02/64] WIP POW --- dist/Captcha.js | 4 +- dist/Tezos.js | 30 +++++- dist/api.js | 249 ++++++++++++++++++------------------------- package-lock.json | 154 ++++++++++++++++++++++++++- package.json | 5 +- src/Captcha.ts | 31 +++--- src/Tezos.ts | 142 ++++++++++++++----------- src/api.ts | 263 +++++++++++++++++++--------------------------- 8 files changed, 485 insertions(+), 393 deletions(-) diff --git a/dist/Captcha.js b/dist/Captcha.js index 1c2056b..0228ceb 100644 --- a/dist/Captcha.js +++ b/dist/Captcha.js @@ -15,6 +15,9 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.checkCaptcha = void 0; const axios_1 = __importDefault(require("axios")); const checkCaptcha = (responseToken) => __awaiter(void 0, void 0, void 0, function* () { + if (!responseToken) { + throw new Error("Missing captcha token."); + } const enableCaptcha = process.env.ENABLE_CAPTCHA || "true"; if (enableCaptcha === "false") { console.log("Captcha disabled"); @@ -23,7 +26,6 @@ const checkCaptcha = (responseToken) => __awaiter(void 0, void 0, void 0, functi const secret = process.env.FAUCET_CAPTCHA_SECRET; const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}`; const res = yield axios_1.default.post(captchaURL); - console.log(res.data); return res.data.success; }); exports.checkCaptcha = checkCaptcha; diff --git a/dist/Tezos.js b/dist/Tezos.js index fc90a77..d810499 100644 --- a/dist/Tezos.js +++ b/dist/Tezos.js @@ -9,13 +9,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.send = void 0; +exports.send = exports.getTezAmountForProfile = void 0; const signer_1 = require("@taquito/signer"); const taquito_1 = require("@taquito/taquito"); +const Types_1 = require("./Types"); const defaultMaxBalance = 6000; +const defaultUserAmount = 1; +const defaultBakerAmount = 6000; +const getTezAmountForProfile = (profile) => { + let amount = 0; + switch (profile) { + case Types_1.Profile.USER: + amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount; + break; + case Types_1.Profile.BAKER: + amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount; + break; + default: + throw new Error(`Unknown profile ${profile}`); + } + return amount; +}; +exports.getTezAmountForProfile = getTezAmountForProfile; const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () { console.log(`Send ${amount} xtz to ${address}`); - return ""; // Connect to RPC endpoint const rpcUrl = process.env.RPC_URL; if (!rpcUrl) { @@ -39,7 +56,9 @@ const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () } // Create signer try { - Tezos.setProvider({ signer: yield signer_1.InMemorySigner.fromSecretKey(privateKey) }); + Tezos.setProvider({ + signer: yield signer_1.InMemorySigner.fromSecretKey(privateKey), + }); } catch (err) { console.log(err); @@ -47,7 +66,10 @@ const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () } // Create and send transaction try { - const operation = yield Tezos.contract.transfer({ to: address, amount: amount }); + const operation = yield Tezos.contract.transfer({ + to: address, + amount: amount, + }); console.log(`Hash: ${operation.hash}`); return operation.hash; } diff --git a/dist/api.js b/dist/api.js index 238fe60..7657de4 100644 --- a/dist/api.js +++ b/dist/api.js @@ -16,12 +16,16 @@ const express_1 = __importDefault(require("express")); const body_parser_1 = __importDefault(require("body-parser")); const morgan_1 = __importDefault(require("morgan")); const dotenv_1 = __importDefault(require("dotenv")); -const vdf_1 = __importDefault(require("@subspace/vdf")); +const crypto_1 = __importDefault(require("crypto")); +const redis_1 = require("redis"); const Types_1 = require("./Types"); const Captcha_1 = require("./Captcha"); const Tezos_1 = require("./Tezos"); -const crypto_1 = require("crypto"); dotenv_1.default.config(); +const redisClient = (0, redis_1.createClient)({ +// url: "redis://localhost:6379", +}); // reject +redisClient.on("error", (err) => console.log("Redis Client Error", err)); const defaultPort = 3000; const defaultUserAmount = 1; const defaultBakerAmount = 6000; @@ -36,164 +40,111 @@ app.use((req, res, next) => { res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); }); -// createVdf().then((vdfInstance: any) => { -// const iterations = 3 -// const challenge = Buffer.from("aa", "hex") -// const intSizeBits = 2048 -// // const intSizeBits = 100; -// const isPietrzak = false -// const res = vdfInstance.generate( -// iterations, -// challenge, -// intSizeBits, -// isPietrzak -// ) -// // console.log(res) -// console.log(Buffer.from(res).toString("hex")) -// console.log(vdfInstance.verify(3, challenge, res, intSizeBits, isPietrzak)) -// }) app.get("/info", (_, res) => { console.log("Get info"); - let profiles = { - user: { - profile: Types_1.Profile.USER, - amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, - currency: "tez", - }, - baker: { - profile: Types_1.Profile.BAKER, - amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, - currency: "tez", - }, - }; - let info = { - faucetAddress: process.env.FAUCET_ADDRESS, - captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), - profiles: profiles, - maxBalance: process.env.MAX_BALANCE, - }; - res.status(200); - res.send(info); -}); -app.post("/send", (req, res) => __awaiter(void 0, void 0, void 0, function* () { - const body = req.body; - const { captchaToken, address, profile } = body; - const responseBody = { - status: "", - message: undefined, - txHash: undefined, - vdfChallenge: "", - }; - let amount = 0; - switch (profile) { - case Types_1.Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount; - break; - case Types_1.Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount; - break; - default: - console.log(`Unknown profile ${profile}`); - responseBody.status = "ERROR"; - responseBody.message = `Unknown profile`; - res.status(400); - res.send(responseBody); - return; + try { + let profiles = { + user: { + profile: Types_1.Profile.USER, + amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, + currency: "tez", + }, + baker: { + profile: Types_1.Profile.BAKER, + amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, + currency: "tez", + }, + }; + let info = { + faucetAddress: process.env.FAUCET_ADDRESS, + captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), + profiles: profiles, + maxBalance: process.env.MAX_BALANCE, + }; + res.status(200); + res.send(info); } - // console.log( - // `Try to send ${amount} xtz to ${address}, with captcha token ${captchaToken}` - // ) - const discriminant_challenge = (0, crypto_1.randomBytes)(10); - console.log({ - discriminant_challenge: Buffer.from(discriminant_challenge).toString("hex"), - }); - responseBody.status = "SUCCESS"; - responseBody.vdfChallenge = { - challenge: discriminant_challenge, - // challenge: "adfdafaafas329084dfadf", - iterations: 10000, - // size: 512, - size: 2048, - }; - res.status(200); - res.send(responseBody); - return; - if (yield (0, Captcha_1.checkCaptcha)(captchaToken)) { - try { - responseBody.txHash = yield (0, Tezos_1.send)(amount, address); - responseBody.status = "SUCCESS"; - res.status(200); - } - catch (error) { - responseBody.message = `${error}`; - responseBody.status = "ERROR"; - res.status(500); - } + catch (error) { + res.status(400); + res.send("Exception"); + } +}); +const DIFFICULTY = 4; +app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { + const { address, captchaToken, profile } = req.body; + console.log(req.body); + const validCaptcha = yield (0, Captcha_1.checkCaptcha)(captchaToken).catch((e) => res.status(400).send(e.message)); + if (validCaptcha) { + console.log("GOOD TOKEN"); } else { - responseBody.status = "ERROR"; - responseBody.message = `Captcha error`; - res.status(400); + console.log("BAD TOKEN"); + res.status(400).send({ status: "ERROR", message: "Captcha error" }); + return; + } + if (!address) { + res.status(400).send("The address property is required."); + return; + } + try { + (0, Tezos_1.getTezAmountForProfile)(profile); } - res.send(responseBody); + catch (e) { + res.status(400).send({ status: "ERROR", message: e.message }); + return; + } + // Generate or return existing PoW challenge. + const challenge = (yield redisClient.get(`address:${address}:challenge`)) || + crypto_1.default.randomBytes(32).toString("hex"); + // const challenge = crypto.randomBytes(32).toString("hex") + // Save the challenge and the associated address in Redis. Will only save if + // not already set. Set the challenge to expire after 30 minutes. + yield redisClient.set(`address:${address}:challenge`, challenge, { + EX: 1800, + NX: true, + }); + console.log({ challenge, difficulty: DIFFICULTY }); + res.status(200).send({ challenge, difficulty: DIFFICULTY }); })); -const vdf = (0, vdf_1.default)(); app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { - const body = req.body; - // const body: VerificationRequestBody = req.body - const { challenge, iterations, size, solution, profile, address } = body; - // console.log({ solution: Buffer.from(solution, "hex") }) - let responseBody = { - status: "", - message: undefined, - txHash: undefined, - }; - // Verify the solution (use the VDF library's verify method) - const v = yield vdf; - // console.log({ v }) - let solutionBuffer = Buffer.from(solution, "base64"); - // console.log({ bufferFromSolution: Buffer.from(solution) }) - // let uint8Array = new Uint8Array(buffer) - console.log({ solutionBuffer, challenge, size, iterations }); - console.log(solutionBuffer.toString("hex")); - const isValid = v.verify(iterations, challenge, solutionBuffer, size, false); - console.log({ isValid }); - if (isValid) { - let amount = 0; - switch (profile) { - case Types_1.Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount; - break; - case Types_1.Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount; - break; - default: - console.log(`Unknown profile ${profile}`); - responseBody.status = "ERROR"; - responseBody.message = `Unknown profile`; - res.status(400); - res.send(responseBody); - return; - } - try { - responseBody.txHash = yield (0, Tezos_1.send)(amount, address); - responseBody.status = "SUCCESS"; - res.status(200); - } - catch (error) { - responseBody.message = `${error}`; - responseBody.status = "ERROR"; - res.status(500); - } + const { address, captchaToken, solution, nonce } = req.body; + const validCaptcha = yield (0, Captcha_1.checkCaptcha)(captchaToken).catch((e) => res.status(400).send(e.message)); + if (validCaptcha) { + console.log("GOOD TOKEN"); } else { - responseBody.status = "ERROR"; - responseBody.message = `Invalid solution`; - res.status(400); + console.log("BAD TOKEN"); + res.status(500).send({ status: "ERROR", message: "Captcha error" }); + return; + } + const challenge = yield redisClient.get(`address:${address}:challenge`); + console.log({ address, solution, nonce }); + // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce + // starts with a certain number of zeroes (the difficulty) + const hash = crypto_1.default + .createHash("sha256") + .update(`${challenge}:${nonce}`) + .digest("hex"); + console.log({ hash }); + const difficulty = DIFFICULTY; // Adjust this value to change the difficulty of the PoW + if (hash === solution && hash.startsWith("0".repeat(difficulty))) { + // The solution is correct + // Here is where you would send the tez to the user's address + // For the sake of this example, we're just logging the address + console.log(`Send tez to ${address}`); + // responseBody.txHash = await send(amount, address) + // Delete the challenge from Redis + yield redisClient.del(`address:${address}:challenge`); + res.status(200).send({ status: "SUCCESS", message: "Tez sent" }); + } + else { + // The solution is incorrect + res.status(400).send({ status: "ERROR", message: "Incorrect solution" }); } - res.send(responseBody); })); const port = process.env.API_PORT || defaultPort; -app.listen(port, () => { +app.listen(port, () => __awaiter(void 0, void 0, void 0, function* () { console.log(`Start API on port ${port}.`); -}); + yield redisClient.connect(); + console.log("Connected to redis."); +})); diff --git a/package-lock.json b/package-lock.json index 2f596b0..0da270c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,8 @@ "body-parser": "^1.20.0", "dotenv": "^16.0.1", "express": "^4.18.1", - "morgan": "^1.10.0" + "morgan": "^1.10.0", + "redis": "^4.6.7" }, "devDependencies": { "@types/cors": "^2.8.12", @@ -40,6 +41,59 @@ "node": ">=8.3.0" } }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", + "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", + "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, "node_modules/@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -894,6 +948,14 @@ "mimic-response": "^1.0.0" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1272,6 +1334,14 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "engines": { + "node": ">= 4" + } + }, "node_modules/get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -4671,6 +4741,19 @@ "node": ">=8.10.0" } }, + "node_modules/redis": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", + "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.8", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.3", + "@redis/time-series": "1.0.4" + } + }, "node_modules/registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -5172,8 +5255,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } }, "dependencies": { @@ -5185,6 +5267,46 @@ "is-promise": "^4.0.0" } }, + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "requires": {} + }, + "@redis/client": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", + "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + } + }, + "@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "requires": {} + }, + "@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "requires": {} + }, + "@redis/search": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", + "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", + "requires": {} + }, + "@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "requires": {} + }, "@sindresorhus/is": { "version": "0.14.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", @@ -5874,6 +5996,11 @@ "mimic-response": "^1.0.0" } }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -6170,6 +6297,11 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" + }, "get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", @@ -8584,6 +8716,19 @@ "picomatch": "^2.2.1" } }, + "redis": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", + "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", + "requires": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.8", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.3", + "@redis/time-series": "1.0.4" + } + }, "registry-auth-token": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", @@ -8965,8 +9110,7 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/package.json b/package.json index c8f7b56..0b96029 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "npx tsc", "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run serve\"", - "serve": "node --experimental-modules --experimental-wasm-modules dist/api.js", + "serve": "node dist/api.js", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { @@ -28,7 +28,8 @@ "body-parser": "^1.20.0", "dotenv": "^16.0.1", "express": "^4.18.1", - "morgan": "^1.10.0" + "morgan": "^1.10.0", + "redis": "^4.6.7" }, "devDependencies": { "@types/cors": "^2.8.12", diff --git a/src/Captcha.ts b/src/Captcha.ts index 7d46849..d90ec1a 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -1,22 +1,21 @@ -import axios from 'axios'; +import axios from "axios" -const checkCaptcha = async (responseToken: string) => { +export const checkCaptcha = async (responseToken: string) => { + if (!responseToken) { + throw new Error("Missing captcha token.") + } - const enableCaptcha: string = process.env.ENABLE_CAPTCHA || "true"; + const enableCaptcha: string = process.env.ENABLE_CAPTCHA || "true" - if (enableCaptcha === "false") { - console.log("Captcha disabled"); - return true; - } + if (enableCaptcha === "false") { + console.log("Captcha disabled") + return true + } - const secret = process.env.FAUCET_CAPTCHA_SECRET; - const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}`; + const secret = process.env.FAUCET_CAPTCHA_SECRET - const res = await axios.post(captchaURL); - console.log(res.data); + const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}` - return res.data.success; -}; - - -export { checkCaptcha }; \ No newline at end of file + const res = await axios.post(captchaURL) + return res.data.success +} diff --git a/src/Tezos.ts b/src/Tezos.ts index 0ce2700..0f12ad9 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -1,60 +1,82 @@ -import { InMemorySigner } from "@taquito/signer"; -import { TezosToolkit } from "@taquito/taquito"; - -const defaultMaxBalance: number = 6000; - -const send = async (amount: number, address: string): Promise => { - console.log(`Send ${amount} xtz to ${address}`); - return "" - // Connect to RPC endpoint - const rpcUrl: string = process.env.RPC_URL; - - if (!rpcUrl) { - console.log("No RPC URL defined"); - throw new Error("API error"); - } - - console.log(`Use ${rpcUrl}`); - - let Tezos: TezosToolkit = new TezosToolkit(rpcUrl); - - // Check max balance - const userBalance: number = (await Tezos.tz.getBalance(address)).toNumber(); - - const maxBalance: number = process.env.MAX_BALANCE || defaultMaxBalance; - if (userBalance > maxBalance * 1000000) { - console.log(`User balance too high (${userBalance / 1000000}), don't send`); - throw new Error("You have already enough ꜩ"); - } - - // Build memory signer fro private key - const privateKey: string = process.env.FAUCET_PRIVATE_KEY; - - if (!privateKey) { - console.log("No private key provided"); - throw new Error("API error"); - } - - // Create signer - try { - Tezos.setProvider({ signer: await InMemorySigner.fromSecretKey(privateKey) }); - } - catch (err) { - console.log(err); - throw new Error("API error"); - } - - // Create and send transaction - try { - const operation = await Tezos.contract.transfer({ to: address, amount: amount }); - console.log(`Hash: ${operation.hash}`); - return operation.hash; - } - catch (err) { - console.log(err); - throw err; - } - -}; - -export { send }; +import { InMemorySigner } from "@taquito/signer" +import { TezosToolkit } from "@taquito/taquito" +import { Profile } from "./Types" + +const defaultMaxBalance: number = 6000 +const defaultUserAmount: number = 1 +const defaultBakerAmount: number = 6000 + +export const getTezAmountForProfile = (profile: Profile) => { + let amount: number = 0 + + switch (profile) { + case Profile.USER: + amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount + break + case Profile.BAKER: + amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount + break + default: + throw new Error(`Unknown profile ${profile}`) + } + + return amount +} + +export const send = async ( + amount: number, + address: string +): Promise => { + console.log(`Send ${amount} xtz to ${address}`) + // Connect to RPC endpoint + const rpcUrl: string = process.env.RPC_URL + + if (!rpcUrl) { + console.log("No RPC URL defined") + throw new Error("API error") + } + + console.log(`Use ${rpcUrl}`) + + let Tezos: TezosToolkit = new TezosToolkit(rpcUrl) + + // Check max balance + const userBalance: number = (await Tezos.tz.getBalance(address)).toNumber() + + const maxBalance: number = process.env.MAX_BALANCE || defaultMaxBalance + if (userBalance > maxBalance * 1000000) { + console.log(`User balance too high (${userBalance / 1000000}), don't send`) + throw new Error("You have already enough ꜩ") + } + + // Build memory signer fro private key + const privateKey: string = process.env.FAUCET_PRIVATE_KEY + + if (!privateKey) { + console.log("No private key provided") + throw new Error("API error") + } + + // Create signer + try { + Tezos.setProvider({ + signer: await InMemorySigner.fromSecretKey(privateKey), + }) + } catch (err) { + console.log(err) + throw new Error("API error") + } + + // Create and send transaction + try { + const operation = await Tezos.contract.transfer({ + to: address, + amount: amount, + }) + console.log(`Hash: ${operation.hash}`) + return operation.hash + } catch (err) { + console.log(err) + throw err + } +} diff --git a/src/api.ts b/src/api.ts index 2682147..1fd7f63 100644 --- a/src/api.ts +++ b/src/api.ts @@ -2,15 +2,18 @@ import express, { Express, Request, Response } from "express" import bodyParser from "body-parser" import morgan from "morgan" import dotenv from "dotenv" -import createVdf from "@subspace/vdf" +import crypto from "crypto" +import { createClient } from "redis" import { Profile, RequestBody, ResponseBody, InfoResponseBody } from "./Types" import { checkCaptcha } from "./Captcha" -import { send } from "./Tezos" -import { randomBytes } from "crypto" -import { log } from "console" +import { getTezAmountForProfile } from "./Tezos" dotenv.config() +const redisClient = createClient({ + // url: "redis://localhost:6379", +}) // reject +redisClient.on("error", (err) => console.log("Redis Client Error", err)) const defaultPort: number = 3000 const defaultUserAmount: number = 1 @@ -33,183 +36,131 @@ app.use((req: Request, res: Response, next) => { next() }) -// createVdf().then((vdfInstance: any) => { -// const iterations = 3 -// const challenge = Buffer.from("aa", "hex") -// const intSizeBits = 2048 -// // const intSizeBits = 100; -// const isPietrzak = false -// const res = vdfInstance.generate( -// iterations, -// challenge, -// intSizeBits, -// isPietrzak -// ) -// // console.log(res) -// console.log(Buffer.from(res).toString("hex")) -// console.log(vdfInstance.verify(3, challenge, res, intSizeBits, isPietrzak)) -// }) - - app.get("/info", (_, res: Response) => { console.log("Get info") + try { + let profiles: any = { + user: { + profile: Profile.USER, + amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, + currency: "tez", + }, + baker: { + profile: Profile.BAKER, + amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, + currency: "tez", + }, + } - let profiles: any = { - user: { - profile: Profile.USER, - amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, - currency: "tez", - }, - baker: { - profile: Profile.BAKER, - amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, - currency: "tez", - }, - } + let info: InfoResponseBody = { + faucetAddress: process.env.FAUCET_ADDRESS, + captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), + profiles: profiles, + maxBalance: process.env.MAX_BALANCE, + } - let info: InfoResponseBody = { - faucetAddress: process.env.FAUCET_ADDRESS, - captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), - profiles: profiles, - maxBalance: process.env.MAX_BALANCE, + res.status(200) + res.send(info) + } catch (error) { + res.status(400) + res.send("Exception") } - - res.status(200) - res.send(info) }) -app.post("/send", async (req: Request, res: Response) => { - const body: RequestBody = req.body +const DIFFICULTY = 4 +app.post("/challenge", async (req: Request, res: Response) => { + const { address, captchaToken, profile } = req.body - const { captchaToken, address, profile } = body + console.log(req.body) - const responseBody: any = { - status: "", - message: undefined, - txHash: undefined, - vdfChallenge: "", - } + const validCaptcha = await checkCaptcha(captchaToken).catch((e) => + res.status(400).send(e.message) + ) - let amount: number = 0 - - switch (profile) { - case Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount - break - case Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount - break - default: - console.log(`Unknown profile ${profile}`) - responseBody.status = "ERROR" - responseBody.message = `Unknown profile` - res.status(400) - res.send(responseBody) - return + if (validCaptcha) { + console.log("GOOD TOKEN") + } else { + console.log("BAD TOKEN") + res.status(400).send({ status: "ERROR", message: "Captcha error" }) + return } - // console.log( - // `Try to send ${amount} xtz to ${address}, with captcha token ${captchaToken}` - // ) - - const discriminant_challenge = randomBytes(10) - console.log({ - discriminant_challenge: Buffer.from(discriminant_challenge).toString("hex"), - }) - - responseBody.status = "SUCCESS" - responseBody.vdfChallenge = { - challenge: discriminant_challenge, - // challenge: "adfdafaafas329084dfadf", - iterations: 10000, - // size: 512, - size: 2048, + if (!address) { + res.status(400).send("The address property is required.") + return } - res.status(200) - res.send(responseBody) - return - - if (await checkCaptcha(captchaToken)) { - try { - responseBody.txHash = await send(amount, address) - responseBody.status = "SUCCESS" - res.status(200) - } catch (error) { - responseBody.message = `${error}` - responseBody.status = "ERROR" - res.status(500) - } - } else { - responseBody.status = "ERROR" - responseBody.message = `Captcha error` - res.status(400) + + try { + getTezAmountForProfile(profile) + } catch (e: any) { + res.status(400).send({ status: "ERROR", message: e.message }) + return } - res.send(responseBody) + // Generate or return existing PoW challenge. + const challenge = + (await redisClient.get(`address:${address}:challenge`)) || + crypto.randomBytes(32).toString("hex") + // const challenge = crypto.randomBytes(32).toString("hex") + + // Save the challenge and the associated address in Redis. Will only save if + // not already set. Set the challenge to expire after 30 minutes. + await redisClient.set(`address:${address}:challenge`, challenge, { + EX: 1800, + NX: true, + }) + console.log({ challenge, difficulty: DIFFICULTY }) + res.status(200).send({ challenge, difficulty: DIFFICULTY }) }) -const vdf = createVdf() - app.post("/verify", async (req: Request, res: Response) => { - const body: any = req.body - // const body: VerificationRequestBody = req.body - - const { challenge, iterations, size, solution, profile, address } = body - // console.log({ solution: Buffer.from(solution, "hex") }) - let responseBody: ResponseBody = { - status: "", - message: undefined, - txHash: undefined, - } + const { address, captchaToken, solution, nonce } = req.body - // Verify the solution (use the VDF library's verify method) - const v = await vdf - // console.log({ v }) - let solutionBuffer = Buffer.from(solution, "base64") - // console.log({ bufferFromSolution: Buffer.from(solution) }) - // let uint8Array = new Uint8Array(buffer) - console.log({ solutionBuffer, challenge, size, iterations }) - console.log(solutionBuffer.toString("hex")) - const isValid = v.verify(iterations, challenge, solutionBuffer, size, false) - console.log({isValid}) - if (isValid) { - let amount: number = 0 - - switch (profile) { - case Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount - break - case Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount - break - default: - console.log(`Unknown profile ${profile}`) - responseBody.status = "ERROR" - responseBody.message = `Unknown profile` - res.status(400) - res.send(responseBody) - return - } - try { - responseBody.txHash = await send(amount, address) - responseBody.status = "SUCCESS" - res.status(200) - } catch (error) { - responseBody.message = `${error}` - responseBody.status = "ERROR" - res.status(500) - } + const validCaptcha = await checkCaptcha(captchaToken).catch((e) => + res.status(400).send(e.message) + ) + + if (validCaptcha) { + console.log("GOOD TOKEN") } else { - responseBody.status = "ERROR" - responseBody.message = `Invalid solution` - res.status(400) + console.log("BAD TOKEN") + res.status(500).send({ status: "ERROR", message: "Captcha error" }) + return } - res.send(responseBody) + const challenge = await redisClient.get(`address:${address}:challenge`) + console.log({ address, solution, nonce }) + // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce + // starts with a certain number of zeroes (the difficulty) + const hash = crypto + .createHash("sha256") + .update(`${challenge}:${nonce}`) + .digest("hex") + + console.log({ hash }) + + const difficulty = DIFFICULTY // Adjust this value to change the difficulty of the PoW + if (hash === solution && hash.startsWith("0".repeat(difficulty))) { + // The solution is correct + // Here is where you would send the tez to the user's address + // For the sake of this example, we're just logging the address + console.log(`Send tez to ${address}`) + // responseBody.txHash = await send(amount, address) + + // Delete the challenge from Redis + await redisClient.del(`address:${address}:challenge`) + + res.status(200).send({ status: "SUCCESS", message: "Tez sent" }) + } else { + // The solution is incorrect + res.status(400).send({ status: "ERROR", message: "Incorrect solution" }) + } }) const port: number = process.env.API_PORT || defaultPort -app.listen(port, () => { +app.listen(port, async () => { console.log(`Start API on port ${port}.`) + await redisClient.connect() + console.log("Connected to redis.") }) From aff32885c3a1d525160b5700b61c6cfaf328a450 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 28 Jun 2023 22:30:51 -0400 Subject: [PATCH 03/64] Working multi challenge --- dist/api.js | 76 +++++++++++++++++++++++++++++++++--------------- src/api.ts | 84 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 109 insertions(+), 51 deletions(-) diff --git a/dist/api.js b/dist/api.js index 7657de4..ff5c556 100644 --- a/dist/api.js +++ b/dist/api.js @@ -22,10 +22,10 @@ const Types_1 = require("./Types"); const Captcha_1 = require("./Captcha"); const Tezos_1 = require("./Tezos"); dotenv_1.default.config(); -const redisClient = (0, redis_1.createClient)({ +const redis = (0, redis_1.createClient)({ // url: "redis://localhost:6379", }); // reject -redisClient.on("error", (err) => console.log("Redis Client Error", err)); +redis.on("error", (err) => console.log("Redis Client Error", err)); const defaultPort = 3000; const defaultUserAmount = 1; const defaultBakerAmount = 6000; @@ -69,10 +69,10 @@ app.get("/info", (_, res) => { res.send("Exception"); } }); -const DIFFICULTY = 4; +const DIFFICULTY = 3; +const CHALLENGES_NEEDED = 4; app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, profile } = req.body; - console.log(req.body); const validCaptcha = yield (0, Captcha_1.checkCaptcha)(captchaToken).catch((e) => res.status(400).send(e.message)); if (validCaptcha) { console.log("GOOD TOKEN"); @@ -93,21 +93,38 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* res.status(400).send({ status: "ERROR", message: e.message }); return; } - // Generate or return existing PoW challenge. - const challenge = (yield redisClient.get(`address:${address}:challenge`)) || - crypto_1.default.randomBytes(32).toString("hex"); - // const challenge = crypto.randomBytes(32).toString("hex") - // Save the challenge and the associated address in Redis. Will only save if - // not already set. Set the challenge to expire after 30 minutes. - yield redisClient.set(`address:${address}:challenge`, challenge, { - EX: 1800, - NX: true, - }); - console.log({ challenge, difficulty: DIFFICULTY }); - res.status(200).send({ challenge, difficulty: DIFFICULTY }); + try { + const challengekey = `address:${address}`; + let challenge = yield redis.hGet(challengekey, "challenge"); + if (!challenge) { + challenge = crypto_1.default.randomBytes(32).toString("hex"); + // Set the challenge and challenge counter. + yield redis.hSet(challengekey, { + challenge, + counter: 1, + }); + yield redis.expire(challengekey, 1800); + } + console.log({ challenge, difficulty: DIFFICULTY }); + res.status(200).send({ challenge, difficulty: DIFFICULTY }); + } + catch (err) { + const message = "Error fetching challenge"; + console.error(message, err); + res.status(500).send({ status: "ERROR", message }); + } })); app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, solution, nonce } = req.body; + if (!address || !solution || !nonce) { + res + .status(400) + .send({ + status: "ERROR", + message: "'address', 'solution', and 'nonce' are required", + }); + return; + } const validCaptcha = yield (0, Captcha_1.checkCaptcha)(captchaToken).catch((e) => res.status(400).send(e.message)); if (validCaptcha) { console.log("GOOD TOKEN"); @@ -117,24 +134,35 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () res.status(500).send({ status: "ERROR", message: "Captcha error" }); return; } - const challenge = yield redisClient.get(`address:${address}:challenge`); - console.log({ address, solution, nonce }); + const challengeKey = `address:${address}`; + // await redis.watch(`address:${address}`) + const { challenge, counter } = yield redis.hGetAll(challengeKey); // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) const hash = crypto_1.default .createHash("sha256") .update(`${challenge}:${nonce}`) .digest("hex"); - console.log({ hash }); - const difficulty = DIFFICULTY; // Adjust this value to change the difficulty of the PoW - if (hash === solution && hash.startsWith("0".repeat(difficulty))) { - // The solution is correct + console.log({ address, solution, hash, nonce, counter }); + if (hash === solution && hash.startsWith("0".repeat(DIFFICULTY) + "8")) { + const challengeCounter = Number(counter); + if (challengeCounter < CHALLENGES_NEEDED) { + console.log("GETTING NEW CHALLENGE"); + const newChallenge = crypto_1.default.randomBytes(32).toString("hex"); + const result = yield redis.hSet(challengeKey, { + challenge: newChallenge, + counter: challengeCounter + 1, + }); + res.status(200).send({ challenge: newChallenge, difficulty: DIFFICULTY }); + return; + } // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`); + // getTezAmountForProfile(profile) // responseBody.txHash = await send(amount, address) // Delete the challenge from Redis - yield redisClient.del(`address:${address}:challenge`); + yield redis.del(challengeKey); res.status(200).send({ status: "SUCCESS", message: "Tez sent" }); } else { @@ -145,6 +173,6 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () const port = process.env.API_PORT || defaultPort; app.listen(port, () => __awaiter(void 0, void 0, void 0, function* () { console.log(`Start API on port ${port}.`); - yield redisClient.connect(); + yield redis.connect(); console.log("Connected to redis."); })); diff --git a/src/api.ts b/src/api.ts index 1fd7f63..aaf27c4 100644 --- a/src/api.ts +++ b/src/api.ts @@ -10,10 +10,10 @@ import { checkCaptcha } from "./Captcha" import { getTezAmountForProfile } from "./Tezos" dotenv.config() -const redisClient = createClient({ +const redis = createClient({ // url: "redis://localhost:6379", }) // reject -redisClient.on("error", (err) => console.log("Redis Client Error", err)) +redis.on("error", (err) => console.log("Redis Client Error", err)) const defaultPort: number = 3000 const defaultUserAmount: number = 1 @@ -67,12 +67,12 @@ app.get("/info", (_, res: Response) => { } }) -const DIFFICULTY = 4 +const DIFFICULTY = 3 +const CHALLENGES_NEEDED = 4 + app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body - console.log(req.body) - const validCaptcha = await checkCaptcha(captchaToken).catch((e) => res.status(400).send(e.message) ) @@ -97,25 +97,42 @@ app.post("/challenge", async (req: Request, res: Response) => { return } - // Generate or return existing PoW challenge. - const challenge = - (await redisClient.get(`address:${address}:challenge`)) || - crypto.randomBytes(32).toString("hex") - // const challenge = crypto.randomBytes(32).toString("hex") - - // Save the challenge and the associated address in Redis. Will only save if - // not already set. Set the challenge to expire after 30 minutes. - await redisClient.set(`address:${address}:challenge`, challenge, { - EX: 1800, - NX: true, - }) - console.log({ challenge, difficulty: DIFFICULTY }) - res.status(200).send({ challenge, difficulty: DIFFICULTY }) + try { + const challengekey = `address:${address}` + let challenge = await redis.hGet(challengekey, "challenge") + + if (!challenge) { + challenge = crypto.randomBytes(32).toString("hex") + // Set the challenge and challenge counter. + await redis.hSet(challengekey, { + challenge, + counter: 1, + }) + await redis.expire(challengekey, 1800) + } + + console.log({ challenge, difficulty: DIFFICULTY }) + res.status(200).send({ challenge, difficulty: DIFFICULTY }) + } catch (err) { + const message = "Error fetching challenge" + console.error(message, err) + res.status(500).send({ status: "ERROR", message }) + } }) app.post("/verify", async (req: Request, res: Response) => { const { address, captchaToken, solution, nonce } = req.body + if (!address || !solution || !nonce) { + res + .status(400) + .send({ + status: "ERROR", + message: "'address', 'solution', and 'nonce' are required", + }) + return + } + const validCaptcha = await checkCaptcha(captchaToken).catch((e) => res.status(400).send(e.message) ) @@ -128,8 +145,10 @@ app.post("/verify", async (req: Request, res: Response) => { return } - const challenge = await redisClient.get(`address:${address}:challenge`) - console.log({ address, solution, nonce }) + const challengeKey = `address:${address}` + // await redis.watch(`address:${address}`) + const { challenge, counter } = await redis.hGetAll(challengeKey) + // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) const hash = crypto @@ -137,18 +156,29 @@ app.post("/verify", async (req: Request, res: Response) => { .update(`${challenge}:${nonce}`) .digest("hex") - console.log({ hash }) + console.log({ address, solution, hash, nonce, counter }) + + if (hash === solution && hash.startsWith("0".repeat(DIFFICULTY) + "8")) { + const challengeCounter = Number(counter) + if (challengeCounter < CHALLENGES_NEEDED) { + console.log("GETTING NEW CHALLENGE") + const newChallenge = crypto.randomBytes(32).toString("hex") + const result = await redis.hSet(challengeKey, { + challenge: newChallenge, + counter: challengeCounter + 1, + }) + res.status(200).send({ challenge: newChallenge, difficulty: DIFFICULTY }) + return + } - const difficulty = DIFFICULTY // Adjust this value to change the difficulty of the PoW - if (hash === solution && hash.startsWith("0".repeat(difficulty))) { - // The solution is correct // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`) + // getTezAmountForProfile(profile) // responseBody.txHash = await send(amount, address) // Delete the challenge from Redis - await redisClient.del(`address:${address}:challenge`) + await redis.del(challengeKey) res.status(200).send({ status: "SUCCESS", message: "Tez sent" }) } else { @@ -161,6 +191,6 @@ const port: number = process.env.API_PORT || defaultPort app.listen(port, async () => { console.log(`Start API on port ${port}.`) - await redisClient.connect() + await redis.connect() console.log("Connected to redis.") }) From fd633b07138911a01274062ee1816a9e6fc9bff0 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 29 Jun 2023 14:46:59 -0400 Subject: [PATCH 04/64] Cleanup --- dist/Captcha.js | 21 ++++++++++++--- dist/Tezos.js | 10 +++---- dist/api.js | 50 ++++++++++------------------------- src/Captcha.ts | 20 ++++++++++++-- src/Tezos.ts | 4 +-- src/api.ts | 70 ++++++++++++++++--------------------------------- 6 files changed, 80 insertions(+), 95 deletions(-) diff --git a/dist/Captcha.js b/dist/Captcha.js index 0228ceb..bae5b20 100644 --- a/dist/Captcha.js +++ b/dist/Captcha.js @@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.checkCaptcha = void 0; +exports.validateCaptcha = void 0; const axios_1 = __importDefault(require("axios")); const checkCaptcha = (responseToken) => __awaiter(void 0, void 0, void 0, function* () { if (!responseToken) { @@ -26,6 +26,21 @@ const checkCaptcha = (responseToken) => __awaiter(void 0, void 0, void 0, functi const secret = process.env.FAUCET_CAPTCHA_SECRET; const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}`; const res = yield axios_1.default.post(captchaURL); - return res.data.success; + return res.data; }); -exports.checkCaptcha = checkCaptcha; +const validateCaptcha = (res, captchaToken) => __awaiter(void 0, void 0, void 0, function* () { + try { + const response = yield checkCaptcha(captchaToken); + console.log(response); + if (!response.success) { + res.status(400).send({ status: "ERROR", message: "Invalid captcha" }); + return false; + } + } + catch (err) { + res.status(400).send({ status: "ERROR", message: "Captcha error" }); + return false; + } + return true; +}); +exports.validateCaptcha = validateCaptcha; diff --git a/dist/Tezos.js b/dist/Tezos.js index d810499..d3a2c75 100644 --- a/dist/Tezos.js +++ b/dist/Tezos.js @@ -9,21 +9,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.send = exports.getTezAmountForProfile = void 0; +exports.send = exports.getTezAmountForProfile = exports.defaultBakerAmount = exports.defaultUserAmount = void 0; const signer_1 = require("@taquito/signer"); const taquito_1 = require("@taquito/taquito"); const Types_1 = require("./Types"); const defaultMaxBalance = 6000; -const defaultUserAmount = 1; -const defaultBakerAmount = 6000; +exports.defaultUserAmount = 1; +exports.defaultBakerAmount = 6000; const getTezAmountForProfile = (profile) => { let amount = 0; switch (profile) { case Types_1.Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount; + amount = process.env.FAUCET_AMOUNT_USER || exports.defaultUserAmount; break; case Types_1.Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount; + amount = process.env.FAUCET_AMOUNT_BAKER || exports.defaultBakerAmount; break; default: throw new Error(`Unknown profile ${profile}`); diff --git a/dist/api.js b/dist/api.js index ff5c556..88d2d5f 100644 --- a/dist/api.js +++ b/dist/api.js @@ -26,14 +26,11 @@ const redis = (0, redis_1.createClient)({ // url: "redis://localhost:6379", }); // reject redis.on("error", (err) => console.log("Redis Client Error", err)); -const defaultPort = 3000; -const defaultUserAmount = 1; -const defaultBakerAmount = 6000; const app = (0, express_1.default)(); app.use(body_parser_1.default.json()); app.use(body_parser_1.default.urlencoded({ extended: true })); app.use((0, morgan_1.default)("dev")); -app.use((req, res, next) => { +app.use((_, res, next) => { const cors = process.env.AUTHORIZED_HOST || "*"; res.setHeader("Access-Control-Allow-Origin", cors); res.setHeader("Access-Control-Allow-Methods", "GET, POST"); @@ -41,51 +38,41 @@ app.use((req, res, next) => { next(); }); app.get("/info", (_, res) => { - console.log("Get info"); try { - let profiles = { + const profiles = { user: { profile: Types_1.Profile.USER, - amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, + amount: process.env.FAUCET_AMOUNT_USER || Tezos_1.defaultUserAmount, currency: "tez", }, baker: { profile: Types_1.Profile.BAKER, - amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, + amount: process.env.FAUCET_AMOUNT_BAKER || Tezos_1.defaultBakerAmount, currency: "tez", }, }; - let info = { + const info = { faucetAddress: process.env.FAUCET_ADDRESS, captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), - profiles: profiles, + profiles, maxBalance: process.env.MAX_BALANCE, }; - res.status(200); - res.send(info); + res.status(200).send(info); } catch (error) { - res.status(400); - res.send("Exception"); + res.status(500).send({ status: "ERROR", message: "An exception occurred" }); } }); const DIFFICULTY = 3; const CHALLENGES_NEEDED = 4; app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, profile } = req.body; - const validCaptcha = yield (0, Captcha_1.checkCaptcha)(captchaToken).catch((e) => res.status(400).send(e.message)); - if (validCaptcha) { - console.log("GOOD TOKEN"); - } - else { - console.log("BAD TOKEN"); - res.status(400).send({ status: "ERROR", message: "Captcha error" }); + if (!address || !profile) { + res.status(400).send("'address' and 'profile' are required"); return; } - if (!address) { - res.status(400).send("The address property is required."); + if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) return; - } try { (0, Tezos_1.getTezAmountForProfile)(profile); } @@ -117,23 +104,14 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, solution, nonce } = req.body; if (!address || !solution || !nonce) { - res - .status(400) - .send({ + res.status(400).send({ status: "ERROR", message: "'address', 'solution', and 'nonce' are required", }); return; } - const validCaptcha = yield (0, Captcha_1.checkCaptcha)(captchaToken).catch((e) => res.status(400).send(e.message)); - if (validCaptcha) { - console.log("GOOD TOKEN"); - } - else { - console.log("BAD TOKEN"); - res.status(500).send({ status: "ERROR", message: "Captcha error" }); + if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) return; - } const challengeKey = `address:${address}`; // await redis.watch(`address:${address}`) const { challenge, counter } = yield redis.hGetAll(challengeKey); @@ -170,7 +148,7 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () res.status(400).send({ status: "ERROR", message: "Incorrect solution" }); } })); -const port = process.env.API_PORT || defaultPort; +const port = process.env.API_PORT || 3000; app.listen(port, () => __awaiter(void 0, void 0, void 0, function* () { console.log(`Start API on port ${port}.`); yield redis.connect(); diff --git a/src/Captcha.ts b/src/Captcha.ts index d90ec1a..a647163 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -1,6 +1,7 @@ import axios from "axios" +import { Response } from "express" -export const checkCaptcha = async (responseToken: string) => { +const checkCaptcha = async (responseToken: string) => { if (!responseToken) { throw new Error("Missing captcha token.") } @@ -17,5 +18,20 @@ export const checkCaptcha = async (responseToken: string) => { const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}` const res = await axios.post(captchaURL) - return res.data.success + return res.data +} + +export const validateCaptcha = async (res: Response, captchaToken: string) => { + try { + const response = await checkCaptcha(captchaToken) + console.log(response) + if (!response.success) { + res.status(400).send({ status: "ERROR", message: "Invalid captcha" }) + return false + } + } catch (err) { + res.status(400).send({ status: "ERROR", message: "Captcha error" }) + return false + } + return true } diff --git a/src/Tezos.ts b/src/Tezos.ts index 0f12ad9..6319d5c 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -3,8 +3,8 @@ import { TezosToolkit } from "@taquito/taquito" import { Profile } from "./Types" const defaultMaxBalance: number = 6000 -const defaultUserAmount: number = 1 -const defaultBakerAmount: number = 6000 +export const defaultUserAmount: number = 1 +export const defaultBakerAmount: number = 6000 export const getTezAmountForProfile = (profile: Profile) => { let amount: number = 0 diff --git a/src/api.ts b/src/api.ts index aaf27c4..a8866b8 100644 --- a/src/api.ts +++ b/src/api.ts @@ -6,25 +6,27 @@ import crypto from "crypto" import { createClient } from "redis" import { Profile, RequestBody, ResponseBody, InfoResponseBody } from "./Types" -import { checkCaptcha } from "./Captcha" -import { getTezAmountForProfile } from "./Tezos" +import { validateCaptcha } from "./Captcha" +import { + getTezAmountForProfile, + defaultBakerAmount, + defaultUserAmount, +} from "./Tezos" dotenv.config() + const redis = createClient({ // url: "redis://localhost:6379", }) // reject -redis.on("error", (err) => console.log("Redis Client Error", err)) -const defaultPort: number = 3000 -const defaultUserAmount: number = 1 -const defaultBakerAmount: number = 6000 +redis.on("error", (err) => console.log("Redis Client Error", err)) const app: Express = express() app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) app.use(morgan("dev")) -app.use((req: Request, res: Response, next) => { +app.use((_, res: Response, next) => { const cors: string = process.env.AUTHORIZED_HOST || "*" res.setHeader("Access-Control-Allow-Origin", cors) res.setHeader("Access-Control-Allow-Methods", "GET, POST") @@ -37,9 +39,8 @@ app.use((req: Request, res: Response, next) => { }) app.get("/info", (_, res: Response) => { - console.log("Get info") try { - let profiles: any = { + const profiles: any = { user: { profile: Profile.USER, amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, @@ -52,18 +53,15 @@ app.get("/info", (_, res: Response) => { }, } - let info: InfoResponseBody = { + const info: InfoResponseBody = { faucetAddress: process.env.FAUCET_ADDRESS, captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), - profiles: profiles, + profiles, maxBalance: process.env.MAX_BALANCE, } - - res.status(200) - res.send(info) + res.status(200).send(info) } catch (error) { - res.status(400) - res.send("Exception") + res.status(500).send({ status: "ERROR", message: "An exception occurred" }) } }) @@ -73,22 +71,12 @@ const CHALLENGES_NEEDED = 4 app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body - const validCaptcha = await checkCaptcha(captchaToken).catch((e) => - res.status(400).send(e.message) - ) - - if (validCaptcha) { - console.log("GOOD TOKEN") - } else { - console.log("BAD TOKEN") - res.status(400).send({ status: "ERROR", message: "Captcha error" }) + if (!address || !profile) { + res.status(400).send("'address' and 'profile' are required") return } - if (!address) { - res.status(400).send("The address property is required.") - return - } + if (!validateCaptcha(res, captchaToken)) return try { getTezAmountForProfile(profile) @@ -124,26 +112,14 @@ app.post("/verify", async (req: Request, res: Response) => { const { address, captchaToken, solution, nonce } = req.body if (!address || !solution || !nonce) { - res - .status(400) - .send({ - status: "ERROR", - message: "'address', 'solution', and 'nonce' are required", - }) + res.status(400).send({ + status: "ERROR", + message: "'address', 'solution', and 'nonce' are required", + }) return } - const validCaptcha = await checkCaptcha(captchaToken).catch((e) => - res.status(400).send(e.message) - ) - - if (validCaptcha) { - console.log("GOOD TOKEN") - } else { - console.log("BAD TOKEN") - res.status(500).send({ status: "ERROR", message: "Captcha error" }) - return - } + if (!validateCaptcha(res, captchaToken)) return const challengeKey = `address:${address}` // await redis.watch(`address:${address}`) @@ -187,7 +163,7 @@ app.post("/verify", async (req: Request, res: Response) => { } }) -const port: number = process.env.API_PORT || defaultPort +const port: number = process.env.API_PORT || 3000 app.listen(port, async () => { console.log(`Start API on port ${port}.`) From 03bbfc9784a2371e5e80d00e68367b9df150749c Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 29 Jun 2023 15:22:43 -0400 Subject: [PATCH 05/64] Split pow logic into functions --- dist/Captcha.js | 1 - dist/api.js | 55 +++++++++++++++++++++++------------------- src/Captcha.ts | 1 - src/api.ts | 63 ++++++++++++++++++++++++++++--------------------- 4 files changed, 67 insertions(+), 53 deletions(-) diff --git a/dist/Captcha.js b/dist/Captcha.js index bae5b20..84e099b 100644 --- a/dist/Captcha.js +++ b/dist/Captcha.js @@ -31,7 +31,6 @@ const checkCaptcha = (responseToken) => __awaiter(void 0, void 0, void 0, functi const validateCaptcha = (res, captchaToken) => __awaiter(void 0, void 0, void 0, function* () { try { const response = yield checkCaptcha(captchaToken); - console.log(response); if (!response.success) { res.status(400).send({ status: "ERROR", message: "Invalid captcha" }); return false; diff --git a/dist/api.js b/dist/api.js index 88d2d5f..be862d9 100644 --- a/dist/api.js +++ b/dist/api.js @@ -12,15 +12,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -const express_1 = __importDefault(require("express")); const body_parser_1 = __importDefault(require("body-parser")); -const morgan_1 = __importDefault(require("morgan")); const dotenv_1 = __importDefault(require("dotenv")); -const crypto_1 = __importDefault(require("crypto")); +const express_1 = __importDefault(require("express")); +const morgan_1 = __importDefault(require("morgan")); const redis_1 = require("redis"); -const Types_1 = require("./Types"); const Captcha_1 = require("./Captcha"); const Tezos_1 = require("./Tezos"); +const Types_1 = require("./Types"); +const pow_1 = require("./pow"); dotenv_1.default.config(); const redis = (0, redis_1.createClient)({ // url: "redis://localhost:6379", @@ -84,12 +84,13 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* const challengekey = `address:${address}`; let challenge = yield redis.hGet(challengekey, "challenge"); if (!challenge) { - challenge = crypto_1.default.randomBytes(32).toString("hex"); + challenge = (0, pow_1.generateChallenge)(); // Set the challenge and challenge counter. yield redis.hSet(challengekey, { challenge, counter: 1, }); + // Challenge should expire after 30m. yield redis.expire(challengekey, 1800); } console.log({ challenge, difficulty: DIFFICULTY }); @@ -112,22 +113,27 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () } if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) return; - const challengeKey = `address:${address}`; - // await redis.watch(`address:${address}`) + const challengeKey = (0, pow_1.getChallengeKey)(address); const { challenge, counter } = yield redis.hGetAll(challengeKey); // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) - const hash = crypto_1.default - .createHash("sha256") - .update(`${challenge}:${nonce}`) - .digest("hex"); - console.log({ address, solution, hash, nonce, counter }); - if (hash === solution && hash.startsWith("0".repeat(DIFFICULTY) + "8")) { + const isValidSolution = (0, pow_1.verifySolution)({ + challenge, + difficulty: DIFFICULTY, + nonce, + solution, + }); + console.log({ address, solution, nonce, counter }); + if (!isValidSolution) { + res.status(400).send({ status: "ERROR", message: "Incorrect solution" }); + return; + } + try { const challengeCounter = Number(counter); if (challengeCounter < CHALLENGES_NEEDED) { - console.log("GETTING NEW CHALLENGE"); - const newChallenge = crypto_1.default.randomBytes(32).toString("hex"); - const result = yield redis.hSet(challengeKey, { + console.log(`GETTING CHALLENGE ${challengeCounter}`); + const newChallenge = (0, pow_1.generateChallenge)(); + yield redis.hSet(challengeKey, { challenge: newChallenge, counter: challengeCounter + 1, }); @@ -139,18 +145,19 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () console.log(`Send tez to ${address}`); // getTezAmountForProfile(profile) // responseBody.txHash = await send(amount, address) - // Delete the challenge from Redis - yield redis.del(challengeKey); res.status(200).send({ status: "SUCCESS", message: "Tez sent" }); + yield redis.del(challengeKey).catch((e) => console.error(e.message)); } - else { - // The solution is incorrect - res.status(400).send({ status: "ERROR", message: "Incorrect solution" }); + catch (err) { + console.error(err); + res.status(500).send({ status: "ERROR", message: "An error occurred" }); } })); const port = process.env.API_PORT || 3000; -app.listen(port, () => __awaiter(void 0, void 0, void 0, function* () { - console.log(`Start API on port ${port}.`); +(() => __awaiter(void 0, void 0, void 0, function* () { + app.listen(port, () => __awaiter(void 0, void 0, void 0, function* () { + console.log(`Start API on port ${port}.`); + })); yield redis.connect(); console.log("Connected to redis."); -})); +}))(); diff --git a/src/Captcha.ts b/src/Captcha.ts index a647163..64f554e 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -24,7 +24,6 @@ const checkCaptcha = async (responseToken: string) => { export const validateCaptcha = async (res: Response, captchaToken: string) => { try { const response = await checkCaptcha(captchaToken) - console.log(response) if (!response.success) { res.status(400).send({ status: "ERROR", message: "Invalid captcha" }) return false diff --git a/src/api.ts b/src/api.ts index a8866b8..102a581 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,17 +1,17 @@ -import express, { Express, Request, Response } from "express" import bodyParser from "body-parser" -import morgan from "morgan" import dotenv from "dotenv" -import crypto from "crypto" +import express, { Express, Request, Response } from "express" +import morgan from "morgan" import { createClient } from "redis" -import { Profile, RequestBody, ResponseBody, InfoResponseBody } from "./Types" import { validateCaptcha } from "./Captcha" import { - getTezAmountForProfile, defaultBakerAmount, defaultUserAmount, + getTezAmountForProfile, } from "./Tezos" +import { InfoResponseBody, Profile, RequestBody, ResponseBody } from "./Types" +import { generateChallenge, getChallengeKey, verifySolution } from "./pow" dotenv.config() @@ -90,12 +90,13 @@ app.post("/challenge", async (req: Request, res: Response) => { let challenge = await redis.hGet(challengekey, "challenge") if (!challenge) { - challenge = crypto.randomBytes(32).toString("hex") + challenge = generateChallenge() // Set the challenge and challenge counter. await redis.hSet(challengekey, { challenge, counter: 1, }) + // Challenge should expire after 30m. await redis.expire(challengekey, 1800) } @@ -121,25 +122,32 @@ app.post("/verify", async (req: Request, res: Response) => { if (!validateCaptcha(res, captchaToken)) return - const challengeKey = `address:${address}` - // await redis.watch(`address:${address}`) + const challengeKey = getChallengeKey(address) + const { challenge, counter } = await redis.hGetAll(challengeKey) // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) - const hash = crypto - .createHash("sha256") - .update(`${challenge}:${nonce}`) - .digest("hex") + const isValidSolution = verifySolution({ + challenge, + difficulty: DIFFICULTY, + nonce, + solution, + }) - console.log({ address, solution, hash, nonce, counter }) + console.log({ address, solution, nonce, counter }) - if (hash === solution && hash.startsWith("0".repeat(DIFFICULTY) + "8")) { + if (!isValidSolution) { + res.status(400).send({ status: "ERROR", message: "Incorrect solution" }) + return + } + + try { const challengeCounter = Number(counter) if (challengeCounter < CHALLENGES_NEEDED) { - console.log("GETTING NEW CHALLENGE") - const newChallenge = crypto.randomBytes(32).toString("hex") - const result = await redis.hSet(challengeKey, { + console.log(`GETTING CHALLENGE ${challengeCounter}`) + const newChallenge = generateChallenge() + await redis.hSet(challengeKey, { challenge: newChallenge, counter: challengeCounter + 1, }) @@ -152,21 +160,22 @@ app.post("/verify", async (req: Request, res: Response) => { console.log(`Send tez to ${address}`) // getTezAmountForProfile(profile) // responseBody.txHash = await send(amount, address) - - // Delete the challenge from Redis - await redis.del(challengeKey) - res.status(200).send({ status: "SUCCESS", message: "Tez sent" }) - } else { - // The solution is incorrect - res.status(400).send({ status: "ERROR", message: "Incorrect solution" }) + + await redis.del(challengeKey).catch((e) => console.error(e.message)) + } catch (err) { + console.error(err) + res.status(500).send({ status: "ERROR", message: "An error occurred" }) } }) const port: number = process.env.API_PORT || 3000 -app.listen(port, async () => { - console.log(`Start API on port ${port}.`) +;(async () => { + app.listen(port, async () => { + console.log(`Start API on port ${port}.`) + }) + await redis.connect() console.log("Connected to redis.") -}) +})() From 47898c29b938d022777766638a79620578642774 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 29 Jun 2023 19:58:35 -0400 Subject: [PATCH 06/64] Validate address --- dist/Tezos.js | 13 ++++++++++++- dist/api.js | 19 ++++++++++++------- dist/pow.js | 14 ++++++++++++++ src/Tezos.ts | 12 ++++++++++++ src/api.ts | 23 ++++++++++++++--------- 5 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 dist/pow.js diff --git a/dist/Tezos.js b/dist/Tezos.js index d3a2c75..1719bfb 100644 --- a/dist/Tezos.js +++ b/dist/Tezos.js @@ -9,9 +9,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.send = exports.getTezAmountForProfile = exports.defaultBakerAmount = exports.defaultUserAmount = void 0; +exports.send = exports.validateAddress = exports.getTezAmountForProfile = exports.defaultBakerAmount = exports.defaultUserAmount = void 0; const signer_1 = require("@taquito/signer"); const taquito_1 = require("@taquito/taquito"); +const utils_1 = require("@taquito/utils"); const Types_1 = require("./Types"); const defaultMaxBalance = 6000; exports.defaultUserAmount = 1; @@ -31,6 +32,16 @@ const getTezAmountForProfile = (profile) => { return amount; }; exports.getTezAmountForProfile = getTezAmountForProfile; +const validateAddress = (res, address) => { + if ((0, utils_1.validateKeyHash)(address) !== 3) { + res + .status(400) + .send({ status: "ERROR", message: `The address '${address}' is invalid` }); + return false; + } + return true; +}; +exports.validateAddress = validateAddress; const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () { console.log(`Send ${amount} xtz to ${address}`); // Connect to RPC endpoint diff --git a/dist/api.js b/dist/api.js index be862d9..596533b 100644 --- a/dist/api.js +++ b/dist/api.js @@ -68,9 +68,11 @@ const CHALLENGES_NEEDED = 4; app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, profile } = req.body; if (!address || !profile) { - res.status(400).send("'address' and 'profile' are required"); + res.status(400).send("'address' and 'profile' fields are required"); return; } + if (!(0, Tezos_1.validateAddress)(res, address)) + return; if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) return; try { @@ -97,7 +99,7 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* res.status(200).send({ challenge, difficulty: DIFFICULTY }); } catch (err) { - const message = "Error fetching challenge"; + const message = "Error getting challenge"; console.error(message, err); res.status(500).send({ status: "ERROR", message }); } @@ -107,10 +109,12 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () if (!address || !solution || !nonce) { res.status(400).send({ status: "ERROR", - message: "'address', 'solution', and 'nonce' are required", + message: "'address', 'solution', and 'nonce' fields are required", }); return; } + if (!(0, Tezos_1.validateAddress)(res, address)) + return; if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) return; const challengeKey = (0, pow_1.getChallengeKey)(address); @@ -143,13 +147,14 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`); - // getTezAmountForProfile(profile) - // responseBody.txHash = await send(amount, address) - res.status(200).send({ status: "SUCCESS", message: "Tez sent" }); + const amount = (0, Tezos_1.getTezAmountForProfile)("BAKER"); + const b = {}; + // b.txHash = await send(amount, address) + res.status(200).send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); yield redis.del(challengeKey).catch((e) => console.error(e.message)); } catch (err) { - console.error(err); + console.error(err.message); res.status(500).send({ status: "ERROR", message: "An error occurred" }); } })); diff --git a/dist/pow.js b/dist/pow.js new file mode 100644 index 0000000..4daf7fb --- /dev/null +++ b/dist/pow.js @@ -0,0 +1,14 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.verifySolution = exports.generateChallenge = exports.getChallengeKey = void 0; +const crypto_1 = require("crypto"); +const getChallengeKey = (address) => `address:${address}`; +exports.getChallengeKey = getChallengeKey; +const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); +exports.generateChallenge = generateChallenge; +const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); +const verifySolution = ({ challenge, difficulty, nonce, solution, }) => { + const hash = getSolution(challenge, nonce); + return hash === solution && hash.startsWith("0".repeat(difficulty) + "8"); +}; +exports.verifySolution = verifySolution; diff --git a/src/Tezos.ts b/src/Tezos.ts index 6319d5c..acabd77 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -1,5 +1,7 @@ import { InMemorySigner } from "@taquito/signer" import { TezosToolkit } from "@taquito/taquito" +import { validateKeyHash } from "@taquito/utils" +import { Response } from "express" import { Profile } from "./Types" const defaultMaxBalance: number = 6000 @@ -23,6 +25,16 @@ export const getTezAmountForProfile = (profile: Profile) => { return amount } +export const validateAddress = (res: Response, address: string) => { + if (validateKeyHash(address) !== 3) { + res + .status(400) + .send({ status: "ERROR", message: `The address '${address}' is invalid` }) + return false + } + return true +} + export const send = async ( amount: number, address: string diff --git a/src/api.ts b/src/api.ts index 102a581..c6baf6e 100644 --- a/src/api.ts +++ b/src/api.ts @@ -9,6 +9,8 @@ import { defaultBakerAmount, defaultUserAmount, getTezAmountForProfile, + send, + validateAddress, } from "./Tezos" import { InfoResponseBody, Profile, RequestBody, ResponseBody } from "./Types" import { generateChallenge, getChallengeKey, verifySolution } from "./pow" @@ -72,10 +74,11 @@ app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body if (!address || !profile) { - res.status(400).send("'address' and 'profile' are required") + res.status(400).send("'address' and 'profile' fields are required") return } + if (!validateAddress(res, address)) return if (!validateCaptcha(res, captchaToken)) return try { @@ -102,8 +105,8 @@ app.post("/challenge", async (req: Request, res: Response) => { console.log({ challenge, difficulty: DIFFICULTY }) res.status(200).send({ challenge, difficulty: DIFFICULTY }) - } catch (err) { - const message = "Error fetching challenge" + } catch (err: any) { + const message = "Error getting challenge" console.error(message, err) res.status(500).send({ status: "ERROR", message }) } @@ -115,11 +118,12 @@ app.post("/verify", async (req: Request, res: Response) => { if (!address || !solution || !nonce) { res.status(400).send({ status: "ERROR", - message: "'address', 'solution', and 'nonce' are required", + message: "'address', 'solution', and 'nonce' fields are required", }) return } + if (!validateAddress(res, address)) return if (!validateCaptcha(res, captchaToken)) return const challengeKey = getChallengeKey(address) @@ -158,13 +162,14 @@ app.post("/verify", async (req: Request, res: Response) => { // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`) - // getTezAmountForProfile(profile) - // responseBody.txHash = await send(amount, address) - res.status(200).send({ status: "SUCCESS", message: "Tez sent" }) + const amount = getTezAmountForProfile("BAKER" as Profile) + const b: any = {} + // b.txHash = await send(amount, address) + res.status(200).send({ ...b, status: "SUCCESS", message: "Tez sent" }) await redis.del(challengeKey).catch((e) => console.error(e.message)) - } catch (err) { - console.error(err) + } catch (err: any) { + console.error(err.message) res.status(500).send({ status: "ERROR", message: "An error occurred" }) } }) From d24c9dbb5aa0726501f26c2dbf8c7727c6f04fd7 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 30 Jun 2023 16:27:12 -0400 Subject: [PATCH 07/64] Add status field --- dist/api.js | 4 ++-- src/api.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/api.js b/dist/api.js index 596533b..7e31aad 100644 --- a/dist/api.js +++ b/dist/api.js @@ -96,7 +96,7 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* yield redis.expire(challengekey, 1800); } console.log({ challenge, difficulty: DIFFICULTY }); - res.status(200).send({ challenge, difficulty: DIFFICULTY }); + res.status(200).send({ status: "SUCCESS", challenge, difficulty: DIFFICULTY }); } catch (err) { const message = "Error getting challenge"; @@ -141,7 +141,7 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () challenge: newChallenge, counter: challengeCounter + 1, }); - res.status(200).send({ challenge: newChallenge, difficulty: DIFFICULTY }); + res.status(200).send({ status: "SUCCESS", challenge: newChallenge, difficulty: DIFFICULTY }); return; } // Here is where you would send the tez to the user's address diff --git a/src/api.ts b/src/api.ts index c6baf6e..2641159 100644 --- a/src/api.ts +++ b/src/api.ts @@ -104,7 +104,7 @@ app.post("/challenge", async (req: Request, res: Response) => { } console.log({ challenge, difficulty: DIFFICULTY }) - res.status(200).send({ challenge, difficulty: DIFFICULTY }) + res.status(200).send({ status: "SUCCESS", challenge, difficulty: DIFFICULTY }) } catch (err: any) { const message = "Error getting challenge" console.error(message, err) @@ -155,7 +155,7 @@ app.post("/verify", async (req: Request, res: Response) => { challenge: newChallenge, counter: challengeCounter + 1, }) - res.status(200).send({ challenge: newChallenge, difficulty: DIFFICULTY }) + res.status(200).send({ status: "SUCCESS", challenge: newChallenge, difficulty: DIFFICULTY }) return } From be8d7dec46990568fba783d503cd2cf068f410ed Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 5 Jul 2023 17:47:00 -0400 Subject: [PATCH 08/64] Send challenge counter with response --- dist/api.js | 22 +++++++++++++++++++--- src/api.ts | 22 +++++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/dist/api.js b/dist/api.js index 7e31aad..27973e2 100644 --- a/dist/api.js +++ b/dist/api.js @@ -96,7 +96,14 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* yield redis.expire(challengekey, 1800); } console.log({ challenge, difficulty: DIFFICULTY }); - res.status(200).send({ status: "SUCCESS", challenge, difficulty: DIFFICULTY }); + res + .status(200) + .send({ + status: "SUCCESS", + challenge, + difficulty: DIFFICULTY, + counter: 1, + }); } catch (err) { const message = "Error getting challenge"; @@ -137,11 +144,19 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () if (challengeCounter < CHALLENGES_NEEDED) { console.log(`GETTING CHALLENGE ${challengeCounter}`); const newChallenge = (0, pow_1.generateChallenge)(); + const incrCounter = challengeCounter + 1; yield redis.hSet(challengeKey, { challenge: newChallenge, - counter: challengeCounter + 1, + counter: incrCounter, + }); + res + .status(200) + .send({ + status: "SUCCESS", + challenge: newChallenge, + difficulty: DIFFICULTY, + counter: incrCounter, }); - res.status(200).send({ status: "SUCCESS", challenge: newChallenge, difficulty: DIFFICULTY }); return; } // Here is where you would send the tez to the user's address @@ -150,6 +165,7 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () const amount = (0, Tezos_1.getTezAmountForProfile)("BAKER"); const b = {}; // b.txHash = await send(amount, address) + b.txHash = "hash"; res.status(200).send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); yield redis.del(challengeKey).catch((e) => console.error(e.message)); } diff --git a/src/api.ts b/src/api.ts index 2641159..83f13e1 100644 --- a/src/api.ts +++ b/src/api.ts @@ -104,7 +104,14 @@ app.post("/challenge", async (req: Request, res: Response) => { } console.log({ challenge, difficulty: DIFFICULTY }) - res.status(200).send({ status: "SUCCESS", challenge, difficulty: DIFFICULTY }) + res + .status(200) + .send({ + status: "SUCCESS", + challenge, + difficulty: DIFFICULTY, + counter: 1, + }) } catch (err: any) { const message = "Error getting challenge" console.error(message, err) @@ -151,11 +158,19 @@ app.post("/verify", async (req: Request, res: Response) => { if (challengeCounter < CHALLENGES_NEEDED) { console.log(`GETTING CHALLENGE ${challengeCounter}`) const newChallenge = generateChallenge() + const incrCounter = challengeCounter + 1 await redis.hSet(challengeKey, { challenge: newChallenge, - counter: challengeCounter + 1, + counter: incrCounter, }) - res.status(200).send({ status: "SUCCESS", challenge: newChallenge, difficulty: DIFFICULTY }) + res + .status(200) + .send({ + status: "SUCCESS", + challenge: newChallenge, + difficulty: DIFFICULTY, + counter: incrCounter, + }) return } @@ -165,6 +180,7 @@ app.post("/verify", async (req: Request, res: Response) => { const amount = getTezAmountForProfile("BAKER" as Profile) const b: any = {} // b.txHash = await send(amount, address) + b.txHash = "hash" res.status(200).send({ ...b, status: "SUCCESS", message: "Tez sent" }) await redis.del(challengeKey).catch((e) => console.error(e.message)) From bdffb078aa80c2c3c4c6fb52040319890b34b143 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 5 Jul 2023 17:50:29 -0400 Subject: [PATCH 09/64] npm rm @subspace/vdf npm --- package-lock.json | 7848 +++++++++++---------------------------------- package.json | 4 +- 2 files changed, 1839 insertions(+), 6013 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0da270c..a7331b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,10 +10,9 @@ "license": "ISC", "dependencies": { "@netlify/functions": "^1.0.0", - "@subspace/vdf": "^0.1.0", "@taquito/signer": "^12.1.1", "@taquito/taquito": "^12.1.1", - "axios": "^0.26.1", + "axios": "^1.4.0", "body-parser": "^1.20.0", "dotenv": "^16.0.1", "express": "^4.18.1", @@ -26,7 +25,6 @@ "@types/morgan": "^1.9.4", "@types/node": "^17.0.36", "nodemon": "^2.0.16", - "npm": "^8.17.0", "typescript": "^4.7.2" } }, @@ -234,19 +232,6 @@ "@stablelib/wipe": "^1.0.1" } }, - "node_modules/@subspace/vdf": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@subspace/vdf/-/vdf-0.1.0.tgz", - "integrity": "sha512-iKYdYOcAtALmxxgreWqnHphT7m8HIyBsAYLrPSRvOJM9hTY+Rfg+EsLiqXLgHoIXyy980dQhoE4yIwu8xXDmvg==", - "dependencies": { - "@types/node": "^11.13.4" - } - }, - "node_modules/@subspace/vdf/node_modules/@types/node": { - "version": "11.15.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.54.tgz", - "integrity": "sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==" - }, "node_modules/@szmarczak/http-timer": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", @@ -270,6 +255,14 @@ "node": ">=6.0.0" } }, + "node_modules/@taquito/http-utils/node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, "node_modules/@taquito/local-forging": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-12.1.1.tgz", @@ -577,12 +570,19 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", "dependencies": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, "node_modules/balanced-match": { @@ -974,6 +974,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "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", @@ -1098,6 +1109,14 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -1281,9 +1300,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", "funding": [ { "type": "individual", @@ -1299,6 +1318,19 @@ } } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2003,6535 +2035,2326 @@ "node": ">=8" } }, - "node_modules/npm": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-8.17.0.tgz", - "integrity": "sha512-tIcfZd541v86Sqrf+t/GW6ivqiT8b/2b3EAjNw3vRe+eVnL4mlkVwu17hjCOrsPVntLb5C6tQG4jPUE5Oveeyw==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/ci-detect", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/run-script", - "abbrev", - "archy", - "cacache", - "chalk", - "chownr", - "cli-columns", - "cli-table3", - "columnify", - "fastest-levenshtein", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmhook", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minipass", - "minipass-pipeline", - "mkdirp", - "mkdirp-infer-owner", - "ms", - "node-gyp", - "nopt", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "npmlog", - "opener", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "read-package-json", - "read-package-json-fast", - "readdir-scoped-modules", - "rimraf", - "semver", - "ssri", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which", - "write-file-atomic" - ], - "dev": true, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^5.0.4", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/config": "^4.2.1", - "@npmcli/fs": "^2.1.0", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/package-json": "^2.0.0", - "@npmcli/run-script": "^4.2.1", - "abbrev": "~1.1.1", - "archy": "~1.0.0", - "cacache": "^16.1.1", - "chalk": "^4.1.2", - "chownr": "^2.0.0", - "cli-columns": "^4.0.0", - "cli-table3": "^0.6.2", - "columnify": "^1.6.0", - "fastest-levenshtein": "^1.0.12", - "glob": "^8.0.1", - "graceful-fs": "^4.2.10", - "hosted-git-info": "^5.0.0", - "ini": "^3.0.0", - "init-package-json": "^3.0.2", - "is-cidr": "^4.0.2", - "json-parse-even-better-errors": "^2.3.1", - "libnpmaccess": "^6.0.2", - "libnpmdiff": "^4.0.2", - "libnpmexec": "^4.0.2", - "libnpmfund": "^3.0.1", - "libnpmhook": "^8.0.2", - "libnpmorg": "^4.0.2", - "libnpmpack": "^4.0.2", - "libnpmpublish": "^6.0.2", - "libnpmsearch": "^5.0.2", - "libnpmteam": "^4.0.2", - "libnpmversion": "^3.0.1", - "make-fetch-happen": "^10.2.0", - "minipass": "^3.1.6", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "ms": "^2.1.2", - "node-gyp": "^9.1.0", - "nopt": "^6.0.0", - "npm-audit-report": "^3.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.1.0", - "npm-pick-manifest": "^7.0.1", - "npm-profile": "^6.2.0", - "npm-registry-fetch": "^13.3.0", - "npm-user-validate": "^1.0.1", - "npmlog": "^6.0.2", - "opener": "^1.5.2", - "p-map": "^4.0.0", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.2", - "proc-log": "^2.0.1", - "qrcode-terminal": "^0.12.0", - "read": "~1.0.7", - "read-package-json": "^5.0.1", - "read-package-json-fast": "^2.0.3", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.1", - "tar": "^6.1.11", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^2.0.0", - "validate-npm-package-name": "^4.0.0", - "which": "^2.0.2", - "write-file-atomic": "^4.0.1" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" + "ee-first": "1.1.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/@colors/colors": { - "version": "1.5.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "engines": { - "node": ">=0.1.90" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/@gar/promisify": { - "version": "1.1.3", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "inBundle": true, - "license": "MIT" + "dependencies": { + "wrappy": "1" + } }, - "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "node_modules/p-cancelable": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", "dev": true, - "inBundle": true, - "license": "ISC" + "engines": { + "node": ">=6" + } }, - "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "5.5.0", + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", - "@npmcli/move-file": "^2.0.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.1.1", - "@npmcli/run-script": "^4.1.3", - "bin-links": "^3.0.0", - "cacache": "^16.0.6", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "minimatch": "^5.1.0", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.0.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.0", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.1", - "proc-log": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.0", - "treeverse": "^2.0.0", - "walk-up-path": "^1.0.0" - }, - "bin": { - "arborist": "bin/index.js" + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/@npmcli/ci-detect": { - "version": "2.0.0", + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "4.2.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/map-workspaces": "^2.0.2", - "ini": "^3.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "proc-log": "^2.0.0", - "read-package-json-fast": "^2.0.3", - "semver": "^7.3.5", - "walk-up-path": "^1.0.0" - }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/@npmcli/disparity-colors": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/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=" + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "dependencies": { - "ansi-styles": "^4.3.0" + "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": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.12" } }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "2.1.1", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "3.0.1", + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^3.0.0", - "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^7.0.0", - "proc-log": "^2.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "1.0.7", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dependencies": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "installed-package-contents": "index.js" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">= 10" + "node": ">= 0.10" } }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "2.0.4", + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^8.0.1", - "minimatch": "^5.0.1", - "read-package-json-fast": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "3.1.1", + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "cacache": "^16.0.0", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", - "semver": "^7.3.5" + "escape-goat": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/@npmcli/move-file": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" + "side-channel": "^1.0.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", + "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": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.6" } }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { - "json-parse-even-better-errors": "^2.3.1" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "3.0.0", + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "infer-owner": "^1.0.4" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bin": { + "rc": "cli.js" } }, - "node_modules/npm/node_modules/@npmcli/query": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "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": { - "npm-package-arg": "^9.1.0", - "postcss-selector-parser": "^6.0.10", - "semver": "^7.3.7" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 6" } }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "4.2.1", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/promise-spawn": "^3.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^2.0.3", - "which": "^2.0.2" + "picomatch": "^2.2.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8.10.0" } }, - "node_modules/npm/node_modules/@tootallnate/once": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/agent-base": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/redis": { + "version": "4.6.7", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", + "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.8", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.3", + "@redis/time-series": "1.0.4" } }, - "node_modules/npm/node_modules/agentkeepalive": { + "node_modules/registry-auth-token": { "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" + "rc": "^1.2.8" }, "engines": { - "node": ">= 8.0.0" + "node": ">=6.0.0" } }, - "node_modules/npm/node_modules/aggregate-error": { - "version": "3.1.0", + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "rc": "^1.2.8" }, "engines": { "node": ">=8" } }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" + "dependencies": { + "lowercase-keys": "^1.0.0" } }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, - "node_modules/npm/node_modules/aproba": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/are-we-there-yet": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" + "tslib": "^1.9.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "npm": ">=2.0.0" } }, - "node_modules/npm/node_modules/asap": { - "version": "2.0.6", - "dev": true, - "inBundle": true, - "license": "MIT" + "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==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" + "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/npm/node_modules/bin-links": { - "version": "3.0.1", + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^5.0.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^3.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bin": { + "semver": "bin/semver" } }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "2.2.0", + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", "dev": true, - "inBundle": true, - "license": "MIT", + "dependencies": { + "semver": "^6.3.0" + }, "engines": { "node": ">=8" } }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/npm/node_modules/builtins": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { - "semver": "^7.0.0" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/npm/node_modules/cacache": { - "version": "16.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", + "node_modules/send/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/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^1.1.1" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">= 0.8.0" } }, - "node_modules/npm/node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "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": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" }, - "engines": { - "node": ">=10" + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm/node_modules/chownr": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=10" - } + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^4.1.0" - }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">=10" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/clean-stack": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" + "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/npm/node_modules/cli-columns": { - "version": "4.0.0", + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "string-width": "^4.2.3", + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.2", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "string-width": "^4.2.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/clone": { - "version": "1.0.4", + "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=", "dev": true, - "inBundle": true, - "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "5.0.0", + "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, - "inBundle": true, - "license": "ISC", "dependencies": { - "mkdirp-infer-owner": "^2.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/color-support": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" + "node": ">=6" } }, - "node_modules/npm/node_modules/columnify": { - "version": "1.6.0", + "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, - "inBundle": true, - "license": "MIT", "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=8.0" } }, - "node_modules/npm/node_modules/common-ancestor-path": { + "node_modules/toidentifier": { "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/console-control-strings": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { - "node": ">=4" + "node": ">=0.6" } }, - "node_modules/npm/node_modules/debug": { - "version": "4.3.4", + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" + "nopt": "~1.0.10" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "node_modules/npm/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT" + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/npm/node_modules/debuglog": { - "version": "1.0.1", + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "inBundle": true, - "license": "MIT", "engines": { - "node": "*" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/defaults": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", + "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": { - "clone": "^1.0.2" - } - }, - "node_modules/npm/node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/depd": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, "engines": { "node": ">= 0.6" } }, - "node_modules/npm/node_modules/dezalgo": { - "version": "1.0.4", + "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==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "asap": "^2.0.0", - "wrappy": "1" + "is-typedarray": "^1.0.0" } }, - "node_modules/npm/node_modules/diff": { - "version": "5.0.0", + "node_modules/typescript": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", + "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">=0.3.1" + "node": ">=4.2.0" } }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.13", + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, "dependencies": { - "iconv-lite": "^0.6.2" + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "engines": { - "node": ">=6" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.12", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" } }, - "node_modules/npm/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/gauge": { - "version": "4.0.4", + "node_modules/update-notifier/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=10" } }, - "node_modules/npm/node_modules/glob": { - "version": "8.0.3", + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "prepend-http": "^2.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=4" } }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.10", - "dev": true, - "inBundle": true, - "license": "ISC" + "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/npm/node_modules/has": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "engines": { "node": ">= 0.4.0" } }, - "node_modules/npm/node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/npm/node_modules/has-unicode": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "5.0.0", + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "lru-cache": "^7.5.1" + "string-width": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "node": ">=8" } }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "5.0.0", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">= 6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "5.0.1", + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, - "inBundle": true, - "license": "MIT", "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" } }, - "node_modules/npm/node_modules/humanize-ms": { - "version": "1.2.1", + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" + "engines": { + "node": ">=8" } }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + }, + "dependencies": { + "@netlify/functions": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-1.0.0.tgz", + "integrity": "sha512-7fnJv3vr8uyyyOYPChwoec6MjzsCw1CoRUO2DhQ1BD6bOyJRlD4DUaOOGlMILB2LCT8P24p5LexEGx8AJb7xdA==", + "requires": { + "is-promise": "^4.0.0" } }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minimatch": "^5.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "requires": {} }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" + "@redis/client": { + "version": "1.5.8", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", + "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" } }, - "node_modules/npm/node_modules/indent-string": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "requires": {} }, - "node_modules/npm/node_modules/infer-owner": { + "@redis/json": { "version": "1.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "requires": {} }, - "node_modules/npm/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } + "@redis/search": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", + "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", + "requires": {} }, - "node_modules/npm/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC" + "@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "requires": {} }, - "node_modules/npm/node_modules/ini": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true }, - "node_modules/npm/node_modules/init-package-json": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^9.0.1", - "promzard": "^0.3.0", - "read": "^1.0.7", - "read-package-json": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "requires": { + "@stablelib/int": "^1.0.1" } }, - "node_modules/npm/node_modules/ip": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "4.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" + "@stablelib/blake2b": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/blake2b/-/blake2b-1.0.1.tgz", + "integrity": "sha512-B3KyKoBAjkIFeH7romcF96i+pVFYk7K2SBQ1pZvaxV+epSBXJ+n0C66esUhyz6FF+5FbdQVm77C5fzGFcEZpKA==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/is-cidr": { - "version": "4.0.2", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "^3.1.1" - }, - "engines": { - "node": ">=10" - } + "@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" }, - "node_modules/npm/node_modules/is-core-module": { - "version": "2.10.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" + "@stablelib/ed25519": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.2.tgz", + "integrity": "sha512-FtnvUwvKbp6l1dNcg4CswMAVFVu/nzLK3oC7/PRtjYyHbWsIkD8j+5cjXHmwcCpdCpRCaTGACkEhhMQ1RcdSOQ==", + "requires": { + "@stablelib/random": "^1.0.1", + "@stablelib/sha512": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/is-lambda": { + "@stablelib/hash": { "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true, - "inBundle": true, - "license": "MIT" + "@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" }, - "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" + "@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "requires": { + "@stablelib/bytes": "^1.0.1" } }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "dev": true, - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff": { - "version": "5.1.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "5.4.1", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "6.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/nacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.3.tgz", + "integrity": "sha512-ZdDGRo4s6ke2rdhwwna5SAikU48AQRNqPPbJ29ZSC781SMUMPpkixKpyZG+NfYhMkFSJ0ZRlFdKW+/ksmpVHWA==", + "requires": { + "@stablelib/poly1305": "^1.0.1", + "@stablelib/random": "^1.0.1", + "@stablelib/wipe": "^1.0.1", + "@stablelib/x25519": "^1.0.2", + "@stablelib/xsalsa20": "^1.0.2" } }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "4.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/disparity-colors": "^2.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^5.0.1", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1", - "tar": "^6.1.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/poly1305": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", + "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", + "requires": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "4.0.10", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^5.0.0", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/fs": "^2.1.1", - "@npmcli/run-script": "^4.2.0", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^9.0.1", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "proc-log": "^2.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "semver": "^7.3.7", - "walk-up-path": "^1.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/random": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.1.tgz", + "integrity": "sha512-zOh+JHX3XG9MSfIB0LZl/YwPP9w3o6WBiJkZvjPoKKu5LKFW4OLV71vMxWp9qG5T43NaWyn0QQTWgqCdO+yOBQ==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^5.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/salsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/salsa20/-/salsa20-1.0.2.tgz", + "integrity": "sha512-nfjKzw0KTKrrKBasEP+j7UP4I8Xudom8lVZIBCp0kQNARXq72IlSic0oabg2FC1NU68L4RdHrNJDd8bFwrphYA==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/constant-time": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "8.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/sha512": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", + "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "4.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "4.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/run-script": "^4.1.3", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/x25519": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.2.tgz", + "integrity": "sha512-wTR0t0Bp1HABLFRbYaE3vFLuco2QbAg6QvxBnzi5j9qjhYezWHW7OiCZyaWbt25UkSaoolUUT4Il0nS/2vcbSw==", + "requires": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.1", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "6.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "normalize-package-data": "^4.0.0", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0", - "semver": "^7.3.7", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@stablelib/xsalsa20": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/xsalsa20/-/xsalsa20-1.0.2.tgz", + "integrity": "sha512-7XdBGbcNgBShmuhDXv1G1WPVCkjZdkb1oPMzSidO7Fve0MHntH6TjFkj5bfLI+aRE+61weO076vYpP/jmaAYog==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/salsa20": "^1.0.2", + "@stablelib/wipe": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "5.0.3", + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^13.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "requires": { + "defer-to-connect": "^1.0.1" } }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "4.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" + "@taquito/http-utils": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-12.1.1.tgz", + "integrity": "sha512-Zlp/eTRVjFs0XEIiAhgxkh6s9npF4dO+e/Sm2XWsDmNPoGI2jdXNH0L+NiKJIOkYcu0CXlcgriTeEaYnbeTvcA==", + "requires": { + "axios": "^0.26.0" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "3.0.6", - "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "@npmcli/git": "^3.0.0", - "@npmcli/run-script": "^4.1.3", - "json-parse-even-better-errors": "^2.3.1", - "proc-log": "^2.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "requires": { + "follow-redirects": "^1.14.8" + } + } } }, - "node_modules/npm/node_modules/lru-cache": { - "version": "7.13.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=12" + "@taquito/local-forging": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-12.1.1.tgz", + "integrity": "sha512-SUA1YYRIpEGsTy5OfUIgIem0k/QsAzGjDCvf/wl5XV/fVBkP/+GN7uvYoqgJblCmsgtsMBhJFtXgs+D6bjGexg==", + "requires": { + "@taquito/utils": "^12.1.1", + "bignumber.js": "^9.0.2" } }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "10.2.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@taquito/michel-codec": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-12.1.1.tgz", + "integrity": "sha512-BAig8YyLyRW5kxV/r0S191W+SvYuiTRJpgSp5IsgCDLAOh+d4/xq6IgU3PuGJgokQDstZdTbjpkrgRCnufR8lw==" + }, + "@taquito/michelson-encoder": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-12.1.1.tgz", + "integrity": "sha512-mWcA1DHHlFj7UswJpEmml853x9e0IYHyeiKZYAo7DtizHz0jiUWtptCuEWiPQ4fMOreFbYZ6KVYenoVfQVNrqA==", + "requires": { + "@taquito/rpc": "^12.1.1", + "@taquito/utils": "^12.1.1", + "bignumber.js": "^9.0.2", + "fast-json-stable-stringify": "^2.1.0" } }, - "node_modules/npm/node_modules/minimatch": { - "version": "5.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" + "@taquito/rpc": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-12.1.1.tgz", + "integrity": "sha512-CgAF9kdmKLa/UbmiqApDtncCQGiG7kEOIYis8IIa0JUT9JD1H8WBbSNF/oNh4e0soWUK9BL2qU369RFnxIW+iA==", + "requires": { + "@taquito/http-utils": "^12.1.1", + "@taquito/utils": "^12.1.1", + "bignumber.js": "^9.0.2" } }, - "node_modules/npm/node_modules/minipass": { - "version": "3.3.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" + "@taquito/signer": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-12.1.1.tgz", + "integrity": "sha512-TONxIbLs7bgmB3TTzcTOYzL8pFLZFBujHDHjB5QHJY5DT+lpByjYZHk2Frqjcy3NDvENVLU6uXeCeba2LK8kwA==", + "requires": { + "@stablelib/blake2b": "^1.0.1", + "@stablelib/ed25519": "^1.0.2", + "@stablelib/nacl": "^1.0.3", + "@taquito/taquito": "^12.1.1", + "@taquito/utils": "^12.1.1", + "elliptic": "^6.5.4", + "pbkdf2": "^3.1.2", + "typedarray-to-buffer": "^4.0.0" }, - "engines": { - "node": ">=8" + "dependencies": { + "typedarray-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" + } } }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" + "@taquito/taquito": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-12.1.1.tgz", + "integrity": "sha512-HvbtClQ7isrDd17X/LEKkPzzeVYA8EMUem3qrkl9qvDO6FpJx/QLbUpYfT2PC0pLUkSrzdLGzmESHAOZhcksaw==", + "requires": { + "@taquito/http-utils": "^12.1.1", + "@taquito/local-forging": "^12.1.1", + "@taquito/michel-codec": "^12.1.1", + "@taquito/michelson-encoder": "^12.1.1", + "@taquito/rpc": "^12.1.1", + "@taquito/utils": "^12.1.1", + "bignumber.js": "^9.0.2", + "rxjs": "^6.6.3" } }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "2.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "@taquito/utils": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-12.1.1.tgz", + "integrity": "sha512-GxNSBrA02vwhy56ayWB49VZficB+j2oyhPdlsRb2CguephmyEYnlUaNV27ILa6dPDW+zv6+QWQj6GyqLBRpIlA==", + "requires": { + "@stablelib/blake2b": "^1.0.1", + "@stablelib/ed25519": "^1.0.2", + "@types/bs58check": "^2.1.0", + "blakejs": "^1.1.1", + "bs58check": "^2.1.2", + "buffer": "^6.0.3", + "elliptic": "^6.5.4", + "typedarray-to-buffer": "^4.0.0" }, - "optionalDependencies": { - "encoding": "^0.1.13" + "dependencies": { + "typedarray-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" + } } }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" + "requires": { + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/npm/node_modules/minipass-json-stream": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" + "@types/bs58check": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz", + "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==", + "requires": { + "@types/node": "*" } }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" + "requires": { + "@types/node": "*" } }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" } }, - "node_modules/npm/node_modules/minizlib": { - "version": "2.1.2", + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" } }, - "node_modules/npm/node_modules/mkdirp": { - "version": "1.0.4", + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/morgan": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", + "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", "dev": true, - "inBundle": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" + "requires": { + "@types/node": "*" } }, - "node_modules/npm/node_modules/mkdirp-infer-owner": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - }, - "engines": { - "node": ">=10" - } + "@types/node": { + "version": "17.0.36", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", + "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==" }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "dev": true, - "inBundle": true, - "license": "MIT" + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true }, - "node_modules/npm/node_modules/mute-stream": { - "version": "0.0.8", - "dev": true, - "inBundle": true, - "license": "ISC" + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true }, - "node_modules/npm/node_modules/negotiator": { - "version": "0.6.3", + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" + "requires": { + "@types/mime": "^1", + "@types/node": "*" } }, - "node_modules/npm/node_modules/node-gyp": { - "version": "9.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.22 || ^14.13 || >=16" + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.11", + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "requires": { + "string-width": "^4.1.0" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "requires": { + "color-convert": "^2.0.1" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { + "anymatch": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, - "node_modules/npm/node_modules/nopt": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "axios": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", + "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chalk": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "1.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" + "base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "requires": { + "safe-buffer": "^5.0.1" } }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "5.0.0", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "dependencies": { + "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/npm/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" + "bignumber.js": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", + "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "9.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "5.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^1.1.2", - "npm-normalize-package-bin": "^1.0.1" - }, - "bin": { - "npm-packlist": "bin/index.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" } }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "7.0.1", + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^9.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" } }, - "node_modules/npm/node_modules/npm-profile": { - "version": "6.2.1", + "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, - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "13.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "make-fetch-happen": "^10.0.6", - "minipass": "^3.1.6", - "minipass-fetch": "^2.0.3", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.1", - "proc-log": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" } }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause" + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" }, - "node_modules/npm/node_modules/npmlog": { - "version": "6.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "requires": { + "base-x": "^3.0.2" } }, - "node_modules/npm/node_modules/once": { - "version": "1.4.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" + "bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "requires": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" } }, - "node_modules/npm/node_modules/opener": { - "version": "1.5.2", - "dev": true, - "inBundle": true, - "license": "(WTFPL OR MIT)", - "bin": { - "opener": "bin/opener-bin.js" + "buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" } }, - "node_modules/npm/node_modules/p-map": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, - "node_modules/npm/node_modules/pacote": { - "version": "13.6.1", + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^3.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/run-script": "^4.1.0", - "cacache": "^16.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.6", - "mkdirp": "^1.0.4", - "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^5.0.0", - "read-package-json-fast": "^2.0.3", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "lib/bin.js" + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", "dependencies": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } } }, - "node_modules/npm/node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" } }, - "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.0.10", + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "engines": { - "node": ">=4" + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "node_modules/npm/node_modules/proc-log": { - "version": "2.0.1", + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" } }, - "node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" + "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==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/npm/node_modules/promise-inflight": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true }, - "node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" + "requires": { + "mimic-response": "^1.0.0" } }, - "node_modules/npm/node_modules/promzard": { - "version": "0.3.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "1" - } + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" + "requires": { + "color-name": "~1.1.4" } }, - "node_modules/npm/node_modules/read": { - "version": "1.0.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "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" } }, - "node_modules/npm/node_modules/read-package-json": { + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "configstore": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^8.0.1", - "json-parse-even-better-errors": "^2.3.1", - "normalize-package-data": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" } }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "2.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - }, - "engines": { - "node": ">=10" + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" } }, - "node_modules/npm/node_modules/readable-stream": { - "version": "3.6.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } + "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==" }, - "node_modules/npm/node_modules/readdir-scoped-modules": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, - "node_modules/npm/node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "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==", + "requires": { + "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/npm/node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "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==", + "requires": { + "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/npm/node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true }, - "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" } }, - "node_modules/npm/node_modules/safe-buffer": { - "version": "5.2.1", + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT" + "requires": { + "mimic-response": "^1.0.0" + } }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true + "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==", + "dev": true }, - "node_modules/npm/node_modules/semver": { - "version": "7.3.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true }, - "node_modules/npm/node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, - "node_modules/npm/node_modules/set-blocking": { + "depd": { "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "3.0.7", - "dev": true, - "inBundle": true, - "license": "ISC" + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, - "node_modules/npm/node_modules/socks": { - "version": "2.7.0", + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" + "requires": { + "is-obj": "^2.0.0" } }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "7.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } + "dotenv": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", + "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==", + "dev": true }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.3.0", - "dev": true, - "inBundle": true, - "license": "CC-BY-3.0" + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "elliptic": { + "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.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.11", - "dev": true, - "inBundle": true, - "license": "CC0-1.0" + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true }, - "node_modules/npm/node_modules/ssri": { - "version": "9.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, - "node_modules/npm/node_modules/string_decoder": { - "version": "1.3.0", + "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==", "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" + "requires": { + "once": "^1.4.0" } }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "node_modules/npm/node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, - "node_modules/npm/node_modules/tar": { - "version": "6.1.11", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 10" + "express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" } }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", - "dev": true, - "inBundle": true, - "license": "MIT" + "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/npm/node_modules/treeverse": { - "version": "2.0.0", + "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, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "requires": { + "to-regex-range": "^5.0.1" } }, - "node_modules/npm/node_modules/unique-filename": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^2.0.0" + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" } }, - "node_modules/npm/node_modules/unique-slug": { - "version": "2.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" } }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "4.0.0", + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } + "optional": true }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, - "node_modules/npm/node_modules/wcwidth": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" } }, - "node_modules/npm/node_modules/which": { - "version": "2.0.2", + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" + "requires": { + "pump": "^3.0.0" } }, - "node_modules/npm/node_modules/wide-align": { - "version": "1.1.5", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "requires": { + "is-glob": "^4.0.1" } }, - "node_modules/npm/node_modules/wrappy": { - "version": "1.0.2", + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", "dev": true, - "inBundle": true, - "license": "ISC" + "requires": { + "ini": "2.0.0" + } }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "4.0.1", + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" } }, - "node_modules/npm/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "ISC" + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" - } + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "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==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" } }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true, - "engines": { - "node": ">=6" + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" } }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" + "iconv-lite": { + "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 < 3" } }, - "node_modules/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=" + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, - "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "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" - } + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", + "dev": true }, - "node_modules/prepend-http": { + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + }, + "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==" + }, + "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, - "engines": { - "node": ">=4" + "requires": { + "binary-extensions": "^2.0.0" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" } }, - "node_modules/pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, - "node_modules/pump": { + "is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "requires": { + "is-extglob": "^2.1.1" } }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" } }, - "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true }, - "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" - } + "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 }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "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/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", "dev": true }, - "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" - } + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } + "is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, - "node_modules/redis": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", - "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.8", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.3", - "@redis/time-series": "1.0.4" - } + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", + "dev": true }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "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/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "requires": { + "json-buffer": "3.0.0" } }, - "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==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "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/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", "dev": true, - "bin": { - "semver": "bin/semver" + "requires": { + "package-json": "^6.3.0" } }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/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/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" + "requires": { + "yallist": "^4.0.0" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "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/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "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": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/touch": { + "make-dir": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", - "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "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/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - }, - "dependencies": { - "@netlify/functions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-1.0.0.tgz", - "integrity": "sha512-7fnJv3vr8uyyyOYPChwoec6MjzsCw1CoRUO2DhQ1BD6bOyJRlD4DUaOOGlMILB2LCT8P24p5LexEGx8AJb7xdA==", - "requires": { - "is-promise": "^4.0.0" - } - }, - "@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "requires": {} - }, - "@redis/client": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", - "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", - "requires": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - } - }, - "@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "requires": {} - }, - "@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "requires": {} - }, - "@redis/search": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", - "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", - "requires": {} - }, - "@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "requires": {} - }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, - "@stablelib/binary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", - "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", - "requires": { - "@stablelib/int": "^1.0.1" - } - }, - "@stablelib/blake2b": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/blake2b/-/blake2b-1.0.1.tgz", - "integrity": "sha512-B3KyKoBAjkIFeH7romcF96i+pVFYk7K2SBQ1pZvaxV+epSBXJ+n0C66esUhyz6FF+5FbdQVm77C5fzGFcEZpKA==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/bytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", - "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" - }, - "@stablelib/constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", - "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" - }, - "@stablelib/ed25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.2.tgz", - "integrity": "sha512-FtnvUwvKbp6l1dNcg4CswMAVFVu/nzLK3oC7/PRtjYyHbWsIkD8j+5cjXHmwcCpdCpRCaTGACkEhhMQ1RcdSOQ==", - "requires": { - "@stablelib/random": "^1.0.1", - "@stablelib/sha512": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/hash": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", - "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" - }, - "@stablelib/int": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", - "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" - }, - "@stablelib/keyagreement": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", - "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", - "requires": { - "@stablelib/bytes": "^1.0.1" - } - }, - "@stablelib/nacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.3.tgz", - "integrity": "sha512-ZdDGRo4s6ke2rdhwwna5SAikU48AQRNqPPbJ29ZSC781SMUMPpkixKpyZG+NfYhMkFSJ0ZRlFdKW+/ksmpVHWA==", - "requires": { - "@stablelib/poly1305": "^1.0.1", - "@stablelib/random": "^1.0.1", - "@stablelib/wipe": "^1.0.1", - "@stablelib/x25519": "^1.0.2", - "@stablelib/xsalsa20": "^1.0.2" - } - }, - "@stablelib/poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", - "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", - "requires": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.1.tgz", - "integrity": "sha512-zOh+JHX3XG9MSfIB0LZl/YwPP9w3o6WBiJkZvjPoKKu5LKFW4OLV71vMxWp9qG5T43NaWyn0QQTWgqCdO+yOBQ==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/salsa20": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/salsa20/-/salsa20-1.0.2.tgz", - "integrity": "sha512-nfjKzw0KTKrrKBasEP+j7UP4I8Xudom8lVZIBCp0kQNARXq72IlSic0oabg2FC1NU68L4RdHrNJDd8bFwrphYA==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/sha512": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", - "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/wipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", - "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" - }, - "@stablelib/x25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.2.tgz", - "integrity": "sha512-wTR0t0Bp1HABLFRbYaE3vFLuco2QbAg6QvxBnzi5j9qjhYezWHW7OiCZyaWbt25UkSaoolUUT4Il0nS/2vcbSw==", - "requires": { - "@stablelib/keyagreement": "^1.0.1", - "@stablelib/random": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/xsalsa20": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/xsalsa20/-/xsalsa20-1.0.2.tgz", - "integrity": "sha512-7XdBGbcNgBShmuhDXv1G1WPVCkjZdkb1oPMzSidO7Fve0MHntH6TjFkj5bfLI+aRE+61weO076vYpP/jmaAYog==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/salsa20": "^1.0.2", - "@stablelib/wipe": "^1.0.1" - } - }, - "@subspace/vdf": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@subspace/vdf/-/vdf-0.1.0.tgz", - "integrity": "sha512-iKYdYOcAtALmxxgreWqnHphT7m8HIyBsAYLrPSRvOJM9hTY+Rfg+EsLiqXLgHoIXyy980dQhoE4yIwu8xXDmvg==", - "requires": { - "@types/node": "^11.13.4" - }, - "dependencies": { - "@types/node": { - "version": "11.15.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.54.tgz", - "integrity": "sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==" - } - } - }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, - "@taquito/http-utils": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-12.1.1.tgz", - "integrity": "sha512-Zlp/eTRVjFs0XEIiAhgxkh6s9npF4dO+e/Sm2XWsDmNPoGI2jdXNH0L+NiKJIOkYcu0CXlcgriTeEaYnbeTvcA==", - "requires": { - "axios": "^0.26.0" - } - }, - "@taquito/local-forging": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-12.1.1.tgz", - "integrity": "sha512-SUA1YYRIpEGsTy5OfUIgIem0k/QsAzGjDCvf/wl5XV/fVBkP/+GN7uvYoqgJblCmsgtsMBhJFtXgs+D6bjGexg==", - "requires": { - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2" - } - }, - "@taquito/michel-codec": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-12.1.1.tgz", - "integrity": "sha512-BAig8YyLyRW5kxV/r0S191W+SvYuiTRJpgSp5IsgCDLAOh+d4/xq6IgU3PuGJgokQDstZdTbjpkrgRCnufR8lw==" - }, - "@taquito/michelson-encoder": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-12.1.1.tgz", - "integrity": "sha512-mWcA1DHHlFj7UswJpEmml853x9e0IYHyeiKZYAo7DtizHz0jiUWtptCuEWiPQ4fMOreFbYZ6KVYenoVfQVNrqA==", - "requires": { - "@taquito/rpc": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2", - "fast-json-stable-stringify": "^2.1.0" - } - }, - "@taquito/rpc": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-12.1.1.tgz", - "integrity": "sha512-CgAF9kdmKLa/UbmiqApDtncCQGiG7kEOIYis8IIa0JUT9JD1H8WBbSNF/oNh4e0soWUK9BL2qU369RFnxIW+iA==", - "requires": { - "@taquito/http-utils": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2" - } - }, - "@taquito/signer": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-12.1.1.tgz", - "integrity": "sha512-TONxIbLs7bgmB3TTzcTOYzL8pFLZFBujHDHjB5QHJY5DT+lpByjYZHk2Frqjcy3NDvENVLU6uXeCeba2LK8kwA==", - "requires": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.2", - "@stablelib/nacl": "^1.0.3", - "@taquito/taquito": "^12.1.1", - "@taquito/utils": "^12.1.1", - "elliptic": "^6.5.4", - "pbkdf2": "^3.1.2", - "typedarray-to-buffer": "^4.0.0" - }, - "dependencies": { - "typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" - } - } - }, - "@taquito/taquito": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-12.1.1.tgz", - "integrity": "sha512-HvbtClQ7isrDd17X/LEKkPzzeVYA8EMUem3qrkl9qvDO6FpJx/QLbUpYfT2PC0pLUkSrzdLGzmESHAOZhcksaw==", - "requires": { - "@taquito/http-utils": "^12.1.1", - "@taquito/local-forging": "^12.1.1", - "@taquito/michel-codec": "^12.1.1", - "@taquito/michelson-encoder": "^12.1.1", - "@taquito/rpc": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2", - "rxjs": "^6.6.3" - } - }, - "@taquito/utils": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-12.1.1.tgz", - "integrity": "sha512-GxNSBrA02vwhy56ayWB49VZficB+j2oyhPdlsRb2CguephmyEYnlUaNV27ILa6dPDW+zv6+QWQj6GyqLBRpIlA==", - "requires": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.2", - "@types/bs58check": "^2.1.0", - "blakejs": "^1.1.1", - "bs58check": "^2.1.2", - "buffer": "^6.0.3", - "elliptic": "^6.5.4", - "typedarray-to-buffer": "^4.0.0" - }, - "dependencies": { - "typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" - } - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bs58check": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz", - "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "@types/morgan": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", - "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "17.0.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", - "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", - "requires": { - "follow-redirects": "^1.14.8" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - }, - "dependencies": { - "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==" - } - } - }, - "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" - }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, - "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, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "requires": { - "base-x": "^3.0.2" - } - }, - "bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "requires": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "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==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "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==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "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==", - "requires": { - "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": { - "version": "1.1.7", - "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.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "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==", - "dev": true - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==", - "dev": true - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "elliptic": { - "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.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "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==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "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==" - }, - "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, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, - "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==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "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 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "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==" - }, - "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, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true - }, - "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 - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "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.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "media-typer": { - "version": "0.3.0", - "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=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "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==" - }, - "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=" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "nodemon": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz", - "integrity": "sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==", - "dev": true, - "requires": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "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 - }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, - "npm": { - "version": "8.17.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-8.17.0.tgz", - "integrity": "sha512-tIcfZd541v86Sqrf+t/GW6ivqiT8b/2b3EAjNw3vRe+eVnL4mlkVwu17hjCOrsPVntLb5C6tQG4jPUE5Oveeyw==", - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^5.0.4", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/config": "^4.2.1", - "@npmcli/fs": "^2.1.0", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/package-json": "^2.0.0", - "@npmcli/run-script": "^4.2.1", - "abbrev": "~1.1.1", - "archy": "~1.0.0", - "cacache": "^16.1.1", - "chalk": "^4.1.2", - "chownr": "^2.0.0", - "cli-columns": "^4.0.0", - "cli-table3": "^0.6.2", - "columnify": "^1.6.0", - "fastest-levenshtein": "^1.0.12", - "glob": "^8.0.1", - "graceful-fs": "^4.2.10", - "hosted-git-info": "^5.0.0", - "ini": "^3.0.0", - "init-package-json": "^3.0.2", - "is-cidr": "^4.0.2", - "json-parse-even-better-errors": "^2.3.1", - "libnpmaccess": "^6.0.2", - "libnpmdiff": "^4.0.2", - "libnpmexec": "^4.0.2", - "libnpmfund": "^3.0.1", - "libnpmhook": "^8.0.2", - "libnpmorg": "^4.0.2", - "libnpmpack": "^4.0.2", - "libnpmpublish": "^6.0.2", - "libnpmsearch": "^5.0.2", - "libnpmteam": "^4.0.2", - "libnpmversion": "^3.0.1", - "make-fetch-happen": "^10.2.0", - "minipass": "^3.1.6", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "ms": "^2.1.2", - "node-gyp": "^9.1.0", - "nopt": "^6.0.0", - "npm-audit-report": "^3.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.1.0", - "npm-pick-manifest": "^7.0.1", - "npm-profile": "^6.2.0", - "npm-registry-fetch": "^13.3.0", - "npm-user-validate": "^1.0.1", - "npmlog": "^6.0.2", - "opener": "^1.5.2", - "p-map": "^4.0.0", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.2", - "proc-log": "^2.0.1", - "qrcode-terminal": "^0.12.0", - "read": "~1.0.7", - "read-package-json": "^5.0.1", - "read-package-json-fast": "^2.0.3", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.1", - "tar": "^6.1.11", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^2.0.0", - "validate-npm-package-name": "^4.0.0", - "which": "^2.0.2", - "write-file-atomic": "^4.0.1" - }, - "dependencies": { - "@colors/colors": { - "version": "1.5.0", - "bundled": true, - "dev": true, - "optional": true - }, - "@gar/promisify": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "@isaacs/string-locale-compare": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "@npmcli/arborist": { - "version": "5.5.0", - "bundled": true, - "dev": true, - "requires": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/map-workspaces": "^2.0.3", - "@npmcli/metavuln-calculator": "^3.0.1", - "@npmcli/move-file": "^2.0.0", - "@npmcli/name-from-folder": "^1.0.1", - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/package-json": "^2.0.0", - "@npmcli/query": "^1.1.1", - "@npmcli/run-script": "^4.1.3", - "bin-links": "^3.0.0", - "cacache": "^16.0.6", - "common-ancestor-path": "^1.0.1", - "json-parse-even-better-errors": "^2.3.1", - "json-stringify-nice": "^1.1.4", - "minimatch": "^5.1.0", - "mkdirp": "^1.0.4", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "npm-install-checks": "^5.0.0", - "npm-package-arg": "^9.0.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.0", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "parse-conflict-json": "^2.0.1", - "proc-log": "^2.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.1", - "read-package-json-fast": "^2.0.2", - "readdir-scoped-modules": "^1.1.0", - "rimraf": "^3.0.2", - "semver": "^7.3.7", - "ssri": "^9.0.0", - "treeverse": "^2.0.0", - "walk-up-path": "^1.0.0" - } - }, - "@npmcli/ci-detect": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "@npmcli/config": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/map-workspaces": "^2.0.2", - "ini": "^3.0.0", - "mkdirp-infer-owner": "^2.0.0", - "nopt": "^6.0.0", - "proc-log": "^2.0.0", - "read-package-json-fast": "^2.0.3", - "semver": "^7.3.5", - "walk-up-path": "^1.0.0" - } - }, - "@npmcli/disparity-colors": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.3.0" - } - }, - "@npmcli/fs": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "requires": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - } - }, - "@npmcli/git": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^3.0.0", - "lru-cache": "^7.4.4", - "mkdirp": "^1.0.4", - "npm-pick-manifest": "^7.0.0", - "proc-log": "^2.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^2.0.2" - } - }, - "@npmcli/installed-package-contents": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "requires": { - "npm-bundled": "^1.1.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "@npmcli/map-workspaces": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/name-from-folder": "^1.0.1", - "glob": "^8.0.1", - "minimatch": "^5.0.1", - "read-package-json-fast": "^2.0.3" - } - }, - "@npmcli/metavuln-calculator": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "cacache": "^16.0.0", - "json-parse-even-better-errors": "^2.3.1", - "pacote": "^13.0.3", - "semver": "^7.3.5" - } - }, - "@npmcli/move-file": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - } - }, - "@npmcli/name-from-folder": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "@npmcli/node-gyp": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "@npmcli/package-json": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.1" - } - }, - "@npmcli/promise-spawn": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "infer-owner": "^1.0.4" - } - }, - "@npmcli/query": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "npm-package-arg": "^9.1.0", - "postcss-selector-parser": "^6.0.10", - "semver": "^7.3.7" - } - }, - "@npmcli/run-script": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/node-gyp": "^2.0.0", - "@npmcli/promise-spawn": "^3.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^2.0.3", - "which": "^2.0.2" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "bundled": true, - "dev": true, - "requires": { - "debug": "4" - } - }, - "agentkeepalive": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "requires": { - "debug": "^4.1.0", - "depd": "^1.1.2", - "humanize-ms": "^1.2.1" - } - }, - "aggregate-error": { - "version": "3.1.0", - "bundled": true, - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "bundled": true, - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "aproba": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "archy": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "are-we-there-yet": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "asap": { - "version": "2.0.6", - "bundled": true, - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "bin-links": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "cmd-shim": "^5.0.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0", - "read-cmd-shim": "^3.0.0", - "rimraf": "^3.0.0", - "write-file-atomic": "^4.0.0" - } - }, - "binary-extensions": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "brace-expansion": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "builtins": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "semver": "^7.0.0" - } - }, - "cacache": { - "version": "16.1.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^1.1.1" - } - }, - "chalk": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chownr": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "cidr-regex": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "ip-regex": "^4.1.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "bundled": true, - "dev": true - }, - "cli-columns": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - } - }, - "cli-table3": { - "version": "0.6.2", - "bundled": true, - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "clone": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "cmd-shim": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "mkdirp-infer-owner": "^2.0.0" - } - }, - "color-convert": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "color-support": { - "version": "1.1.3", - "bundled": true, - "dev": true - }, - "columnify": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "requires": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" - } - }, - "common-ancestor-path": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "cssesc": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "debug": { - "version": "4.3.4", - "bundled": true, - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true - } - } - }, - "debuglog": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "defaults": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "depd": { - "version": "1.1.2", - "bundled": true, - "dev": true - }, - "dezalgo": { - "version": "1.0.4", - "bundled": true, - "dev": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "diff": { - "version": "5.0.0", - "bundled": true, - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "bundled": true, - "dev": true - }, - "encoding": { - "version": "0.1.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - } - }, - "env-paths": { - "version": "2.2.1", - "bundled": true, - "dev": true - }, - "err-code": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "bundled": true, - "dev": true - }, - "fs-minipass": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true, - "dev": true - }, - "gauge": { - "version": "4.0.4", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - } - }, - "glob": { - "version": "8.0.3", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "bundled": true, - "dev": true - }, - "has": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "hosted-git-info": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^7.5.1" - } - }, - "http-cache-semantics": { - "version": "4.1.0", - "bundled": true, - "dev": true - }, - "http-proxy-agent": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "humanize-ms": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "ignore-walk": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "minimatch": "^5.0.1" - } - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true, - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "bundled": true, - "dev": true - }, - "infer-owner": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true - }, - "ini": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "init-package-json": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "npm-package-arg": "^9.0.1", - "promzard": "^0.3.0", - "read": "^1.0.7", - "read-package-json": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^4.0.0" - } - }, - "ip": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "ip-regex": { - "version": "4.3.0", - "bundled": true, - "dev": true - }, - "is-cidr": { - "version": "4.0.2", - "bundled": true, - "dev": true, - "requires": { - "cidr-regex": "^3.1.1" - } - }, - "is-core-module": { - "version": "2.10.0", - "bundled": true, - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "is-lambda": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "bundled": true, - "dev": true - }, - "json-stringify-nice": { - "version": "1.1.4", - "bundled": true, - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "bundled": true, - "dev": true - }, - "just-diff": { - "version": "5.1.1", - "bundled": true, - "dev": true - }, - "just-diff-apply": { - "version": "5.4.1", - "bundled": true, - "dev": true - }, - "libnpmaccess": { - "version": "6.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "minipass": "^3.1.1", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmdiff": { - "version": "4.0.4", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/disparity-colors": "^2.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "binary-extensions": "^2.2.0", - "diff": "^5.0.0", - "minimatch": "^5.0.1", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1", - "tar": "^6.1.0" - } - }, - "libnpmexec": { - "version": "4.0.10", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/arborist": "^5.0.0", - "@npmcli/ci-detect": "^2.0.0", - "@npmcli/fs": "^2.1.1", - "@npmcli/run-script": "^4.2.0", - "chalk": "^4.1.0", - "mkdirp-infer-owner": "^2.0.0", - "npm-package-arg": "^9.0.1", - "npmlog": "^6.0.2", - "pacote": "^13.6.1", - "proc-log": "^2.0.0", - "read": "^1.0.7", - "read-package-json-fast": "^2.0.2", - "semver": "^7.3.7", - "walk-up-path": "^1.0.0" - } - }, - "libnpmfund": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/arborist": "^5.0.0" - } - }, - "libnpmhook": { - "version": "8.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmorg": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmpack": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/run-script": "^4.1.3", - "npm-package-arg": "^9.0.1", - "pacote": "^13.6.1" - } - }, - "libnpmpublish": { - "version": "6.0.4", - "bundled": true, - "dev": true, - "requires": { - "normalize-package-data": "^4.0.0", - "npm-package-arg": "^9.0.1", - "npm-registry-fetch": "^13.0.0", - "semver": "^7.3.7", - "ssri": "^9.0.0" - } - }, - "libnpmsearch": { - "version": "5.0.3", - "bundled": true, - "dev": true, - "requires": { - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmteam": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "requires": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^13.0.0" - } - }, - "libnpmversion": { - "version": "3.0.6", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/git": "^3.0.0", - "@npmcli/run-script": "^4.1.3", - "json-parse-even-better-errors": "^2.3.1", - "proc-log": "^2.0.0", - "semver": "^7.3.7" - } - }, - "lru-cache": { - "version": "7.13.2", - "bundled": true, - "dev": true - }, - "make-fetch-happen": { - "version": "10.2.0", - "bundled": true, - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - } - }, - "minimatch": { - "version": "5.1.0", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minipass": { - "version": "3.3.4", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "minipass-collect": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-fetch": { - "version": "2.1.0", - "bundled": true, - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } - }, - "minipass-flush": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-json-stream": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minipass-sized": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0" - } - }, - "minizlib": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - } - }, - "mkdirp": { - "version": "1.0.4", - "bundled": true, - "dev": true - }, - "mkdirp-infer-owner": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^2.0.0", - "infer-owner": "^1.0.4", - "mkdirp": "^1.0.3" - } - }, - "ms": { - "version": "2.1.3", - "bundled": true, - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "bundled": true, - "dev": true - }, - "node-gyp": { - "version": "9.1.0", - "bundled": true, - "dev": true, - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "glob": { - "version": "7.2.3", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "nopt": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "abbrev": "1" - } - } - } - }, - "nopt": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "abbrev": "^1.0.0" - } - }, - "normalize-package-data": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^5.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - } - }, - "npm-audit-report": { - "version": "3.0.0", - "bundled": true, - "dev": true, - "requires": { - "chalk": "^4.0.0" - } - }, - "npm-bundled": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-install-checks": { - "version": "5.0.0", - "bundled": true, - "dev": true, - "requires": { - "semver": "^7.1.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "npm-package-arg": { - "version": "9.1.0", - "bundled": true, - "dev": true, - "requires": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" - } - }, - "npm-packlist": { - "version": "5.1.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "^8.0.1", - "ignore-walk": "^5.0.1", - "npm-bundled": "^1.1.2", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "7.0.1", - "bundled": true, - "dev": true, - "requires": { - "npm-install-checks": "^5.0.0", - "npm-normalize-package-bin": "^1.0.1", - "npm-package-arg": "^9.0.0", - "semver": "^7.3.5" - } - }, - "npm-profile": { - "version": "6.2.1", - "bundled": true, - "dev": true, - "requires": { - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0" - } - }, - "npm-registry-fetch": { - "version": "13.3.0", - "bundled": true, - "dev": true, - "requires": { - "make-fetch-happen": "^10.0.6", - "minipass": "^3.1.6", - "minipass-fetch": "^2.0.3", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^9.0.1", - "proc-log": "^2.0.0" - } - }, - "npm-user-validate": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "npmlog": { - "version": "6.0.2", - "bundled": true, - "dev": true, - "requires": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.2", - "bundled": true, - "dev": true - }, - "p-map": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "pacote": { - "version": "13.6.1", - "bundled": true, - "dev": true, - "requires": { - "@npmcli/git": "^3.0.0", - "@npmcli/installed-package-contents": "^1.0.7", - "@npmcli/promise-spawn": "^3.0.0", - "@npmcli/run-script": "^4.1.0", - "cacache": "^16.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "infer-owner": "^1.0.4", - "minipass": "^3.1.6", - "mkdirp": "^1.0.4", - "npm-package-arg": "^9.0.0", - "npm-packlist": "^5.1.0", - "npm-pick-manifest": "^7.0.0", - "npm-registry-fetch": "^13.0.1", - "proc-log": "^2.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^5.0.0", - "read-package-json-fast": "^2.0.3", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11" - } - }, - "parse-conflict-json": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.1", - "just-diff": "^5.0.1", - "just-diff-apply": "^5.2.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "postcss-selector-parser": { - "version": "6.0.10", - "bundled": true, - "dev": true, - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "proc-log": { - "version": "2.0.1", - "bundled": true, - "dev": true - }, - "promise-all-reject-late": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-call-limit": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "dev": true, - "requires": { - "read": "1" - } - }, - "qrcode-terminal": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "read": { - "version": "1.0.7", - "bundled": true, - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "read-cmd-shim": { - "version": "3.0.0", - "bundled": true, - "dev": true - }, - "read-package-json": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "^8.0.1", - "json-parse-even-better-errors": "^2.3.1", - "normalize-package-data": "^4.0.0", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "read-package-json-fast": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "requires": { - "json-parse-even-better-errors": "^2.3.0", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "readable-stream": { - "version": "3.6.0", - "bundled": true, - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "retry": { - "version": "0.12.0", - "bundled": true, - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "requires": { - "glob": "^7.1.3" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "glob": { - "version": "7.2.3", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "minimatch": { - "version": "3.1.2", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - } - } - }, - "safe-buffer": { - "version": "5.2.1", - "bundled": true, - "dev": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "7.3.7", - "bundled": true, - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "bundled": true, - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "bundled": true, - "dev": true - }, - "smart-buffer": { - "version": "4.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true - }, - "socks": { - "version": "2.7.0", - "bundled": true, - "dev": true, - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - } - }, - "socks-proxy-agent": { - "version": "7.0.0", - "bundled": true, - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - } - }, - "spdx-correct": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { + } + } + }, + "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.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "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=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "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==" + }, + "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=" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "on-finished": { "version": "2.3.0", - "bundled": true, - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.11", - "bundled": true, - "dev": true - }, - "ssri": { - "version": "9.0.1", - "bundled": true, - "dev": true, - "requires": { - "minipass": "^3.1.1" - } - }, - "string_decoder": { - "version": "1.3.0", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "bundled": true, - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "supports-color": { - "version": "7.2.0", - "bundled": true, - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "tar": { - "version": "6.1.11", - "bundled": true, - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^3.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true, - "dev": true - }, - "tiny-relative-date": { - "version": "1.3.0", - "bundled": true, - "dev": true - }, - "treeverse": { - "version": "2.0.0", - "bundled": true, - "dev": true - }, - "unique-filename": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validate-npm-package-name": { - "version": "4.0.0", - "bundled": true, - "dev": true, - "requires": { - "builtins": "^5.0.0" - } - }, - "walk-up-path": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "wcwidth": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "which": { - "version": "2.0.2", - "bundled": true, - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "wide-align": { - "version": "1.1.5", - "bundled": true, - "dev": true, + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "ee-first": "1.1.1" } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "write-file-atomic": { - "version": "4.0.1", - "bundled": true, + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "nodemon": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz", + "integrity": "sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5", + "update-notifier": "^5.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "ms": "^2.1.1" } }, - "yallist": { - "version": "4.0.0", - "bundled": true, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "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 + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "dev": true + }, "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -8628,6 +4451,11 @@ "ipaddr.js": "1.9.1" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", diff --git a/package.json b/package.json index 0b96029..d421bd1 100644 --- a/package.json +++ b/package.json @@ -21,10 +21,9 @@ "homepage": "https://github.com/oxheadalpha/tezos-testnet-faucet-backend#readme", "dependencies": { "@netlify/functions": "^1.0.0", - "@subspace/vdf": "^0.1.0", "@taquito/signer": "^12.1.1", "@taquito/taquito": "^12.1.1", - "axios": "^0.26.1", + "axios": "^1.4.0", "body-parser": "^1.20.0", "dotenv": "^16.0.1", "express": "^4.18.1", @@ -37,7 +36,6 @@ "@types/morgan": "^1.9.4", "@types/node": "^17.0.36", "nodemon": "^2.0.16", - "npm": "^8.17.0", "typescript": "^4.7.2" } } From e66374fff357a50b4f24be0cd4b4bbc8082c714e Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 5 Jul 2023 18:08:48 -0400 Subject: [PATCH 10/64] npm audit fix --- package-lock.json | 1709 ++------------------------------------------- 1 file changed, 59 insertions(+), 1650 deletions(-) diff --git a/package-lock.json b/package-lock.json index a7331b9..df52948 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,15 +92,6 @@ "@redis/client": "^1.0.0" } }, - "node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/@stablelib/binary": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", @@ -232,18 +223,6 @@ "@stablelib/wipe": "^1.0.1" } }, - "node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/@taquito/http-utils": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-12.1.1.tgz", @@ -519,43 +498,10 @@ "node": ">= 0.6" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", @@ -684,28 +630,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -782,48 +706,6 @@ "node": ">= 0.8" } }, - "node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cacheable-request/node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -836,55 +718,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chalk/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -912,12 +745,6 @@ "fsevents": "~2.3.2" } }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, "node_modules/cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -927,27 +754,6 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - } - }, "node_modules/cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", @@ -956,24 +762,6 @@ "node": ">=0.10.0" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -991,23 +779,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1065,15 +836,6 @@ "sha.js": "^2.4.8" } }, - "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1082,33 +844,6 @@ "ms": "2.0.0" } }, - "node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "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==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -1134,18 +869,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/dotenv": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", @@ -1154,12 +877,6 @@ "node": ">=12" } }, - "node_modules/duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==", - "dev": true - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1179,12 +896,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1193,24 +904,6 @@ "node": ">= 0.8" } }, - "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==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -1387,18 +1080,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -1411,49 +1092,6 @@ "node": ">= 6" } }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -1485,15 +1123,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -1526,12 +1155,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -1583,38 +1206,11 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, "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": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -1635,18 +1231,6 @@ "node": ">=8" } }, - "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "dependencies": { - "ci-info": "^2.0.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1656,15 +1240,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -1677,34 +1252,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -1714,113 +1261,11 @@ "node": ">=0.12.0" } }, - "node_modules/is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "dependencies": { - "package-json": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -1882,15 +1327,6 @@ "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==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -1913,12 +1349,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "node_modules/morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -1959,22 +1389,21 @@ } }, "node_modules/nodemon": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz", - "integrity": "sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==", + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, - "hasInstallScript": true, "dependencies": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" + "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" @@ -2005,7 +1434,7 @@ "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "dependencies": { "abbrev": "1" @@ -2026,15 +1455,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -2062,48 +1482,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2144,15 +1522,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2176,28 +1545,6 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/qs": { "version": "6.10.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", @@ -2234,27 +1581,6 @@ "node": ">= 0.8" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "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/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -2293,39 +1619,6 @@ "@redis/time-series": "1.0.4" } }, - "node_modules/registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "dependencies": { - "rc": "^1.2.8" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, "node_modules/ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -2379,27 +1672,6 @@ "semver": "bin/semver" } }, - "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "dependencies": { - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -2472,11 +1744,26 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/statuses": { "version": "2.0.1", @@ -2494,41 +1781,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2541,15 +1793,6 @@ "node": ">=4" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2587,18 +1830,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -2611,15 +1842,6 @@ "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==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", @@ -2639,18 +1861,6 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, - "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "dependencies": { - "crypto-random-string": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -2659,61 +1869,6 @@ "node": ">= 0.8" } }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2735,62 +1890,6 @@ "node": ">= 0.8" } }, - "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "dependencies": { - "string-width": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -2846,12 +1945,6 @@ "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", "requires": {} }, - "@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "dev": true - }, "@stablelib/binary": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", @@ -2983,15 +2076,6 @@ "@stablelib/wipe": "^1.0.1" } }, - "@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dev": true, - "requires": { - "defer-to-connect": "^1.0.1" - } - }, "@taquito/http-utils": { "version": "12.1.1", "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-12.1.1.tgz", @@ -3217,38 +2301,14 @@ "negotiator": "0.6.3" } }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "array-flatten": { @@ -3345,22 +2405,6 @@ "unpipe": "1.0.0" } }, - "boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", - "dev": true, - "requires": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - } - }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3417,38 +2461,6 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, - "cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - } - } - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -3458,39 +2470,6 @@ "get-intrinsic": "^1.0.2" } }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -3507,12 +2486,6 @@ "readdirp": "~3.6.0" } }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -3522,41 +2495,11 @@ "safe-buffer": "^5.0.1" } }, - "cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", - "dev": true - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha512-yjLXh88P599UOyPTFX0POsd7WxnbsVsGohcwzHOLspIhhpalPw1BcqED8NblyZLKcGrL8dTgMlcaZxV2jAD41Q==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, "cluster-key-slot": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3571,20 +2514,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", - "dev": true, - "requires": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" - } - }, "content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3633,12 +2562,6 @@ "sha.js": "^2.4.8" } }, - "crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", - "dev": true - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3647,27 +2570,6 @@ "ms": "2.0.0" } }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "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==", - "dev": true - }, - "defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3683,26 +2585,11 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, - "dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, "dotenv": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha512-CEj8FwwNA4cVH2uFCoHUrmojhYh1vmCdOaneKJXwkeY1i9jnlslVo9dx+hQ5Hl9GnH/Bwy/IjxAyOePyPKYnzA==", - "dev": true - }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3722,32 +2609,11 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, - "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==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", - "dev": true - }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -3876,15 +2742,6 @@ "has-symbols": "^1.0.1" } }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, "glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -3894,40 +2751,6 @@ "is-glob": "^4.0.1" } }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, - "got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dev": true, - "requires": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -3947,12 +2770,6 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, - "has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", - "dev": true - }, "hash-base": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", @@ -3982,12 +2799,6 @@ "minimalistic-crypto-utils": "^1.0.1" } }, - "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", - "dev": true - }, "http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -4019,29 +2830,11 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -4056,27 +2849,12 @@ "binary-extensions": "^2.0.0" } }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, "is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -4086,113 +2864,17 @@ "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", - "dev": true - }, "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 }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, "is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true - }, - "json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dev": true, - "requires": { - "json-buffer": "3.0.0" - } - }, - "latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", - "dev": true, - "requires": { - "package-json": "^6.3.0" - } - }, - "lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", @@ -4236,12 +2918,6 @@ "mime-db": "1.52.0" } }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -4261,12 +2937,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -4300,21 +2970,21 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "nodemon": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.16.tgz", - "integrity": "sha512-zsrcaOfTWRuUzBn3P44RDliLlp263Z/76FPoHFr3cFFkOz0lTPAcIw8dCzfdVIx/t3AtDYCZRCDkoCojJqaG3w==", + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, "requires": { "chokidar": "^3.5.2", "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.5", - "update-notifier": "^5.1.0" + "undefsafe": "^2.0.5" }, "dependencies": { "debug": { @@ -4337,7 +3007,7 @@ "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "requires": { "abbrev": "1" @@ -4349,12 +3019,6 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "dev": true - }, "object-inspect": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", @@ -4373,41 +3037,6 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "dev": true - }, - "package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", - "dev": true, - "requires": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -4436,12 +3065,6 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", - "dev": true - }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -4462,25 +3085,6 @@ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", - "dev": true, - "requires": { - "escape-goat": "^2.0.0" - } - }, "qs": { "version": "6.10.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", @@ -4505,26 +3109,6 @@ "unpipe": "1.0.0" } }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } - } - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -4557,33 +3141,6 @@ "@redis/time-series": "1.0.4" } }, - "registry-auth-token": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", - "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", - "dev": true, - "requires": { - "rc": "^1.2.8" - } - }, - "responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", - "dev": true, - "requires": { - "lowercase-keys": "^1.0.0" - } - }, "ripemd160": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", @@ -4617,23 +3174,6 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, - "semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", - "dev": true, - "requires": { - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, "send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -4696,11 +3236,22 @@ "object-inspect": "^1.9.0" } }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } }, "statuses": { "version": "2.0.1", @@ -4715,32 +3266,6 @@ "safe-buffer": "~5.2.0" } }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "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=", - "dev": true - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -4750,12 +3275,6 @@ "has-flag": "^3.0.0" } }, - "to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "dev": true - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -4784,12 +3303,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -4799,15 +3312,6 @@ "mime-types": "~2.1.24" } }, - "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==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, "typescript": { "version": "4.7.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", @@ -4820,62 +3324,11 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, - "unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", - "dev": true, - "requires": { - "crypto-random-string": "^2.0.0" - } - }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, - "update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", - "dev": true, - "requires": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, - "dependencies": { - "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dev": true, - "requires": { - "prepend-http": "^2.0.0" - } - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4891,50 +3344,6 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, - "widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", - "dev": true, - "requires": { - "string-width": "^4.0.0" - } - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", - "dev": true - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", From 919670a4811ef643764ec142264cf5c0b0500585 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 5 Jul 2023 18:15:18 -0400 Subject: [PATCH 11/64] Return error if no challenge exists when verifying --- dist/api.js | 4 ++++ src/api.ts | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/dist/api.js b/dist/api.js index 27973e2..655572d 100644 --- a/dist/api.js +++ b/dist/api.js @@ -126,6 +126,10 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () return; const challengeKey = (0, pow_1.getChallengeKey)(address); const { challenge, counter } = yield redis.hGetAll(challengeKey); + if (!challenge) { + res.status(400).send({ status: "ERROR", message: "No challenge found" }); + return; + } // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) const isValidSolution = (0, pow_1.verifySolution)({ diff --git a/src/api.ts b/src/api.ts index 83f13e1..a02836b 100644 --- a/src/api.ts +++ b/src/api.ts @@ -137,6 +137,11 @@ app.post("/verify", async (req: Request, res: Response) => { const { challenge, counter } = await redis.hGetAll(challengeKey) + if (!challenge) { + res.status(400).send({ status: "ERROR", message: "No challenge found" }) + return + } + // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) const isValidSolution = verifySolution({ From efbf41092a2a6d5b8896dcc9f659b807a7f033e3 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 11 Jul 2023 17:11:44 -0400 Subject: [PATCH 12/64] Cleanup --- dist/Tezos.js | 4 +- dist/api.js | 102 ++++++++++++++++++--------------------- dist/pow.js | 25 +++++++++- src/Tezos.ts | 4 +- src/api.ts | 131 +++++++++++++++++++++++++------------------------- 5 files changed, 142 insertions(+), 124 deletions(-) diff --git a/dist/Tezos.js b/dist/Tezos.js index 1719bfb..e51e883 100644 --- a/dist/Tezos.js +++ b/dist/Tezos.js @@ -19,7 +19,7 @@ exports.defaultUserAmount = 1; exports.defaultBakerAmount = 6000; const getTezAmountForProfile = (profile) => { let amount = 0; - switch (profile) { + switch (profile.toUpperCase()) { case Types_1.Profile.USER: amount = process.env.FAUCET_AMOUNT_USER || exports.defaultUserAmount; break; @@ -27,7 +27,7 @@ const getTezAmountForProfile = (profile) => { amount = process.env.FAUCET_AMOUNT_BAKER || exports.defaultBakerAmount; break; default: - throw new Error(`Unknown profile ${profile}`); + throw new Error(`Unknown profile '${profile}'`); } return amount; }; diff --git a/dist/api.js b/dist/api.js index 655572d..89e9cac 100644 --- a/dist/api.js +++ b/dist/api.js @@ -63,105 +63,96 @@ app.get("/info", (_, res) => { res.status(500).send({ status: "ERROR", message: "An exception occurred" }); } }); -const DIFFICULTY = 3; +const DIFFICULTY = 4; const CHALLENGES_NEEDED = 4; app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, profile } = req.body; if (!address || !profile) { - res.status(400).send("'address' and 'profile' fields are required"); - return; + return res.status(400).send({ + satus: "ERROR", + message: "'address' and 'profile' fields are required", + }); } if (!(0, Tezos_1.validateAddress)(res, address)) return; - if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) - return; + // if (!(await validateCaptcha(res, captchaToken))) return try { (0, Tezos_1.getTezAmountForProfile)(profile); } catch (e) { - res.status(400).send({ status: "ERROR", message: e.message }); - return; + return res.status(400).send({ status: "ERROR", message: e.message }); } try { - const challengekey = `address:${address}`; - let challenge = yield redis.hGet(challengekey, "challenge"); + const challengeKey = (0, pow_1.getChallengeKey)(address); + let { challenge, counter } = yield (0, pow_1.getChallenge)(redis, challengeKey); if (!challenge) { challenge = (0, pow_1.generateChallenge)(); - // Set the challenge and challenge counter. - yield redis.hSet(challengekey, { - challenge, - counter: 1, - }); - // Challenge should expire after 30m. - yield redis.expire(challengekey, 1800); + counter = 1; + yield (0, pow_1.saveChallenge)(redis, { challenge, challengeKey, counter }); } console.log({ challenge, difficulty: DIFFICULTY }); - res - .status(200) - .send({ + res.status(200).send({ status: "SUCCESS", challenge, + counter, difficulty: DIFFICULTY, - counter: 1, }); } catch (err) { const message = "Error getting challenge"; console.error(message, err); - res.status(500).send({ status: "ERROR", message }); + return res.status(500).send({ status: "ERROR", message }); } })); app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, solution, nonce } = req.body; if (!address || !solution || !nonce) { - res.status(400).send({ + return res.status(400).send({ status: "ERROR", message: "'address', 'solution', and 'nonce' fields are required", }); - return; } if (!(0, Tezos_1.validateAddress)(res, address)) return; - if (!(0, Captcha_1.validateCaptcha)(res, captchaToken)) - return; - const challengeKey = (0, pow_1.getChallengeKey)(address); - const { challenge, counter } = yield redis.hGetAll(challengeKey); - if (!challenge) { - res.status(400).send({ status: "ERROR", message: "No challenge found" }); - return; - } - // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce - // starts with a certain number of zeroes (the difficulty) - const isValidSolution = (0, pow_1.verifySolution)({ - challenge, - difficulty: DIFFICULTY, - nonce, - solution, - }); - console.log({ address, solution, nonce, counter }); - if (!isValidSolution) { - res.status(400).send({ status: "ERROR", message: "Incorrect solution" }); + if (!(yield (0, Captcha_1.validateCaptcha)(res, captchaToken))) return; - } try { - const challengeCounter = Number(counter); - if (challengeCounter < CHALLENGES_NEEDED) { - console.log(`GETTING CHALLENGE ${challengeCounter}`); + const challengeKey = (0, pow_1.getChallengeKey)(address); + const { challenge, counter } = yield (0, pow_1.getChallenge)(redis, challengeKey); + if (!challenge || !counter) { + return res + .status(400) + .send({ status: "ERROR", message: "No challenge found" }); + } + // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce + // starts with a certain number of zeroes (the difficulty) + const isValidSolution = (0, pow_1.verifySolution)({ + challenge, + difficulty: DIFFICULTY, + nonce, + solution, + }); + console.log({ address, solution, nonce, counter }); + if (!isValidSolution) { + return res + .status(400) + .send({ status: "ERROR", message: "Incorrect solution" }); + } + if (counter < CHALLENGES_NEEDED) { + console.log(`GETTING CHALLENGE ${counter}`); const newChallenge = (0, pow_1.generateChallenge)(); - const incrCounter = challengeCounter + 1; - yield redis.hSet(challengeKey, { + const incrCounter = counter + 1; + yield (0, pow_1.saveChallenge)(redis, { challenge: newChallenge, + challengeKey, counter: incrCounter, }); - res - .status(200) - .send({ + return res.status(200).send({ status: "SUCCESS", challenge: newChallenge, - difficulty: DIFFICULTY, counter: incrCounter, + difficulty: DIFFICULTY, }); - return; } // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address @@ -172,10 +163,13 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () b.txHash = "hash"; res.status(200).send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); yield redis.del(challengeKey).catch((e) => console.error(e.message)); + return; } catch (err) { console.error(err.message); - res.status(500).send({ status: "ERROR", message: "An error occurred" }); + return res + .status(500) + .send({ status: "ERROR", message: "An error occurred" }); } })); const port = process.env.API_PORT || 3000; diff --git a/dist/pow.js b/dist/pow.js index 4daf7fb..730e2e1 100644 --- a/dist/pow.js +++ b/dist/pow.js @@ -1,11 +1,34 @@ "use strict"; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; Object.defineProperty(exports, "__esModule", { value: true }); -exports.verifySolution = exports.generateChallenge = exports.getChallengeKey = void 0; +exports.verifySolution = exports.getChallenge = exports.saveChallenge = exports.generateChallenge = exports.getChallengeKey = void 0; const crypto_1 = require("crypto"); const getChallengeKey = (address) => `address:${address}`; exports.getChallengeKey = getChallengeKey; const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); exports.generateChallenge = generateChallenge; +const saveChallenge = (redis, { challenge, challengeKey, counter, expiration = 1800, // 30m + }) => __awaiter(void 0, void 0, void 0, function* () { + yield redis.hSet(challengeKey, { + challenge, + counter, + }); + yield redis.expire(challengeKey, expiration); +}); +exports.saveChallenge = saveChallenge; +const getChallenge = (redis, challengeKey) => __awaiter(void 0, void 0, void 0, function* () { + const data = yield redis.hGetAll(challengeKey); + return Object.assign(Object.assign({}, data), (data.counter && { counter: Number(data.counter) })); +}); +exports.getChallenge = getChallenge; const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); const verifySolution = ({ challenge, difficulty, nonce, solution, }) => { const hash = getSolution(challenge, nonce); diff --git a/src/Tezos.ts b/src/Tezos.ts index acabd77..7488891 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -11,7 +11,7 @@ export const defaultBakerAmount: number = 6000 export const getTezAmountForProfile = (profile: Profile) => { let amount: number = 0 - switch (profile) { + switch (profile.toUpperCase()) { case Profile.USER: amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount break @@ -19,7 +19,7 @@ export const getTezAmountForProfile = (profile: Profile) => { amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount break default: - throw new Error(`Unknown profile ${profile}`) + throw new Error(`Unknown profile '${profile}'`) } return amount diff --git a/src/api.ts b/src/api.ts index a02836b..015a421 100644 --- a/src/api.ts +++ b/src/api.ts @@ -13,7 +13,13 @@ import { validateAddress, } from "./Tezos" import { InfoResponseBody, Profile, RequestBody, ResponseBody } from "./Types" -import { generateChallenge, getChallengeKey, verifySolution } from "./pow" +import { + generateChallenge, + getChallengeKey, + saveChallenge, + getChallenge, + verifySolution, +} from "./pow" dotenv.config() @@ -21,7 +27,7 @@ const redis = createClient({ // url: "redis://localhost:6379", }) // reject -redis.on("error", (err) => console.log("Redis Client Error", err)) +redis.on("error", (err: any) => console.log("Redis Client Error", err)) const app: Express = express() app.use(bodyParser.json()) @@ -67,55 +73,49 @@ app.get("/info", (_, res: Response) => { } }) -const DIFFICULTY = 3 +const DIFFICULTY = 4 const CHALLENGES_NEEDED = 4 app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body if (!address || !profile) { - res.status(400).send("'address' and 'profile' fields are required") - return + return res.status(400).send({ + satus: "ERROR", + message: "'address' and 'profile' fields are required", + }) } if (!validateAddress(res, address)) return - if (!validateCaptcha(res, captchaToken)) return + // if (!(await validateCaptcha(res, captchaToken))) return try { getTezAmountForProfile(profile) } catch (e: any) { - res.status(400).send({ status: "ERROR", message: e.message }) - return + return res.status(400).send({ status: "ERROR", message: e.message }) } try { - const challengekey = `address:${address}` - let challenge = await redis.hGet(challengekey, "challenge") + const challengeKey = getChallengeKey(address) + let { challenge, counter } = await getChallenge(redis, challengeKey) if (!challenge) { challenge = generateChallenge() - // Set the challenge and challenge counter. - await redis.hSet(challengekey, { - challenge, - counter: 1, - }) - // Challenge should expire after 30m. - await redis.expire(challengekey, 1800) + counter = 1 + await saveChallenge(redis, { challenge, challengeKey, counter }) } console.log({ challenge, difficulty: DIFFICULTY }) - res - .status(200) - .send({ - status: "SUCCESS", - challenge, - difficulty: DIFFICULTY, - counter: 1, - }) + res.status(200).send({ + status: "SUCCESS", + challenge, + counter, + difficulty: DIFFICULTY, + }) } catch (err: any) { const message = "Error getting challenge" console.error(message, err) - res.status(500).send({ status: "ERROR", message }) + return res.status(500).send({ status: "ERROR", message }) } }) @@ -123,60 +123,58 @@ app.post("/verify", async (req: Request, res: Response) => { const { address, captchaToken, solution, nonce } = req.body if (!address || !solution || !nonce) { - res.status(400).send({ + return res.status(400).send({ status: "ERROR", message: "'address', 'solution', and 'nonce' fields are required", }) - return } if (!validateAddress(res, address)) return - if (!validateCaptcha(res, captchaToken)) return - - const challengeKey = getChallengeKey(address) + if (!(await validateCaptcha(res, captchaToken))) return - const { challenge, counter } = await redis.hGetAll(challengeKey) + try { + const challengeKey = getChallengeKey(address) + const { challenge, counter } = await getChallenge(redis, challengeKey) - if (!challenge) { - res.status(400).send({ status: "ERROR", message: "No challenge found" }) - return - } + if (!challenge || !counter) { + return res + .status(400) + .send({ status: "ERROR", message: "No challenge found" }) + } - // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce - // starts with a certain number of zeroes (the difficulty) - const isValidSolution = verifySolution({ - challenge, - difficulty: DIFFICULTY, - nonce, - solution, - }) + // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce + // starts with a certain number of zeroes (the difficulty) + const isValidSolution = verifySolution({ + challenge, + difficulty: DIFFICULTY, + nonce, + solution, + }) - console.log({ address, solution, nonce, counter }) + console.log({ address, solution, nonce, counter }) - if (!isValidSolution) { - res.status(400).send({ status: "ERROR", message: "Incorrect solution" }) - return - } + if (!isValidSolution) { + return res + .status(400) + .send({ status: "ERROR", message: "Incorrect solution" }) + } - try { - const challengeCounter = Number(counter) - if (challengeCounter < CHALLENGES_NEEDED) { - console.log(`GETTING CHALLENGE ${challengeCounter}`) + if (counter < CHALLENGES_NEEDED) { + console.log(`GETTING CHALLENGE ${counter}`) const newChallenge = generateChallenge() - const incrCounter = challengeCounter + 1 - await redis.hSet(challengeKey, { + const incrCounter = counter + 1 + await saveChallenge(redis, { challenge: newChallenge, + challengeKey, counter: incrCounter, }) - res - .status(200) - .send({ - status: "SUCCESS", - challenge: newChallenge, - difficulty: DIFFICULTY, - counter: incrCounter, - }) - return + + return res.status(200).send({ + status: "SUCCESS", + challenge: newChallenge, + counter: incrCounter, + difficulty: DIFFICULTY, + }) } // Here is where you would send the tez to the user's address @@ -189,9 +187,12 @@ app.post("/verify", async (req: Request, res: Response) => { res.status(200).send({ ...b, status: "SUCCESS", message: "Tez sent" }) await redis.del(challengeKey).catch((e) => console.error(e.message)) + return } catch (err: any) { console.error(err.message) - res.status(500).send({ status: "ERROR", message: "An error occurred" }) + return res + .status(500) + .send({ status: "ERROR", message: "An error occurred" }) } }) From be16e79c45199e84d4f769023159ba1f7235d213 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 14 Jul 2023 15:19:56 -0400 Subject: [PATCH 13/64] Track if captcha was used + export redis client --- dist/api.js | 40 ++++++++++++++++++------------- dist/pow.js | 23 ++++++++++-------- src/api.ts | 35 +++++++++++++++------------ src/pow.ts | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 42 deletions(-) create mode 100644 src/pow.ts diff --git a/dist/api.js b/dist/api.js index 89e9cac..adef7a6 100644 --- a/dist/api.js +++ b/dist/api.js @@ -12,6 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); +exports.redis = void 0; const body_parser_1 = __importDefault(require("body-parser")); const dotenv_1 = __importDefault(require("dotenv")); const express_1 = __importDefault(require("express")); @@ -22,10 +23,10 @@ const Tezos_1 = require("./Tezos"); const Types_1 = require("./Types"); const pow_1 = require("./pow"); dotenv_1.default.config(); -const redis = (0, redis_1.createClient)({ +exports.redis = (0, redis_1.createClient)({ // url: "redis://localhost:6379", -}); // reject -redis.on("error", (err) => console.log("Redis Client Error", err)); +}); +exports.redis.on("error", (err) => console.log("Redis Client Error", err)); const app = (0, express_1.default)(); app.use(body_parser_1.default.json()); app.use(body_parser_1.default.urlencoded({ extended: true })); @@ -75,7 +76,8 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } if (!(0, Tezos_1.validateAddress)(res, address)) return; - // if (!(await validateCaptcha(res, captchaToken))) return + if (captchaToken && !(yield (0, Captcha_1.validateCaptcha)(res, captchaToken))) + return; try { (0, Tezos_1.getTezAmountForProfile)(profile); } @@ -84,14 +86,20 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } try { const challengeKey = (0, pow_1.getChallengeKey)(address); - let { challenge, counter } = yield (0, pow_1.getChallenge)(redis, challengeKey); + let { challenge, counter } = yield (0, pow_1.getChallenge)(challengeKey); if (!challenge) { challenge = (0, pow_1.generateChallenge)(); counter = 1; - yield (0, pow_1.saveChallenge)(redis, { challenge, challengeKey, counter }); + yield (0, pow_1.saveChallenge)({ + challenge, + challengeKey, + counter, + // If a captcha was sent it was validated above. + usedCaptcha: !!captchaToken, + }); } console.log({ challenge, difficulty: DIFFICULTY }); - res.status(200).send({ + return res.status(200).send({ status: "SUCCESS", challenge, counter, @@ -105,7 +113,7 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } })); app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { - const { address, captchaToken, solution, nonce } = req.body; + const { address, captchaToken, solution, nonce, profile } = req.body; if (!address || !solution || !nonce) { return res.status(400).send({ status: "ERROR", @@ -114,11 +122,9 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () } if (!(0, Tezos_1.validateAddress)(res, address)) return; - if (!(yield (0, Captcha_1.validateCaptcha)(res, captchaToken))) - return; try { const challengeKey = (0, pow_1.getChallengeKey)(address); - const { challenge, counter } = yield (0, pow_1.getChallenge)(redis, challengeKey); + const { challenge, counter, usedCaptcha } = yield (0, pow_1.getChallenge)(challengeKey); if (!challenge || !counter) { return res .status(400) @@ -142,7 +148,7 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () console.log(`GETTING CHALLENGE ${counter}`); const newChallenge = (0, pow_1.generateChallenge)(); const incrCounter = counter + 1; - yield (0, pow_1.saveChallenge)(redis, { + yield (0, pow_1.saveChallenge)({ challenge: newChallenge, challengeKey, counter: incrCounter, @@ -162,7 +168,7 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () // b.txHash = await send(amount, address) b.txHash = "hash"; res.status(200).send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); - yield redis.del(challengeKey).catch((e) => console.error(e.message)); + yield exports.redis.del(challengeKey).catch((e) => console.error(e.message)); return; } catch (err) { @@ -174,9 +180,9 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () })); const port = process.env.API_PORT || 3000; (() => __awaiter(void 0, void 0, void 0, function* () { - app.listen(port, () => __awaiter(void 0, void 0, void 0, function* () { - console.log(`Start API on port ${port}.`); - })); - yield redis.connect(); + yield exports.redis.connect(); console.log("Connected to redis."); + app.listen(port, () => { + console.log(`Start API on port ${port}.`); + }); }))(); diff --git a/dist/pow.js b/dist/pow.js index 730e2e1..3b4228d 100644 --- a/dist/pow.js +++ b/dist/pow.js @@ -11,22 +11,25 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", { value: true }); exports.verifySolution = exports.getChallenge = exports.saveChallenge = exports.generateChallenge = exports.getChallengeKey = void 0; const crypto_1 = require("crypto"); +const api_1 = require("./api"); const getChallengeKey = (address) => `address:${address}`; exports.getChallengeKey = getChallengeKey; const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); exports.generateChallenge = generateChallenge; -const saveChallenge = (redis, { challenge, challengeKey, counter, expiration = 1800, // 30m - }) => __awaiter(void 0, void 0, void 0, function* () { - yield redis.hSet(challengeKey, { - challenge, - counter, - }); - yield redis.expire(challengeKey, expiration); +const saveChallenge = ({ challenge, challengeKey, counter, expiration = 1800, // 30m +usedCaptcha, }) => __awaiter(void 0, void 0, void 0, function* () { + yield api_1.redis.hSet(challengeKey, Object.assign({ challenge, + counter }, (typeof usedCaptcha === "boolean" && { + usedCaptcha: String(usedCaptcha), + }))); + yield api_1.redis.expire(challengeKey, expiration); }); exports.saveChallenge = saveChallenge; -const getChallenge = (redis, challengeKey) => __awaiter(void 0, void 0, void 0, function* () { - const data = yield redis.hGetAll(challengeKey); - return Object.assign(Object.assign({}, data), (data.counter && { counter: Number(data.counter) })); +const getChallenge = (challengeKey) => __awaiter(void 0, void 0, void 0, function* () { + const data = yield api_1.redis.hGetAll(challengeKey); + if (!Object.keys(data).length) + return {}; + return Object.assign(Object.assign({}, data), { counter: Number(data.counter), usedCaptcha: data.usedCaptcha === "true" }); }); exports.getChallenge = getChallenge; const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); diff --git a/src/api.ts b/src/api.ts index 015a421..320b8ba 100644 --- a/src/api.ts +++ b/src/api.ts @@ -23,9 +23,9 @@ import { dotenv.config() -const redis = createClient({ +export const redis = createClient({ // url: "redis://localhost:6379", -}) // reject +}) redis.on("error", (err: any) => console.log("Redis Client Error", err)) @@ -35,7 +35,7 @@ app.use(bodyParser.urlencoded({ extended: true })) app.use(morgan("dev")) app.use((_, res: Response, next) => { - const cors: string = process.env.AUTHORIZED_HOST || "*" + const cors = process.env.AUTHORIZED_HOST || "*" res.setHeader("Access-Control-Allow-Origin", cors) res.setHeader("Access-Control-Allow-Methods", "GET, POST") res.setHeader( @@ -87,7 +87,7 @@ app.post("/challenge", async (req: Request, res: Response) => { } if (!validateAddress(res, address)) return - // if (!(await validateCaptcha(res, captchaToken))) return + if (captchaToken && !(await validateCaptcha(res, captchaToken))) return try { getTezAmountForProfile(profile) @@ -97,16 +97,22 @@ app.post("/challenge", async (req: Request, res: Response) => { try { const challengeKey = getChallengeKey(address) - let { challenge, counter } = await getChallenge(redis, challengeKey) + let { challenge, counter } = await getChallenge(challengeKey) if (!challenge) { challenge = generateChallenge() counter = 1 - await saveChallenge(redis, { challenge, challengeKey, counter }) + await saveChallenge({ + challenge, + challengeKey, + counter, + // If a captcha was sent it was validated above. + usedCaptcha: !!captchaToken, + }) } console.log({ challenge, difficulty: DIFFICULTY }) - res.status(200).send({ + return res.status(200).send({ status: "SUCCESS", challenge, counter, @@ -120,7 +126,7 @@ app.post("/challenge", async (req: Request, res: Response) => { }) app.post("/verify", async (req: Request, res: Response) => { - const { address, captchaToken, solution, nonce } = req.body + const { address, captchaToken, solution, nonce, profile } = req.body if (!address || !solution || !nonce) { return res.status(400).send({ @@ -130,11 +136,10 @@ app.post("/verify", async (req: Request, res: Response) => { } if (!validateAddress(res, address)) return - if (!(await validateCaptcha(res, captchaToken))) return try { const challengeKey = getChallengeKey(address) - const { challenge, counter } = await getChallenge(redis, challengeKey) + const { challenge, counter, usedCaptcha } = await getChallenge(challengeKey) if (!challenge || !counter) { return res @@ -163,7 +168,7 @@ app.post("/verify", async (req: Request, res: Response) => { console.log(`GETTING CHALLENGE ${counter}`) const newChallenge = generateChallenge() const incrCounter = counter + 1 - await saveChallenge(redis, { + await saveChallenge({ challenge: newChallenge, challengeKey, counter: incrCounter, @@ -199,10 +204,10 @@ app.post("/verify", async (req: Request, res: Response) => { const port: number = process.env.API_PORT || 3000 ;(async () => { - app.listen(port, async () => { - console.log(`Start API on port ${port}.`) - }) - await redis.connect() console.log("Connected to redis.") + + app.listen(port, () => { + console.log(`Start API on port ${port}.`) + }) })() diff --git a/src/pow.ts b/src/pow.ts new file mode 100644 index 0000000..e1df3aa --- /dev/null +++ b/src/pow.ts @@ -0,0 +1,69 @@ +import { createHash, randomBytes } from "crypto" +import { redis } from "./api" + +export const getChallengeKey = (address: string): string => `address:${address}` + +export const generateChallenge = (bytesSize: number = 32) => + randomBytes(bytesSize).toString("hex") + +interface Challenge { + challenge: string + counter: number + usedCaptcha: boolean +} + +type SaveChallengeArgs = Omit & { + challengeKey: string + usedCaptcha?: boolean + expiration?: number +} + +export const saveChallenge = async ({ + challenge, + challengeKey, + counter, + expiration = 1800, // 30m + usedCaptcha, +}: SaveChallengeArgs) => { + await redis.hSet(challengeKey, { + challenge, + counter, + ...(typeof usedCaptcha === "boolean" && { + usedCaptcha: String(usedCaptcha), + }), + }) + await redis.expire(challengeKey, expiration) +} + +export const getChallenge = async ( + challengeKey: string +): Promise> => { + const data = await redis.hGetAll(challengeKey) + + if (!Object.keys(data).length) return {} + + return { + ...data, + counter: Number(data.counter), + usedCaptcha: data.usedCaptcha === "true", + } +} + +const getSolution = (challenge: string, nonce: number) => + createHash("sha256").update(`${challenge}:${nonce}`).digest("hex") + +interface VerifySolutionArgs { + challenge: string + difficulty: number + nonce: number + solution: string +} +export const verifySolution = ({ + challenge, + difficulty, + nonce, + solution, +}: VerifySolutionArgs) => { + const hash = getSolution(challenge, nonce) + return hash === solution && hash.startsWith("0".repeat(difficulty) + "8") +} From 1d4d55a35dfbded6bf1b5f45447efb50f7575c6d Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 14 Jul 2023 15:45:14 -0400 Subject: [PATCH 14/64] Make sure challenge is deleted before Tez is sent --- dist/api.js | 12 +++++++++--- src/api.ts | 15 +++++++++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/dist/api.js b/dist/api.js index adef7a6..707aeaf 100644 --- a/dist/api.js +++ b/dist/api.js @@ -160,6 +160,12 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () difficulty: DIFFICULTY, }); } + // The challenge should be deleted from redis before Tez is sent. If it + // failed to delete, the user could keep getting Tez with the same solution. + yield exports.redis.del(challengeKey).catch((e) => { + console.error(`Redis failed to delete ${challengeKey}.`); + throw e; + }); // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`); @@ -167,9 +173,9 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () const b = {}; // b.txHash = await send(amount, address) b.txHash = "hash"; - res.status(200).send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); - yield exports.redis.del(challengeKey).catch((e) => console.error(e.message)); - return; + return res + .status(200) + .send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); } catch (err) { console.error(err.message); diff --git a/src/api.ts b/src/api.ts index 320b8ba..53f51ad 100644 --- a/src/api.ts +++ b/src/api.ts @@ -182,6 +182,14 @@ app.post("/verify", async (req: Request, res: Response) => { }) } + // The challenge should be deleted from redis before Tez is sent. If it + // failed to delete, the user could keep getting Tez with the same solution. + await redis.del(challengeKey).catch((e) => { + console.error(`Redis failed to delete ${challengeKey}.`) + throw e + }) + + // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`) @@ -189,10 +197,9 @@ app.post("/verify", async (req: Request, res: Response) => { const b: any = {} // b.txHash = await send(amount, address) b.txHash = "hash" - res.status(200).send({ ...b, status: "SUCCESS", message: "Tez sent" }) - - await redis.del(challengeKey).catch((e) => console.error(e.message)) - return + return res + .status(200) + .send({ ...b, status: "SUCCESS", message: "Tez sent" }) } catch (err: any) { console.error(err.message) return res From 9bdb453d5323207d318a6188cee8a0c726a0a870 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Mon, 17 Jul 2023 18:56:50 -0400 Subject: [PATCH 15/64] Start code to determine a challenge's difficulty --- dist/api.js | 44 ++++++++++++++++++++------------------------ dist/pow.js | 23 +++++++++++++++++------ src/api.ts | 51 +++++++++++++++++++++++---------------------------- src/pow.ts | 25 +++++++++++++++++++++---- 4 files changed, 81 insertions(+), 62 deletions(-) diff --git a/dist/api.js b/dist/api.js index 707aeaf..f547394 100644 --- a/dist/api.js +++ b/dist/api.js @@ -25,8 +25,7 @@ const pow_1 = require("./pow"); dotenv_1.default.config(); exports.redis = (0, redis_1.createClient)({ // url: "redis://localhost:6379", -}); -exports.redis.on("error", (err) => console.log("Redis Client Error", err)); +}).on("error", (err) => console.log("Redis Client Error", err)); const app = (0, express_1.default)(); app.use(body_parser_1.default.json()); app.use(body_parser_1.default.urlencoded({ extended: true })); @@ -64,7 +63,6 @@ app.get("/info", (_, res) => { res.status(500).send({ status: "ERROR", message: "An exception occurred" }); } }); -const DIFFICULTY = 4; const CHALLENGES_NEEDED = 4; app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, profile } = req.body; @@ -86,24 +84,26 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } try { const challengeKey = (0, pow_1.getChallengeKey)(address); - let { challenge, counter } = yield (0, pow_1.getChallenge)(challengeKey); + let { challenge, counter, difficulty } = (yield (0, pow_1.getChallenge)(challengeKey)) || {}; if (!challenge) { - challenge = (0, pow_1.generateChallenge)(); + ; + ({ challenge, difficulty } = (0, pow_1.createChallenge)()); counter = 1; yield (0, pow_1.saveChallenge)({ challenge, challengeKey, counter, + difficulty, // If a captcha was sent it was validated above. usedCaptcha: !!captchaToken, }); } - console.log({ challenge, difficulty: DIFFICULTY }); + console.log({ challenge, difficulty }); return res.status(200).send({ status: "SUCCESS", challenge, counter, - difficulty: DIFFICULTY, + difficulty, }); } catch (err) { @@ -113,7 +113,7 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } })); app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { - const { address, captchaToken, solution, nonce, profile } = req.body; + const { address, solution, nonce, profile } = req.body; if (!address || !solution || !nonce) { return res.status(400).send({ status: "ERROR", @@ -124,17 +124,18 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () return; try { const challengeKey = (0, pow_1.getChallengeKey)(address); - const { challenge, counter, usedCaptcha } = yield (0, pow_1.getChallenge)(challengeKey); - if (!challenge || !counter) { + const redisChallenge = yield (0, pow_1.getChallenge)(challengeKey); + if (!redisChallenge) { return res .status(400) .send({ status: "ERROR", message: "No challenge found" }); } + const { challenge, counter, difficulty, usedCaptcha } = redisChallenge; // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) const isValidSolution = (0, pow_1.verifySolution)({ challenge, - difficulty: DIFFICULTY, + difficulty, nonce, solution, }); @@ -146,19 +147,14 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () } if (counter < CHALLENGES_NEEDED) { console.log(`GETTING CHALLENGE ${counter}`); - const newChallenge = (0, pow_1.generateChallenge)(); - const incrCounter = counter + 1; - yield (0, pow_1.saveChallenge)({ - challenge: newChallenge, - challengeKey, - counter: incrCounter, - }); - return res.status(200).send({ - status: "SUCCESS", - challenge: newChallenge, - counter: incrCounter, - difficulty: DIFFICULTY, - }); + const newChallenge = (0, pow_1.createChallenge)(); + const state = { + challenge: newChallenge.challenge, + counter: counter + 1, + difficulty: newChallenge.difficulty, + }; + yield (0, pow_1.saveChallenge)(Object.assign({ challengeKey }, state)); + return res.status(200).send(Object.assign({ status: "SUCCESS" }, state)); } // The challenge should be deleted from redis before Tez is sent. If it // failed to delete, the user could keep getting Tez with the same solution. diff --git a/dist/pow.js b/dist/pow.js index 3b4228d..ad89583 100644 --- a/dist/pow.js +++ b/dist/pow.js @@ -9,17 +9,28 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.verifySolution = exports.getChallenge = exports.saveChallenge = exports.generateChallenge = exports.getChallengeKey = void 0; +exports.verifySolution = exports.getChallenge = exports.saveChallenge = exports.createChallenge = exports.getChallengeKey = void 0; const crypto_1 = require("crypto"); const api_1 = require("./api"); const getChallengeKey = (address) => `address:${address}`; exports.getChallengeKey = getChallengeKey; +const determineDifficulty = () => { + const challengeSize = 32; + const difficulty = 4; + return { challengeSize, difficulty }; +}; const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); -exports.generateChallenge = generateChallenge; -const saveChallenge = ({ challenge, challengeKey, counter, expiration = 1800, // 30m +const createChallenge = () => { + const { challengeSize, difficulty } = determineDifficulty(); + const challenge = generateChallenge(challengeSize); + return { challenge, difficulty }; +}; +exports.createChallenge = createChallenge; +const saveChallenge = ({ challenge, challengeKey, counter, difficulty, expiration = 1800, // 30m usedCaptcha, }) => __awaiter(void 0, void 0, void 0, function* () { yield api_1.redis.hSet(challengeKey, Object.assign({ challenge, - counter }, (typeof usedCaptcha === "boolean" && { + counter, + difficulty }, (typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }))); yield api_1.redis.expire(challengeKey, expiration); @@ -28,8 +39,8 @@ exports.saveChallenge = saveChallenge; const getChallenge = (challengeKey) => __awaiter(void 0, void 0, void 0, function* () { const data = yield api_1.redis.hGetAll(challengeKey); if (!Object.keys(data).length) - return {}; - return Object.assign(Object.assign({}, data), { counter: Number(data.counter), usedCaptcha: data.usedCaptcha === "true" }); + return null; + return Object.assign(Object.assign({}, data), { counter: Number(data.counter), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true" }); }); exports.getChallenge = getChallenge; const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); diff --git a/src/api.ts b/src/api.ts index 53f51ad..9de5cb6 100644 --- a/src/api.ts +++ b/src/api.ts @@ -14,7 +14,7 @@ import { } from "./Tezos" import { InfoResponseBody, Profile, RequestBody, ResponseBody } from "./Types" import { - generateChallenge, + createChallenge, getChallengeKey, saveChallenge, getChallenge, @@ -25,9 +25,7 @@ dotenv.config() export const redis = createClient({ // url: "redis://localhost:6379", -}) - -redis.on("error", (err: any) => console.log("Redis Client Error", err)) +}).on("error", (err: any) => console.log("Redis Client Error", err)) const app: Express = express() app.use(bodyParser.json()) @@ -73,7 +71,6 @@ app.get("/info", (_, res: Response) => { } }) -const DIFFICULTY = 4 const CHALLENGES_NEEDED = 4 app.post("/challenge", async (req: Request, res: Response) => { @@ -97,26 +94,29 @@ app.post("/challenge", async (req: Request, res: Response) => { try { const challengeKey = getChallengeKey(address) - let { challenge, counter } = await getChallenge(challengeKey) + let { challenge, counter, difficulty } = + (await getChallenge(challengeKey)) || {} if (!challenge) { - challenge = generateChallenge() + ;({ challenge, difficulty } = createChallenge()) counter = 1 await saveChallenge({ challenge, challengeKey, counter, + difficulty, // If a captcha was sent it was validated above. usedCaptcha: !!captchaToken, }) } - console.log({ challenge, difficulty: DIFFICULTY }) + console.log({ challenge, difficulty }) + return res.status(200).send({ status: "SUCCESS", challenge, counter, - difficulty: DIFFICULTY, + difficulty, }) } catch (err: any) { const message = "Error getting challenge" @@ -126,7 +126,7 @@ app.post("/challenge", async (req: Request, res: Response) => { }) app.post("/verify", async (req: Request, res: Response) => { - const { address, captchaToken, solution, nonce, profile } = req.body + const { address, solution, nonce, profile } = req.body if (!address || !solution || !nonce) { return res.status(400).send({ @@ -139,19 +139,19 @@ app.post("/verify", async (req: Request, res: Response) => { try { const challengeKey = getChallengeKey(address) - const { challenge, counter, usedCaptcha } = await getChallenge(challengeKey) - - if (!challenge || !counter) { + const redisChallenge = await getChallenge(challengeKey) + if (!redisChallenge) { return res .status(400) .send({ status: "ERROR", message: "No challenge found" }) } + const { challenge, counter, difficulty, usedCaptcha } = redisChallenge // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty) const isValidSolution = verifySolution({ challenge, - difficulty: DIFFICULTY, + difficulty, nonce, solution, }) @@ -166,20 +166,15 @@ app.post("/verify", async (req: Request, res: Response) => { if (counter < CHALLENGES_NEEDED) { console.log(`GETTING CHALLENGE ${counter}`) - const newChallenge = generateChallenge() - const incrCounter = counter + 1 - await saveChallenge({ - challenge: newChallenge, - challengeKey, - counter: incrCounter, - }) - - return res.status(200).send({ - status: "SUCCESS", - challenge: newChallenge, - counter: incrCounter, - difficulty: DIFFICULTY, - }) + const newChallenge = createChallenge() + const state = { + challenge: newChallenge.challenge, + counter: counter + 1, + difficulty: newChallenge.difficulty, + } + + await saveChallenge({ challengeKey, ...state }) + return res.status(200).send({ status: "SUCCESS", ...state }) } // The challenge should be deleted from redis before Tez is sent. If it diff --git a/src/pow.ts b/src/pow.ts index e1df3aa..bedccf1 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -3,12 +3,26 @@ import { redis } from "./api" export const getChallengeKey = (address: string): string => `address:${address}` -export const generateChallenge = (bytesSize: number = 32) => + +const determineDifficulty = () => { + const challengeSize = 32 + const difficulty = 4 + return { challengeSize, difficulty } +} + +const generateChallenge = (bytesSize: number = 32) => randomBytes(bytesSize).toString("hex") +export const createChallenge = () => { + const { challengeSize, difficulty } = determineDifficulty() + const challenge = generateChallenge(challengeSize) + return { challenge, difficulty } +} + interface Challenge { challenge: string counter: number + difficulty: number usedCaptcha: boolean } @@ -22,12 +36,14 @@ export const saveChallenge = async ({ challenge, challengeKey, counter, + difficulty, expiration = 1800, // 30m usedCaptcha, }: SaveChallengeArgs) => { await redis.hSet(challengeKey, { challenge, counter, + difficulty, ...(typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }), @@ -37,16 +53,17 @@ export const saveChallenge = async ({ export const getChallenge = async ( challengeKey: string -): Promise> => { +): Promise => { const data = await redis.hGetAll(challengeKey) - if (!Object.keys(data).length) return {} + if (!Object.keys(data).length) return null return { ...data, counter: Number(data.counter), + difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", - } + } as Challenge } const getSolution = (challenge: string, nonce: number) => From 81af5541937afd4a86088f78468e0a9c29942e6c Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 18 Jul 2023 15:01:16 -0400 Subject: [PATCH 16/64] WIP challenges needed logic --- dist/api.js | 31 ++++++++++++++----------------- dist/pow.js | 32 ++++++++++++++++++++++++-------- src/api.ts | 37 +++++++++++++++++++------------------ src/pow.ts | 36 +++++++++++++++++++++--------------- 4 files changed, 78 insertions(+), 58 deletions(-) diff --git a/dist/api.js b/dist/api.js index f547394..c2c130b 100644 --- a/dist/api.js +++ b/dist/api.js @@ -63,7 +63,6 @@ app.get("/info", (_, res) => { res.status(500).send({ status: "ERROR", message: "An exception occurred" }); } }); -const CHALLENGES_NEEDED = 4; app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { const { address, captchaToken, profile } = req.body; if (!address || !profile) { @@ -84,18 +83,19 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } try { const challengeKey = (0, pow_1.getChallengeKey)(address); - let { challenge, counter, difficulty } = (yield (0, pow_1.getChallenge)(challengeKey)) || {}; + let { challenge, challengesNeeded, counter, difficulty } = (yield (0, pow_1.getChallenge)(challengeKey)) || {}; if (!challenge) { - ; - ({ challenge, difficulty } = (0, pow_1.createChallenge)()); + // If a captcha was sent it was validated above. + const usedCaptcha = !!captchaToken; + ({ challenge, challengesNeeded, difficulty } = + (0, pow_1.createChallenge)(usedCaptcha)); counter = 1; - yield (0, pow_1.saveChallenge)({ + yield (0, pow_1.saveChallenge)(challengeKey, { challenge, - challengeKey, + challengesNeeded, counter, difficulty, - // If a captcha was sent it was validated above. - usedCaptcha: !!captchaToken, + usedCaptcha, }); } console.log({ challenge, difficulty }); @@ -130,9 +130,7 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () .status(400) .send({ status: "ERROR", message: "No challenge found" }); } - const { challenge, counter, difficulty, usedCaptcha } = redisChallenge; - // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce - // starts with a certain number of zeroes (the difficulty) + const { challenge, challengesNeeded, counter, difficulty, usedCaptcha } = redisChallenge; const isValidSolution = (0, pow_1.verifySolution)({ challenge, difficulty, @@ -145,16 +143,15 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () .status(400) .send({ status: "ERROR", message: "Incorrect solution" }); } - if (counter < CHALLENGES_NEEDED) { - console.log(`GETTING CHALLENGE ${counter}`); - const newChallenge = (0, pow_1.createChallenge)(); - const state = { + if (counter < challengesNeeded) { + const newChallenge = (0, pow_1.createChallenge)(usedCaptcha); + const resData = { challenge: newChallenge.challenge, counter: counter + 1, difficulty: newChallenge.difficulty, }; - yield (0, pow_1.saveChallenge)(Object.assign({ challengeKey }, state)); - return res.status(200).send(Object.assign({ status: "SUCCESS" }, state)); + yield (0, pow_1.saveChallenge)(challengeKey, Object.assign({ challengesNeeded: newChallenge.challengesNeeded }, resData)); + return res.status(200).send(Object.assign({ status: "SUCCESS" }, resData)); } // The challenge should be deleted from redis before Tez is sent. If it // failed to delete, the user could keep getting Tez with the same solution. diff --git a/dist/pow.js b/dist/pow.js index ad89583..1d0b12e 100644 --- a/dist/pow.js +++ b/dist/pow.js @@ -8,29 +8,43 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; Object.defineProperty(exports, "__esModule", { value: true }); exports.verifySolution = exports.getChallenge = exports.saveChallenge = exports.createChallenge = exports.getChallengeKey = void 0; const crypto_1 = require("crypto"); const api_1 = require("./api"); const getChallengeKey = (address) => `address:${address}`; exports.getChallengeKey = getChallengeKey; +// TODO: Implement const determineDifficulty = () => { const challengeSize = 32; const difficulty = 4; return { challengeSize, difficulty }; }; +// TODO: Implement +const determineChallengesNeeded = (usedCaptcha) => usedCaptcha ? 2 : 4; const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); -const createChallenge = () => { +const createChallenge = (usedCaptcha) => { const { challengeSize, difficulty } = determineDifficulty(); + const challengesNeeded = determineChallengesNeeded(usedCaptcha); const challenge = generateChallenge(challengeSize); - return { challenge, difficulty }; + return { challenge, challengesNeeded, difficulty }; }; exports.createChallenge = createChallenge; -const saveChallenge = ({ challenge, challengeKey, counter, difficulty, expiration = 1800, // 30m -usedCaptcha, }) => __awaiter(void 0, void 0, void 0, function* () { - yield api_1.redis.hSet(challengeKey, Object.assign({ challenge, - counter, - difficulty }, (typeof usedCaptcha === "boolean" && { +const saveChallenge = (challengeKey, _a) => __awaiter(void 0, void 0, void 0, function* () { + var { usedCaptcha, expiration = 1800 } = _a, // 30m + args = __rest(_a, ["usedCaptcha", "expiration"]); + yield api_1.redis.hSet(challengeKey, Object.assign(Object.assign({}, args), (typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }))); yield api_1.redis.expire(challengeKey, expiration); @@ -40,12 +54,14 @@ const getChallenge = (challengeKey) => __awaiter(void 0, void 0, void 0, functio const data = yield api_1.redis.hGetAll(challengeKey); if (!Object.keys(data).length) return null; - return Object.assign(Object.assign({}, data), { counter: Number(data.counter), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true" }); + return Object.assign(Object.assign({}, data), { challengesNeeded: Number(data.challengesNeeded), counter: Number(data.counter), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true" }); }); exports.getChallenge = getChallenge; const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); const verifySolution = ({ challenge, difficulty, nonce, solution, }) => { const hash = getSolution(challenge, nonce); + // Validate the SHA-256 hash of the challenge concatenated with the nonce + // starts with a certain number of zeroes (the difficulty). return hash === solution && hash.startsWith("0".repeat(difficulty) + "8"); }; exports.verifySolution = verifySolution; diff --git a/src/api.ts b/src/api.ts index 9de5cb6..79fe180 100644 --- a/src/api.ts +++ b/src/api.ts @@ -71,8 +71,6 @@ app.get("/info", (_, res: Response) => { } }) -const CHALLENGES_NEEDED = 4 - app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body @@ -94,19 +92,21 @@ app.post("/challenge", async (req: Request, res: Response) => { try { const challengeKey = getChallengeKey(address) - let { challenge, counter, difficulty } = + let { challenge, challengesNeeded, counter, difficulty } = (await getChallenge(challengeKey)) || {} if (!challenge) { - ;({ challenge, difficulty } = createChallenge()) + // If a captcha was sent it was validated above. + const usedCaptcha = !!captchaToken + ;({ challenge, challengesNeeded, difficulty } = + createChallenge(usedCaptcha)) counter = 1 - await saveChallenge({ + await saveChallenge(challengeKey, { challenge, - challengeKey, + challengesNeeded, counter, difficulty, - // If a captcha was sent it was validated above. - usedCaptcha: !!captchaToken, + usedCaptcha, }) } @@ -146,9 +146,9 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "No challenge found" }) } - const { challenge, counter, difficulty, usedCaptcha } = redisChallenge - // Validate the solution by checking that the SHA-256 hash of the challenge concatenated with the nonce - // starts with a certain number of zeroes (the difficulty) + const { challenge, challengesNeeded, counter, difficulty, usedCaptcha } = + redisChallenge + const isValidSolution = verifySolution({ challenge, difficulty, @@ -164,17 +164,19 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "Incorrect solution" }) } - if (counter < CHALLENGES_NEEDED) { - console.log(`GETTING CHALLENGE ${counter}`) - const newChallenge = createChallenge() - const state = { + if (counter < challengesNeeded) { + const newChallenge = createChallenge(usedCaptcha) + const resData = { challenge: newChallenge.challenge, counter: counter + 1, difficulty: newChallenge.difficulty, } - await saveChallenge({ challengeKey, ...state }) - return res.status(200).send({ status: "SUCCESS", ...state }) + await saveChallenge(challengeKey, { + challengesNeeded: newChallenge.challengesNeeded, + ...resData, + }) + return res.status(200).send({ status: "SUCCESS", ...resData }) } // The challenge should be deleted from redis before Tez is sent. If it @@ -184,7 +186,6 @@ app.post("/verify", async (req: Request, res: Response) => { throw e }) - // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address console.log(`Send tez to ${address}`) diff --git a/src/pow.ts b/src/pow.ts index bedccf1..8617ee3 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -3,47 +3,50 @@ import { redis } from "./api" export const getChallengeKey = (address: string): string => `address:${address}` - +// TODO: Implement const determineDifficulty = () => { const challengeSize = 32 const difficulty = 4 return { challengeSize, difficulty } } +// TODO: Implement +const determineChallengesNeeded = (usedCaptcha: boolean) => + usedCaptcha ? 2 : 4 + const generateChallenge = (bytesSize: number = 32) => randomBytes(bytesSize).toString("hex") -export const createChallenge = () => { +export const createChallenge = (usedCaptcha: boolean) => { const { challengeSize, difficulty } = determineDifficulty() + const challengesNeeded = determineChallengesNeeded(usedCaptcha) const challenge = generateChallenge(challengeSize) - return { challenge, difficulty } + return { challenge, challengesNeeded, difficulty } } interface Challenge { challenge: string + challengesNeeded: number counter: number difficulty: number usedCaptcha: boolean } type SaveChallengeArgs = Omit & { - challengeKey: string usedCaptcha?: boolean expiration?: number } -export const saveChallenge = async ({ - challenge, - challengeKey, - counter, - difficulty, - expiration = 1800, // 30m - usedCaptcha, -}: SaveChallengeArgs) => { +export const saveChallenge = async ( + challengeKey: string, + { + usedCaptcha, + expiration = 1800, // 30m + ...args + }: SaveChallengeArgs + ) => { await redis.hSet(challengeKey, { - challenge, - counter, - difficulty, + ...args, ...(typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }), @@ -60,6 +63,7 @@ export const getChallenge = async ( return { ...data, + challengesNeeded: Number(data.challengesNeeded), counter: Number(data.counter), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", @@ -82,5 +86,7 @@ export const verifySolution = ({ solution, }: VerifySolutionArgs) => { const hash = getSolution(challenge, nonce) + // Validate the SHA-256 hash of the challenge concatenated with the nonce + // starts with a certain number of zeroes (the difficulty). return hash === solution && hash.startsWith("0".repeat(difficulty) + "8") } From 228a893c8bdf96dda4a0843c9b9ce35aad715c07 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 18 Jul 2023 15:03:14 -0400 Subject: [PATCH 17/64] Only check 0's in solution --- dist/pow.js | 2 +- src/pow.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/pow.js b/dist/pow.js index 1d0b12e..04b8ee9 100644 --- a/dist/pow.js +++ b/dist/pow.js @@ -62,6 +62,6 @@ const verifySolution = ({ challenge, difficulty, nonce, solution, }) => { const hash = getSolution(challenge, nonce); // Validate the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty). - return hash === solution && hash.startsWith("0".repeat(difficulty) + "8"); + return hash === solution && hash.startsWith("0".repeat(difficulty)); }; exports.verifySolution = verifySolution; diff --git a/src/pow.ts b/src/pow.ts index 8617ee3..6d21423 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -88,5 +88,5 @@ export const verifySolution = ({ const hash = getSolution(challenge, nonce) // Validate the SHA-256 hash of the challenge concatenated with the nonce // starts with a certain number of zeroes (the difficulty). - return hash === solution && hash.startsWith("0".repeat(difficulty) + "8") + return hash === solution && hash.startsWith("0".repeat(difficulty)) } From 12c5030776c1e3a341032d1cc0a6938c61c238e3 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 18 Jul 2023 15:38:45 -0400 Subject: [PATCH 18/64] Rename values and modify difficulties --- dist/api.js | 16 ++++++++-------- dist/pow.js | 10 +++++----- src/api.ts | 16 ++++++++-------- src/pow.ts | 22 +++++++++++----------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/dist/api.js b/dist/api.js index c2c130b..6368bab 100644 --- a/dist/api.js +++ b/dist/api.js @@ -83,17 +83,17 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* } try { const challengeKey = (0, pow_1.getChallengeKey)(address); - let { challenge, challengesNeeded, counter, difficulty } = (yield (0, pow_1.getChallenge)(challengeKey)) || {}; + let { challenge, challengesNeeded, challengeCounter, difficulty } = (yield (0, pow_1.getChallenge)(challengeKey)) || {}; if (!challenge) { // If a captcha was sent it was validated above. const usedCaptcha = !!captchaToken; ({ challenge, challengesNeeded, difficulty } = (0, pow_1.createChallenge)(usedCaptcha)); - counter = 1; + challengeCounter = 1; yield (0, pow_1.saveChallenge)(challengeKey, { challenge, challengesNeeded, - counter, + challengeCounter, difficulty, usedCaptcha, }); @@ -102,7 +102,7 @@ app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* return res.status(200).send({ status: "SUCCESS", challenge, - counter, + challengeCounter, difficulty, }); } @@ -130,24 +130,24 @@ app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () .status(400) .send({ status: "ERROR", message: "No challenge found" }); } - const { challenge, challengesNeeded, counter, difficulty, usedCaptcha } = redisChallenge; + const { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha } = redisChallenge; const isValidSolution = (0, pow_1.verifySolution)({ challenge, difficulty, nonce, solution, }); - console.log({ address, solution, nonce, counter }); + console.log({ address, solution, nonce, challengeCounter }); if (!isValidSolution) { return res .status(400) .send({ status: "ERROR", message: "Incorrect solution" }); } - if (counter < challengesNeeded) { + if (challengeCounter < challengesNeeded) { const newChallenge = (0, pow_1.createChallenge)(usedCaptcha); const resData = { challenge: newChallenge.challenge, - counter: counter + 1, + challengeCounter: challengeCounter + 1, difficulty: newChallenge.difficulty, }; yield (0, pow_1.saveChallenge)(challengeKey, Object.assign({ challengesNeeded: newChallenge.challengesNeeded }, resData)); diff --git a/dist/pow.js b/dist/pow.js index 04b8ee9..c9cb2d5 100644 --- a/dist/pow.js +++ b/dist/pow.js @@ -26,17 +26,17 @@ const api_1 = require("./api"); const getChallengeKey = (address) => `address:${address}`; exports.getChallengeKey = getChallengeKey; // TODO: Implement -const determineDifficulty = () => { +const determineDifficulty = (usedCaptcha) => { const challengeSize = 32; - const difficulty = 4; + const difficulty = usedCaptcha ? 4 : 5; return { challengeSize, difficulty }; }; // TODO: Implement -const determineChallengesNeeded = (usedCaptcha) => usedCaptcha ? 2 : 4; +const determineChallengesNeeded = (usedCaptcha) => usedCaptcha ? 5 : 6; const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); const createChallenge = (usedCaptcha) => { - const { challengeSize, difficulty } = determineDifficulty(); const challengesNeeded = determineChallengesNeeded(usedCaptcha); + const { challengeSize, difficulty } = determineDifficulty(usedCaptcha); const challenge = generateChallenge(challengeSize); return { challenge, challengesNeeded, difficulty }; }; @@ -54,7 +54,7 @@ const getChallenge = (challengeKey) => __awaiter(void 0, void 0, void 0, functio const data = yield api_1.redis.hGetAll(challengeKey); if (!Object.keys(data).length) return null; - return Object.assign(Object.assign({}, data), { challengesNeeded: Number(data.challengesNeeded), counter: Number(data.counter), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true" }); + return Object.assign(Object.assign({}, data), { challengeCounter: Number(data.challengeCounter), challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true" }); }); exports.getChallenge = getChallenge; const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); diff --git a/src/api.ts b/src/api.ts index 79fe180..292a054 100644 --- a/src/api.ts +++ b/src/api.ts @@ -92,7 +92,7 @@ app.post("/challenge", async (req: Request, res: Response) => { try { const challengeKey = getChallengeKey(address) - let { challenge, challengesNeeded, counter, difficulty } = + let { challenge, challengesNeeded, challengeCounter, difficulty } = (await getChallenge(challengeKey)) || {} if (!challenge) { @@ -100,11 +100,11 @@ app.post("/challenge", async (req: Request, res: Response) => { const usedCaptcha = !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) - counter = 1 + challengeCounter = 1 await saveChallenge(challengeKey, { challenge, challengesNeeded, - counter, + challengeCounter, difficulty, usedCaptcha, }) @@ -115,7 +115,7 @@ app.post("/challenge", async (req: Request, res: Response) => { return res.status(200).send({ status: "SUCCESS", challenge, - counter, + challengeCounter, difficulty, }) } catch (err: any) { @@ -146,7 +146,7 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "No challenge found" }) } - const { challenge, challengesNeeded, counter, difficulty, usedCaptcha } = + const { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha } = redisChallenge const isValidSolution = verifySolution({ @@ -156,7 +156,7 @@ app.post("/verify", async (req: Request, res: Response) => { solution, }) - console.log({ address, solution, nonce, counter }) + console.log({ address, solution, nonce, challengeCounter }) if (!isValidSolution) { return res @@ -164,11 +164,11 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "Incorrect solution" }) } - if (counter < challengesNeeded) { + if (challengeCounter < challengesNeeded) { const newChallenge = createChallenge(usedCaptcha) const resData = { challenge: newChallenge.challenge, - counter: counter + 1, + challengeCounter: challengeCounter + 1, difficulty: newChallenge.difficulty, } diff --git a/src/pow.ts b/src/pow.ts index 6d21423..2a8ba47 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -4,35 +4,35 @@ import { redis } from "./api" export const getChallengeKey = (address: string): string => `address:${address}` // TODO: Implement -const determineDifficulty = () => { +const determineDifficulty = (usedCaptcha: boolean) => { const challengeSize = 32 - const difficulty = 4 + const difficulty = usedCaptcha ? 4 : 5 return { challengeSize, difficulty } } // TODO: Implement const determineChallengesNeeded = (usedCaptcha: boolean) => - usedCaptcha ? 2 : 4 + usedCaptcha ? 5 : 6 const generateChallenge = (bytesSize: number = 32) => randomBytes(bytesSize).toString("hex") export const createChallenge = (usedCaptcha: boolean) => { - const { challengeSize, difficulty } = determineDifficulty() const challengesNeeded = determineChallengesNeeded(usedCaptcha) + const { challengeSize, difficulty } = determineDifficulty(usedCaptcha) const challenge = generateChallenge(challengeSize) return { challenge, challengesNeeded, difficulty } } -interface Challenge { +interface ChallengeState { challenge: string + challengeCounter: number challengesNeeded: number - counter: number difficulty: number usedCaptcha: boolean } -type SaveChallengeArgs = Omit & { +type SaveChallengeArgs = Omit & { usedCaptcha?: boolean expiration?: number } @@ -44,7 +44,7 @@ export const saveChallenge = async ( expiration = 1800, // 30m ...args }: SaveChallengeArgs - ) => { +) => { await redis.hSet(challengeKey, { ...args, ...(typeof usedCaptcha === "boolean" && { @@ -56,18 +56,18 @@ export const saveChallenge = async ( export const getChallenge = async ( challengeKey: string -): Promise => { +): Promise => { const data = await redis.hGetAll(challengeKey) if (!Object.keys(data).length) return null return { ...data, + challengeCounter: Number(data.challengeCounter), challengesNeeded: Number(data.challengesNeeded), - counter: Number(data.counter), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", - } as Challenge + } as ChallengeState } const getSolution = (challenge: string, nonce: number) => From e6dce985b0a5512ed4d4f9a98bb18a3927f443d5 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 25 Jul 2023 19:59:39 -0400 Subject: [PATCH 19/64] Fix google DNS not resolving when running in k8s --- src/Captcha.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Captcha.ts b/src/Captcha.ts index 64f554e..c31e2c7 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -15,7 +15,7 @@ const checkCaptcha = async (responseToken: string) => { const secret = process.env.FAUCET_CAPTCHA_SECRET - const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}` + const captchaURL = `https://google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}` const res = await axios.post(captchaURL) return res.data From 4e0130606d02f15304d5a98bcd2520f4f7acb262 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 28 Jul 2023 17:16:58 -0400 Subject: [PATCH 20/64] Cleanup packages --- package-lock.json | 2048 ++++++++------------------------------------- package.json | 20 +- 2 files changed, 360 insertions(+), 1708 deletions(-) diff --git a/package-lock.json b/package-lock.json index df52948..8a0154b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "tezos-testnet-faucet-backend", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,34 +9,21 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@netlify/functions": "^1.0.0", - "@taquito/signer": "^12.1.1", - "@taquito/taquito": "^12.1.1", + "@taquito/signer": "^17.1.0", + "@taquito/taquito": "^17.1.0", "axios": "^1.4.0", - "body-parser": "^1.20.0", - "dotenv": "^16.0.1", - "express": "^4.18.1", + "body-parser": "^1.20.2", + "dotenv": "^16.3.1", + "express": "^4.18.2", "morgan": "^1.10.0", "redis": "^4.6.7" }, "devDependencies": { - "@types/cors": "^2.8.12", - "@types/express": "^4.17.13", + "@types/express": "^4.17.17", "@types/morgan": "^1.9.4", - "@types/node": "^17.0.36", - "nodemon": "^2.0.16", - "typescript": "^4.7.2" - } - }, - "node_modules/@netlify/functions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-1.0.0.tgz", - "integrity": "sha512-7fnJv3vr8uyyyOYPChwoec6MjzsCw1CoRUO2DhQ1BD6bOyJRlD4DUaOOGlMILB2LCT8P24p5LexEGx8AJb7xdA==", - "dependencies": { - "is-promise": "^4.0.0" - }, - "engines": { - "node": ">=8.3.0" + "@types/node": "^20.4.5", + "nodemon": "^3.0.1", + "typescript": "^5.1.6" } }, "node_modules/@redis/bloom": { @@ -121,11 +108,11 @@ "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" }, "node_modules/@stablelib/ed25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.2.tgz", - "integrity": "sha512-FtnvUwvKbp6l1dNcg4CswMAVFVu/nzLK3oC7/PRtjYyHbWsIkD8j+5cjXHmwcCpdCpRCaTGACkEhhMQ1RcdSOQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.3.tgz", + "integrity": "sha512-puIMWaX9QlRsbhxfDc5i+mNPMY+0TmQEskunY1rZEBPi1acBCVQAhnsk/1Hk50DGPtVsZtAWQg4NHGlVaO9Hqg==", "dependencies": { - "@stablelib/random": "^1.0.1", + "@stablelib/random": "^1.0.2", "@stablelib/sha512": "^1.0.1", "@stablelib/wipe": "^1.0.1" } @@ -135,6 +122,16 @@ "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" }, + "node_modules/@stablelib/hmac": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, "node_modules/@stablelib/int": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", @@ -149,17 +146,28 @@ } }, "node_modules/@stablelib/nacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.3.tgz", - "integrity": "sha512-ZdDGRo4s6ke2rdhwwna5SAikU48AQRNqPPbJ29ZSC781SMUMPpkixKpyZG+NfYhMkFSJ0ZRlFdKW+/ksmpVHWA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.4.tgz", + "integrity": "sha512-PJ2U/MrkXSKUM8C4qFs87WeCNxri7KQwR8Cdwm9q2sweGuAtTvOJGuW0F3N+zn+ySLPJA98SYWSSpogMJ1gCmw==", "dependencies": { "@stablelib/poly1305": "^1.0.1", - "@stablelib/random": "^1.0.1", + "@stablelib/random": "^1.0.2", "@stablelib/wipe": "^1.0.1", - "@stablelib/x25519": "^1.0.2", + "@stablelib/x25519": "^1.0.3", "@stablelib/xsalsa20": "^1.0.2" } }, + "node_modules/@stablelib/pbkdf2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/pbkdf2/-/pbkdf2-1.0.1.tgz", + "integrity": "sha512-d5jwK6jW1DkMyzqY8D1Io+fRXcsUVr95lk5LKX9ghaUdAITTc1ZL0bff+R0IrwSixbHluxhnivG7vDw59AZ/Nw==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/hmac": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, "node_modules/@stablelib/poly1305": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", @@ -170,9 +178,9 @@ } }, "node_modules/@stablelib/random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.1.tgz", - "integrity": "sha512-zOh+JHX3XG9MSfIB0LZl/YwPP9w3o6WBiJkZvjPoKKu5LKFW4OLV71vMxWp9qG5T43NaWyn0QQTWgqCdO+yOBQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", "dependencies": { "@stablelib/binary": "^1.0.1", "@stablelib/wipe": "^1.0.1" @@ -204,12 +212,12 @@ "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" }, "node_modules/@stablelib/x25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.2.tgz", - "integrity": "sha512-wTR0t0Bp1HABLFRbYaE3vFLuco2QbAg6QvxBnzi5j9qjhYezWHW7OiCZyaWbt25UkSaoolUUT4Il0nS/2vcbSw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", "dependencies": { "@stablelib/keyagreement": "^1.0.1", - "@stablelib/random": "^1.0.1", + "@stablelib/random": "^1.0.2", "@stablelib/wipe": "^1.0.1" } }, @@ -223,164 +231,156 @@ "@stablelib/wipe": "^1.0.1" } }, + "node_modules/@taquito/core": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-17.1.0.tgz", + "integrity": "sha512-tfdgC7/Q5U9lN3UzvuJYf8Z7iBWyOtqILRuWRGFM6VtSXwNwcNK62f8FNKAgyHahFkVA4vVdD9zrt8NbM/TB2g==", + "engines": { + "node": ">=16" + } + }, "node_modules/@taquito/http-utils": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-12.1.1.tgz", - "integrity": "sha512-Zlp/eTRVjFs0XEIiAhgxkh6s9npF4dO+e/Sm2XWsDmNPoGI2jdXNH0L+NiKJIOkYcu0CXlcgriTeEaYnbeTvcA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-17.1.0.tgz", + "integrity": "sha512-vkArbB7h9jMAf6apOERBoUYi/ARiBF5xuJunsPf/hECXz0kjaKGI7dKC6PsWJrvhfR/cACXKu4CAKG41WDNprw==", "dependencies": { - "axios": "^0.26.0" + "@taquito/core": "^17.1.0", + "axios": "0.26.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, "node_modules/@taquito/http-utils/node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.0.tgz", + "integrity": "sha512-lKoGLMYtHvFrPVt3r+RBMp9nh34N0M8zEfCWqdWZx6phynIEhQqAdydpyBAAG211zlhX9Rgu08cOamy6XjE5Og==", "dependencies": { "follow-redirects": "^1.14.8" } }, "node_modules/@taquito/local-forging": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-12.1.1.tgz", - "integrity": "sha512-SUA1YYRIpEGsTy5OfUIgIem0k/QsAzGjDCvf/wl5XV/fVBkP/+GN7uvYoqgJblCmsgtsMBhJFtXgs+D6bjGexg==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-17.1.0.tgz", + "integrity": "sha512-vKjjMDoVxgxbjYFhREaNtuI0OT6Jnty6+x+Tfzuk7alLf8zwDBvDXyXz+47WgFZb4Y3RtojRlnpIP4EhbtLnJQ==", "dependencies": { - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2" + "@taquito/core": "^17.1.0", + "@taquito/utils": "^17.1.0", + "bignumber.js": "^9.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, "node_modules/@taquito/michel-codec": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-12.1.1.tgz", - "integrity": "sha512-BAig8YyLyRW5kxV/r0S191W+SvYuiTRJpgSp5IsgCDLAOh+d4/xq6IgU3PuGJgokQDstZdTbjpkrgRCnufR8lw==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-17.1.0.tgz", + "integrity": "sha512-PjXySJonM77a6uoEOJwGxcz0+1kckahsepMMkjDDdkNhLjTExnNLY5bDoNwzvKj3Ag53zhIWzGwNb4qls1C0XQ==", + "dependencies": { + "@taquito/core": "^17.1.0" + }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, "node_modules/@taquito/michelson-encoder": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-12.1.1.tgz", - "integrity": "sha512-mWcA1DHHlFj7UswJpEmml853x9e0IYHyeiKZYAo7DtizHz0jiUWtptCuEWiPQ4fMOreFbYZ6KVYenoVfQVNrqA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-17.1.0.tgz", + "integrity": "sha512-1sYJp3QENlX2FoT/8poB+CcTH52S5RgIhVM4N0VOWR2MF8+y2SRVjMfrStfC9oDrH4jTt/ESQQFThcyw9XVEMg==", "dependencies": { - "@taquito/rpc": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2", + "@taquito/rpc": "^17.1.0", + "@taquito/utils": "^17.1.0", + "bignumber.js": "^9.1.0", "fast-json-stable-stringify": "^2.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, "node_modules/@taquito/rpc": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-12.1.1.tgz", - "integrity": "sha512-CgAF9kdmKLa/UbmiqApDtncCQGiG7kEOIYis8IIa0JUT9JD1H8WBbSNF/oNh4e0soWUK9BL2qU369RFnxIW+iA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-17.1.0.tgz", + "integrity": "sha512-/nzsGMxHbZOea4C9BnmXGaQVYwERNKF9IwFzdrBVTS7m+lfoRku9QfV88b3K77wXvcpZYSuXa1x4tJIXS8hHXw==", "dependencies": { - "@taquito/http-utils": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2" + "@taquito/core": "^17.1.0", + "@taquito/http-utils": "^17.1.0", + "@taquito/utils": "^17.1.0", + "bignumber.js": "^9.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, "node_modules/@taquito/signer": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-12.1.1.tgz", - "integrity": "sha512-TONxIbLs7bgmB3TTzcTOYzL8pFLZFBujHDHjB5QHJY5DT+lpByjYZHk2Frqjcy3NDvENVLU6uXeCeba2LK8kwA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-17.1.0.tgz", + "integrity": "sha512-TuDUMcDEURlD8EFse4UtUr7M+XhZOFEIOug2aAsn4428DZngCPq968e3YOAu67VTOaEkWNp4ILvEj/p9lyB1gQ==", "dependencies": { "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.2", - "@stablelib/nacl": "^1.0.3", - "@taquito/taquito": "^12.1.1", - "@taquito/utils": "^12.1.1", + "@stablelib/ed25519": "^1.0.3", + "@stablelib/hmac": "^1.0.1", + "@stablelib/nacl": "^1.0.4", + "@stablelib/pbkdf2": "^1.0.1", + "@stablelib/sha512": "^1.0.1", + "@taquito/taquito": "^17.1.0", + "@taquito/utils": "^17.1.0", + "@types/bn.js": "^5.1.1", + "bip39": "3.0.4", "elliptic": "^6.5.4", "pbkdf2": "^3.1.2", "typedarray-to-buffer": "^4.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, - "node_modules/@taquito/signer/node_modules/typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/@taquito/taquito": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-12.1.1.tgz", - "integrity": "sha512-HvbtClQ7isrDd17X/LEKkPzzeVYA8EMUem3qrkl9qvDO6FpJx/QLbUpYfT2PC0pLUkSrzdLGzmESHAOZhcksaw==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-17.1.0.tgz", + "integrity": "sha512-hmIPgSun3sH40ay1xk4YHR37nhqhjIaRxACZLWkX5vr+N7amFKfPWxUJvI1mlTuT8GFQsVVQMtYMLMs8YOh04Q==", "hasInstallScript": true, "dependencies": { - "@taquito/http-utils": "^12.1.1", - "@taquito/local-forging": "^12.1.1", - "@taquito/michel-codec": "^12.1.1", - "@taquito/michelson-encoder": "^12.1.1", - "@taquito/rpc": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2", - "rxjs": "^6.6.3" + "@taquito/core": "^17.1.0", + "@taquito/http-utils": "^17.1.0", + "@taquito/local-forging": "^17.1.0", + "@taquito/michel-codec": "^17.1.0", + "@taquito/michelson-encoder": "^17.1.0", + "@taquito/rpc": "^17.1.0", + "@taquito/utils": "^17.1.0", + "bignumber.js": "^9.1.0", + "rxjs": "^7.8.1" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, "node_modules/@taquito/utils": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-12.1.1.tgz", - "integrity": "sha512-GxNSBrA02vwhy56ayWB49VZficB+j2oyhPdlsRb2CguephmyEYnlUaNV27ILa6dPDW+zv6+QWQj6GyqLBRpIlA==", + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.1.0.tgz", + "integrity": "sha512-ob5Zth16vhyFq/RP5wr3t11M8jdnwMA1dmxNljVwwBuDW/qHgHr6lBS8hFOVe6ZTwf4DO+3lRYRHiaBaXS82Hw==", "dependencies": { "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.2", + "@stablelib/ed25519": "^1.0.3", + "@taquito/core": "^17.1.0", "@types/bs58check": "^2.1.0", - "blakejs": "^1.1.1", + "bignumber.js": "^9.1.0", + "blakejs": "^1.2.1", "bs58check": "^2.1.2", "buffer": "^6.0.3", "elliptic": "^6.5.4", "typedarray-to-buffer": "^4.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=16" } }, - "node_modules/@taquito/utils/node_modules/typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "dependencies": { + "@types/node": "*" + } }, "node_modules/@types/body-parser": { "version": "1.19.2", @@ -409,35 +409,36 @@ "@types/node": "*" } }, - "node_modules/@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", "dev": true, "dependencies": { "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", + "@types/express-serve-static-core": "^4.17.33", "@types/qs": "*", "@types/serve-static": "*" } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.35", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz", + "integrity": "sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg==", "dev": true, "dependencies": { "@types/node": "*", "@types/qs": "*", - "@types/range-parser": "*" + "@types/range-parser": "*", + "@types/send": "*" } }, + "node_modules/@types/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -454,9 +455,9 @@ } }, "node_modules/@types/node": { - "version": "17.0.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", - "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==" + "version": "20.4.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", + "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -470,16 +471,27 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, - "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "node_modules/@types/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz", + "integrity": "sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q==", "dev": true, "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, + "node_modules/@types/serve-static": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.2.tgz", + "integrity": "sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw==", + "dev": true, + "dependencies": { + "@types/http-errors": "*", + "@types/mime": "*", + "@types/node": "*" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -581,9 +593,9 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", + "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", "engines": { "node": "*" } @@ -597,6 +609,22 @@ "node": ">=8" } }, + "node_modules/bip39": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.0.4.tgz", + "integrity": "sha512-YZKQlb752TrUWqHWj7XAwCSjYEgGAk+/Aas3V7NyjQeZYsztO8JnQUaCWhcnL4T+jL8nvB8typ2jRPzTlgugNw==", + "dependencies": { + "@types/node": "11.11.6", + "create-hash": "^1.1.0", + "pbkdf2": "^3.0.9", + "randombytes": "^2.0.1" + } + }, + "node_modules/bip39/node_modules/@types/node": { + "version": "11.11.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", + "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" + }, "node_modules/blakejs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", @@ -608,20 +636,20 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", + "qs": "6.11.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -791,9 +819,9 @@ } }, "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==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } @@ -870,11 +898,14 @@ } }, "node_modules/dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==", + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", "engines": { "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" } }, "node_modules/ee-first": { @@ -918,13 +949,13 @@ } }, "node_modules/express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.0", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -943,7 +974,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.10.3", + "qs": "6.11.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.18.0", @@ -958,6 +989,43 @@ "node": ">= 0.10.0" } }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "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", @@ -1068,13 +1136,14 @@ } }, "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1" + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1112,6 +1181,17 @@ "node": ">=4" } }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -1261,10 +1341,17 @@ "node": ">=0.12.0" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } }, "node_modules/md5.js": { "version": "1.3.5", @@ -1279,7 +1366,7 @@ "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=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { "node": ">= 0.6" } @@ -1287,12 +1374,12 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "engines": { "node": ">= 0.6" } @@ -1335,7 +1422,7 @@ "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=" + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" }, "node_modules/minimatch": { "version": "3.1.2", @@ -1378,7 +1465,7 @@ "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/negotiator": { "version": "0.6.3", @@ -1389,9 +1476,9 @@ } }, "node_modules/nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -1399,8 +1486,8 @@ "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" @@ -1409,7 +1496,7 @@ "nodemon": "bin/nodemon.js" }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, "funding": { "type": "opencollective", @@ -1456,9 +1543,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1493,7 +1580,7 @@ "node_modules/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=" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/pbkdf2": { "version": "3.1.2", @@ -1546,9 +1633,9 @@ "dev": true }, "node_modules/qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", "dependencies": { "side-channel": "^1.0.4" }, @@ -1559,6 +1646,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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", @@ -1568,9 +1663,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -1582,9 +1677,9 @@ } }, "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==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -1629,14 +1724,11 @@ } }, "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" + "tslib": "^2.1.0" } }, "node_modules/safe-buffer": { @@ -1664,12 +1756,18 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { @@ -1745,24 +1843,15 @@ } }, "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "dependencies": { - "semver": "~7.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=10" } }, "node_modules/statuses": { @@ -1826,9 +1915,9 @@ } }, "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" }, "node_modules/type-is": { "version": "1.6.18", @@ -1842,17 +1931,36 @@ "node": ">= 0.6" } }, + "node_modules/typedarray-to-buffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", + "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/typescript": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", - "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", + "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/undefsafe": { @@ -1864,7 +1972,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -1872,12 +1980,12 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "engines": { "node": ">= 0.4.0" } @@ -1885,7 +1993,7 @@ "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "engines": { "node": ">= 0.8" } @@ -1895,1459 +2003,5 @@ "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } - }, - "dependencies": { - "@netlify/functions": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@netlify/functions/-/functions-1.0.0.tgz", - "integrity": "sha512-7fnJv3vr8uyyyOYPChwoec6MjzsCw1CoRUO2DhQ1BD6bOyJRlD4DUaOOGlMILB2LCT8P24p5LexEGx8AJb7xdA==", - "requires": { - "is-promise": "^4.0.0" - } - }, - "@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "requires": {} - }, - "@redis/client": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.8.tgz", - "integrity": "sha512-xzElwHIO6rBAqzPeVnCzgvrnBEcFL1P0w8P65VNLRkdVW8rOE58f52hdj0BDgmsdOm4f1EoXPZtH4Fh7M/qUpw==", - "requires": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - } - }, - "@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "requires": {} - }, - "@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "requires": {} - }, - "@redis/search": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.3.tgz", - "integrity": "sha512-4Dg1JjvCevdiCBTZqjhKkGoC5/BcB7k9j99kdMnaXFXg8x4eyOIVg9487CMv7/BUVkFLZCaIh8ead9mU15DNng==", - "requires": {} - }, - "@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "requires": {} - }, - "@stablelib/binary": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", - "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", - "requires": { - "@stablelib/int": "^1.0.1" - } - }, - "@stablelib/blake2b": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/blake2b/-/blake2b-1.0.1.tgz", - "integrity": "sha512-B3KyKoBAjkIFeH7romcF96i+pVFYk7K2SBQ1pZvaxV+epSBXJ+n0C66esUhyz6FF+5FbdQVm77C5fzGFcEZpKA==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/bytes": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", - "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" - }, - "@stablelib/constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", - "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" - }, - "@stablelib/ed25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/ed25519/-/ed25519-1.0.2.tgz", - "integrity": "sha512-FtnvUwvKbp6l1dNcg4CswMAVFVu/nzLK3oC7/PRtjYyHbWsIkD8j+5cjXHmwcCpdCpRCaTGACkEhhMQ1RcdSOQ==", - "requires": { - "@stablelib/random": "^1.0.1", - "@stablelib/sha512": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/hash": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", - "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" - }, - "@stablelib/int": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", - "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" - }, - "@stablelib/keyagreement": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", - "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", - "requires": { - "@stablelib/bytes": "^1.0.1" - } - }, - "@stablelib/nacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@stablelib/nacl/-/nacl-1.0.3.tgz", - "integrity": "sha512-ZdDGRo4s6ke2rdhwwna5SAikU48AQRNqPPbJ29ZSC781SMUMPpkixKpyZG+NfYhMkFSJ0ZRlFdKW+/ksmpVHWA==", - "requires": { - "@stablelib/poly1305": "^1.0.1", - "@stablelib/random": "^1.0.1", - "@stablelib/wipe": "^1.0.1", - "@stablelib/x25519": "^1.0.2", - "@stablelib/xsalsa20": "^1.0.2" - } - }, - "@stablelib/poly1305": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/poly1305/-/poly1305-1.0.1.tgz", - "integrity": "sha512-1HlG3oTSuQDOhSnLwJRKeTRSAdFNVB/1djy2ZbS35rBSJ/PFqx9cf9qatinWghC2UbfOYD8AcrtbUQl8WoxabA==", - "requires": { - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/random": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.1.tgz", - "integrity": "sha512-zOh+JHX3XG9MSfIB0LZl/YwPP9w3o6WBiJkZvjPoKKu5LKFW4OLV71vMxWp9qG5T43NaWyn0QQTWgqCdO+yOBQ==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/salsa20": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/salsa20/-/salsa20-1.0.2.tgz", - "integrity": "sha512-nfjKzw0KTKrrKBasEP+j7UP4I8Xudom8lVZIBCp0kQNARXq72IlSic0oabg2FC1NU68L4RdHrNJDd8bFwrphYA==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/constant-time": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/sha512": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/sha512/-/sha512-1.0.1.tgz", - "integrity": "sha512-13gl/iawHV9zvDKciLo1fQ8Bgn2Pvf7OV6amaRVKiq3pjQ3UmEpXxWiAfV8tYjUpeZroBxtyrwtdooQT/i3hzw==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/hash": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/wipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", - "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" - }, - "@stablelib/x25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.2.tgz", - "integrity": "sha512-wTR0t0Bp1HABLFRbYaE3vFLuco2QbAg6QvxBnzi5j9qjhYezWHW7OiCZyaWbt25UkSaoolUUT4Il0nS/2vcbSw==", - "requires": { - "@stablelib/keyagreement": "^1.0.1", - "@stablelib/random": "^1.0.1", - "@stablelib/wipe": "^1.0.1" - } - }, - "@stablelib/xsalsa20": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@stablelib/xsalsa20/-/xsalsa20-1.0.2.tgz", - "integrity": "sha512-7XdBGbcNgBShmuhDXv1G1WPVCkjZdkb1oPMzSidO7Fve0MHntH6TjFkj5bfLI+aRE+61weO076vYpP/jmaAYog==", - "requires": { - "@stablelib/binary": "^1.0.1", - "@stablelib/salsa20": "^1.0.2", - "@stablelib/wipe": "^1.0.1" - } - }, - "@taquito/http-utils": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-12.1.1.tgz", - "integrity": "sha512-Zlp/eTRVjFs0XEIiAhgxkh6s9npF4dO+e/Sm2XWsDmNPoGI2jdXNH0L+NiKJIOkYcu0CXlcgriTeEaYnbeTvcA==", - "requires": { - "axios": "^0.26.0" - }, - "dependencies": { - "axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", - "requires": { - "follow-redirects": "^1.14.8" - } - } - } - }, - "@taquito/local-forging": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-12.1.1.tgz", - "integrity": "sha512-SUA1YYRIpEGsTy5OfUIgIem0k/QsAzGjDCvf/wl5XV/fVBkP/+GN7uvYoqgJblCmsgtsMBhJFtXgs+D6bjGexg==", - "requires": { - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2" - } - }, - "@taquito/michel-codec": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-12.1.1.tgz", - "integrity": "sha512-BAig8YyLyRW5kxV/r0S191W+SvYuiTRJpgSp5IsgCDLAOh+d4/xq6IgU3PuGJgokQDstZdTbjpkrgRCnufR8lw==" - }, - "@taquito/michelson-encoder": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-12.1.1.tgz", - "integrity": "sha512-mWcA1DHHlFj7UswJpEmml853x9e0IYHyeiKZYAo7DtizHz0jiUWtptCuEWiPQ4fMOreFbYZ6KVYenoVfQVNrqA==", - "requires": { - "@taquito/rpc": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2", - "fast-json-stable-stringify": "^2.1.0" - } - }, - "@taquito/rpc": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-12.1.1.tgz", - "integrity": "sha512-CgAF9kdmKLa/UbmiqApDtncCQGiG7kEOIYis8IIa0JUT9JD1H8WBbSNF/oNh4e0soWUK9BL2qU369RFnxIW+iA==", - "requires": { - "@taquito/http-utils": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2" - } - }, - "@taquito/signer": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-12.1.1.tgz", - "integrity": "sha512-TONxIbLs7bgmB3TTzcTOYzL8pFLZFBujHDHjB5QHJY5DT+lpByjYZHk2Frqjcy3NDvENVLU6uXeCeba2LK8kwA==", - "requires": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.2", - "@stablelib/nacl": "^1.0.3", - "@taquito/taquito": "^12.1.1", - "@taquito/utils": "^12.1.1", - "elliptic": "^6.5.4", - "pbkdf2": "^3.1.2", - "typedarray-to-buffer": "^4.0.0" - }, - "dependencies": { - "typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" - } - } - }, - "@taquito/taquito": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-12.1.1.tgz", - "integrity": "sha512-HvbtClQ7isrDd17X/LEKkPzzeVYA8EMUem3qrkl9qvDO6FpJx/QLbUpYfT2PC0pLUkSrzdLGzmESHAOZhcksaw==", - "requires": { - "@taquito/http-utils": "^12.1.1", - "@taquito/local-forging": "^12.1.1", - "@taquito/michel-codec": "^12.1.1", - "@taquito/michelson-encoder": "^12.1.1", - "@taquito/rpc": "^12.1.1", - "@taquito/utils": "^12.1.1", - "bignumber.js": "^9.0.2", - "rxjs": "^6.6.3" - } - }, - "@taquito/utils": { - "version": "12.1.1", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-12.1.1.tgz", - "integrity": "sha512-GxNSBrA02vwhy56ayWB49VZficB+j2oyhPdlsRb2CguephmyEYnlUaNV27ILa6dPDW+zv6+QWQj6GyqLBRpIlA==", - "requires": { - "@stablelib/blake2b": "^1.0.1", - "@stablelib/ed25519": "^1.0.2", - "@types/bs58check": "^2.1.0", - "blakejs": "^1.1.1", - "bs58check": "^2.1.2", - "buffer": "^6.0.3", - "elliptic": "^6.5.4", - "typedarray-to-buffer": "^4.0.0" - }, - "dependencies": { - "typedarray-to-buffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-4.0.0.tgz", - "integrity": "sha512-6dOYeZfS3O9RtRD1caom0sMxgK59b27+IwoNy8RDPsmslSGOyU+mpTamlaIW7aNKi90ZQZ9DFaZL3YRoiSCULQ==" - } - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/bs58check": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz", - "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cors": { - "version": "2.8.12", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", - "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", - "dev": true - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", - "dev": true - }, - "@types/morgan": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", - "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "17.0.36", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.36.tgz", - "integrity": "sha512-V3orv+ggDsWVHP99K3JlwtH20R7J4IhI1Kksgc+64q5VxgfRkQG8Ws3MFm/FZOKDYGy9feGFlZ70/HpCNe9QaA==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", - "dev": true - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "axios": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.4.0.tgz", - "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==", - "requires": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - }, - "dependencies": { - "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==" - } - } - }, - "bignumber.js": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.2.tgz", - "integrity": "sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw==" - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true - }, - "blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" - }, - "bn.js": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "body-parser": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", - "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.10.3", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - } - }, - "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, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, - "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "requires": { - "base-x": "^3.0.2" - } - }, - "bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "requires": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "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==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "cluster-key-slot": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", - "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" - }, - "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", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - } - }, - "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==" - }, - "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, - "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==", - "requires": { - "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": { - "version": "1.1.7", - "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.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "dotenv": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", - "integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==" - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "elliptic": { - "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.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" - }, - "express": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", - "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.0", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.5.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.10.3", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - } - }, - "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==" - }, - "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, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - } - }, - "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" - }, - "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - } - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" - }, - "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==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, - "hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "requires": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "requires": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "iconv-lite": { - "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 < 3" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" - }, - "ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", - "dev": true - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "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==" - }, - "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, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "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 - }, - "is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" - }, - "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.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "media-typer": { - "version": "0.3.0", - "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=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "requires": { - "mime-db": "1.52.0" - } - }, - "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==" - }, - "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=" - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" - }, - "nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", - "dev": true, - "requires": { - "chokidar": "^3.5.2", - "debug": "^3.2.7", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.1.2", - "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, - "nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "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 - }, - "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "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=" - }, - "pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", - "requires": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "pstree.remy": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", - "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", - "dev": true - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "requires": { - "side-channel": "^1.0.4" - } - }, - "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==" - }, - "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "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==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "redis": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.7.tgz", - "integrity": "sha512-KrkuNJNpCwRm5vFJh0tteMxW8SaUzkm5fBH7eL5hd/D0fAkzvapxbfGPP/r+4JAXdQuX7nebsBkBqA2RHB7Usw==", - "requires": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.8", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.3", - "@redis/time-series": "1.0.4" - } - }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "requires": { - "tslib": "^1.9.0" - } - }, - "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==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "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.1", - "safe-buffer": "^5.0.1" - } - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", - "dev": true, - "requires": { - "semver": "~7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - }, - "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" - } - }, - "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, - "requires": { - "has-flag": "^3.0.0" - } - }, - "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, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" - }, - "touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "requires": { - "nopt": "~1.0.10" - } - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "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.24" - } - }, - "typescript": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.2.tgz", - "integrity": "sha512-Mamb1iX2FDUpcTRzltPxgWMKy3fhg0TN378ylbktPGPK/99KbDtMQ4W1hwgsbPAsG3a0xKa1vmw4VKZQbkvz5A==", - "dev": true - }, - "undefsafe": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", - "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", - "dev": true - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "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=" - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } } } diff --git a/package.json b/package.json index d421bd1..1b254e9 100644 --- a/package.json +++ b/package.json @@ -20,22 +20,20 @@ }, "homepage": "https://github.com/oxheadalpha/tezos-testnet-faucet-backend#readme", "dependencies": { - "@netlify/functions": "^1.0.0", - "@taquito/signer": "^12.1.1", - "@taquito/taquito": "^12.1.1", + "@taquito/signer": "^17.1.0", + "@taquito/taquito": "^17.1.0", "axios": "^1.4.0", - "body-parser": "^1.20.0", - "dotenv": "^16.0.1", - "express": "^4.18.1", + "body-parser": "^1.20.2", + "dotenv": "^16.3.1", + "express": "^4.18.2", "morgan": "^1.10.0", "redis": "^4.6.7" }, "devDependencies": { - "@types/cors": "^2.8.12", - "@types/express": "^4.17.13", + "@types/express": "^4.17.17", "@types/morgan": "^1.9.4", - "@types/node": "^17.0.36", - "nodemon": "^2.0.16", - "typescript": "^4.7.2" + "@types/node": "^20.4.5", + "nodemon": "^3.0.1", + "typescript": "^5.1.6" } } From 4deae8c8db472b545d15d0ef047d419adffe4834 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 28 Jul 2023 17:19:40 -0400 Subject: [PATCH 21/64] Don't track dist/ --- .gitignore | 3 +- dist/Captcha.js | 45 ------------ dist/Tezos.js | 92 ------------------------ dist/Types.js | 9 --- dist/api.js | 187 ------------------------------------------------ dist/pow.js | 67 ----------------- 6 files changed, 2 insertions(+), 401 deletions(-) delete mode 100644 dist/Captcha.js delete mode 100644 dist/Tezos.js delete mode 100644 dist/Types.js delete mode 100644 dist/api.js delete mode 100644 dist/pow.js diff --git a/.gitignore b/.gitignore index 3ec544c..deed335 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -.env \ No newline at end of file +dist/ +.env diff --git a/dist/Captcha.js b/dist/Captcha.js deleted file mode 100644 index 84e099b..0000000 --- a/dist/Captcha.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.validateCaptcha = void 0; -const axios_1 = __importDefault(require("axios")); -const checkCaptcha = (responseToken) => __awaiter(void 0, void 0, void 0, function* () { - if (!responseToken) { - throw new Error("Missing captcha token."); - } - const enableCaptcha = process.env.ENABLE_CAPTCHA || "true"; - if (enableCaptcha === "false") { - console.log("Captcha disabled"); - return true; - } - const secret = process.env.FAUCET_CAPTCHA_SECRET; - const captchaURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}`; - const res = yield axios_1.default.post(captchaURL); - return res.data; -}); -const validateCaptcha = (res, captchaToken) => __awaiter(void 0, void 0, void 0, function* () { - try { - const response = yield checkCaptcha(captchaToken); - if (!response.success) { - res.status(400).send({ status: "ERROR", message: "Invalid captcha" }); - return false; - } - } - catch (err) { - res.status(400).send({ status: "ERROR", message: "Captcha error" }); - return false; - } - return true; -}); -exports.validateCaptcha = validateCaptcha; diff --git a/dist/Tezos.js b/dist/Tezos.js deleted file mode 100644 index e51e883..0000000 --- a/dist/Tezos.js +++ /dev/null @@ -1,92 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.send = exports.validateAddress = exports.getTezAmountForProfile = exports.defaultBakerAmount = exports.defaultUserAmount = void 0; -const signer_1 = require("@taquito/signer"); -const taquito_1 = require("@taquito/taquito"); -const utils_1 = require("@taquito/utils"); -const Types_1 = require("./Types"); -const defaultMaxBalance = 6000; -exports.defaultUserAmount = 1; -exports.defaultBakerAmount = 6000; -const getTezAmountForProfile = (profile) => { - let amount = 0; - switch (profile.toUpperCase()) { - case Types_1.Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || exports.defaultUserAmount; - break; - case Types_1.Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || exports.defaultBakerAmount; - break; - default: - throw new Error(`Unknown profile '${profile}'`); - } - return amount; -}; -exports.getTezAmountForProfile = getTezAmountForProfile; -const validateAddress = (res, address) => { - if ((0, utils_1.validateKeyHash)(address) !== 3) { - res - .status(400) - .send({ status: "ERROR", message: `The address '${address}' is invalid` }); - return false; - } - return true; -}; -exports.validateAddress = validateAddress; -const send = (amount, address) => __awaiter(void 0, void 0, void 0, function* () { - console.log(`Send ${amount} xtz to ${address}`); - // Connect to RPC endpoint - const rpcUrl = process.env.RPC_URL; - if (!rpcUrl) { - console.log("No RPC URL defined"); - throw new Error("API error"); - } - console.log(`Use ${rpcUrl}`); - let Tezos = new taquito_1.TezosToolkit(rpcUrl); - // Check max balance - const userBalance = (yield Tezos.tz.getBalance(address)).toNumber(); - const maxBalance = process.env.MAX_BALANCE || defaultMaxBalance; - if (userBalance > maxBalance * 1000000) { - console.log(`User balance too high (${userBalance / 1000000}), don't send`); - throw new Error("You have already enough ꜩ"); - } - // Build memory signer fro private key - const privateKey = process.env.FAUCET_PRIVATE_KEY; - if (!privateKey) { - console.log("No private key provided"); - throw new Error("API error"); - } - // Create signer - try { - Tezos.setProvider({ - signer: yield signer_1.InMemorySigner.fromSecretKey(privateKey), - }); - } - catch (err) { - console.log(err); - throw new Error("API error"); - } - // Create and send transaction - try { - const operation = yield Tezos.contract.transfer({ - to: address, - amount: amount, - }); - console.log(`Hash: ${operation.hash}`); - return operation.hash; - } - catch (err) { - console.log(err); - throw err; - } -}); -exports.send = send; diff --git a/dist/Types.js b/dist/Types.js deleted file mode 100644 index 18c4347..0000000 --- a/dist/Types.js +++ /dev/null @@ -1,9 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Profile = void 0; -var Profile; -(function (Profile) { - Profile["USER"] = "USER"; - Profile["BAKER"] = "BAKER"; -})(Profile || (Profile = {})); -exports.Profile = Profile; diff --git a/dist/api.js b/dist/api.js deleted file mode 100644 index 6368bab..0000000 --- a/dist/api.js +++ /dev/null @@ -1,187 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __importDefault = (this && this.__importDefault) || function (mod) { - return (mod && mod.__esModule) ? mod : { "default": mod }; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.redis = void 0; -const body_parser_1 = __importDefault(require("body-parser")); -const dotenv_1 = __importDefault(require("dotenv")); -const express_1 = __importDefault(require("express")); -const morgan_1 = __importDefault(require("morgan")); -const redis_1 = require("redis"); -const Captcha_1 = require("./Captcha"); -const Tezos_1 = require("./Tezos"); -const Types_1 = require("./Types"); -const pow_1 = require("./pow"); -dotenv_1.default.config(); -exports.redis = (0, redis_1.createClient)({ -// url: "redis://localhost:6379", -}).on("error", (err) => console.log("Redis Client Error", err)); -const app = (0, express_1.default)(); -app.use(body_parser_1.default.json()); -app.use(body_parser_1.default.urlencoded({ extended: true })); -app.use((0, morgan_1.default)("dev")); -app.use((_, res, next) => { - const cors = process.env.AUTHORIZED_HOST || "*"; - res.setHeader("Access-Control-Allow-Origin", cors); - res.setHeader("Access-Control-Allow-Methods", "GET, POST"); - res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); - next(); -}); -app.get("/info", (_, res) => { - try { - const profiles = { - user: { - profile: Types_1.Profile.USER, - amount: process.env.FAUCET_AMOUNT_USER || Tezos_1.defaultUserAmount, - currency: "tez", - }, - baker: { - profile: Types_1.Profile.BAKER, - amount: process.env.FAUCET_AMOUNT_BAKER || Tezos_1.defaultBakerAmount, - currency: "tez", - }, - }; - const info = { - faucetAddress: process.env.FAUCET_ADDRESS, - captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), - profiles, - maxBalance: process.env.MAX_BALANCE, - }; - res.status(200).send(info); - } - catch (error) { - res.status(500).send({ status: "ERROR", message: "An exception occurred" }); - } -}); -app.post("/challenge", (req, res) => __awaiter(void 0, void 0, void 0, function* () { - const { address, captchaToken, profile } = req.body; - if (!address || !profile) { - return res.status(400).send({ - satus: "ERROR", - message: "'address' and 'profile' fields are required", - }); - } - if (!(0, Tezos_1.validateAddress)(res, address)) - return; - if (captchaToken && !(yield (0, Captcha_1.validateCaptcha)(res, captchaToken))) - return; - try { - (0, Tezos_1.getTezAmountForProfile)(profile); - } - catch (e) { - return res.status(400).send({ status: "ERROR", message: e.message }); - } - try { - const challengeKey = (0, pow_1.getChallengeKey)(address); - let { challenge, challengesNeeded, challengeCounter, difficulty } = (yield (0, pow_1.getChallenge)(challengeKey)) || {}; - if (!challenge) { - // If a captcha was sent it was validated above. - const usedCaptcha = !!captchaToken; - ({ challenge, challengesNeeded, difficulty } = - (0, pow_1.createChallenge)(usedCaptcha)); - challengeCounter = 1; - yield (0, pow_1.saveChallenge)(challengeKey, { - challenge, - challengesNeeded, - challengeCounter, - difficulty, - usedCaptcha, - }); - } - console.log({ challenge, difficulty }); - return res.status(200).send({ - status: "SUCCESS", - challenge, - challengeCounter, - difficulty, - }); - } - catch (err) { - const message = "Error getting challenge"; - console.error(message, err); - return res.status(500).send({ status: "ERROR", message }); - } -})); -app.post("/verify", (req, res) => __awaiter(void 0, void 0, void 0, function* () { - const { address, solution, nonce, profile } = req.body; - if (!address || !solution || !nonce) { - return res.status(400).send({ - status: "ERROR", - message: "'address', 'solution', and 'nonce' fields are required", - }); - } - if (!(0, Tezos_1.validateAddress)(res, address)) - return; - try { - const challengeKey = (0, pow_1.getChallengeKey)(address); - const redisChallenge = yield (0, pow_1.getChallenge)(challengeKey); - if (!redisChallenge) { - return res - .status(400) - .send({ status: "ERROR", message: "No challenge found" }); - } - const { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha } = redisChallenge; - const isValidSolution = (0, pow_1.verifySolution)({ - challenge, - difficulty, - nonce, - solution, - }); - console.log({ address, solution, nonce, challengeCounter }); - if (!isValidSolution) { - return res - .status(400) - .send({ status: "ERROR", message: "Incorrect solution" }); - } - if (challengeCounter < challengesNeeded) { - const newChallenge = (0, pow_1.createChallenge)(usedCaptcha); - const resData = { - challenge: newChallenge.challenge, - challengeCounter: challengeCounter + 1, - difficulty: newChallenge.difficulty, - }; - yield (0, pow_1.saveChallenge)(challengeKey, Object.assign({ challengesNeeded: newChallenge.challengesNeeded }, resData)); - return res.status(200).send(Object.assign({ status: "SUCCESS" }, resData)); - } - // The challenge should be deleted from redis before Tez is sent. If it - // failed to delete, the user could keep getting Tez with the same solution. - yield exports.redis.del(challengeKey).catch((e) => { - console.error(`Redis failed to delete ${challengeKey}.`); - throw e; - }); - // Here is where you would send the tez to the user's address - // For the sake of this example, we're just logging the address - console.log(`Send tez to ${address}`); - const amount = (0, Tezos_1.getTezAmountForProfile)("BAKER"); - const b = {}; - // b.txHash = await send(amount, address) - b.txHash = "hash"; - return res - .status(200) - .send(Object.assign(Object.assign({}, b), { status: "SUCCESS", message: "Tez sent" })); - } - catch (err) { - console.error(err.message); - return res - .status(500) - .send({ status: "ERROR", message: "An error occurred" }); - } -})); -const port = process.env.API_PORT || 3000; -(() => __awaiter(void 0, void 0, void 0, function* () { - yield exports.redis.connect(); - console.log("Connected to redis."); - app.listen(port, () => { - console.log(`Start API on port ${port}.`); - }); -}))(); diff --git a/dist/pow.js b/dist/pow.js deleted file mode 100644 index c9cb2d5..0000000 --- a/dist/pow.js +++ /dev/null @@ -1,67 +0,0 @@ -"use strict"; -var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { - function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } - return new (P || (P = Promise))(function (resolve, reject) { - function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } - function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } - step((generator = generator.apply(thisArg, _arguments || [])).next()); - }); -}; -var __rest = (this && this.__rest) || function (s, e) { - var t = {}; - for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -}; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.verifySolution = exports.getChallenge = exports.saveChallenge = exports.createChallenge = exports.getChallengeKey = void 0; -const crypto_1 = require("crypto"); -const api_1 = require("./api"); -const getChallengeKey = (address) => `address:${address}`; -exports.getChallengeKey = getChallengeKey; -// TODO: Implement -const determineDifficulty = (usedCaptcha) => { - const challengeSize = 32; - const difficulty = usedCaptcha ? 4 : 5; - return { challengeSize, difficulty }; -}; -// TODO: Implement -const determineChallengesNeeded = (usedCaptcha) => usedCaptcha ? 5 : 6; -const generateChallenge = (bytesSize = 32) => (0, crypto_1.randomBytes)(bytesSize).toString("hex"); -const createChallenge = (usedCaptcha) => { - const challengesNeeded = determineChallengesNeeded(usedCaptcha); - const { challengeSize, difficulty } = determineDifficulty(usedCaptcha); - const challenge = generateChallenge(challengeSize); - return { challenge, challengesNeeded, difficulty }; -}; -exports.createChallenge = createChallenge; -const saveChallenge = (challengeKey, _a) => __awaiter(void 0, void 0, void 0, function* () { - var { usedCaptcha, expiration = 1800 } = _a, // 30m - args = __rest(_a, ["usedCaptcha", "expiration"]); - yield api_1.redis.hSet(challengeKey, Object.assign(Object.assign({}, args), (typeof usedCaptcha === "boolean" && { - usedCaptcha: String(usedCaptcha), - }))); - yield api_1.redis.expire(challengeKey, expiration); -}); -exports.saveChallenge = saveChallenge; -const getChallenge = (challengeKey) => __awaiter(void 0, void 0, void 0, function* () { - const data = yield api_1.redis.hGetAll(challengeKey); - if (!Object.keys(data).length) - return null; - return Object.assign(Object.assign({}, data), { challengeCounter: Number(data.challengeCounter), challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true" }); -}); -exports.getChallenge = getChallenge; -const getSolution = (challenge, nonce) => (0, crypto_1.createHash)("sha256").update(`${challenge}:${nonce}`).digest("hex"); -const verifySolution = ({ challenge, difficulty, nonce, solution, }) => { - const hash = getSolution(challenge, nonce); - // Validate the SHA-256 hash of the challenge concatenated with the nonce - // starts with a certain number of zeroes (the difficulty). - return hash === solution && hash.startsWith("0".repeat(difficulty)); -}; -exports.verifySolution = verifySolution; From 1c611437e2bf9af51ab63a9f938344c4ffc7d1d3 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 28 Jul 2023 17:24:54 -0400 Subject: [PATCH 22/64] Fix /info bug --- src/api.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/api.ts b/src/api.ts index 292a054..8a44ea8 100644 --- a/src/api.ts +++ b/src/api.ts @@ -61,12 +61,13 @@ app.get("/info", (_, res: Response) => { const info: InfoResponseBody = { faucetAddress: process.env.FAUCET_ADDRESS, - captchaEnable: JSON.parse(process.env.ENABLE_CAPTCHA), + captchaEnable: process.env.ENABLE_CAPTCHA === "true", profiles, maxBalance: process.env.MAX_BALANCE, } res.status(200).send(info) } catch (error) { + console.error(error) res.status(500).send({ status: "ERROR", message: "An exception occurred" }) } }) From f60f04caa9e964b627f335a845de0b7ff61f5688 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 28 Jul 2023 17:32:32 -0400 Subject: [PATCH 23/64] Cleanup --- src/Tezos.ts | 6 +++--- src/api.ts | 30 ++++++++++++++++++++---------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/Tezos.ts b/src/Tezos.ts index 7488891..ae4b7c0 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -50,7 +50,7 @@ export const send = async ( console.log(`Use ${rpcUrl}`) - let Tezos: TezosToolkit = new TezosToolkit(rpcUrl) + const Tezos: TezosToolkit = new TezosToolkit(rpcUrl) // Check max balance const userBalance: number = (await Tezos.tz.getBalance(address)).toNumber() @@ -61,8 +61,8 @@ export const send = async ( throw new Error("You have already enough ꜩ") } - // Build memory signer fro private key - const privateKey: string = process.env.FAUCET_PRIVATE_KEY + // Build memory signer for private key + const privateKey = process.env.FAUCET_PRIVATE_KEY if (!privateKey) { console.log("No private key provided") diff --git a/src/api.ts b/src/api.ts index 8a44ea8..baa6b7a 100644 --- a/src/api.ts +++ b/src/api.ts @@ -129,15 +129,24 @@ app.post("/challenge", async (req: Request, res: Response) => { app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body - if (!address || !solution || !nonce) { + if (!address || !solution || !nonce || !profile) { return res.status(400).send({ status: "ERROR", - message: "'address', 'solution', and 'nonce' fields are required", + message: + "'address', 'solution', 'nonce', and 'profile' fields are required", }) } if (!validateAddress(res, address)) return + let amount + + try { + amount = getTezAmountForProfile(profile) + } catch (e: any) { + return res.status(400).send({ status: "ERROR", message: e.message }) + } + try { const challengeKey = getChallengeKey(address) const redisChallenge = await getChallenge(challengeKey) @@ -147,8 +156,13 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "No challenge found" }) } - const { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha } = - redisChallenge + const { + challenge, + challengesNeeded, + challengeCounter, + difficulty, + usedCaptcha, + } = redisChallenge const isValidSolution = verifySolution({ challenge, @@ -189,14 +203,10 @@ app.post("/verify", async (req: Request, res: Response) => { // Here is where you would send the tez to the user's address // For the sake of this example, we're just logging the address - console.log(`Send tez to ${address}`) - const amount = getTezAmountForProfile("BAKER" as Profile) - const b: any = {} - // b.txHash = await send(amount, address) - b.txHash = "hash" + const txHash = await send(amount, address) return res .status(200) - .send({ ...b, status: "SUCCESS", message: "Tez sent" }) + .send({ txHash, status: "SUCCESS", message: "Tez sent" }) } catch (err: any) { console.error(err.message) return res From aff0cfce34473be2b99f5781eb649684400514d4 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 1 Aug 2023 19:07:48 -0400 Subject: [PATCH 24/64] Improve dockerfile --- .dockerignore | 1 + Dockerfile | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.dockerignore b/.dockerignore index 03952b9..8e40c7e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,3 +2,4 @@ LICENSE.md node_modules README.md +Dockerignore diff --git a/Dockerfile b/Dockerfile index 6a0225c..94a5542 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,18 @@ -FROM node:16-alpine +FROM node:18-alpine WORKDIR /tezos-faucet-backend -COPY package.json . +RUN chown node:node /tezos-faucet-backend + +USER node + +COPY --chown=node:node package.json ./ +COPY --chown=node:node package-lock.json ./ RUN npm install -COPY . . +COPY --chown=node:node . ./ -RUN ./node_modules/typescript/bin/tsc -p ./tsconfig.json +RUN ./node_modules/typescript/bin/tsc -CMD ["node", "./dist/api.js"] \ No newline at end of file +CMD ["node", "./dist/api.js"] From 09a0fb2770bf9498fe537bf33dfa6c41214e7ee8 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 1 Aug 2023 19:09:48 -0400 Subject: [PATCH 25/64] Run dotenv immediately --- src/api.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/api.ts b/src/api.ts index baa6b7a..f736855 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,5 +1,7 @@ -import bodyParser from "body-parser" import dotenv from "dotenv" +dotenv.config() + +import bodyParser from "body-parser" import express, { Express, Request, Response } from "express" import morgan from "morgan" import { createClient } from "redis" @@ -21,7 +23,6 @@ import { verifySolution, } from "./pow" -dotenv.config() export const redis = createClient({ // url: "redis://localhost:6379", @@ -208,14 +209,14 @@ app.post("/verify", async (req: Request, res: Response) => { .status(200) .send({ txHash, status: "SUCCESS", message: "Tez sent" }) } catch (err: any) { - console.error(err.message) + console.error(err) return res .status(500) .send({ status: "ERROR", message: "An error occurred" }) } }) -const port: number = process.env.API_PORT || 3000 +const port = process.env.API_PORT || 3000 ;(async () => { await redis.connect() From 2eba83c2a7752d16852bae2ece2945e2a23a24c9 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 1 Aug 2023 19:14:49 -0400 Subject: [PATCH 26/64] Setup Taquito TezosToolkit once --- src/Tezos.ts | 79 +++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/src/Tezos.ts b/src/Tezos.ts index ae4b7c0..4229cd8 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -4,12 +4,12 @@ import { validateKeyHash } from "@taquito/utils" import { Response } from "express" import { Profile } from "./Types" -const defaultMaxBalance: number = 6000 -export const defaultUserAmount: number = 1 -export const defaultBakerAmount: number = 6000 +const defaultMaxBalance = 6000 +export const defaultUserAmount = 1 +export const defaultBakerAmount = 6000 export const getTezAmountForProfile = (profile: Profile) => { - let amount: number = 0 + let amount = 0 switch (profile.toUpperCase()) { case Profile.USER: @@ -35,60 +35,63 @@ export const validateAddress = (res: Response, address: string) => { return true } -export const send = async ( - amount: number, - address: string -): Promise => { - console.log(`Send ${amount} xtz to ${address}`) - // Connect to RPC endpoint - const rpcUrl: string = process.env.RPC_URL - +// Setup the TezosToolkit to interact with the chain. +const Tezos = (() => { + const rpcUrl = process.env.RPC_URL if (!rpcUrl) { - console.log("No RPC URL defined") - throw new Error("API error") + throw new Error("No RPC_URL defined.") } - console.log(`Use ${rpcUrl}`) + const TezToolkit = new TezosToolkit(rpcUrl) - const Tezos: TezosToolkit = new TezosToolkit(rpcUrl) - - // Check max balance - const userBalance: number = (await Tezos.tz.getBalance(address)).toNumber() - - const maxBalance: number = process.env.MAX_BALANCE || defaultMaxBalance - if (userBalance > maxBalance * 1000000) { - console.log(`User balance too high (${userBalance / 1000000}), don't send`) - throw new Error("You have already enough ꜩ") + const faucetPrivateKey = process.env.FAUCET_PRIVATE_KEY + if (!faucetPrivateKey) { + throw new Error("No FAUCET_PRIVATE_KEY defined.") } - // Build memory signer for private key - const privateKey = process.env.FAUCET_PRIVATE_KEY + // Create signer + TezToolkit.setProvider({ + signer: new InMemorySigner(faucetPrivateKey), + }) - if (!privateKey) { - console.log("No private key provided") - throw new Error("API error") - } + return TezToolkit +})() - // Create signer +export const send = async ( + amount: number, + address: string +): Promise => { + // Check max balance try { - Tezos.setProvider({ - signer: await InMemorySigner.fromSecretKey(privateKey), - }) + const userBalance = (await Tezos.tz.getBalance(address)).toNumber() + const maxBalance = Number(process.env.MAX_BALANCE || defaultMaxBalance) + if (userBalance > maxBalance * 1000000) { + console.log( + `User balance too high (${userBalance / 1000000}), don't send` + ) + throw new Error("You have already enough ꜩ") + } } catch (err) { - console.log(err) - throw new Error("API error") + console.error(err) + throw new Error(`Error getting ${address} balance.`) } // Create and send transaction try { + /* Note: `transfer` doesn't work well when running on node v19+. The + underlying Axios requests breaks with "ECONNRESET error socket hang up". I + believe this is because node v19 sets HTTP(S) `keepAlive` to true by default + and the Tezos node ends up killing the long-lived connection. It isn't easy + to configure Axios in Taquito to work around this. */ const operation = await Tezos.contract.transfer({ to: address, - amount: amount, + amount, }) + console.log(`Sent ${amount} xtz to ${address}`) console.log(`Hash: ${operation.hash}`) return operation.hash } catch (err) { - console.log(err) + console.error(`Error sending Tez to ${address}.`) throw err } } From 0539bb05b69307811060ca3cb1919c89a6b4aba9 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 1 Aug 2023 19:39:08 -0400 Subject: [PATCH 27/64] Cleanup captcha logic and check first if it's enabled --- src/Captcha.ts | 34 ++++++++++++++-------------------- src/api.ts | 4 ++-- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/Captcha.ts b/src/Captcha.ts index c31e2c7..60e7a6f 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -1,30 +1,23 @@ import axios from "axios" import { Response } from "express" -const checkCaptcha = async (responseToken: string) => { - if (!responseToken) { - throw new Error("Missing captcha token.") - } - - const enableCaptcha: string = process.env.ENABLE_CAPTCHA || "true" - - if (enableCaptcha === "false") { - console.log("Captcha disabled") - return true - } +export const CAPTCHA_ENABLED = process.env.ENABLE_CAPTCHA !== "false" - const secret = process.env.FAUCET_CAPTCHA_SECRET +export const validateCaptcha = async (res: Response, captchaToken: string) => { + try { + if (!CAPTCHA_ENABLED) { + console.log("Captcha disabled") + return true + } - const captchaURL = `https://google.com/recaptcha/api/siteverify?secret=${secret}&response=${responseToken}` + if (!captchaToken) { + throw new Error("Missing captcha token.") + } - const res = await axios.post(captchaURL) - return res.data -} + const captchaURL = `https://google.com/recaptcha/api/siteverify?secret=${process.env.FAUCET_CAPTCHA_SECRET}&response=${captchaToken}` -export const validateCaptcha = async (res: Response, captchaToken: string) => { - try { - const response = await checkCaptcha(captchaToken) - if (!response.success) { + const res = (await axios.post(captchaURL)).data + if (!res.success) { res.status(400).send({ status: "ERROR", message: "Invalid captcha" }) return false } @@ -32,5 +25,6 @@ export const validateCaptcha = async (res: Response, captchaToken: string) => { res.status(400).send({ status: "ERROR", message: "Captcha error" }) return false } + return true } diff --git a/src/api.ts b/src/api.ts index f736855..66770da 100644 --- a/src/api.ts +++ b/src/api.ts @@ -6,7 +6,7 @@ import express, { Express, Request, Response } from "express" import morgan from "morgan" import { createClient } from "redis" -import { validateCaptcha } from "./Captcha" +import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" import { defaultBakerAmount, defaultUserAmount, @@ -99,7 +99,7 @@ app.post("/challenge", async (req: Request, res: Response) => { if (!challenge) { // If a captcha was sent it was validated above. - const usedCaptcha = !!captchaToken + const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 From 63fa5ce6c5bea2b07a090df1bf5764fec496e07a Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 2 Aug 2023 14:49:47 -0400 Subject: [PATCH 28/64] Fix typings and Tezos amount conversions + cleanup --- src/Captcha.ts | 17 +++++++++++++++-- src/Tezos.ts | 33 +++++++++++++++------------------ src/Types.ts | 42 ++++++++++++++++++++---------------------- src/api.ts | 14 ++++++-------- src/environment.d.ts | 28 ++++++++++++++-------------- 5 files changed, 70 insertions(+), 64 deletions(-) diff --git a/src/Captcha.ts b/src/Captcha.ts index 60e7a6f..917c29b 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -14,14 +14,27 @@ export const validateCaptcha = async (res: Response, captchaToken: string) => { throw new Error("Missing captcha token.") } - const captchaURL = `https://google.com/recaptcha/api/siteverify?secret=${process.env.FAUCET_CAPTCHA_SECRET}&response=${captchaToken}` + const captchaURL = `https://google.com/recaptcha/api/siteverify` + + const res = ( + await axios.post( + captchaURL, + {}, + { + params: { + secret: process.env.FAUCET_CAPTCHA_SECRET, + response: captchaToken, + }, + } + ) + ).data - const res = (await axios.post(captchaURL)).data if (!res.success) { res.status(400).send({ status: "ERROR", message: "Invalid captcha" }) return false } } catch (err) { + console.error(err) res.status(400).send({ status: "ERROR", message: "Captcha error" }) return false } diff --git a/src/Tezos.ts b/src/Tezos.ts index 4229cd8..a317885 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -4,25 +4,26 @@ import { validateKeyHash } from "@taquito/utils" import { Response } from "express" import { Profile } from "./Types" +const defaultUserAmount = 1 +export const FAUCET_AMOUNT_USER = + Number(process.env.FAUCET_AMOUNT_USER) || defaultUserAmount + +const defaultBakerAmount = 6000 +export const FAUCET_AMOUNT_BAKER = + Number(process.env.FAUCET_AMOUNT_BAKER) || defaultBakerAmount + const defaultMaxBalance = 6000 -export const defaultUserAmount = 1 -export const defaultBakerAmount = 6000 +export const MAX_BALANCE = Number(process.env.MAX_BALANCE) || defaultMaxBalance export const getTezAmountForProfile = (profile: Profile) => { - let amount = 0 - switch (profile.toUpperCase()) { case Profile.USER: - amount = process.env.FAUCET_AMOUNT_USER || defaultUserAmount - break + return FAUCET_AMOUNT_USER case Profile.BAKER: - amount = process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount - break + return FAUCET_AMOUNT_BAKER default: throw new Error(`Unknown profile '${profile}'`) } - - return amount } export const validateAddress = (res: Response, address: string) => { @@ -64,8 +65,7 @@ export const send = async ( // Check max balance try { const userBalance = (await Tezos.tz.getBalance(address)).toNumber() - const maxBalance = Number(process.env.MAX_BALANCE || defaultMaxBalance) - if (userBalance > maxBalance * 1000000) { + if (userBalance > MAX_BALANCE * 1000000) { console.log( `User balance too high (${userBalance / 1000000}), don't send` ) @@ -79,14 +79,11 @@ export const send = async ( // Create and send transaction try { /* Note: `transfer` doesn't work well when running on node v19+. The - underlying Axios requests breaks with "ECONNRESET error socket hang up". I - believe this is because node v19 sets HTTP(S) `keepAlive` to true by default + underlying Axios requests breaks with "ECONNRESET error socket hang up". + This is likely because node v19 sets HTTP(S) `keepAlive` to true by default and the Tezos node ends up killing the long-lived connection. It isn't easy to configure Axios in Taquito to work around this. */ - const operation = await Tezos.contract.transfer({ - to: address, - amount, - }) + const operation = await Tezos.contract.transfer({ to: address, amount }) console.log(`Sent ${amount} xtz to ${address}`) console.log(`Hash: ${operation.hash}`) return operation.hash diff --git a/src/Types.ts b/src/Types.ts index 3c1f93a..e1761bf 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -1,31 +1,29 @@ -enum Profile { - USER = "USER", - BAKER = "BAKER" +export enum Profile { + USER = "USER", + BAKER = "BAKER", } -type RequestBody = { - captchaToken: string; - address: string; - profile: string; +export type RequestBody = { + captchaToken: string + address: string + profile: string } -type ResponseBody = { - status: string; - txHash: string | undefined; - message: string | undefined; +export type ResponseBody = { + status: string + txHash?: string + message?: string } -type InfoResponseBody = { - faucetAddress: string; - captchaEnable: boolean; - profiles: ProfileInfo; - maxBalance: number; +export type ProfileInfo = { + profile: string + amount: number + currency: string } -type ProfileInfo = { - profile: string; - amount: number; - currency: string; +export type InfoResponseBody = { + faucetAddress: string + captchaEnabled: boolean + profiles: ProfileInfo + maxBalance: number } - -export { Profile, RequestBody, ResponseBody, InfoResponseBody, ProfileInfo }; \ No newline at end of file diff --git a/src/api.ts b/src/api.ts index 66770da..88045d9 100644 --- a/src/api.ts +++ b/src/api.ts @@ -8,13 +8,11 @@ import { createClient } from "redis" import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" import { - defaultBakerAmount, - defaultUserAmount, + MAX_BALANCE, getTezAmountForProfile, send, validateAddress, } from "./Tezos" -import { InfoResponseBody, Profile, RequestBody, ResponseBody } from "./Types" import { createChallenge, getChallengeKey, @@ -22,7 +20,7 @@ import { getChallenge, verifySolution, } from "./pow" - +import { InfoResponseBody, Profile } from "./Types" export const redis = createClient({ // url: "redis://localhost:6379", @@ -50,21 +48,21 @@ app.get("/info", (_, res: Response) => { const profiles: any = { user: { profile: Profile.USER, - amount: process.env.FAUCET_AMOUNT_USER || defaultUserAmount, + amount: getTezAmountForProfile(Profile.USER), currency: "tez", }, baker: { profile: Profile.BAKER, - amount: process.env.FAUCET_AMOUNT_BAKER || defaultBakerAmount, + amount: getTezAmountForProfile(Profile.BAKER), currency: "tez", }, } const info: InfoResponseBody = { faucetAddress: process.env.FAUCET_ADDRESS, - captchaEnable: process.env.ENABLE_CAPTCHA === "true", + captchaEnabled: CAPTCHA_ENABLED, + maxBalance: MAX_BALANCE, profiles, - maxBalance: process.env.MAX_BALANCE, } res.status(200).send(info) } catch (error) { diff --git a/src/environment.d.ts b/src/environment.d.ts index be7c258..dd31369 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -1,18 +1,18 @@ declare global { - namespace NodeJS { - interface ProcessEnv { - FAUCET_PRIVATE_KEY: string; - FAUCET_ADDRESS: string; - ENABLE_CAPTCHA: string; - FAUCET_CAPTCHA_SECRET: string; - AUTHORIZED_HOST: string; - API_PORT: number; - RPC_URL: string; - FAUCET_AMOUNT_USER: number; - FAUCET_AMOUNT_BAKER: number; - MAX_BALANCE: number; - } + namespace NodeJS { + interface ProcessEnv { + FAUCET_PRIVATE_KEY: string + FAUCET_ADDRESS: string + ENABLE_CAPTCHA: string + FAUCET_CAPTCHA_SECRET: string + AUTHORIZED_HOST: string + API_PORT: string + RPC_URL: string + FAUCET_AMOUNT_USER: string + FAUCET_AMOUNT_BAKER: string + MAX_BALANCE: string } + } } -export { } \ No newline at end of file +export {} From a9038929a54fedd9f60449e7b16eb9d309ebdc7c Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 2 Aug 2023 18:37:31 -0400 Subject: [PATCH 29/64] Make redis url and password configurable --- src/api.ts | 7 ++++--- src/environment.d.ts | 16 +++++++++------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/api.ts b/src/api.ts index 88045d9..c44d92f 100644 --- a/src/api.ts +++ b/src/api.ts @@ -23,8 +23,9 @@ import { import { InfoResponseBody, Profile } from "./Types" export const redis = createClient({ - // url: "redis://localhost:6379", -}).on("error", (err: any) => console.log("Redis Client Error", err)) + url: process.env.REDIS_URL, + password: process.env.REDIS_PASSWORD, +}).on("error", (err: any) => console.log("Redis Client Error:", err)) const app: Express = express() app.use(bodyParser.json()) @@ -221,6 +222,6 @@ const port = process.env.API_PORT || 3000 console.log("Connected to redis.") app.listen(port, () => { - console.log(`Start API on port ${port}.`) + console.log(`Listening on port ${port}.`) }) })() diff --git a/src/environment.d.ts b/src/environment.d.ts index dd31369..c08e22f 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -1,16 +1,18 @@ declare global { namespace NodeJS { interface ProcessEnv { - FAUCET_PRIVATE_KEY: string - FAUCET_ADDRESS: string - ENABLE_CAPTCHA: string - FAUCET_CAPTCHA_SECRET: string - AUTHORIZED_HOST: string API_PORT: string - RPC_URL: string - FAUCET_AMOUNT_USER: string + AUTHORIZED_HOST: string + ENABLE_CAPTCHA: string + FAUCET_ADDRESS: string FAUCET_AMOUNT_BAKER: string + FAUCET_AMOUNT_USER: string + FAUCET_CAPTCHA_SECRET: string + FAUCET_PRIVATE_KEY: string MAX_BALANCE: string + REDIS_PASSWORD: string + REDIS_URL: string + RPC_URL: string } } } From c6488e7eaa92aae6d3e16c70ae4c1c55a349ec5c Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 4 Aug 2023 17:14:30 -0400 Subject: [PATCH 30/64] Use winston instead of morgan --- package-lock.json | 365 ++++++++++++++++++++++++++++++++-------------- package.json | 11 +- 2 files changed, 258 insertions(+), 118 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8a0154b..7603e2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,23 +9,40 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@taquito/signer": "^17.1.0", - "@taquito/taquito": "^17.1.0", + "@taquito/signer": "^17.1.1", + "@taquito/taquito": "^17.1.1", "axios": "^1.4.0", "body-parser": "^1.20.2", "dotenv": "^16.3.1", "express": "^4.18.2", - "morgan": "^1.10.0", - "redis": "^4.6.7" + "redis": "^4.6.7", + "winston": "^3.10.0" }, "devDependencies": { "@types/express": "^4.17.17", - "@types/morgan": "^1.9.4", - "@types/node": "^20.4.5", + "@types/node": "^20.4.6", "nodemon": "^3.0.1", "typescript": "^5.1.6" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, "node_modules/@redis/bloom": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", @@ -232,19 +249,19 @@ } }, "node_modules/@taquito/core": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/core/-/core-17.1.0.tgz", - "integrity": "sha512-tfdgC7/Q5U9lN3UzvuJYf8Z7iBWyOtqILRuWRGFM6VtSXwNwcNK62f8FNKAgyHahFkVA4vVdD9zrt8NbM/TB2g==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/core/-/core-17.1.1.tgz", + "integrity": "sha512-ib+dzHbVT+0maYGAVdeIk9v9CNkOiB5j8CwnHUygBkEajoOdWTPlsrldRhRTAOnbj+iQk0kdkUECD6KY6iNknw==", "engines": { "node": ">=16" } }, "node_modules/@taquito/http-utils": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-17.1.0.tgz", - "integrity": "sha512-vkArbB7h9jMAf6apOERBoUYi/ARiBF5xuJunsPf/hECXz0kjaKGI7dKC6PsWJrvhfR/cACXKu4CAKG41WDNprw==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/http-utils/-/http-utils-17.1.1.tgz", + "integrity": "sha512-Bp0MifEqXHln9MWI6v/3rMNlO5N5mTpN+AbA/8uQeIKoDg3/H9yoxihg91TB1rhaG81PqyqxuF3OQ+/rvDmIxg==", "dependencies": { - "@taquito/core": "^17.1.0", + "@taquito/core": "^17.1.1", "axios": "0.26.0" }, "engines": { @@ -260,12 +277,12 @@ } }, "node_modules/@taquito/local-forging": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-17.1.0.tgz", - "integrity": "sha512-vKjjMDoVxgxbjYFhREaNtuI0OT6Jnty6+x+Tfzuk7alLf8zwDBvDXyXz+47WgFZb4Y3RtojRlnpIP4EhbtLnJQ==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/local-forging/-/local-forging-17.1.1.tgz", + "integrity": "sha512-CP5+24QNffvRh2SymYs0POZl001FdbwezEZBWnMdQkI3oKoOqmMYeTprhi/lYOb3oK7Y7kF0FBUhN2CfTt3Itw==", "dependencies": { - "@taquito/core": "^17.1.0", - "@taquito/utils": "^17.1.0", + "@taquito/core": "^17.1.1", + "@taquito/utils": "^17.1.1", "bignumber.js": "^9.1.0" }, "engines": { @@ -273,23 +290,23 @@ } }, "node_modules/@taquito/michel-codec": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-17.1.0.tgz", - "integrity": "sha512-PjXySJonM77a6uoEOJwGxcz0+1kckahsepMMkjDDdkNhLjTExnNLY5bDoNwzvKj3Ag53zhIWzGwNb4qls1C0XQ==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/michel-codec/-/michel-codec-17.1.1.tgz", + "integrity": "sha512-f21XWLa1PMovCgJTLo3jKUHdeonkeBt9JD6QFY5gIUi4uWdA6UYTst23P0YkIENmB4YXnO50wz/rrEjeyAhHeQ==", "dependencies": { - "@taquito/core": "^17.1.0" + "@taquito/core": "^17.1.1" }, "engines": { "node": ">=16" } }, "node_modules/@taquito/michelson-encoder": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-17.1.0.tgz", - "integrity": "sha512-1sYJp3QENlX2FoT/8poB+CcTH52S5RgIhVM4N0VOWR2MF8+y2SRVjMfrStfC9oDrH4jTt/ESQQFThcyw9XVEMg==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/michelson-encoder/-/michelson-encoder-17.1.1.tgz", + "integrity": "sha512-pQUJslapmOQorwLcy8wvaZIpq6I1taeva0avL9u3jo7aM3ZENozL1/BYPlCYA7jtEYvuuw2hCRqyxzg41HqWXw==", "dependencies": { - "@taquito/rpc": "^17.1.0", - "@taquito/utils": "^17.1.0", + "@taquito/rpc": "^17.1.1", + "@taquito/utils": "^17.1.1", "bignumber.js": "^9.1.0", "fast-json-stable-stringify": "^2.1.0" }, @@ -298,13 +315,13 @@ } }, "node_modules/@taquito/rpc": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-17.1.0.tgz", - "integrity": "sha512-/nzsGMxHbZOea4C9BnmXGaQVYwERNKF9IwFzdrBVTS7m+lfoRku9QfV88b3K77wXvcpZYSuXa1x4tJIXS8hHXw==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/rpc/-/rpc-17.1.1.tgz", + "integrity": "sha512-yJ2LZYc65GMk0XdOHFFIora7I1Q4XeYG/5oH8n8HoSQIeuwFhjSBGnrwWr5fQf503lKmjHyiuftziY4mkVumGg==", "dependencies": { - "@taquito/core": "^17.1.0", - "@taquito/http-utils": "^17.1.0", - "@taquito/utils": "^17.1.0", + "@taquito/core": "^17.1.1", + "@taquito/http-utils": "^17.1.1", + "@taquito/utils": "^17.1.1", "bignumber.js": "^9.1.0" }, "engines": { @@ -312,9 +329,9 @@ } }, "node_modules/@taquito/signer": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-17.1.0.tgz", - "integrity": "sha512-TuDUMcDEURlD8EFse4UtUr7M+XhZOFEIOug2aAsn4428DZngCPq968e3YOAu67VTOaEkWNp4ILvEj/p9lyB1gQ==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/signer/-/signer-17.1.1.tgz", + "integrity": "sha512-eeA/BCrFmqNGryw3BdjQxLoSpbV0SVf8UFiBXOsXSYdXI6leg/jQrn6KHSrAeM8nksoLnz0y9tDt0g4Q7gMAeA==", "dependencies": { "@stablelib/blake2b": "^1.0.1", "@stablelib/ed25519": "^1.0.3", @@ -322,8 +339,8 @@ "@stablelib/nacl": "^1.0.4", "@stablelib/pbkdf2": "^1.0.1", "@stablelib/sha512": "^1.0.1", - "@taquito/taquito": "^17.1.0", - "@taquito/utils": "^17.1.0", + "@taquito/taquito": "^17.1.1", + "@taquito/utils": "^17.1.1", "@types/bn.js": "^5.1.1", "bip39": "3.0.4", "elliptic": "^6.5.4", @@ -335,18 +352,18 @@ } }, "node_modules/@taquito/taquito": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-17.1.0.tgz", - "integrity": "sha512-hmIPgSun3sH40ay1xk4YHR37nhqhjIaRxACZLWkX5vr+N7amFKfPWxUJvI1mlTuT8GFQsVVQMtYMLMs8YOh04Q==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/taquito/-/taquito-17.1.1.tgz", + "integrity": "sha512-BjkjaoaXVdi92ImDfsh9jRpXTD/4NrFcaB4PcpPpfdtX/jIa2098MIH9Zdm/MdPmy9rtaZcHRej4B+BWJJ7JXg==", "hasInstallScript": true, "dependencies": { - "@taquito/core": "^17.1.0", - "@taquito/http-utils": "^17.1.0", - "@taquito/local-forging": "^17.1.0", - "@taquito/michel-codec": "^17.1.0", - "@taquito/michelson-encoder": "^17.1.0", - "@taquito/rpc": "^17.1.0", - "@taquito/utils": "^17.1.0", + "@taquito/core": "^17.1.1", + "@taquito/http-utils": "^17.1.1", + "@taquito/local-forging": "^17.1.1", + "@taquito/michel-codec": "^17.1.1", + "@taquito/michelson-encoder": "^17.1.1", + "@taquito/rpc": "^17.1.1", + "@taquito/utils": "^17.1.1", "bignumber.js": "^9.1.0", "rxjs": "^7.8.1" }, @@ -355,13 +372,13 @@ } }, "node_modules/@taquito/utils": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.1.0.tgz", - "integrity": "sha512-ob5Zth16vhyFq/RP5wr3t11M8jdnwMA1dmxNljVwwBuDW/qHgHr6lBS8hFOVe6ZTwf4DO+3lRYRHiaBaXS82Hw==", + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/@taquito/utils/-/utils-17.1.1.tgz", + "integrity": "sha512-KcK7Qa2+SCcevxSJixA3utDtlPYS5DGXpZdMlrAjwjozMiuDGSLM63D1CrW/ojYI0t3tPuErty10cPhURZ+d4A==", "dependencies": { "@stablelib/blake2b": "^1.0.1", "@stablelib/ed25519": "^1.0.3", - "@taquito/core": "^17.1.0", + "@taquito/core": "^17.1.1", "@types/bs58check": "^2.1.0", "bignumber.js": "^9.1.0", "blakejs": "^1.2.1", @@ -445,19 +462,10 @@ "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", "dev": true }, - "node_modules/@types/morgan": { - "version": "1.9.4", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", - "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/node": { - "version": "20.4.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz", - "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==" + "version": "20.4.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.6.tgz", + "integrity": "sha512-q0RkvNgMweWWIvSMDiXhflGUKMdIxBo2M2tYM/0kEGDueQByFzK4KZAgu5YHGFNxziTlppNpTIBcqHQAxlfHdA==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -492,6 +500,11 @@ "@types/node": "*" } }, + "node_modules/@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -528,6 +541,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -576,22 +594,6 @@ } ] }, - "node_modules/basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "dependencies": { - "safe-buffer": "5.1.2" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/basic-auth/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/bignumber.js": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", @@ -790,6 +792,46 @@ "node": ">=0.10.0" } }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.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==", + "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": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -927,6 +969,11 @@ "minimalistic-crypto-utils": "^1.0.1" } }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -1031,6 +1078,11 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1060,6 +1112,11 @@ "node": ">= 0.8" } }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, "node_modules/follow-redirects": { "version": "1.15.2", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", @@ -1299,6 +1356,11 @@ "node": ">= 0.10" } }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -1341,6 +1403,40 @@ "node": ">=0.12.0" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/logform": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "dependencies": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/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/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -1436,32 +1532,6 @@ "node": "*" } }, - "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "dependencies": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/morgan/node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -1561,12 +1631,12 @@ "node": ">= 0.8" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "engines": { - "node": ">= 0.8" + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" } }, "node_modules/parseurl": { @@ -1750,6 +1820,14 @@ } ] }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1842,6 +1920,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, "node_modules/simple-update-notifier": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", @@ -1854,6 +1940,14 @@ "node": ">=10" } }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -1882,6 +1976,11 @@ "node": ">=4" } }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1914,6 +2013,14 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, "node_modules/tslib": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", @@ -1998,6 +2105,40 @@ "node": ">= 0.8" } }, + "node_modules/winston": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz", + "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", diff --git a/package.json b/package.json index 1b254e9..a4d6379 100644 --- a/package.json +++ b/package.json @@ -20,19 +20,18 @@ }, "homepage": "https://github.com/oxheadalpha/tezos-testnet-faucet-backend#readme", "dependencies": { - "@taquito/signer": "^17.1.0", - "@taquito/taquito": "^17.1.0", + "@taquito/signer": "^17.1.1", + "@taquito/taquito": "^17.1.1", "axios": "^1.4.0", "body-parser": "^1.20.2", "dotenv": "^16.3.1", "express": "^4.18.2", - "morgan": "^1.10.0", - "redis": "^4.6.7" + "redis": "^4.6.7", + "winston": "^3.10.0" }, "devDependencies": { "@types/express": "^4.17.17", - "@types/morgan": "^1.9.4", - "@types/node": "^20.4.5", + "@types/node": "^20.4.6", "nodemon": "^3.0.1", "typescript": "^5.1.6" } From 3aa2f93574580483bb9521651b6bdf5412689c95 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 4 Aug 2023 17:15:10 -0400 Subject: [PATCH 31/64] Create winston http logger --- src/Tezos.ts | 3 +-- src/api.ts | 9 ++------- src/logging.ts | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 9 deletions(-) create mode 100644 src/logging.ts diff --git a/src/Tezos.ts b/src/Tezos.ts index a317885..020e8cf 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -84,8 +84,7 @@ export const send = async ( and the Tezos node ends up killing the long-lived connection. It isn't easy to configure Axios in Taquito to work around this. */ const operation = await Tezos.contract.transfer({ to: address, amount }) - console.log(`Sent ${amount} xtz to ${address}`) - console.log(`Hash: ${operation.hash}`) + console.log(`Sent ${amount} xtz to ${address}\nHash: ${operation.hash}`) return operation.hash } catch (err) { console.error(`Error sending Tez to ${address}.`) diff --git a/src/api.ts b/src/api.ts index c44d92f..f52e6c5 100644 --- a/src/api.ts +++ b/src/api.ts @@ -3,9 +3,9 @@ dotenv.config() import bodyParser from "body-parser" import express, { Express, Request, Response } from "express" -import morgan from "morgan" import { createClient } from "redis" +import { httpLogger } from "./logging" import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" import { MAX_BALANCE, @@ -30,8 +30,7 @@ export const redis = createClient({ const app: Express = express() app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) -app.use(morgan("dev")) - +app.use(httpLogger) app.use((_, res: Response, next) => { const cors = process.env.AUTHORIZED_HOST || "*" res.setHeader("Access-Control-Allow-Origin", cors) @@ -111,8 +110,6 @@ app.post("/challenge", async (req: Request, res: Response) => { }) } - console.log({ challenge, difficulty }) - return res.status(200).send({ status: "SUCCESS", challenge, @@ -171,8 +168,6 @@ app.post("/verify", async (req: Request, res: Response) => { solution, }) - console.log({ address, solution, nonce, challengeCounter }) - if (!isValidSolution) { return res .status(400) diff --git a/src/logging.ts b/src/logging.ts new file mode 100644 index 0000000..abb7de2 --- /dev/null +++ b/src/logging.ts @@ -0,0 +1,36 @@ +import { Request, Response, NextFunction } from "express" +import winston from "winston" + +const httpWinstonLogger = winston.createLogger({ + level: "http", + format: winston.format.combine( + winston.format.timestamp(), + winston.format.printf( + ({ + timestamp, + message: { method, url, status, responseTime, address }, + }) => + `${timestamp}: ${method?.padEnd(7)} ${url?.padEnd(10)} ${status} ${( + responseTime + "ms" + ).padEnd(5)} ${address}` + ) + ), + transports: [new winston.transports.Console()], +}) + +export const httpLogger = (req: Request, res: Response, next: NextFunction) => { + const start = Date.now() + res.on("finish", () => { + const responseTime = Date.now() - start + const logEntry = { + method: req.method, + url: req.originalUrl, + status: res.statusCode, + responseTime, + // Don't log an entire really long random string a user could send. + address: req?.body?.address?.slice(0, 36) || "-", + } + httpWinstonLogger.http(logEntry) + }) + next() +} From 9d54507902a591ac3236f4144dabb4bf5bfcb1cd Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 4 Aug 2023 17:50:11 -0400 Subject: [PATCH 32/64] Move 'USER node' to top of Dockerfile' --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 94a5542..4370bd6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,11 @@ FROM node:18-alpine +USER node + WORKDIR /tezos-faucet-backend RUN chown node:node /tezos-faucet-backend -USER node - COPY --chown=node:node package.json ./ COPY --chown=node:node package-lock.json ./ From 9f9826b45d49c691f87fcd7b110d8faf4d40dfd0 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 4 Aug 2023 18:10:32 -0400 Subject: [PATCH 33/64] Better logic when user has too much Tez --- src/Tezos.ts | 19 ++++++------------- src/api.ts | 13 +++++++++---- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Tezos.ts b/src/Tezos.ts index 020e8cf..09f3913 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -58,22 +58,15 @@ const Tezos = (() => { return TezToolkit })() -export const send = async ( +export const sendTez = async ( amount: number, address: string -): Promise => { +): Promise => { // Check max balance - try { - const userBalance = (await Tezos.tz.getBalance(address)).toNumber() - if (userBalance > MAX_BALANCE * 1000000) { - console.log( - `User balance too high (${userBalance / 1000000}), don't send` - ) - throw new Error("You have already enough ꜩ") - } - } catch (err) { - console.error(err) - throw new Error(`Error getting ${address} balance.`) + const userBalance = (await Tezos.tz.getBalance(address)).toNumber() + if (userBalance > MAX_BALANCE * 1000000) { + console.log(`${address} balance too high (${userBalance / 1000000}). Not sending.`) + return } // Create and send transaction diff --git a/src/api.ts b/src/api.ts index f52e6c5..9890fd6 100644 --- a/src/api.ts +++ b/src/api.ts @@ -10,7 +10,7 @@ import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" import { MAX_BALANCE, getTezAmountForProfile, - send, + sendTez, validateAddress, } from "./Tezos" import { @@ -196,9 +196,14 @@ app.post("/verify", async (req: Request, res: Response) => { throw e }) - // Here is where you would send the tez to the user's address - // For the sake of this example, we're just logging the address - const txHash = await send(amount, address) + const txHash = await sendTez(amount, address) + + if (!txHash) { + return res + .status(403) + .send({ status: "ERROR", message: "You have already enough ꜩ" }) + } + return res .status(200) .send({ txHash, status: "SUCCESS", message: "Tez sent" }) From 8bca1b1928cc5ed8013d53d18acf6000de654d3e Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 9 Aug 2023 08:30:00 -0400 Subject: [PATCH 34/64] Use ts 'satisfies' --- src/pow.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pow.ts b/src/pow.ts index 2a8ba47..92fb523 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -62,12 +62,12 @@ export const getChallenge = async ( if (!Object.keys(data).length) return null return { - ...data, + challenge: data.challenge, challengeCounter: Number(data.challengeCounter), challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", - } as ChallengeState + } satisfies ChallengeState as ChallengeState } const getSolution = (challenge: string, nonce: number) => From 0dc5840c95a868c96e6ba1d272710cef15a54f72 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 10 Aug 2023 14:54:07 -0400 Subject: [PATCH 35/64] Make sure challenge was deleted before sending Tez --- src/api.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/api.ts b/src/api.ts index 9890fd6..1ed7f61 100644 --- a/src/api.ts +++ b/src/api.ts @@ -190,12 +190,20 @@ app.post("/verify", async (req: Request, res: Response) => { } // The challenge should be deleted from redis before Tez is sent. If it - // failed to delete, the user could keep getting Tez with the same solution. - await redis.del(challengeKey).catch((e) => { + // failed to delete or was already deleted by another request, the user + // could keep getting Tez with the same solution. + const deletedCount = await redis.del(challengeKey).catch((e) => { console.error(`Redis failed to delete ${challengeKey}.`) throw e }) + if (deletedCount === 0) { + // Challenge was already used/deleted, so do not send Tez + return res + .status(403) + .send({ status: "ERROR", message: "PoW challenge not found" }) + } + const txHash = await sendTez(amount, address) if (!txHash) { From 8b61206524246d93671912ee83d1da6e0c1a957f Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 10 Aug 2023 16:31:28 -0400 Subject: [PATCH 36/64] Revamp readme and add .env.example --- .env.example | 15 +++++ README.md | 148 ++++++++++++++++++++++++------------------------- package.json | 4 +- src/logging.ts | 2 +- 4 files changed, 91 insertions(+), 78 deletions(-) create mode 100644 .env.example diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..deeb942 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +FAUCET_CAPTCHA_SECRET=6LefC8... +FAUCET_ADDRESS=tz1PW... +FAUCET_PRIVATE_KEY=edsk... + +RPC_URL=http://localhost:8732 + +REDIS_URL=redis://localhost:6379 +REDIS_PASSWORD=password + +ENABLE_CAPTCHA=true +AUTHORIZED_HOST="*" +API_PORT=3000 +FAUCET_AMOUNT_USER=1 +FAUCET_AMOUNT_BAKER=6000 +MAX_BALANCE=6000 diff --git a/README.md b/README.md index 20ea321..9b2543f 100644 --- a/README.md +++ b/README.md @@ -1,120 +1,118 @@ -# Tezos testnet faucet API +# Tezos Faucet Backend ## Overview -Backend for Tezos faucet front app: https://github.com/oxheadalpha/tezos-faucet. +The Tezos Faucet Backend (frontend code [here](https://github.com/oxheadalpha/tezos-faucet)) provides a reliable and secure way to distribute Tez to users. Through the implementation of a Proof of Work (PoW) mechanism, combined with CAPTCHA, we ensure users expend computational resources, thereby preventing bots and malicious actors from spamming and draining the faucet. -## Prerequisite +Here's a general flow of how it works: -Create a ReCaptcha project (shared with faucet front app). +1. **Requesting Tez**: A user initiates the process by making a request for tez. The backend responds by sending a challenge to the user. +2. **Solving Challenges**: The user must solve the challenge by finding a correct solution. The complexity of the challenge can vary, and the user doesn't know in advance how many challenges they'll need to solve. +3. **Verification & Receiving Tez**: Once the user submits a solution, the backend verifies it. If the solution is correct but there are more challenges to be solved, the user will be sent another challenge. This repeats until all challenges are solved correctly. Only then is the requested Tez granted to the user. +## Prerequisites -## Local run for development +- **Node.js** v18 +- **Captcha** (Optional): Create a Google [ReCaptcha](https://www.google.com/recaptcha/about/) project. The public site key will be shared with the frontend. Activate domain verification in ReCAPTCHA parameters to allow only communication from the frontend faucet app. +- **Redis**: Set up a Redis server to store PoW challenge data. It's recommended to use a single-instance Redis setup for the challenge data, as this ensures atomicity and helps in avoiding potential exploits. Given that the challenge data isn't persistent or long-term essential, a single instance suffices and is easier to maintain. -Compile Typescript sources to `/dist` directory: +## Config -``` -npm run build -``` +Set environment variables or add them to a `.env` file. See `.env.example`. -Run API with `nodemon`: -``` -npm run serve -``` +Mandatory: -## Deploy +- `FAUCET_PRIVATE_KEY`: Faucet's private key to sign transactions +- `FAUCET_ADDRESS`: Public address of the faucet +- `FAUCET_CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if `ENABLE_CAPTCHA=true`) +- `RPC_URL`: Tezos node RPC URL to connect to -### Build +Optional: -``` -docker build . -t tezos-faucet-backend -``` +- `ENABLE_CAPTCHA`: `true` to enable ReCAPTCHA, `false` otherwise (default: `true`) +- `AUTHORIZED_HOST`: CORS origin whitelist (default `'*'`) +- `API_PORT`: API listening port (default: `3000`) +- `FAUCET_AMOUNT_USER`: number of XTZ to send for the `USER` profile (default: 1) +- `FAUCET_AMOUNT_BAKER`: number of XTZ to send for the `BAKER` profile (default: 6000) +- `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: 6000) -### Run +## Running the API + +Install dependencies and compile Typescript sources to `/dist` directory: ``` -docker run -p 3000:3000 tezos-faucet-backend +npm install +npm run build ``` -## Config - -Set environment variables - -Mandatory: - -- `FAUCET_PRIVATE_KEY`: private key of the faucet, to sign transaction -- `FAUCET_ADDRESS`: faucet address -- `FAUCET_CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if ENABLE_CAPTCHA=true) -- `RPC_URL`: Tezos node RPC URL to connect to - -Optional: +Run API: -- `ENABLE_CAPTCHA`: true to enable ReCAPTCHA, false otherwise (default: true) -- `AUTHORIZED_HOST`: authorized host, for CORS (default: *). -- `API_PORT`: API listening port (default: 3000) -- `FAUCET_AMOUNT_USER`: number of XTZ to send for a regular request (default: 1) -- `FAUCET_AMOUNT_BAKER`: number of XTZ to send for a baker request (default: 6000) -- `MAX_BALANCE`: maximum user balance beyond which sending of XTZ is refused (default: 6000) +``` +npm run start +``` -## Security +For developing with auto reloading: -Activate domain verification in ReCAPTCHA parameters to allow only calls from the Front faucet. +``` +npm run dev +``` -## Use +## Docker -### Request +### Build -Request URL: ``` -POST /send +docker build . -t tezos-faucet-backend ``` -Request body: +### Run + ``` -{ - captchaToken:"...", - address:"tz1...", - profile:"USER" -} +docker run -p 3000:3000 tezos-faucet-backend ``` -- `token`: ReCaptcha user response token -- `address`: address to send XTZ to -- `profile`: USER for a regular user who will get 1 xtz. BAKER for a baker profile, who will get 6000 xtz. +## API Endpoints -### Response +### GET /info -#### Success +Returns general information about the faucet, including the faucet's address, whether captcha is enabled, the max balance allowed, and the Tez amounts granted per profile. -Return code: HTTP 200 +Example response: -Response body: -``` +```json { - "status": "SUCCESS", - "txHash":"..." + "faucetAddress": "tz1...", + "captchaEnabled": true, + "maxBalance": 6000, + "profiles": { + "user": { + "profile": "USER", + "amount": 1, + "currency": "tez" + }, + "baker": { + "profile": "BAKER", + "amount": 6000, + "currency": "tez" + } + } } ``` -- `status`: SUCCESS -- `txHash`: hash of transaction +### POST /challenge +Initiates the Tez request procedure. The user provides their address, profile type (`BAKER` or `USER`), and captcha token (optional). -#### Error +If a challenge already exists for the user's address in Redis it will be returned in the response. Otherwise the endpoint generates a new challenge and stores it, along with associated data in Redis. -Return code: +The response contains the challenge string, a challenge counter starting at 1, and the difficulty. The challenge counter indicates the current challenge in a series of Proof of Work challenges that the user must complete. Users aren't privy in advance to the exact number of PoW challenges they'll need to solve to receive the requested Tez. -- HTTP 400: Bad request (wrong captcha token) -- HTTP 500: Server or Tezos node error +### POST /verify +Allows users to submit solutions to the challenges. The user provides their address, nonce, solution string, and profile type. -Response body: -``` -{ - "status": "ERROR", - "message": "Captcha error" -} -``` +The endpoint verifies the solution by trying to regenerate it using the challenge string and nonce. + +If the solution is correct but the required number of challenges have not yet been satisfied, a new challenge is generated and returned in the response. -- `status`: ERROR -- `message`: error message +If all challenges have been completed, the user's address is granted the Tez amount for their profile type. The transaction hash is returned to indicate the transfer was successful. diff --git a/package.json b/package.json index a4d6379..1a97498 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "dist/api.js", "scripts": { "build": "npx tsc", - "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run serve\"", - "serve": "node dist/api.js", + "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run start\"", + "start": "node dist/api.js", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { diff --git a/src/logging.ts b/src/logging.ts index abb7de2..7bdd84f 100644 --- a/src/logging.ts +++ b/src/logging.ts @@ -10,7 +10,7 @@ const httpWinstonLogger = winston.createLogger({ timestamp, message: { method, url, status, responseTime, address }, }) => - `${timestamp}: ${method?.padEnd(7)} ${url?.padEnd(10)} ${status} ${( + `${timestamp} ${method?.padEnd(7)} ${url?.padEnd(10)} ${status} ${( responseTime + "ms" ).padEnd(5)} ${address}` ) From 809532a55f3feeddc6ca2403ed52562aaf089a4b Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 10 Aug 2023 23:15:38 -0400 Subject: [PATCH 37/64] Add graceful shutdown handler + update .dockerignore --- .dockerignore | 10 +++++++++- src/api.ts | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.dockerignore b/.dockerignore index 8e40c7e..e5fa5f0 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,13 @@ +.dockerignore +.DS_Store +.env* +.git +.github .gitignore +.vscode +dist +Dockerfile LICENSE.md node_modules +npm-debug.log README.md -Dockerignore diff --git a/src/api.ts b/src/api.ts index 1ed7f61..461abeb 100644 --- a/src/api.ts +++ b/src/api.ts @@ -25,7 +25,9 @@ import { InfoResponseBody, Profile } from "./Types" export const redis = createClient({ url: process.env.REDIS_URL, password: process.env.REDIS_PASSWORD, -}).on("error", (err: any) => console.log("Redis Client Error:", err)) +}) + .on("connect", () => console.log("Connected to redis.")) + .on("error", (err: any) => console.error("Redis Client Error:", err)) const app: Express = express() app.use(bodyParser.json()) @@ -192,9 +194,9 @@ app.post("/verify", async (req: Request, res: Response) => { // The challenge should be deleted from redis before Tez is sent. If it // failed to delete or was already deleted by another request, the user // could keep getting Tez with the same solution. - const deletedCount = await redis.del(challengeKey).catch((e) => { + const deletedCount = await redis.del(challengeKey).catch((err) => { console.error(`Redis failed to delete ${challengeKey}.`) - throw e + throw err }) if (deletedCount === 0) { @@ -223,13 +225,31 @@ app.post("/verify", async (req: Request, res: Response) => { } }) -const port = process.env.API_PORT || 3000 - +// Connect to redis, start server, and setup listeners for graceful shutdown. ;(async () => { await redis.connect() - console.log("Connected to redis.") - app.listen(port, () => { + const port = process.env.API_PORT || 3000 + const server = app.listen(port, () => console.log(`Listening on port ${port}.`) - }) + ) + + const gracefulShutdown = async (signal: string) => { + console.log(`${signal} signal received`) + + try { + await redis.quit() + console.log("Redis connection closed.") + } catch (err) { + console.error("Error closing Redis connection:", err) + } + + server.close(() => { + console.log("HTTP server closed.") + process.exit(0) + }) + } + + process.on("SIGINT", () => gracefulShutdown("SIGINT")) + process.on("SIGTERM", () => gracefulShutdown("SIGTERM")) })() From 321e430f98bd906149ea660a6023e3b20d5733d1 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 10 Aug 2023 23:51:25 -0400 Subject: [PATCH 38/64] Better env var names --- .env.example | 21 ++++++++++++--------- README.md | 6 +++--- src/Captcha.ts | 2 +- src/Tezos.ts | 12 ++++++------ src/environment.d.ts | 6 +++--- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.env.example b/.env.example index deeb942..b3ea98d 100644 --- a/.env.example +++ b/.env.example @@ -1,15 +1,18 @@ -FAUCET_CAPTCHA_SECRET=6LefC8... +API_PORT=3000 + +AUTHORIZED_HOST="*" + +ENABLE_CAPTCHA=true +CAPTCHA_SECRET=6LefC8... + FAUCET_ADDRESS=tz1PW... FAUCET_PRIVATE_KEY=edsk... -RPC_URL=http://localhost:8732 +BAKER_PROFILE_AMOUNT=6000 +USER_PROFILE_AMOUNT=1 +MAX_BALANCE=6000 -REDIS_URL=redis://localhost:6379 REDIS_PASSWORD=password +REDIS_URL=redis://localhost:6379 -ENABLE_CAPTCHA=true -AUTHORIZED_HOST="*" -API_PORT=3000 -FAUCET_AMOUNT_USER=1 -FAUCET_AMOUNT_BAKER=6000 -MAX_BALANCE=6000 +RPC_URL=http://localhost:8732 diff --git a/README.md b/README.md index 9b2543f..6e34d56 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Mandatory: - `FAUCET_PRIVATE_KEY`: Faucet's private key to sign transactions - `FAUCET_ADDRESS`: Public address of the faucet -- `FAUCET_CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if `ENABLE_CAPTCHA=true`) +- `CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if `ENABLE_CAPTCHA=true`) - `RPC_URL`: Tezos node RPC URL to connect to Optional: @@ -32,8 +32,8 @@ Optional: - `ENABLE_CAPTCHA`: `true` to enable ReCAPTCHA, `false` otherwise (default: `true`) - `AUTHORIZED_HOST`: CORS origin whitelist (default `'*'`) - `API_PORT`: API listening port (default: `3000`) -- `FAUCET_AMOUNT_USER`: number of XTZ to send for the `USER` profile (default: 1) -- `FAUCET_AMOUNT_BAKER`: number of XTZ to send for the `BAKER` profile (default: 6000) +- `USER_PROFILE_AMOUNT`: number of XTZ to send for the `USER` profile (default: 1) +- `BAKER_PROFILE_AMOUNT`: number of XTZ to send for the `BAKER` profile (default: 6000) - `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: 6000) ## Running the API diff --git a/src/Captcha.ts b/src/Captcha.ts index 917c29b..0f2a238 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -22,7 +22,7 @@ export const validateCaptcha = async (res: Response, captchaToken: string) => { {}, { params: { - secret: process.env.FAUCET_CAPTCHA_SECRET, + secret: process.env.CAPTCHA_SECRET, response: captchaToken, }, } diff --git a/src/Tezos.ts b/src/Tezos.ts index 09f3913..a094262 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -5,12 +5,12 @@ import { Response } from "express" import { Profile } from "./Types" const defaultUserAmount = 1 -export const FAUCET_AMOUNT_USER = - Number(process.env.FAUCET_AMOUNT_USER) || defaultUserAmount +export const USER_PROFILE_AMOUNT = + Number(process.env.USER_PROFILE_AMOUNT) || defaultUserAmount const defaultBakerAmount = 6000 -export const FAUCET_AMOUNT_BAKER = - Number(process.env.FAUCET_AMOUNT_BAKER) || defaultBakerAmount +export const BAKER_PROFILE_AMOUNT = + Number(process.env.BAKER_PROFILE_AMOUNT) || defaultBakerAmount const defaultMaxBalance = 6000 export const MAX_BALANCE = Number(process.env.MAX_BALANCE) || defaultMaxBalance @@ -18,9 +18,9 @@ export const MAX_BALANCE = Number(process.env.MAX_BALANCE) || defaultMaxBalance export const getTezAmountForProfile = (profile: Profile) => { switch (profile.toUpperCase()) { case Profile.USER: - return FAUCET_AMOUNT_USER + return USER_PROFILE_AMOUNT case Profile.BAKER: - return FAUCET_AMOUNT_BAKER + return BAKER_PROFILE_AMOUNT default: throw new Error(`Unknown profile '${profile}'`) } diff --git a/src/environment.d.ts b/src/environment.d.ts index c08e22f..523c783 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -5,9 +5,9 @@ declare global { AUTHORIZED_HOST: string ENABLE_CAPTCHA: string FAUCET_ADDRESS: string - FAUCET_AMOUNT_BAKER: string - FAUCET_AMOUNT_USER: string - FAUCET_CAPTCHA_SECRET: string + BAKER_PROFILE_AMOUNT: string + USER_PROFILE_AMOUNT: string + CAPTCHA_SECRET: string FAUCET_PRIVATE_KEY: string MAX_BALANCE: string REDIS_PASSWORD: string From 42364feb8b4b28827cd78c059e35c0f6baa26f51 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 13:31:31 -0400 Subject: [PATCH 39/64] aider: Add profile to challenge state data in Redis and modify create and verify challenge functions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Aider chat conversation: USER: as part of the challenge state data stored in redis, please add which profile was used for the challenge. ASSISTANT: ^C KeyboardInterrupt USER: as part of the challenge state data stored in redis, please add which profile was used for the challenge. ASSISTANT: To add the profile to the challenge state data stored in Redis, we need to modify the `ChallengeState` interface and the functions that create and retrieve the challenge state. Please add the following files to the chat so I can propose changes: - `src/pow.ts` - `src/api.ts` USER: I added these *read-write* files: src/api.ts, src/pow.ts ASSISTANT: Great, let's proceed with the changes. First, we need to modify the `ChallengeState` interface in `src/pow.ts` to include a `profile` property. ```typescript src/pow.ts <<<<<<< HEAD interface ChallengeState { challenge: string challengeCounter: number challengesNeeded: number difficulty: number usedCaptcha: boolean } ======= interface ChallengeState { challenge: string challengeCounter: number challengesNeeded: number difficulty: number usedCaptcha: boolean profile: string } >>>>>>> updated ``` Next, we need to modify the `saveChallenge` function in `src/pow.ts` to save the `profile` as part of the challenge state. ```typescript src/pow.ts <<<<<<< HEAD type SaveChallengeArgs = Omit & { usedCaptcha?: boolean expiration?: number } export const saveChallenge = async ( challengeKey: string, { usedCaptcha, expiration = 1800, // 30m ...args }: SaveChallengeArgs ) => { await redis.hSet(challengeKey, { ...args, ...(typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }), }) await redis.expire(challengeKey, expiration) } ======= type SaveChallengeArgs = Omit & { usedCaptcha?: boolean expiration?: number profile: string } export const saveChallenge = async ( challengeKey: string, { usedCaptcha, expiration = 1800, // 30m profile, ...args }: SaveChallengeArgs ) => { await redis.hSet(challengeKey, { ...args, profile, ...(typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }), }) await redis.expire(challengeKey, expiration) } >>>>>>> updated ``` Then, we need to modify the `getChallenge` function in `src/pow.ts` to retrieve the `profile` from the challenge state. ```typescript src/pow.ts <<<<<<< HEAD export const getChallenge = async ( challengeKey: string ): Promise => { const data = await redis.hGetAll(challengeKey) if (!Object.keys(data).length) return null return { challenge: data.challenge, challengeCounter: Number(data.challengeCounter), challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", } satisfies ChallengeState as ChallengeState } ======= export const getChallenge = async ( challengeKey: string ): Promise => { const data = await redis.hGetAll(challengeKey) if (!Object.keys(data).length) return null return { challenge: data.challenge, challengeCounter: Number(data.challengeCounter), challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", profile: data.profile, } satisfies ChallengeState as ChallengeState } >>>>>>> updated ``` Finally, we need to modify the `/challenge` and `/verify` endpoints in `src/api.ts` to include the `profile` when creating and verifying the challenge. ```typescript src/api.ts <<<<<<< HEAD app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body // ... existing code ... await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, }) // ... existing code ... }) app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body // ... existing code ... await saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, ...resData, }) // ... existing code ... }) ======= app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body // ... existing code ... await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, profile, }) // ... existing code ... }) app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body // ... existing code ... await saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, profile, ...resData, }) // ... existing code ... }) >>>>>>> updated ``` These changes will add the `profile` to the challenge state data stored in Redis and ensure it is used when creating and verifying the challenge. USER: InvalidEditBlock: edit failed! src/api.ts does not contain the *exact sequence* of HEAD lines you specified. Try again. DO NOT skip blank lines, comments, docstrings, etc! The HEAD block needs to be EXACTLY the same as the lines in src/api.ts with nothing missing! src/api.ts does not contain these 28 exact lines in a row: ``` app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body // ... existing code ... await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, }) // ... existing code ... }) app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body // ... existing code ... await saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, ...resData, }) // ... existing code ... }) ``` ASSISTANT: I apologize for the confusion. I used placeholders in the HEAD section, which is not allowed. Let's correct this. First, let's modify the `/challenge` endpoint in `src/api.ts` to include the `profile` when creating the challenge. ```typescript src/api.ts <<<<<<< HEAD app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body if (!address || !profile) { return res.status(400).send({ satus: "ERROR", message: "'address' and 'profile' fields are required", }) } if (!validateAddress(res, address)) return if (captchaToken && !(await validateCaptcha(res, captchaToken))) return try { getTezAmountForProfile(profile) } catch (e: any) { return res.status(400).send({ status: "ERROR", message: e.message }) } try { const challengeKey = getChallengeKey(address) let { challenge, challengesNeeded, challengeCounter, difficulty } = (await getChallenge(challengeKey)) || {} if (!challenge) { // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, }) } return res.status(200).send({ status: "SUCCESS", challenge, challengeCounter, difficulty, }) } catch (err: any) { const message = "Error getting challenge" console.error(message, err) return res.status(500).send({ status: "ERROR", message }) } }) ======= app.post("/challenge", async (req: Request, res: Response) => { const { address, captchaToken, profile } = req.body if (!address || !profile) { return res.status(400).send({ satus: "ERROR", message: "'address' and 'profile' fields are required", }) } if (!validateAddress(res, address)) return if (captchaToken && !(await validateCaptcha(res, captchaToken))) return try { getTezAmountForProfile(profile) } catch (e: any) { return res.status(400).send({ status: "ERROR", message: e.message }) } try { const challengeKey = getChallengeKey(address) let { challenge, challengesNeeded, challengeCounter, difficulty } = (await getChallenge(challengeKey)) || {} if (!challenge) { // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, profile, }) } return res.status(200).send({ status: "SUCCESS", challenge, challengeCounter, difficulty, }) } catch (err: any) { const message = "Error getting challenge" console.error(message, err) return res.status(500).send({ status: "ERROR", message }) } }) >>>>>>> updated ``` Next, let's modify the `/verify` endpoint in `src/api.ts` to include the `profile` when verifying the challenge. ```typescript src/api.ts <<<<<<< HEAD app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body if (!address || !solution || !nonce || !profile) { return res.status(400).send({ status: "ERROR", message: "'address', 'solution', 'nonce', and 'profile' fields are required", }) } if (!validateAddress(res, address)) return let amount try { amount = getTezAmountForProfile(profile) } catch (e: any) { return res.status(400).send({ status: "ERROR", message: e.message }) } try { const challengeKey = getChallengeKey(address) const redisChallenge = await getChallenge(challengeKey) if (!redisChallenge) { return res .status(400) .send({ status: "ERROR", message: "No challenge found" }) } const { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, } = redisChallenge const isValidSolution = verifySolution({ challenge, difficulty, nonce, solution, }) if (!isValidSolution) { return res .status(400) .send({ status: "ERROR", message: "Incorrect solution" }) } if (challengeCounter < challengesNeeded) { const newChallenge = createChallenge(usedCaptcha) const resData = { challenge: newChallenge.challenge, challengeCounter: challengeCounter + 1, difficulty: newChallenge.difficulty, } await saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, ...resData, }) return res.status(200).send({ status: "SUCCESS", ...resData }) } // The challenge should be deleted from redis before Tez is sent. If it // failed to delete or was already deleted by another request, the user // could keep getting Tez with the same solution. const deletedCount = await redis.del(challengeKey).catch((err) => { console.error(`Redis failed to delete ${challengeKey}.`) throw err }) if (deletedCount === 0) { // Challenge was already used/deleted, so do not send Tez return res .status(403) .send({ status: "ERROR", message: "PoW challenge not found" }) } const txHash = await sendTez(amount, address) if (!txHash) { return res .status(403) .send({ status: "ERROR", message: "You have already enough ꜩ" }) } return res .status(200) .send({ txHash, status: "SUCCESS", message: "Tez sent" }) } catch (err: any) { console.error(err) return res .status(500) .send({ status: "ERROR", message: "An error occurred" }) } }) ======= app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body if (!address || !solution || !nonce || !profile) { return res.status(400).send({ status: "ERROR", message: "'address', 'solution', 'nonce', and 'profile' fields are required", }) } if (!validateAddress(res, address)) return let amount try { amount = getTezAmountForProfile(profile) } catch (e: any) { return res.status(400).send({ status: "ERROR", message: e.message }) } try { const challengeKey = getChallengeKey(address) const redisChallenge = await getChallenge(challengeKey) if (!redisChallenge) { return res .status(400) .send({ status: "ERROR", message: "No challenge found" }) } const { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, } = redisChallenge const isValidSolution = verifySolution({ challenge, difficulty, nonce, solution, }) if (!isValidSolution) { return res .status(400) .send({ status: "ERROR", message: "Incorrect solution" }) } if (challengeCounter < challengesNeeded) { const newChallenge = createChallenge(usedCaptcha) const resData = { challenge: newChallenge.challenge, challengeCounter: challengeCounter + 1, difficulty: newChallenge.difficulty, } await saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, profile, ...resData, }) return res.status(200).send({ status: "SUCCESS", ...resData }) } // The challenge should be deleted from redis before Tez is sent. If it // failed to delete or was already deleted by another request, the user // could keep getting Tez with the same solution. const deletedCount = await redis.del(challengeKey).catch((err) => { console.error(`Redis failed to delete ${challengeKey}.`) throw err }) if (deletedCount === 0) { // Challenge was already used/deleted, so do not send Tez return res .status(403) .send({ status: "ERROR", message: "PoW challenge not found" }) } const txHash = await sendTez(amount, address) if (!txHash) { return res .status(403) .send({ status: "ERROR", message: "You have already enough ꜩ" }) } return res .status(200) .send({ txHash, status: "SUCCESS", message: "Tez sent" }) } catch (err: any) { console.error(err) return res .status(500) .send({ status: "ERROR", message: "An error occurred" }) } }) >>>>>>> updated ``` These changes will ensure the `profile` is included when creating and verifying the challenge. --- src/api.ts | 2 ++ src/pow.ts | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/api.ts b/src/api.ts index 461abeb..21cee1a 100644 --- a/src/api.ts +++ b/src/api.ts @@ -109,6 +109,7 @@ app.post("/challenge", async (req: Request, res: Response) => { challengeCounter, difficulty, usedCaptcha, + profile, }) } @@ -186,6 +187,7 @@ app.post("/verify", async (req: Request, res: Response) => { await saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, + profile, ...resData, }) return res.status(200).send({ status: "SUCCESS", ...resData }) diff --git a/src/pow.ts b/src/pow.ts index 92fb523..ad2d3be 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -30,11 +30,13 @@ interface ChallengeState { challengesNeeded: number difficulty: number usedCaptcha: boolean + profile: string } type SaveChallengeArgs = Omit & { usedCaptcha?: boolean expiration?: number + profile: string } export const saveChallenge = async ( @@ -42,11 +44,13 @@ export const saveChallenge = async ( { usedCaptcha, expiration = 1800, // 30m + profile, ...args }: SaveChallengeArgs ) => { await redis.hSet(challengeKey, { ...args, + profile, ...(typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }), @@ -67,6 +71,7 @@ export const getChallenge = async ( challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", + profile: data.profile, } satisfies ChallengeState as ChallengeState } From e283f316fcc7787d257b544382018ce7e013e7fa Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 13:39:25 -0400 Subject: [PATCH 40/64] aider: Ensure that if a user requests a challenge with a different profile before the previous challenge is completely solved, they will have to start over from scratch solving challenges for the new profile. # Aider chat conversation: USER: I did `git reset --hard HEAD~1` to discard the last edits. ASSISTANT: Ok. USER: I added these *read-write* files: src/Tezos.ts ASSISTANT: Ok. USER: ensure that if a user requests a challenge with a different profile before the previous challenge is completely solved, they will have to start over from scratch solving challenges for the new profile. ASSISTANT: To implement this, we need to modify the `/challenge` endpoint in the `src/api.ts` file. When a new challenge is requested, we should check if the profile in the request matches the profile in the existing challenge state. If they don't match, we should create a new challenge state for the new profile. Here are the steps to implement this: 1. In the `/challenge` endpoint, after retrieving the existing challenge state, check if the profile in the request matches the profile in the challenge state. 2. If they don't match, create a new challenge state for the new profile. Here is the *edit block* for the `src/api.ts` file: ```typescript src/api.ts <<<<<<< HEAD if (!challenge) { // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, profile, }) } ======= // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken const existingProfile = (await getChallenge(challengeKey))?.profile if (!challenge || profile !== existingProfile) { ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 await saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, difficulty, usedCaptcha, profile, }) } >>>>>>> updated ``` This change ensures that if a user requests a challenge with a different profile before the previous challenge is completely solved, they will have to start over from scratch solving challenges for the new profile. --- src/api.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/api.ts b/src/api.ts index 21cee1a..e8a1eae 100644 --- a/src/api.ts +++ b/src/api.ts @@ -97,9 +97,10 @@ app.post("/challenge", async (req: Request, res: Response) => { let { challenge, challengesNeeded, challengeCounter, difficulty } = (await getChallenge(challengeKey)) || {} - if (!challenge) { - // If a captcha was sent it was validated above. - const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken + // If a captcha was sent it was validated above. + const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken + const existingProfile = (await getChallenge(challengeKey))?.profile + if (!challenge || profile !== existingProfile) { ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 From 608986fc281afd154b97dc53e4e676a4ab7fe904 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 13:45:55 -0400 Subject: [PATCH 41/64] Fix aider code --- src/api.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/api.ts b/src/api.ts index e8a1eae..c6dcf66 100644 --- a/src/api.ts +++ b/src/api.ts @@ -94,13 +94,18 @@ app.post("/challenge", async (req: Request, res: Response) => { try { const challengeKey = getChallengeKey(address) - let { challenge, challengesNeeded, challengeCounter, difficulty } = - (await getChallenge(challengeKey)) || {} + let { + challenge, + challengesNeeded, + challengeCounter, + difficulty, + profile: existingProfile, + } = (await getChallenge(challengeKey)) || {} - // If a captcha was sent it was validated above. - const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken - const existingProfile = (await getChallenge(challengeKey))?.profile + // If no challenge exists or the profile has changed, start a new challenge. if (!challenge || profile !== existingProfile) { + // If a captcha was sent it was validated above. + const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge(usedCaptcha)) challengeCounter = 1 From 13caf90acf5eb6f1655b9547e487e8717973be9d Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 13:52:36 -0400 Subject: [PATCH 42/64] Add profile to httpLogger --- src/logging.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/logging.ts b/src/logging.ts index 7bdd84f..7614a1d 100644 --- a/src/logging.ts +++ b/src/logging.ts @@ -8,11 +8,11 @@ const httpWinstonLogger = winston.createLogger({ winston.format.printf( ({ timestamp, - message: { method, url, status, responseTime, address }, + message: { method, url, status, responseTime, address, profile }, }) => `${timestamp} ${method?.padEnd(7)} ${url?.padEnd(10)} ${status} ${( responseTime + "ms" - ).padEnd(5)} ${address}` + ).padEnd(5)} ${address} ${profile.toUpperCase()}` ) ), transports: [new winston.transports.Console()], @@ -29,6 +29,7 @@ export const httpLogger = (req: Request, res: Response, next: NextFunction) => { responseTime, // Don't log an entire really long random string a user could send. address: req?.body?.address?.slice(0, 36) || "-", + profile: req?.body?.profile?.slice(0, 5) || "-", } httpWinstonLogger.http(logEntry) }) From 606785c2e7cc1e442c5521903f4cc3e890f84cda Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 14:51:01 -0400 Subject: [PATCH 43/64] Make code that sends Tez DRY --- src/Tezos.ts | 24 ++++++++++++++++++++++-- src/api.ts | 18 ++++++------------ 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Tezos.ts b/src/Tezos.ts index a094262..42ea91a 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -58,14 +58,16 @@ const Tezos = (() => { return TezToolkit })() -export const sendTez = async ( +const sendTez = async ( amount: number, address: string ): Promise => { // Check max balance const userBalance = (await Tezos.tz.getBalance(address)).toNumber() if (userBalance > MAX_BALANCE * 1000000) { - console.log(`${address} balance too high (${userBalance / 1000000}). Not sending.`) + console.log( + `${address} balance too high (${userBalance / 1000000}). Not sending.` + ) return } @@ -84,3 +86,21 @@ export const sendTez = async ( throw err } } + +export const sendTezAndRespond = async ( + res: Response, + amount: number, + address: string +) => { + const txHash = await sendTez(amount, address) + + if (!txHash) { + return res + .status(403) + .send({ status: "ERROR", message: "You have already enough ꜩ" }) + } + + return res + .status(200) + .send({ txHash, status: "SUCCESS", message: "Tez sent" }) +} diff --git a/src/api.ts b/src/api.ts index c6dcf66..1e7ef6f 100644 --- a/src/api.ts +++ b/src/api.ts @@ -10,7 +10,7 @@ import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" import { MAX_BALANCE, getTezAmountForProfile, - sendTez, + sendTezAndRespond, validateAddress, } from "./Tezos" import { @@ -153,6 +153,10 @@ app.post("/verify", async (req: Request, res: Response) => { return res.status(400).send({ status: "ERROR", message: e.message }) } + if (process.env.DISABLE_CHALLENGES === "true") { + return sendTezAndRespond(res, amount, address) + } + try { const challengeKey = getChallengeKey(address) const redisChallenge = await getChallenge(challengeKey) @@ -214,17 +218,7 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "PoW challenge not found" }) } - const txHash = await sendTez(amount, address) - - if (!txHash) { - return res - .status(403) - .send({ status: "ERROR", message: "You have already enough ꜩ" }) - } - - return res - .status(200) - .send({ txHash, status: "SUCCESS", message: "Tez sent" }) + return sendTezAndRespond(res, amount, address) } catch (err: any) { console.error(err) return res From a222bd217a2a40268a78b343f2fa59d981c7b894 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 14:55:27 -0400 Subject: [PATCH 44/64] Add ability to disable needing to solve challenges --- .env.example | 2 ++ src/api.ts | 24 ++++++++++++++++++++---- src/environment.d.ts | 2 ++ src/pow.ts | 2 ++ 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index b3ea98d..3807d56 100644 --- a/.env.example +++ b/.env.example @@ -16,3 +16,5 @@ REDIS_PASSWORD=password REDIS_URL=redis://localhost:6379 RPC_URL=http://localhost:8732 + +DISABLE_CHALLENGES=false diff --git a/src/api.ts b/src/api.ts index 1e7ef6f..d02e284 100644 --- a/src/api.ts +++ b/src/api.ts @@ -14,6 +14,7 @@ import { validateAddress, } from "./Tezos" import { + DISABLE_CHALLENGES, createChallenge, getChallengeKey, saveChallenge, @@ -74,6 +75,15 @@ app.get("/info", (_, res: Response) => { }) app.post("/challenge", async (req: Request, res: Response) => { + if (DISABLE_CHALLENGES) { + return res + .status(200) + .send({ + status: "SUCCESS", + message: "Challenges are disabled. Use the /verify endpoint.", + }) + } + const { address, captchaToken, profile } = req.body if (!address || !profile) { @@ -135,11 +145,17 @@ app.post("/challenge", async (req: Request, res: Response) => { app.post("/verify", async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body - if (!address || !solution || !nonce || !profile) { + if (!address || !profile) { + return res.status(400).send({ + status: "ERROR", + message: "'address' and 'profile' fields are required", + }) + } + + if (!DISABLE_CHALLENGES && (!solution || !nonce)) { return res.status(400).send({ status: "ERROR", - message: - "'address', 'solution', 'nonce', and 'profile' fields are required", + message: "'solution', and 'nonce', fields are required", }) } @@ -153,7 +169,7 @@ app.post("/verify", async (req: Request, res: Response) => { return res.status(400).send({ status: "ERROR", message: e.message }) } - if (process.env.DISABLE_CHALLENGES === "true") { + if (DISABLE_CHALLENGES) { return sendTezAndRespond(res, amount, address) } diff --git a/src/environment.d.ts b/src/environment.d.ts index 523c783..bc8973e 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -3,6 +3,7 @@ declare global { interface ProcessEnv { API_PORT: string AUTHORIZED_HOST: string + DISABLE_CHALLENGES: string ENABLE_CAPTCHA: string FAUCET_ADDRESS: string BAKER_PROFILE_AMOUNT: string @@ -13,6 +14,7 @@ declare global { REDIS_PASSWORD: string REDIS_URL: string RPC_URL: string + DISABLE_CHALLENGES: string } } } diff --git a/src/pow.ts b/src/pow.ts index ad2d3be..66a42f6 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -1,6 +1,8 @@ import { createHash, randomBytes } from "crypto" import { redis } from "./api" +export const DISABLE_CHALLENGES = process.env.DISABLE_CHALLENGES === 'true' + export const getChallengeKey = (address: string): string => `address:${address}` // TODO: Implement From eec6ae3a84bfca738e3f83aefca3930a689cdf5c Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 15:50:21 -0400 Subject: [PATCH 45/64] WIP per profile configuration of challenges --- src/Tezos.ts | 6 +++--- src/Types.ts | 8 ++++---- src/api.ts | 28 ++++++++++++++-------------- src/pow.ts | 26 ++++++++++++++------------ 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/Tezos.ts b/src/Tezos.ts index 42ea91a..a4e76cd 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -2,7 +2,7 @@ import { InMemorySigner } from "@taquito/signer" import { TezosToolkit } from "@taquito/taquito" import { validateKeyHash } from "@taquito/utils" import { Response } from "express" -import { Profile } from "./Types" +import { Profile, Profiles } from "./Types" const defaultUserAmount = 1 export const USER_PROFILE_AMOUNT = @@ -17,9 +17,9 @@ export const MAX_BALANCE = Number(process.env.MAX_BALANCE) || defaultMaxBalance export const getTezAmountForProfile = (profile: Profile) => { switch (profile.toUpperCase()) { - case Profile.USER: + case Profiles.USER: return USER_PROFILE_AMOUNT - case Profile.BAKER: + case Profiles.BAKER: return BAKER_PROFILE_AMOUNT default: throw new Error(`Unknown profile '${profile}'`) diff --git a/src/Types.ts b/src/Types.ts index e1761bf..9b09ebd 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -1,7 +1,7 @@ -export enum Profile { - USER = "USER", - BAKER = "BAKER", -} +export const USER = "USER" +export const BAKER = "BAKER" +export type Profile = typeof USER | typeof BAKER +export const Profiles: Record = { USER, BAKER } export type RequestBody = { captchaToken: string diff --git a/src/api.ts b/src/api.ts index d02e284..fa3a7e0 100644 --- a/src/api.ts +++ b/src/api.ts @@ -21,7 +21,7 @@ import { getChallenge, verifySolution, } from "./pow" -import { InfoResponseBody, Profile } from "./Types" +import { InfoResponseBody, Profiles } from "./Types" export const redis = createClient({ url: process.env.REDIS_URL, @@ -50,13 +50,13 @@ app.get("/info", (_, res: Response) => { try { const profiles: any = { user: { - profile: Profile.USER, - amount: getTezAmountForProfile(Profile.USER), + profile: Profiles.USER, + amount: getTezAmountForProfile(Profiles.USER), currency: "tez", }, baker: { - profile: Profile.BAKER, - amount: getTezAmountForProfile(Profile.BAKER), + profile: Profiles.BAKER, + amount: getTezAmountForProfile(Profiles.BAKER), currency: "tez", }, } @@ -76,12 +76,10 @@ app.get("/info", (_, res: Response) => { app.post("/challenge", async (req: Request, res: Response) => { if (DISABLE_CHALLENGES) { - return res - .status(200) - .send({ - status: "SUCCESS", - message: "Challenges are disabled. Use the /verify endpoint.", - }) + return res.status(200).send({ + status: "SUCCESS", + message: "Challenges are disabled. Use the /verify endpoint.", + }) } const { address, captchaToken, profile } = req.body @@ -116,8 +114,10 @@ app.post("/challenge", async (req: Request, res: Response) => { if (!challenge || profile !== existingProfile) { // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken - ;({ challenge, challengesNeeded, difficulty } = - createChallenge(usedCaptcha)) + ;({ challenge, challengesNeeded, difficulty } = createChallenge( + usedCaptcha, + profile + )) challengeCounter = 1 await saveChallenge(challengeKey, { challenge, @@ -204,7 +204,7 @@ app.post("/verify", async (req: Request, res: Response) => { } if (challengeCounter < challengesNeeded) { - const newChallenge = createChallenge(usedCaptcha) + const newChallenge = createChallenge(usedCaptcha, profile) const resData = { challenge: newChallenge.challenge, challengeCounter: challengeCounter + 1, diff --git a/src/pow.ts b/src/pow.ts index 66a42f6..c613b83 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -1,27 +1,32 @@ import { createHash, randomBytes } from "crypto" import { redis } from "./api" +import { Profile } from "./Types" export const DISABLE_CHALLENGES = process.env.DISABLE_CHALLENGES === 'true' export const getChallengeKey = (address: string): string => `address:${address}` // TODO: Implement -const determineDifficulty = (usedCaptcha: boolean) => { +const determineDifficulty = (usedCaptcha: boolean, profile: Profile) => { const challengeSize = 32 - const difficulty = usedCaptcha ? 4 : 5 + const difficulty = usedCaptcha + ? (Number(process.env[`${profile}_PROFILE_CAPTCHA_DIFFICULTY`]) || 4) + : (Number(process.env[`${profile}_PROFILE_DIFFICULTY`]) || 5) return { challengeSize, difficulty } } // TODO: Implement -const determineChallengesNeeded = (usedCaptcha: boolean) => - usedCaptcha ? 5 : 6 +const determineChallengesNeeded = (usedCaptcha: boolean, profile: Profile) => + usedCaptcha + ? (Number(process.env[`${profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`]) || 5) + : (Number(process.env[`${profile}_PROFILE_CHALLENGES_NEEDED`]) || 6) const generateChallenge = (bytesSize: number = 32) => randomBytes(bytesSize).toString("hex") -export const createChallenge = (usedCaptcha: boolean) => { - const challengesNeeded = determineChallengesNeeded(usedCaptcha) - const { challengeSize, difficulty } = determineDifficulty(usedCaptcha) +export const createChallenge = (usedCaptcha: boolean, profile: Profile) => { + const challengesNeeded = determineChallengesNeeded(usedCaptcha, profile) + const { challengeSize, difficulty } = determineDifficulty(usedCaptcha, profile) const challenge = generateChallenge(challengeSize) return { challenge, challengesNeeded, difficulty } } @@ -32,13 +37,12 @@ interface ChallengeState { challengesNeeded: number difficulty: number usedCaptcha: boolean - profile: string + profile: Profile } type SaveChallengeArgs = Omit & { usedCaptcha?: boolean expiration?: number - profile: string } export const saveChallenge = async ( @@ -46,13 +50,11 @@ export const saveChallenge = async ( { usedCaptcha, expiration = 1800, // 30m - profile, ...args }: SaveChallengeArgs ) => { await redis.hSet(challengeKey, { ...args, - profile, ...(typeof usedCaptcha === "boolean" && { usedCaptcha: String(usedCaptcha), }), @@ -73,7 +75,7 @@ export const getChallenge = async ( challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", - profile: data.profile, + profile: data.profile as Profile, } satisfies ChallengeState as ChallengeState } From eeba199c2d5c0c9413d8d6f2f59599a73f52c3f4 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 17:28:10 -0400 Subject: [PATCH 46/64] Configurable difficulty and challenges needed per profile --- .env.example | 18 +++++++++++---- src/Tezos.ts | 8 ++++--- src/env.ts | 54 ++++++++++++++++++++++++++++++++++++++++++++ src/environment.d.ts | 14 ++++++++++-- src/pow.ts | 12 +++++----- 5 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 src/env.ts diff --git a/.env.example b/.env.example index 3807d56..dc6be88 100644 --- a/.env.example +++ b/.env.example @@ -8,13 +8,23 @@ CAPTCHA_SECRET=6LefC8... FAUCET_ADDRESS=tz1PW... FAUCET_PRIVATE_KEY=edsk... -BAKER_PROFILE_AMOUNT=6000 -USER_PROFILE_AMOUNT=1 -MAX_BALANCE=6000 - REDIS_PASSWORD=password REDIS_URL=redis://localhost:6379 RPC_URL=http://localhost:8732 DISABLE_CHALLENGES=false + +MAX_BALANCE=6000 + +USER_PROFILE_AMOUNT=1 +USER_PROFILE_CAPTCHA_DIFFICULTY=4 +USER_PROFILE_DIFFICULTY=5 +USER_PROFILE_CAPTCHA_CHALLENGES_NEEDED=5 +USER_PROFILE_CHALLENGES_NEEDED=6 + +BAKER_PROFILE_AMOUNT=6000 +BAKER_PROFILE_CAPTCHA_DIFFICULTY=4 +BAKER_PROFILE_DIFFICULTY=5 +BAKER_PROFILE_CAPTCHA_CHALLENGES_NEEDED=5 +BAKER_PROFILE_CHALLENGES_NEEDED=6 diff --git a/src/Tezos.ts b/src/Tezos.ts index a4e76cd..bd6e0af 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -2,18 +2,20 @@ import { InMemorySigner } from "@taquito/signer" import { TezosToolkit } from "@taquito/taquito" import { validateKeyHash } from "@taquito/utils" import { Response } from "express" + +import parsedEnv from "./env" import { Profile, Profiles } from "./Types" const defaultUserAmount = 1 export const USER_PROFILE_AMOUNT = - Number(process.env.USER_PROFILE_AMOUNT) || defaultUserAmount + parsedEnv.profile.USER_PROFILE_AMOUNT || defaultUserAmount const defaultBakerAmount = 6000 export const BAKER_PROFILE_AMOUNT = - Number(process.env.BAKER_PROFILE_AMOUNT) || defaultBakerAmount + parsedEnv.profile.BAKER_PROFILE_AMOUNT || defaultBakerAmount const defaultMaxBalance = 6000 -export const MAX_BALANCE = Number(process.env.MAX_BALANCE) || defaultMaxBalance +export const MAX_BALANCE = parsedEnv.MAX_BALANCE || defaultMaxBalance export const getTezAmountForProfile = (profile: Profile) => { switch (profile.toUpperCase()) { diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 0000000..87457fa --- /dev/null +++ b/src/env.ts @@ -0,0 +1,54 @@ +import { Profile, Profiles } from "./Types" +import { ProfileEnvVars } from "./environment" + + +type ProfileEnvVarsNumber = { + [K in keyof ProfileEnvVars]: number +} + +const envVarAsNumber = (envVar: string) => { + const value = process.env[envVar] + let numValue + + if (value !== undefined) { + numValue = Number(value) + if (isNaN(numValue)) { + throw new Error(`Environment variable ${envVar} is not a valid number`) + } + } + + return numValue +} + +const MAX_BALANCE = envVarAsNumber("MAX_BALANCE") + +export const profile = (( + profiles: typeof Profiles +): ProfileEnvVarsNumber => { + const result: ProfileEnvVarsNumber = + {} as ProfileEnvVarsNumber + + for (const profile in profiles) { + const envVars = [ + `${profile}_PROFILE_AMOUNT`, + `${profile}_PROFILE_AMOUNT`, + `${profile}_PROFILE_DIFFICULTY`, + `${profile}_PROFILE_CAPTCHA_DIFFICULTY`, + `${profile}_PROFILE_CHALLENGES_NEEDED`, + `${profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`, + ] + + envVars.forEach((envVar) => { + const numValue = envVarAsNumber(envVar) + if (numValue) { + result[envVar as keyof ProfileEnvVarsNumber] = numValue + } + }) + } + + return result +})(Profiles) + +/** Returns number-as-string env vars as numbers. Such as MAX_BALANCE and the + * profile specific challenge env vars. */ +export default { MAX_BALANCE, profile } diff --git a/src/environment.d.ts b/src/environment.d.ts index bc8973e..ed1e1b3 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -1,6 +1,17 @@ +import { Profile } from "./Types" + +export type ProfileEnvVars = { + [K in + | `${Profile}_PROFILE_AMOUNT` + | `${Profile}_PROFILE_CAPTCHA_DIFFICULTY` + | `${Profile}_PROFILE_DIFFICULTY` + | `${Profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED` + | `${Profile}_PROFILE_CHALLENGES_NEEDED`]: string +} + declare global { namespace NodeJS { - interface ProcessEnv { + interface ProcessEnv extends ProfileEnvVars { API_PORT: string AUTHORIZED_HOST: string DISABLE_CHALLENGES: string @@ -14,7 +25,6 @@ declare global { REDIS_PASSWORD: string REDIS_URL: string RPC_URL: string - DISABLE_CHALLENGES: string } } } diff --git a/src/pow.ts b/src/pow.ts index c613b83..f62fbfd 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -1,25 +1,25 @@ import { createHash, randomBytes } from "crypto" + import { redis } from "./api" +import parsedEnv from "./env" import { Profile } from "./Types" export const DISABLE_CHALLENGES = process.env.DISABLE_CHALLENGES === 'true' export const getChallengeKey = (address: string): string => `address:${address}` -// TODO: Implement const determineDifficulty = (usedCaptcha: boolean, profile: Profile) => { const challengeSize = 32 const difficulty = usedCaptcha - ? (Number(process.env[`${profile}_PROFILE_CAPTCHA_DIFFICULTY`]) || 4) - : (Number(process.env[`${profile}_PROFILE_DIFFICULTY`]) || 5) + ? parsedEnv.profile[`${profile}_PROFILE_CAPTCHA_DIFFICULTY`] || 4 + : parsedEnv.profile[`${profile}_PROFILE_DIFFICULTY`] || 5 return { challengeSize, difficulty } } -// TODO: Implement const determineChallengesNeeded = (usedCaptcha: boolean, profile: Profile) => usedCaptcha - ? (Number(process.env[`${profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`]) || 5) - : (Number(process.env[`${profile}_PROFILE_CHALLENGES_NEEDED`]) || 6) + ? parsedEnv.profile[`${profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`] || 5 + : parsedEnv.profile[`${profile}_PROFILE_CHALLENGES_NEEDED`] || 6 const generateChallenge = (bytesSize: number = 32) => randomBytes(bytesSize).toString("hex") From 9c2f400fe618047e62cd9f5415bb6a8a189f3d24 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 11 Aug 2023 17:57:40 -0400 Subject: [PATCH 47/64] Update readme --- .gitignore | 2 ++ README.md | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index deed335..b321198 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules/ dist/ .env + +.aider* diff --git a/README.md b/README.md index 6e34d56..394c2be 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Here's a general flow of how it works: - **Node.js** v18 - **Captcha** (Optional): Create a Google [ReCaptcha](https://www.google.com/recaptcha/about/) project. The public site key will be shared with the frontend. Activate domain verification in ReCAPTCHA parameters to allow only communication from the frontend faucet app. -- **Redis**: Set up a Redis server to store PoW challenge data. It's recommended to use a single-instance Redis setup for the challenge data, as this ensures atomicity and helps in avoiding potential exploits. Given that the challenge data isn't persistent or long-term essential, a single instance suffices and is easier to maintain. +- **Redis** (Optional): If `DISABLE_CHALLENGES` is not set to `false`, set up a Redis server to store PoW challenge data. It's recommended to use a single-instance Redis setup for the challenge data, as this ensures atomicity and helps in avoiding potential exploits. Given that the challenge data isn't persistent or long-term essential, a single instance suffices and is easier to maintain. ## Config @@ -27,14 +27,21 @@ Mandatory: - `CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if `ENABLE_CAPTCHA=true`) - `RPC_URL`: Tezos node RPC URL to connect to +Per Profile Configurable. Valid profiles are `USER` and `BAKER`: + +- `{PROFILE}_PROFILE_AMOUNT`: The amount of Tez to be distributed for the specified profile. Default for `USER`: `1`, for `BAKER`: `6000`. +- `{PROFILE}_PROFILE_CAPTCHA_DIFFICULTY`: The difficulty level of the challenge if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `4`. +- `{PROFILE}_PROFILE_DIFFICULTY`: The difficulty level of the challenge if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. +- `{PROFILE}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`: The number of challenges needed if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. +- `{PROFILE}_PROFILE_CHALLENGES_NEEDED`: The number of challenges needed if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `6`. + Optional: - `ENABLE_CAPTCHA`: `true` to enable ReCAPTCHA, `false` otherwise (default: `true`) -- `AUTHORIZED_HOST`: CORS origin whitelist (default `'*'`) +- `AUTHORIZED_HOST`: CORS origin whitelist (default `*`) - `API_PORT`: API listening port (default: `3000`) -- `USER_PROFILE_AMOUNT`: number of XTZ to send for the `USER` profile (default: 1) -- `BAKER_PROFILE_AMOUNT`: number of XTZ to send for the `BAKER` profile (default: 6000) -- `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: 6000) +- `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: `6000`) +- `DISABLE_CHALLENGES`: `true` to disable challenges (default: `false`) ## Running the API From 9dbf557cc13580ad399109e4da5522e1ee5c636a Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Mon, 14 Aug 2023 19:16:21 -0400 Subject: [PATCH 48/64] Use middleware functions --- src/Tezos.ts | 48 ++++++---------- src/api.ts | 138 +++++++++++++++++----------------------------- src/middleware.ts | 98 ++++++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 117 deletions(-) create mode 100644 src/middleware.ts diff --git a/src/Tezos.ts b/src/Tezos.ts index bd6e0af..f6d2bd9 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -1,6 +1,5 @@ import { InMemorySigner } from "@taquito/signer" import { TezosToolkit } from "@taquito/taquito" -import { validateKeyHash } from "@taquito/utils" import { Response } from "express" import parsedEnv from "./env" @@ -18,7 +17,7 @@ const defaultMaxBalance = 6000 export const MAX_BALANCE = parsedEnv.MAX_BALANCE || defaultMaxBalance export const getTezAmountForProfile = (profile: Profile) => { - switch (profile.toUpperCase()) { + switch (profile) { case Profiles.USER: return USER_PROFILE_AMOUNT case Profiles.BAKER: @@ -28,16 +27,6 @@ export const getTezAmountForProfile = (profile: Profile) => { } } -export const validateAddress = (res: Response, address: string) => { - if (validateKeyHash(address) !== 3) { - res - .status(400) - .send({ status: "ERROR", message: `The address '${address}' is invalid` }) - return false - } - return true -} - // Setup the TezosToolkit to interact with the chain. const Tezos = (() => { const rpcUrl = process.env.RPC_URL @@ -73,20 +62,14 @@ const sendTez = async ( return } - // Create and send transaction - try { - /* Note: `transfer` doesn't work well when running on node v19+. The + /* Note: `transfer` doesn't work well when running on node v19+. The underlying Axios requests breaks with "ECONNRESET error socket hang up". This is likely because node v19 sets HTTP(S) `keepAlive` to true by default and the Tezos node ends up killing the long-lived connection. It isn't easy to configure Axios in Taquito to work around this. */ - const operation = await Tezos.contract.transfer({ to: address, amount }) - console.log(`Sent ${amount} xtz to ${address}\nHash: ${operation.hash}`) - return operation.hash - } catch (err) { - console.error(`Error sending Tez to ${address}.`) - throw err - } + const operation = await Tezos.contract.transfer({ to: address, amount }) + console.log(`Sent ${amount} xtz to ${address}\nHash: ${operation.hash}`) + return operation.hash } export const sendTezAndRespond = async ( @@ -94,15 +77,20 @@ export const sendTezAndRespond = async ( amount: number, address: string ) => { - const txHash = await sendTez(amount, address) + try { + const txHash = await sendTez(amount, address) + + if (!txHash) { + return res + .status(403) + .send({ status: "ERROR", message: "You have already enough ꜩ" }) + } - if (!txHash) { return res - .status(403) - .send({ status: "ERROR", message: "You have already enough ꜩ" }) + .status(200) + .send({ txHash, status: "SUCCESS", message: "Tez sent" }) + } catch (err) { + console.error(`Error sending Tez to ${address}.`) + throw err } - - return res - .status(200) - .send({ txHash, status: "SUCCESS", message: "Tez sent" }) } diff --git a/src/api.ts b/src/api.ts index fa3a7e0..70a8861 100644 --- a/src/api.ts +++ b/src/api.ts @@ -2,17 +2,13 @@ import dotenv from "dotenv" dotenv.config() import bodyParser from "body-parser" -import express, { Express, Request, Response } from "express" +import express, { Express, NextFunction, Request, Response } from "express" import { createClient } from "redis" import { httpLogger } from "./logging" +import { challengeMiddleware, verifyMiddleware } from "./middleware" import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" -import { - MAX_BALANCE, - getTezAmountForProfile, - sendTezAndRespond, - validateAddress, -} from "./Tezos" +import { MAX_BALANCE, getTezAmountForProfile, sendTezAndRespond } from "./Tezos" import { DISABLE_CHALLENGES, createChallenge, @@ -74,93 +70,60 @@ app.get("/info", (_, res: Response) => { } }) -app.post("/challenge", async (req: Request, res: Response) => { - if (DISABLE_CHALLENGES) { - return res.status(200).send({ - status: "SUCCESS", - message: "Challenges are disabled. Use the /verify endpoint.", - }) - } - - const { address, captchaToken, profile } = req.body - - if (!address || !profile) { - return res.status(400).send({ - satus: "ERROR", - message: "'address' and 'profile' fields are required", - }) - } - - if (!validateAddress(res, address)) return - if (captchaToken && !(await validateCaptcha(res, captchaToken))) return +app.post( + "/challenge", + challengeMiddleware, + async (req: Request, res: Response) => { + const { address, captchaToken, profile } = req.body - try { - getTezAmountForProfile(profile) - } catch (e: any) { - return res.status(400).send({ status: "ERROR", message: e.message }) - } + if (captchaToken && !(await validateCaptcha(res, captchaToken))) return - try { - const challengeKey = getChallengeKey(address) - let { - challenge, - challengesNeeded, - challengeCounter, - difficulty, - profile: existingProfile, - } = (await getChallenge(challengeKey)) || {} - - // If no challenge exists or the profile has changed, start a new challenge. - if (!challenge || profile !== existingProfile) { - // If a captcha was sent it was validated above. - const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken - ;({ challenge, challengesNeeded, difficulty } = createChallenge( - usedCaptcha, - profile - )) - challengeCounter = 1 - await saveChallenge(challengeKey, { + try { + const challengeKey = getChallengeKey(address) + let { challenge, challengesNeeded, challengeCounter, difficulty, - usedCaptcha, - profile, + profile: existingProfile, + } = (await getChallenge(challengeKey)) || {} + + // If no challenge exists or the profile has changed, start a new challenge. + if (!challenge || profile !== existingProfile) { + // If a captcha was sent it was validated above. + const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken + ;({ challenge, challengesNeeded, difficulty } = createChallenge( + usedCaptcha, + profile + )) + challengeCounter = 1 + await saveChallenge(challengeKey, { + challenge, + challengesNeeded, + challengeCounter, + difficulty, + usedCaptcha, + profile, + }) + } + + return res.status(200).send({ + status: "SUCCESS", + challenge, + challengeCounter, + difficulty, }) + } catch (err: any) { + const message = "Error getting challenge" + console.error(message, err) + return res.status(500).send({ status: "ERROR", message }) } - - return res.status(200).send({ - status: "SUCCESS", - challenge, - challengeCounter, - difficulty, - }) - } catch (err: any) { - const message = "Error getting challenge" - console.error(message, err) - return res.status(500).send({ status: "ERROR", message }) } -}) +) -app.post("/verify", async (req: Request, res: Response) => { +app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { const { address, solution, nonce, profile } = req.body - if (!address || !profile) { - return res.status(400).send({ - status: "ERROR", - message: "'address' and 'profile' fields are required", - }) - } - - if (!DISABLE_CHALLENGES && (!solution || !nonce)) { - return res.status(400).send({ - status: "ERROR", - message: "'solution', and 'nonce', fields are required", - }) - } - - if (!validateAddress(res, address)) return - let amount try { @@ -169,11 +132,12 @@ app.post("/verify", async (req: Request, res: Response) => { return res.status(400).send({ status: "ERROR", message: e.message }) } - if (DISABLE_CHALLENGES) { - return sendTezAndRespond(res, amount, address) - } - try { + if (DISABLE_CHALLENGES) { + await sendTezAndRespond(res, amount, address) + return + } + const challengeKey = getChallengeKey(address) const redisChallenge = await getChallenge(challengeKey) if (!redisChallenge) { @@ -234,7 +198,7 @@ app.post("/verify", async (req: Request, res: Response) => { .send({ status: "ERROR", message: "PoW challenge not found" }) } - return sendTezAndRespond(res, amount, address) + await sendTezAndRespond(res, amount, address) } catch (err: any) { console.error(err) return res diff --git a/src/middleware.ts b/src/middleware.ts new file mode 100644 index 0000000..40524ac --- /dev/null +++ b/src/middleware.ts @@ -0,0 +1,98 @@ +import { validateKeyHash } from "@taquito/utils" +import { Request, Response, NextFunction } from "express" + +import { DISABLE_CHALLENGES } from "./pow" +import { Profiles } from "./Types" + +const checkChallengesEnabled = ( + req: Request, + res: Response, + next: NextFunction +) => { + if (DISABLE_CHALLENGES) { + return res.status(200).send({ + status: "SUCCESS", + message: "Challenges are disabled. Use the /verify endpoint.", + }) + } + next() +} + +const transformBody = (req: Request, res: Response, next: NextFunction) => { + const { profile } = req.body + if (typeof profile === "string") { + req.body.profile = req.body.profile.toUpperCase() + } + next() +} + +const validateAddress = (req: Request, res: Response, next: NextFunction) => { + const { address } = req.body + + if (!address) { + return res.status(400).send({ + status: "ERROR", + message: "'address' field is required", + }) + } + + if (validateKeyHash(address) !== 3) { + return res.status(400).send({ + status: "ERROR", + message: `The address '${address}' is invalid`, + }) + } + + next() +} + +const validateProfile = (req: Request, res: Response, next: NextFunction) => { + const { profile } = req.body + + if (!profile) { + return res.status(400).send({ + status: "ERROR", + message: "'profile' field is required", + }) + } + + if (!Profiles[profile]) { + return res.status(400).send({ + status: "ERROR", + message: `Unknown profile '${profile}'`, + }) + } + + next() +} + +export const challengeMiddleware = [ + checkChallengesEnabled, + transformBody, + validateProfile, + validateAddress, +] + +const validateChallengeBody = ( + req: Request, + res: Response, + next: NextFunction +) => { + const { solution, nonce } = req.body + + if (!DISABLE_CHALLENGES && (!solution || !nonce)) { + return res.status(400).send({ + status: "ERROR", + message: "'solution', and 'nonce', fields are required", + }) + } + + next() +} + +export const verifyMiddleware = [ + transformBody, + validateProfile, + validateAddress, + validateChallengeBody, +] From 6b470a2e54b313f6a903bba2a8e2fc903ac99755 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Mon, 14 Aug 2023 19:57:03 -0400 Subject: [PATCH 49/64] Make sure existing profile is used in /verify --- src/Tezos.ts | 5 +++-- src/api.ts | 21 +++++++-------------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/Tezos.ts b/src/Tezos.ts index f6d2bd9..80b2429 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -74,10 +74,11 @@ const sendTez = async ( export const sendTezAndRespond = async ( res: Response, - amount: number, - address: string + address: string, + profile: Profile ) => { try { + const amount = getTezAmountForProfile(profile) const txHash = await sendTez(amount, address) if (!txHash) { diff --git a/src/api.ts b/src/api.ts index 70a8861..8af7634 100644 --- a/src/api.ts +++ b/src/api.ts @@ -85,11 +85,11 @@ app.post( challengesNeeded, challengeCounter, difficulty, - profile: existingProfile, + profile: currentProfile, } = (await getChallenge(challengeKey)) || {} - + console.log(profile, currentProfile, challengeCounter) // If no challenge exists or the profile has changed, start a new challenge. - if (!challenge || profile !== existingProfile) { + if (!challenge || profile !== currentProfile) { // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken ;({ challenge, challengesNeeded, difficulty } = createChallenge( @@ -122,19 +122,11 @@ app.post( ) app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { - const { address, solution, nonce, profile } = req.body - - let amount - try { - amount = getTezAmountForProfile(profile) - } catch (e: any) { - return res.status(400).send({ status: "ERROR", message: e.message }) - } + const { address, solution, nonce, profile } = req.body - try { if (DISABLE_CHALLENGES) { - await sendTezAndRespond(res, amount, address) + await sendTezAndRespond(res, address, profile) return } @@ -151,6 +143,7 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { challengesNeeded, challengeCounter, difficulty, + profile: currentProfile, usedCaptcha, } = redisChallenge @@ -198,7 +191,7 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { .send({ status: "ERROR", message: "PoW challenge not found" }) } - await sendTezAndRespond(res, amount, address) + await sendTezAndRespond(res, address, currentProfile) } catch (err: any) { console.error(err) return res From 44f00c4bb8ecbef40b41dd8c65b82acb350bb87c Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 15 Aug 2023 15:28:46 -0400 Subject: [PATCH 50/64] Enable source maps --- Dockerfile | 2 +- package.json | 2 +- src/api.ts | 3 ++- src/middleware.ts | 14 +++++++------- tsconfig.json | 4 ++-- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4370bd6..1f71c9c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,4 +15,4 @@ COPY --chown=node:node . ./ RUN ./node_modules/typescript/bin/tsc -CMD ["node", "./dist/api.js"] +CMD ["node", "--enable-source-maps", "./dist/api.js"] diff --git a/package.json b/package.json index 1a97498..6076e03 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "build": "npx tsc", "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run start\"", - "start": "node dist/api.js", + "start": "node --enable-source-maps dist/api.js", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { diff --git a/src/api.ts b/src/api.ts index 8af7634..16698b0 100644 --- a/src/api.ts +++ b/src/api.ts @@ -87,7 +87,7 @@ app.post( difficulty, profile: currentProfile, } = (await getChallenge(challengeKey)) || {} - console.log(profile, currentProfile, challengeCounter) + // If no challenge exists or the profile has changed, start a new challenge. if (!challenge || profile !== currentProfile) { // If a captcha was sent it was validated above. @@ -192,6 +192,7 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { } await sendTezAndRespond(res, address, currentProfile) + return } catch (err: any) { console.error(err) return res diff --git a/src/middleware.ts b/src/middleware.ts index 40524ac..38027f6 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -66,13 +66,6 @@ const validateProfile = (req: Request, res: Response, next: NextFunction) => { next() } -export const challengeMiddleware = [ - checkChallengesEnabled, - transformBody, - validateProfile, - validateAddress, -] - const validateChallengeBody = ( req: Request, res: Response, @@ -90,6 +83,13 @@ const validateChallengeBody = ( next() } +export const challengeMiddleware = [ + checkChallengesEnabled, + transformBody, + validateProfile, + validateAddress, +] + export const verifyMiddleware = [ transformBody, validateProfile, diff --git a/tsconfig.json b/tsconfig.json index 07430ac..d9404e7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -42,7 +42,7 @@ // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ @@ -92,4 +92,4 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ } -} \ No newline at end of file +} From cddc4d2b4e7d64f021544a8411e6029e8ce483d1 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Tue, 15 Aug 2023 16:29:14 -0400 Subject: [PATCH 51/64] Get pubkey hash from the private key --- .env.example | 1 - README.md | 1 - src/Tezos.ts | 44 ++++++++++++++++++++++---------------------- src/api.ts | 8 ++++---- src/environment.d.ts | 7 ++----- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/.env.example b/.env.example index dc6be88..f915f0a 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,6 @@ AUTHORIZED_HOST="*" ENABLE_CAPTCHA=true CAPTCHA_SECRET=6LefC8... -FAUCET_ADDRESS=tz1PW... FAUCET_PRIVATE_KEY=edsk... REDIS_PASSWORD=password diff --git a/README.md b/README.md index 394c2be..54bd96d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,6 @@ Set environment variables or add them to a `.env` file. See `.env.example`. Mandatory: - `FAUCET_PRIVATE_KEY`: Faucet's private key to sign transactions -- `FAUCET_ADDRESS`: Public address of the faucet - `CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if `ENABLE_CAPTCHA=true`) - `RPC_URL`: Tezos node RPC URL to connect to diff --git a/src/Tezos.ts b/src/Tezos.ts index 80b2429..222369d 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -5,6 +5,28 @@ import { Response } from "express" import parsedEnv from "./env" import { Profile, Profiles } from "./Types" +// Setup the TezosToolkit to interact with the chain. +export const Tezos = (() => { + const rpcUrl = process.env.RPC_URL + if (!rpcUrl) { + throw new Error("No RPC_URL defined.") + } + + const TezToolkit = new TezosToolkit(rpcUrl) + + const faucetPrivateKey = process.env.FAUCET_PRIVATE_KEY + if (!faucetPrivateKey) { + throw new Error("No FAUCET_PRIVATE_KEY defined.") + } + + // Create signer + TezToolkit.setProvider({ + signer: new InMemorySigner(faucetPrivateKey), + }) + + return TezToolkit +})() + const defaultUserAmount = 1 export const USER_PROFILE_AMOUNT = parsedEnv.profile.USER_PROFILE_AMOUNT || defaultUserAmount @@ -27,28 +49,6 @@ export const getTezAmountForProfile = (profile: Profile) => { } } -// Setup the TezosToolkit to interact with the chain. -const Tezos = (() => { - const rpcUrl = process.env.RPC_URL - if (!rpcUrl) { - throw new Error("No RPC_URL defined.") - } - - const TezToolkit = new TezosToolkit(rpcUrl) - - const faucetPrivateKey = process.env.FAUCET_PRIVATE_KEY - if (!faucetPrivateKey) { - throw new Error("No FAUCET_PRIVATE_KEY defined.") - } - - // Create signer - TezToolkit.setProvider({ - signer: new InMemorySigner(faucetPrivateKey), - }) - - return TezToolkit -})() - const sendTez = async ( amount: number, address: string diff --git a/src/api.ts b/src/api.ts index 16698b0..883b219 100644 --- a/src/api.ts +++ b/src/api.ts @@ -2,13 +2,13 @@ import dotenv from "dotenv" dotenv.config() import bodyParser from "body-parser" -import express, { Express, NextFunction, Request, Response } from "express" +import express, { Express, Request, Response } from "express" import { createClient } from "redis" import { httpLogger } from "./logging" import { challengeMiddleware, verifyMiddleware } from "./middleware" import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" -import { MAX_BALANCE, getTezAmountForProfile, sendTezAndRespond } from "./Tezos" +import { MAX_BALANCE, Tezos, getTezAmountForProfile, sendTezAndRespond } from "./Tezos" import { DISABLE_CHALLENGES, createChallenge, @@ -42,7 +42,7 @@ app.use((_, res: Response, next) => { next() }) -app.get("/info", (_, res: Response) => { +app.get("/info", async (_, res: Response) => { try { const profiles: any = { user: { @@ -58,7 +58,7 @@ app.get("/info", (_, res: Response) => { } const info: InfoResponseBody = { - faucetAddress: process.env.FAUCET_ADDRESS, + faucetAddress: await Tezos.signer.publicKeyHash(), captchaEnabled: CAPTCHA_ENABLED, maxBalance: MAX_BALANCE, profiles, diff --git a/src/environment.d.ts b/src/environment.d.ts index ed1e1b3..ec564ff 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -14,12 +14,9 @@ declare global { interface ProcessEnv extends ProfileEnvVars { API_PORT: string AUTHORIZED_HOST: string - DISABLE_CHALLENGES: string - ENABLE_CAPTCHA: string - FAUCET_ADDRESS: string - BAKER_PROFILE_AMOUNT: string - USER_PROFILE_AMOUNT: string CAPTCHA_SECRET: string + ENABLE_CAPTCHA: string + DISABLE_CHALLENGES: string FAUCET_PRIVATE_KEY: string MAX_BALANCE: string REDIS_PASSWORD: string From ee8fe870d2573b6eea721e4c5b149a60bef2fc13 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 16 Aug 2023 13:58:26 -0400 Subject: [PATCH 52/64] Ability to configure multiple profiles + cleanup --- Dockerfile | 2 +- package.json | 4 +-- profiles.json | 16 ++++++++++ src/Tezos.ts | 35 ++++++---------------- src/Types.ts | 11 +++---- src/api.ts | 70 +++++++++++++++++++++----------------------- src/env.ts | 54 ---------------------------------- src/environment.d.ts | 13 +------- src/middleware.ts | 4 +-- src/pow.ts | 13 ++++---- src/profiles.ts | 56 +++++++++++++++++++++++++++++++++++ tsconfig.json | 2 +- 12 files changed, 131 insertions(+), 149 deletions(-) create mode 100644 profiles.json delete mode 100644 src/env.ts create mode 100644 src/profiles.ts diff --git a/Dockerfile b/Dockerfile index 1f71c9c..912bd19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,4 +15,4 @@ COPY --chown=node:node . ./ RUN ./node_modules/typescript/bin/tsc -CMD ["node", "--enable-source-maps", "./dist/api.js"] +CMD ["node", "--enable-source-maps", "./dist/src/api.js"] diff --git a/package.json b/package.json index 6076e03..6dfb002 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,11 @@ "name": "tezos-testnet-faucet-backend", "version": "1.0.0", "description": "", - "main": "dist/api.js", + "main": "dist/src/api.js", "scripts": { "build": "npx tsc", "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run start\"", - "start": "node --enable-source-maps dist/api.js", + "start": "node --enable-source-maps dist/src/api.js", "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { diff --git a/profiles.json b/profiles.json new file mode 100644 index 0000000..79f0102 --- /dev/null +++ b/profiles.json @@ -0,0 +1,16 @@ +{ + "USER": { + "amount": 1, + "challengesNeeded": 6, + "challengesNeededWithCaptcha": 5, + "difficulty": 5, + "difficultyWithCaptcha": 4 + }, + "BAKER": { + "amount": 6000, + "challengesNeeded": 7, + "challengesNeededWithCaptcha": 5, + "difficulty": 5, + "difficultyWithCaptcha": 4 + } +} diff --git a/src/Tezos.ts b/src/Tezos.ts index 222369d..62366b3 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -1,9 +1,15 @@ import { InMemorySigner } from "@taquito/signer" import { TezosToolkit } from "@taquito/taquito" import { Response } from "express" +import profiles, { Profile } from "./profiles" -import parsedEnv from "./env" -import { Profile, Profiles } from "./Types" +export const MAX_BALANCE = process.env.MAX_BALANCE + ? Number(process.env.MAX_BALANCE) + : 6000 + +if (isNaN(MAX_BALANCE)) { + throw new Error("Env var MAX_BALANCE must be a number.") +} // Setup the TezosToolkit to interact with the chain. export const Tezos = (() => { @@ -27,28 +33,6 @@ export const Tezos = (() => { return TezToolkit })() -const defaultUserAmount = 1 -export const USER_PROFILE_AMOUNT = - parsedEnv.profile.USER_PROFILE_AMOUNT || defaultUserAmount - -const defaultBakerAmount = 6000 -export const BAKER_PROFILE_AMOUNT = - parsedEnv.profile.BAKER_PROFILE_AMOUNT || defaultBakerAmount - -const defaultMaxBalance = 6000 -export const MAX_BALANCE = parsedEnv.MAX_BALANCE || defaultMaxBalance - -export const getTezAmountForProfile = (profile: Profile) => { - switch (profile) { - case Profiles.USER: - return USER_PROFILE_AMOUNT - case Profiles.BAKER: - return BAKER_PROFILE_AMOUNT - default: - throw new Error(`Unknown profile '${profile}'`) - } -} - const sendTez = async ( amount: number, address: string @@ -78,8 +62,7 @@ export const sendTezAndRespond = async ( profile: Profile ) => { try { - const amount = getTezAmountForProfile(profile) - const txHash = await sendTez(amount, address) + const txHash = await sendTez(profiles[profile].amount, address) if (!txHash) { return res diff --git a/src/Types.ts b/src/Types.ts index 9b09ebd..b654c2c 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -1,12 +1,9 @@ -export const USER = "USER" -export const BAKER = "BAKER" -export type Profile = typeof USER | typeof BAKER -export const Profiles: Record = { USER, BAKER } +import { Profile } from "./profiles" export type RequestBody = { captchaToken: string address: string - profile: string + profile: Profile } export type ResponseBody = { @@ -16,7 +13,7 @@ export type ResponseBody = { } export type ProfileInfo = { - profile: string + profile: Profile amount: number currency: string } @@ -24,6 +21,6 @@ export type ProfileInfo = { export type InfoResponseBody = { faucetAddress: string captchaEnabled: boolean - profiles: ProfileInfo + profiles: Record maxBalance: number } diff --git a/src/api.ts b/src/api.ts index 883b219..34684e4 100644 --- a/src/api.ts +++ b/src/api.ts @@ -5,19 +5,13 @@ import bodyParser from "body-parser" import express, { Express, Request, Response } from "express" import { createClient } from "redis" -import { httpLogger } from "./logging" import { challengeMiddleware, verifyMiddleware } from "./middleware" +import { httpLogger } from "./logging" +import { MAX_BALANCE, Tezos, sendTezAndRespond } from "./Tezos" import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" -import { MAX_BALANCE, Tezos, getTezAmountForProfile, sendTezAndRespond } from "./Tezos" -import { - DISABLE_CHALLENGES, - createChallenge, - getChallengeKey, - saveChallenge, - getChallenge, - verifySolution, -} from "./pow" -import { InfoResponseBody, Profiles } from "./Types" +import * as pow from "./pow" +import profiles, { Profile } from "./profiles" +import { InfoResponseBody, ProfileInfo } from "./Types" export const redis = createClient({ url: process.env.REDIS_URL, @@ -44,29 +38,29 @@ app.use((_, res: Response, next) => { app.get("/info", async (_, res: Response) => { try { - const profiles: any = { - user: { - profile: Profiles.USER, - amount: getTezAmountForProfile(Profiles.USER), - currency: "tez", - }, - baker: { - profile: Profiles.BAKER, - amount: getTezAmountForProfile(Profiles.BAKER), - currency: "tez", - }, - } + const profilesInfo: Record = Object.fromEntries( + Object.entries(profiles).map(([profile, profileConfig]) => [ + profile, + { + profile, + amount: profileConfig.amount, + currency: "tez", + }, + ]) + ) const info: InfoResponseBody = { faucetAddress: await Tezos.signer.publicKeyHash(), captchaEnabled: CAPTCHA_ENABLED, maxBalance: MAX_BALANCE, - profiles, + profiles: profilesInfo, } - res.status(200).send(info) + return res.status(200).send(info) } catch (error) { console.error(error) - res.status(500).send({ status: "ERROR", message: "An exception occurred" }) + return res + .status(500) + .send({ status: "ERROR", message: "An exception occurred" }) } }) @@ -79,25 +73,27 @@ app.post( if (captchaToken && !(await validateCaptcha(res, captchaToken))) return try { - const challengeKey = getChallengeKey(address) + const challengeKey = pow.getChallengeKey(address) let { challenge, challengesNeeded, challengeCounter, difficulty, profile: currentProfile, - } = (await getChallenge(challengeKey)) || {} + } = (await pow.getChallenge(challengeKey)) || {} // If no challenge exists or the profile has changed, start a new challenge. if (!challenge || profile !== currentProfile) { // If a captcha was sent it was validated above. const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken - ;({ challenge, challengesNeeded, difficulty } = createChallenge( + + challengeCounter = 1 + ;({ challenge, challengesNeeded, difficulty } = pow.createChallenge( usedCaptcha, profile )) - challengeCounter = 1 - await saveChallenge(challengeKey, { + + await pow.saveChallenge(challengeKey, { challenge, challengesNeeded, challengeCounter, @@ -125,13 +121,13 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { try { const { address, solution, nonce, profile } = req.body - if (DISABLE_CHALLENGES) { + if (pow.DISABLE_CHALLENGES) { await sendTezAndRespond(res, address, profile) return } - const challengeKey = getChallengeKey(address) - const redisChallenge = await getChallenge(challengeKey) + const challengeKey = pow.getChallengeKey(address) + const redisChallenge = await pow.getChallenge(challengeKey) if (!redisChallenge) { return res .status(400) @@ -147,7 +143,7 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { usedCaptcha, } = redisChallenge - const isValidSolution = verifySolution({ + const isValidSolution = pow.verifySolution({ challenge, difficulty, nonce, @@ -161,14 +157,14 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { } if (challengeCounter < challengesNeeded) { - const newChallenge = createChallenge(usedCaptcha, profile) + const newChallenge = pow.createChallenge(usedCaptcha, profile) const resData = { challenge: newChallenge.challenge, challengeCounter: challengeCounter + 1, difficulty: newChallenge.difficulty, } - await saveChallenge(challengeKey, { + await pow.saveChallenge(challengeKey, { challengesNeeded: newChallenge.challengesNeeded, profile, ...resData, diff --git a/src/env.ts b/src/env.ts deleted file mode 100644 index 87457fa..0000000 --- a/src/env.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Profile, Profiles } from "./Types" -import { ProfileEnvVars } from "./environment" - - -type ProfileEnvVarsNumber = { - [K in keyof ProfileEnvVars]: number -} - -const envVarAsNumber = (envVar: string) => { - const value = process.env[envVar] - let numValue - - if (value !== undefined) { - numValue = Number(value) - if (isNaN(numValue)) { - throw new Error(`Environment variable ${envVar} is not a valid number`) - } - } - - return numValue -} - -const MAX_BALANCE = envVarAsNumber("MAX_BALANCE") - -export const profile = (( - profiles: typeof Profiles -): ProfileEnvVarsNumber => { - const result: ProfileEnvVarsNumber = - {} as ProfileEnvVarsNumber - - for (const profile in profiles) { - const envVars = [ - `${profile}_PROFILE_AMOUNT`, - `${profile}_PROFILE_AMOUNT`, - `${profile}_PROFILE_DIFFICULTY`, - `${profile}_PROFILE_CAPTCHA_DIFFICULTY`, - `${profile}_PROFILE_CHALLENGES_NEEDED`, - `${profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`, - ] - - envVars.forEach((envVar) => { - const numValue = envVarAsNumber(envVar) - if (numValue) { - result[envVar as keyof ProfileEnvVarsNumber] = numValue - } - }) - } - - return result -})(Profiles) - -/** Returns number-as-string env vars as numbers. Such as MAX_BALANCE and the - * profile specific challenge env vars. */ -export default { MAX_BALANCE, profile } diff --git a/src/environment.d.ts b/src/environment.d.ts index ec564ff..05308a0 100644 --- a/src/environment.d.ts +++ b/src/environment.d.ts @@ -1,17 +1,6 @@ -import { Profile } from "./Types" - -export type ProfileEnvVars = { - [K in - | `${Profile}_PROFILE_AMOUNT` - | `${Profile}_PROFILE_CAPTCHA_DIFFICULTY` - | `${Profile}_PROFILE_DIFFICULTY` - | `${Profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED` - | `${Profile}_PROFILE_CHALLENGES_NEEDED`]: string -} - declare global { namespace NodeJS { - interface ProcessEnv extends ProfileEnvVars { + interface ProcessEnv { API_PORT: string AUTHORIZED_HOST: string CAPTCHA_SECRET: string diff --git a/src/middleware.ts b/src/middleware.ts index 38027f6..f1577e5 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -2,7 +2,7 @@ import { validateKeyHash } from "@taquito/utils" import { Request, Response, NextFunction } from "express" import { DISABLE_CHALLENGES } from "./pow" -import { Profiles } from "./Types" +import profiles, { Profile } from "./profiles" const checkChallengesEnabled = ( req: Request, @@ -56,7 +56,7 @@ const validateProfile = (req: Request, res: Response, next: NextFunction) => { }) } - if (!Profiles[profile]) { + if (!profiles[profile]) { return res.status(400).send({ status: "ERROR", message: `Unknown profile '${profile}'`, diff --git a/src/pow.ts b/src/pow.ts index f62fbfd..87a66b7 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -1,8 +1,7 @@ import { createHash, randomBytes } from "crypto" import { redis } from "./api" -import parsedEnv from "./env" -import { Profile } from "./Types" +import profiles, { Profile } from "./profiles" export const DISABLE_CHALLENGES = process.env.DISABLE_CHALLENGES === 'true' @@ -11,15 +10,15 @@ export const getChallengeKey = (address: string): string => `address:${address}` const determineDifficulty = (usedCaptcha: boolean, profile: Profile) => { const challengeSize = 32 const difficulty = usedCaptcha - ? parsedEnv.profile[`${profile}_PROFILE_CAPTCHA_DIFFICULTY`] || 4 - : parsedEnv.profile[`${profile}_PROFILE_DIFFICULTY`] || 5 + ? profiles[profile].difficultyWithCaptcha + : profiles[profile].difficulty return { challengeSize, difficulty } } const determineChallengesNeeded = (usedCaptcha: boolean, profile: Profile) => usedCaptcha - ? parsedEnv.profile[`${profile}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`] || 5 - : parsedEnv.profile[`${profile}_PROFILE_CHALLENGES_NEEDED`] || 6 + ? profiles[profile].challengesNeededWithCaptcha + : profiles[profile].challengesNeeded const generateChallenge = (bytesSize: number = 32) => randomBytes(bytesSize).toString("hex") @@ -75,7 +74,7 @@ export const getChallenge = async ( challengesNeeded: Number(data.challengesNeeded), difficulty: Number(data.difficulty), usedCaptcha: data.usedCaptcha === "true", - profile: data.profile as Profile, + profile: data.profile satisfies Profile as Profile, } satisfies ChallengeState as ChallengeState } diff --git a/src/profiles.ts b/src/profiles.ts new file mode 100644 index 0000000..840d6af --- /dev/null +++ b/src/profiles.ts @@ -0,0 +1,56 @@ +import profiles from "../profiles.json" + +export type Profile = string + +type ProfileConfig = { + amount: number + challengesNeeded: number + challengesNeededWithCaptcha: number + difficulty: number + difficultyWithCaptcha: number +} + +const validateProperty = ( + profile: ProfileConfig, + property: keyof ProfileConfig +): number => { + const value = Number(profile[property]) + if (isNaN(value)) { + throw new Error(`Profile ${property} must be a number`) + } + return value +} + +const validateProfile = (profile: ProfileConfig): ProfileConfig => { + const properties: (keyof ProfileConfig)[] = [ + "amount", + "challengesNeeded", + "challengesNeededWithCaptcha", + "difficulty", + "difficultyWithCaptcha", + ] + + return properties.reduce((acc, property) => { + acc[property] = validateProperty(profile, property) + return acc + }, {} as ProfileConfig) +} + +const validatedProfiles = new Proxy( + Object.entries(profiles).reduce((acc, [key, profile]) => { + acc[key.toUpperCase()] = validateProfile(profile) + return acc + }, {} as Record), + { + get: (target, prop) => { + const key = String(prop) + if (key in target) { + return target[key] + } else { + throw new Error(`Profile '${key}' does not exist`) + } + }, + } +) + +export default validatedProfiles diff --git a/tsconfig.json b/tsconfig.json index d9404e7..cd586c0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -23,7 +23,7 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ + // "rootDir": "./src", /* Specify the root folder within your source files. */ // "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ From 57a180fae887de9df507de18bb13fe883670de56 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 16 Aug 2023 14:12:20 -0400 Subject: [PATCH 53/64] Update README --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 54bd96d..7257f25 100644 --- a/README.md +++ b/README.md @@ -26,21 +26,25 @@ Mandatory: - `CAPTCHA_SECRET`: faucet ReCAPTCHA secret key (mandatory if `ENABLE_CAPTCHA=true`) - `RPC_URL`: Tezos node RPC URL to connect to -Per Profile Configurable. Valid profiles are `USER` and `BAKER`: +### Profile Configuration -- `{PROFILE}_PROFILE_AMOUNT`: The amount of Tez to be distributed for the specified profile. Default for `USER`: `1`, for `BAKER`: `6000`. -- `{PROFILE}_PROFILE_CAPTCHA_DIFFICULTY`: The difficulty level of the challenge if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `4`. -- `{PROFILE}_PROFILE_DIFFICULTY`: The difficulty level of the challenge if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. -- `{PROFILE}_PROFILE_CAPTCHA_CHALLENGES_NEEDED`: The number of challenges needed if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. -- `{PROFILE}_PROFILE_CHALLENGES_NEEDED`: The number of challenges needed if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `6`. +Profiles are configured in the [profiles.json](./profiles.json) file. Each profile is an object with the following properties: + +- `amount`: The amount of Tez to be distributed for the specified profile. Default for `USER`: `1`, for `BAKER`: `6000`. +- `challengesNeeded`: The number of challenges needed if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `6`. +- `challengesNeededWithCaptcha`: The number of challenges needed if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. +- `difficulty`: The difficulty level of the challenge if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. +- `difficultyWithCaptcha`: The difficulty level of the challenge if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `4`. + +The [src/profiles.ts](src/profiles.ts) file imports this JSON file and validates these properties. If any property is missing or invalid, an error will be thrown. Optional: -- `ENABLE_CAPTCHA`: `true` to enable ReCAPTCHA, `false` otherwise (default: `true`) -- `AUTHORIZED_HOST`: CORS origin whitelist (default `*`) - `API_PORT`: API listening port (default: `3000`) -- `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: `6000`) +- `AUTHORIZED_HOST`: CORS origin whitelist (default `*`) - `DISABLE_CHALLENGES`: `true` to disable challenges (default: `false`) +- `ENABLE_CAPTCHA`: `true` to enable ReCAPTCHA, `false` otherwise (default: `true`) +- `MAX_BALANCE`: maximum address balance beyond which sending of XTZ is refused (default: `6000`) ## Running the API From 62edcd7320902897ce25529bb45ea1bece03e941 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 16 Aug 2023 14:13:00 -0400 Subject: [PATCH 54/64] Only validate amount if DISABLE_CHALLENGES --- src/profiles.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/profiles.ts b/src/profiles.ts index 840d6af..4cf66c2 100644 --- a/src/profiles.ts +++ b/src/profiles.ts @@ -1,4 +1,5 @@ import profiles from "../profiles.json" +import { DISABLE_CHALLENGES } from "./pow" export type Profile = string @@ -16,19 +17,21 @@ const validateProperty = ( ): number => { const value = Number(profile[property]) if (isNaN(value)) { - throw new Error(`Profile ${property} must be a number`) + throw new Error(`Profile '${property}' must be a number`) } return value } const validateProfile = (profile: ProfileConfig): ProfileConfig => { - const properties: (keyof ProfileConfig)[] = [ - "amount", - "challengesNeeded", - "challengesNeededWithCaptcha", - "difficulty", - "difficultyWithCaptcha", - ] + const properties: (keyof ProfileConfig)[] = DISABLE_CHALLENGES + ? ["amount"] + : [ + "amount", + "challengesNeeded", + "challengesNeededWithCaptcha", + "difficulty", + "difficultyWithCaptcha", + ] return properties.reduce((acc, property) => { acc[property] = validateProperty(profile, property) From 22e548ce0b06517cfc8c33f2d0b956e4003185ae Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 16 Aug 2023 14:13:59 -0400 Subject: [PATCH 55/64] Remove old env vars --- .env.example | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/.env.example b/.env.example index f915f0a..a44e9fd 100644 --- a/.env.example +++ b/.env.example @@ -15,15 +15,3 @@ RPC_URL=http://localhost:8732 DISABLE_CHALLENGES=false MAX_BALANCE=6000 - -USER_PROFILE_AMOUNT=1 -USER_PROFILE_CAPTCHA_DIFFICULTY=4 -USER_PROFILE_DIFFICULTY=5 -USER_PROFILE_CAPTCHA_CHALLENGES_NEEDED=5 -USER_PROFILE_CHALLENGES_NEEDED=6 - -BAKER_PROFILE_AMOUNT=6000 -BAKER_PROFILE_CAPTCHA_DIFFICULTY=4 -BAKER_PROFILE_DIFFICULTY=5 -BAKER_PROFILE_CAPTCHA_CHALLENGES_NEEDED=5 -BAKER_PROFILE_CHALLENGES_NEEDED=6 From 731bcd1f88485188eb93346cb300e04789ae54ab Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 16 Aug 2023 14:37:16 -0400 Subject: [PATCH 56/64] Update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7257f25..450af0b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Profiles are configured in the [profiles.json](./profiles.json) file. Each profi - `difficulty`: The difficulty level of the challenge if no CAPTCHA is provided. Default for both `USER` and `BAKER`: `5`. - `difficultyWithCaptcha`: The difficulty level of the challenge if a valid CAPTCHA is provided. Default for both `USER` and `BAKER`: `4`. -The [src/profiles.ts](src/profiles.ts) file imports this JSON file and validates these properties. If any property is missing or invalid, an error will be thrown. +The [src/profiles.ts](src/profiles.ts) file imports this JSON file and validates these properties. If any property is missing or invalid, an error will be thrown. If `DISABLE_CHALLENGES` is `true`, only `amount` is required. Optional: From f39995e3b35a5128c9ab2b78266025c338b75cb5 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 16 Aug 2023 14:37:50 -0400 Subject: [PATCH 57/64] Validate amount is greater than 0 --- package.json | 2 +- src/profiles.ts | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index 6dfb002..92bf6f9 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "dist/src/api.js", "scripts": { "build": "npx tsc", - "dev": "nodemon -e ts -w src --exec \"npx tsc && npm run start\"", + "dev": "nodemon -e ts -w src -w profiles.json --exec \"npx tsc && npm run start\"", "start": "node --enable-source-maps dist/src/api.js", "test": "echo \"Error: no test specified\" && exit 1" }, diff --git a/src/profiles.ts b/src/profiles.ts index 4cf66c2..269904a 100644 --- a/src/profiles.ts +++ b/src/profiles.ts @@ -16,9 +16,17 @@ const validateProperty = ( property: keyof ProfileConfig ): number => { const value = Number(profile[property]) + if (isNaN(value)) { throw new Error(`Profile '${property}' must be a number`) } + + // If the property is 'amount' or if challenges are enabled, then the value of + // the property must be greater than 0. If it's not, an error is thrown. + if ((property === "amount" || !DISABLE_CHALLENGES) && value <= 0) { + throw new Error(`Profile '${property}' must be greater than 0`) + } + return value } @@ -39,21 +47,12 @@ const validateProfile = (profile: ProfileConfig): ProfileConfig => { }, {} as ProfileConfig) } -const validatedProfiles = new Proxy( - Object.entries(profiles).reduce((acc, [key, profile]) => { +const validatedProfiles = Object.entries(profiles).reduce( + (acc, [key, profile]) => { acc[key.toUpperCase()] = validateProfile(profile) return acc - }, {} as Record), - { - get: (target, prop) => { - const key = String(prop) - if (key in target) { - return target[key] - } else { - throw new Error(`Profile '${key}' does not exist`) - } - }, - } + }, + {} as Record ) export default validatedProfiles From 89b63372dc82f872e01f8f41e6ff4d454838dea1 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 17 Aug 2023 20:24:07 -0400 Subject: [PATCH 58/64] Make env.ts to handle env var type conversions --- src/Captcha.ts | 6 +++--- src/Tezos.ts | 16 +++++----------- src/api.ts | 15 +++++++-------- src/env.ts | 16 ++++++++++++++++ src/middleware.ts | 8 ++++---- src/pow.ts | 2 -- src/profiles.ts | 6 +++--- 7 files changed, 38 insertions(+), 31 deletions(-) create mode 100644 src/env.ts diff --git a/src/Captcha.ts b/src/Captcha.ts index 0f2a238..2adcda1 100644 --- a/src/Captcha.ts +++ b/src/Captcha.ts @@ -1,11 +1,11 @@ import axios from "axios" import { Response } from "express" -export const CAPTCHA_ENABLED = process.env.ENABLE_CAPTCHA !== "false" +import env from "./env" export const validateCaptcha = async (res: Response, captchaToken: string) => { try { - if (!CAPTCHA_ENABLED) { + if (!env.ENABLE_CAPTCHA) { console.log("Captcha disabled") return true } @@ -22,7 +22,7 @@ export const validateCaptcha = async (res: Response, captchaToken: string) => { {}, { params: { - secret: process.env.CAPTCHA_SECRET, + secret: env.CAPTCHA_SECRET, response: captchaToken, }, } diff --git a/src/Tezos.ts b/src/Tezos.ts index 62366b3..0f2b264 100644 --- a/src/Tezos.ts +++ b/src/Tezos.ts @@ -1,26 +1,20 @@ import { InMemorySigner } from "@taquito/signer" import { TezosToolkit } from "@taquito/taquito" import { Response } from "express" -import profiles, { Profile } from "./profiles" - -export const MAX_BALANCE = process.env.MAX_BALANCE - ? Number(process.env.MAX_BALANCE) - : 6000 -if (isNaN(MAX_BALANCE)) { - throw new Error("Env var MAX_BALANCE must be a number.") -} +import env from "./env" +import profiles, { Profile } from "./profiles" // Setup the TezosToolkit to interact with the chain. export const Tezos = (() => { - const rpcUrl = process.env.RPC_URL + const rpcUrl = env.RPC_URL if (!rpcUrl) { throw new Error("No RPC_URL defined.") } const TezToolkit = new TezosToolkit(rpcUrl) - const faucetPrivateKey = process.env.FAUCET_PRIVATE_KEY + const faucetPrivateKey = env.FAUCET_PRIVATE_KEY if (!faucetPrivateKey) { throw new Error("No FAUCET_PRIVATE_KEY defined.") } @@ -39,7 +33,7 @@ const sendTez = async ( ): Promise => { // Check max balance const userBalance = (await Tezos.tz.getBalance(address)).toNumber() - if (userBalance > MAX_BALANCE * 1000000) { + if (userBalance > env.MAX_BALANCE * 1000000) { console.log( `${address} balance too high (${userBalance / 1000000}). Not sending.` ) diff --git a/src/api.ts b/src/api.ts index 34684e4..92ead00 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,5 +1,4 @@ -import dotenv from "dotenv" -dotenv.config() +import env from "./env" import bodyParser from "body-parser" import express, { Express, Request, Response } from "express" @@ -7,8 +6,8 @@ import { createClient } from "redis" import { challengeMiddleware, verifyMiddleware } from "./middleware" import { httpLogger } from "./logging" -import { MAX_BALANCE, Tezos, sendTezAndRespond } from "./Tezos" -import { validateCaptcha, CAPTCHA_ENABLED } from "./Captcha" +import { Tezos, sendTezAndRespond } from "./Tezos" +import { validateCaptcha } from "./Captcha" import * as pow from "./pow" import profiles, { Profile } from "./profiles" import { InfoResponseBody, ProfileInfo } from "./Types" @@ -51,8 +50,8 @@ app.get("/info", async (_, res: Response) => { const info: InfoResponseBody = { faucetAddress: await Tezos.signer.publicKeyHash(), - captchaEnabled: CAPTCHA_ENABLED, - maxBalance: MAX_BALANCE, + captchaEnabled: env.ENABLE_CAPTCHA, + maxBalance: env.MAX_BALANCE, profiles: profilesInfo, } return res.status(200).send(info) @@ -85,7 +84,7 @@ app.post( // If no challenge exists or the profile has changed, start a new challenge. if (!challenge || profile !== currentProfile) { // If a captcha was sent it was validated above. - const usedCaptcha = CAPTCHA_ENABLED && !!captchaToken + const usedCaptcha = env.ENABLE_CAPTCHA && !!captchaToken challengeCounter = 1 ;({ challenge, challengesNeeded, difficulty } = pow.createChallenge( @@ -121,7 +120,7 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { try { const { address, solution, nonce, profile } = req.body - if (pow.DISABLE_CHALLENGES) { + if (env.DISABLE_CHALLENGES) { await sendTezAndRespond(res, address, profile) return } diff --git a/src/env.ts b/src/env.ts new file mode 100644 index 0000000..72fbac7 --- /dev/null +++ b/src/env.ts @@ -0,0 +1,16 @@ +import "dotenv/config" + +const { ENABLE_CAPTCHA, DISABLE_CHALLENGES, MAX_BALANCE } = process.env + +const env = { + ...process.env, + ENABLE_CAPTCHA: ENABLE_CAPTCHA !== "false", + DISABLE_CHALLENGES: DISABLE_CHALLENGES === "true", + MAX_BALANCE: MAX_BALANCE ? Number(MAX_BALANCE) : 6000, +} + +if (isNaN(env.MAX_BALANCE)) { + throw new Error("Env var MAX_BALANCE must be a number.") +} + +export default env diff --git a/src/middleware.ts b/src/middleware.ts index f1577e5..5612c8f 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -1,15 +1,15 @@ import { validateKeyHash } from "@taquito/utils" import { Request, Response, NextFunction } from "express" -import { DISABLE_CHALLENGES } from "./pow" -import profiles, { Profile } from "./profiles" +import env from "./env" +import profiles from "./profiles" const checkChallengesEnabled = ( req: Request, res: Response, next: NextFunction ) => { - if (DISABLE_CHALLENGES) { + if (env.DISABLE_CHALLENGES) { return res.status(200).send({ status: "SUCCESS", message: "Challenges are disabled. Use the /verify endpoint.", @@ -73,7 +73,7 @@ const validateChallengeBody = ( ) => { const { solution, nonce } = req.body - if (!DISABLE_CHALLENGES && (!solution || !nonce)) { + if (!env.DISABLE_CHALLENGES && (!solution || !nonce)) { return res.status(400).send({ status: "ERROR", message: "'solution', and 'nonce', fields are required", diff --git a/src/pow.ts b/src/pow.ts index 87a66b7..9adeaa7 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -3,8 +3,6 @@ import { createHash, randomBytes } from "crypto" import { redis } from "./api" import profiles, { Profile } from "./profiles" -export const DISABLE_CHALLENGES = process.env.DISABLE_CHALLENGES === 'true' - export const getChallengeKey = (address: string): string => `address:${address}` const determineDifficulty = (usedCaptcha: boolean, profile: Profile) => { diff --git a/src/profiles.ts b/src/profiles.ts index 269904a..1c105a5 100644 --- a/src/profiles.ts +++ b/src/profiles.ts @@ -1,5 +1,5 @@ +import env from "./env" import profiles from "../profiles.json" -import { DISABLE_CHALLENGES } from "./pow" export type Profile = string @@ -23,7 +23,7 @@ const validateProperty = ( // If the property is 'amount' or if challenges are enabled, then the value of // the property must be greater than 0. If it's not, an error is thrown. - if ((property === "amount" || !DISABLE_CHALLENGES) && value <= 0) { + if ((property === "amount" || !env.DISABLE_CHALLENGES) && value <= 0) { throw new Error(`Profile '${property}' must be greater than 0`) } @@ -31,7 +31,7 @@ const validateProperty = ( } const validateProfile = (profile: ProfileConfig): ProfileConfig => { - const properties: (keyof ProfileConfig)[] = DISABLE_CHALLENGES + const properties: (keyof ProfileConfig)[] = env.DISABLE_CHALLENGES ? ["amount"] : [ "amount", From 2029d5f498223565581c15ac61f82d8be782fda6 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Thu, 17 Aug 2023 20:34:46 -0400 Subject: [PATCH 59/64] Update comments --- README.md | 2 +- src/env.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 450af0b..6f4fd19 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Here's a general flow of how it works: ## Config -Set environment variables or add them to a `.env` file. See `.env.example`. +Set environment variables or add them to a `.env` file. See [.env.example](.env.example). The [src/env.ts](src/env.ts) file handles necessary type conversions from environment variable strings. Mandatory: diff --git a/src/env.ts b/src/env.ts index 72fbac7..4c69ebc 100644 --- a/src/env.ts +++ b/src/env.ts @@ -1,5 +1,8 @@ import "dotenv/config" +// This file is responsible for handling environment variables. +// It imports all environment variables from process.env and performs necessary type conversions. +// For some values, it's better to use the converted values from this file instead of process.env directly. const { ENABLE_CAPTCHA, DISABLE_CHALLENGES, MAX_BALANCE } = process.env const env = { From 872c4ea05b70466a2d7d9b05782957276b30e99e Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Mon, 21 Aug 2023 17:31:29 -0400 Subject: [PATCH 60/64] Update package.json fields --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index 92bf6f9..5d40a25 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "tezos-testnet-faucet-backend", - "version": "1.0.0", - "description": "", + "name": "tezos-faucet-backend", + "version": "2.0.0", + "description": "Tezos Faucet Backend", "main": "dist/src/api.js", "scripts": { "build": "npx tsc", @@ -11,14 +11,14 @@ }, "repository": { "type": "git", - "url": "git+https://github.com/oxheadalpha/tezos-testnet-faucet-backend.git" + "url": "git+https://github.com/oxheadalpha/tezos-faucet-backend.git" }, "author": "", "license": "ISC", "bugs": { - "url": "https://github.com/oxheadalpha/tezos-testnet-faucet-backend/issues" + "url": "https://github.com/oxheadalpha/tezos-faucet-backend/issues" }, - "homepage": "https://github.com/oxheadalpha/tezos-testnet-faucet-backend#readme", + "homepage": "https://github.com/oxheadalpha/tezos-faucet-backend#readme", "dependencies": { "@taquito/signer": "^17.1.1", "@taquito/taquito": "^17.1.1", From 97ccf7d1fe00353831c861b668b3a23659e22b99 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 23 Aug 2023 18:03:21 -0400 Subject: [PATCH 61/64] Make workdir /app + validate profiles.json isn't empty --- Dockerfile | 4 ++-- src/profiles.ts | 19 +++++++++++-------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index 912bd19..1b58eeb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,9 +2,9 @@ FROM node:18-alpine USER node -WORKDIR /tezos-faucet-backend +WORKDIR /app -RUN chown node:node /tezos-faucet-backend +RUN chown node:node /app COPY --chown=node:node package.json ./ COPY --chown=node:node package-lock.json ./ diff --git a/src/profiles.ts b/src/profiles.ts index 1c105a5..582932b 100644 --- a/src/profiles.ts +++ b/src/profiles.ts @@ -1,6 +1,12 @@ -import env from "./env" +import env from "./env" import profiles from "../profiles.json" +const profileEntries = Object.entries(profiles) + +if (!profileEntries.length) { + throw new Error("No profiles defined in profiles.json.") +} + export type Profile = string type ProfileConfig = { @@ -47,12 +53,9 @@ const validateProfile = (profile: ProfileConfig): ProfileConfig => { }, {} as ProfileConfig) } -const validatedProfiles = Object.entries(profiles).reduce( - (acc, [key, profile]) => { - acc[key.toUpperCase()] = validateProfile(profile) - return acc - }, - {} as Record -) +const validatedProfiles = profileEntries.reduce((acc, [key, profile]) => { + acc[key.toUpperCase()] = validateProfile(profile) + return acc +}, {} as Record) export default validatedProfiles From 016ef179300badb25e73541835fcabbf0423ef1d Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 23 Aug 2023 19:20:07 -0400 Subject: [PATCH 62/64] Don't connect to redis when challenges are disabled --- src/api.ts | 29 ++++++++++++++--------------- src/pow.ts | 2 +- src/redis.ts | 10 ++++++++++ 3 files changed, 25 insertions(+), 16 deletions(-) create mode 100644 src/redis.ts diff --git a/src/api.ts b/src/api.ts index 92ead00..173ff41 100644 --- a/src/api.ts +++ b/src/api.ts @@ -2,8 +2,8 @@ import env from "./env" import bodyParser from "body-parser" import express, { Express, Request, Response } from "express" -import { createClient } from "redis" +import redis from "./redis" import { challengeMiddleware, verifyMiddleware } from "./middleware" import { httpLogger } from "./logging" import { Tezos, sendTezAndRespond } from "./Tezos" @@ -12,13 +12,6 @@ import * as pow from "./pow" import profiles, { Profile } from "./profiles" import { InfoResponseBody, ProfileInfo } from "./Types" -export const redis = createClient({ - url: process.env.REDIS_URL, - password: process.env.REDIS_PASSWORD, -}) - .on("connect", () => console.log("Connected to redis.")) - .on("error", (err: any) => console.error("Redis Client Error:", err)) - const app: Express = express() app.use(bodyParser.json()) app.use(bodyParser.urlencoded({ extended: true })) @@ -174,7 +167,7 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { // The challenge should be deleted from redis before Tez is sent. If it // failed to delete or was already deleted by another request, the user // could keep getting Tez with the same solution. - const deletedCount = await redis.del(challengeKey).catch((err) => { + const deletedCount = await redis.del(challengeKey).catch((err: any) => { console.error(`Redis failed to delete ${challengeKey}.`) throw err }) @@ -198,7 +191,11 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { // Connect to redis, start server, and setup listeners for graceful shutdown. ;(async () => { - await redis.connect() + if (!env.DISABLE_CHALLENGES) { + await redis.connect() + } else { + console.log("Challenges are disabled. Not connecting to redis.") + } const port = process.env.API_PORT || 3000 const server = app.listen(port, () => @@ -208,11 +205,13 @@ app.post("/verify", verifyMiddleware, async (req: Request, res: Response) => { const gracefulShutdown = async (signal: string) => { console.log(`${signal} signal received`) - try { - await redis.quit() - console.log("Redis connection closed.") - } catch (err) { - console.error("Error closing Redis connection:", err) + if (!env.DISABLE_CHALLENGES) { + try { + await redis.quit() + console.log("Redis connection closed.") + } catch (err) { + console.error("Error closing Redis connection:", err) + } } server.close(() => { diff --git a/src/pow.ts b/src/pow.ts index 9adeaa7..9808e7c 100644 --- a/src/pow.ts +++ b/src/pow.ts @@ -1,6 +1,6 @@ import { createHash, randomBytes } from "crypto" -import { redis } from "./api" +import redis from "./redis" import profiles, { Profile } from "./profiles" export const getChallengeKey = (address: string): string => `address:${address}` diff --git a/src/redis.ts b/src/redis.ts new file mode 100644 index 0000000..7fc530d --- /dev/null +++ b/src/redis.ts @@ -0,0 +1,10 @@ +import { createClient } from "redis" + +const redis = createClient({ + url: process.env.REDIS_URL, + password: process.env.REDIS_PASSWORD, +}) + .on("connect", () => console.log("Connected to redis.")) + .on("error", (err: any) => console.error("Redis Client Error:", err)) + +export default redis From 823ce91f5eeda2a950c7c15f62d71db38028ebcc Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Wed, 23 Aug 2023 19:59:03 -0400 Subject: [PATCH 63/64] Return challengesDisabled and remove profile from /info res --- src/Types.ts | 2 +- src/api.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Types.ts b/src/Types.ts index b654c2c..6f5484e 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -13,7 +13,6 @@ export type ResponseBody = { } export type ProfileInfo = { - profile: Profile amount: number currency: string } @@ -21,6 +20,7 @@ export type ProfileInfo = { export type InfoResponseBody = { faucetAddress: string captchaEnabled: boolean + challengesDisabled: boolean profiles: Record maxBalance: number } diff --git a/src/api.ts b/src/api.ts index 173ff41..46a66c4 100644 --- a/src/api.ts +++ b/src/api.ts @@ -34,7 +34,6 @@ app.get("/info", async (_, res: Response) => { Object.entries(profiles).map(([profile, profileConfig]) => [ profile, { - profile, amount: profileConfig.amount, currency: "tez", }, @@ -44,6 +43,7 @@ app.get("/info", async (_, res: Response) => { const info: InfoResponseBody = { faucetAddress: await Tezos.signer.publicKeyHash(), captchaEnabled: env.ENABLE_CAPTCHA, + challengesDisabled: env.DISABLE_CHALLENGES, maxBalance: env.MAX_BALANCE, profiles: profilesInfo, } From 5a66e59410b028e039c857f182eee967d23fa9e8 Mon Sep 17 00:00:00 2001 From: Aryeh Harris Date: Fri, 25 Aug 2023 11:08:16 -0400 Subject: [PATCH 64/64] Add section about programmatic faucet to readme --- .gitignore | 2 -- README.md | 6 ++++++ package-lock.json | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index b321198..deed335 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ node_modules/ dist/ .env - -.aider* diff --git a/README.md b/README.md index 6f4fd19..94074a6 100644 --- a/README.md +++ b/README.md @@ -126,3 +126,9 @@ The endpoint verifies the solution by trying to regenerate it using the challeng If the solution is correct but the required number of challenges have not yet been satisfied, a new challenge is generated and returned in the response. If all challenges have been completed, the user's address is granted the Tez amount for their profile type. The transaction hash is returned to indicate the transfer was successful. + +## Programmatic Faucet Usage + +For programmatic usage of the faucet, we provide a `getTez.js` script located in the `/scripts` directory of the frontend repository. Please refer to it for more details on how to use it. This script can be run from a JavaScript program or directly from a shell. It interacts with the backend to request Tez, solve the required challenges, and verify the solutions. + +Please note that the `getTez.js` script does not use CAPTCHA. Therefore, when using the programmatic faucet, challenges can be configured to be more difficult and require more of them to be solved. diff --git a/package-lock.json b/package-lock.json index 7603e2a..f98604f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "tezos-testnet-faucet-backend", - "version": "1.0.0", + "name": "tezos-faucet-backend", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "tezos-testnet-faucet-backend", - "version": "1.0.0", + "name": "tezos-faucet-backend", + "version": "2.0.0", "license": "ISC", "dependencies": { "@taquito/signer": "^17.1.1",