From 536b227cdbf158fea94776e93bb894fdd7a8de98 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 28 Feb 2023 20:23:51 -0500 Subject: [PATCH 01/65] Update .gitignore --- .gitignore | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index ce5d611..bd3afc3 100644 --- a/.gitignore +++ b/.gitignore @@ -58,10 +58,7 @@ typings/ .env # custom -sign.js -t.js -p.js config.json certs -/cdn -dump.rdb \ No newline at end of file +cdn +dist \ No newline at end of file From b655fec99a0ccc60e239287d2a73e07aa1a24b0e Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 28 Feb 2023 20:25:27 -0500 Subject: [PATCH 02/65] Move logger to src folder --- src/config-manager.js | 2 +- src/database.js | 2 +- logger.js => src/logger.js | 0 src/server.js | 2 +- src/services/api/index.js | 2 +- src/services/api/routes/v1/register.js | 2 +- src/services/assets/index.js | 2 +- src/services/conntest/index.js | 2 +- src/services/datastore/index.js | 2 +- src/services/local-cdn/index.js | 2 +- src/services/nasc/index.js | 2 +- src/services/nnid/index.js | 2 +- src/services/nnid/routes/people.js | 2 +- 13 files changed, 12 insertions(+), 12 deletions(-) rename logger.js => src/logger.js (100%) diff --git a/src/config-manager.js b/src/config-manager.js index 6376355..954f2a4 100644 --- a/src/config-manager.js +++ b/src/config-manager.js @@ -1,7 +1,7 @@ const fs = require('fs-extra'); const get = require('lodash.get'); const set = require('lodash.set'); -const logger = require('../logger'); +const logger = require('./logger'); require('dotenv').config(); diff --git a/src/database.js b/src/database.js index bfce6ef..209b5ef 100644 --- a/src/database.js +++ b/src/database.js @@ -4,7 +4,7 @@ const joi = require('joi'); const util = require('./util'); const { PNID } = require('./models/pnid'); const { Server } = require('./models/server'); -const logger = require('../logger'); +const logger = require('./logger'); const { config } = require('./config-manager'); const { connection_string, options } = config.mongoose; diff --git a/logger.js b/src/logger.js similarity index 100% rename from logger.js rename to src/logger.js diff --git a/src/server.js b/src/server.js index 9372a3a..a0b86cd 100644 --- a/src/server.js +++ b/src/server.js @@ -10,7 +10,7 @@ const xmlparser = require('./middleware/xml-parser'); const cache = require('./cache'); const database = require('./database'); const util = require('./util'); -const logger = require('../logger'); +const logger = require('./logger'); const { config } = configManager; diff --git a/src/services/api/index.js b/src/services/api/index.js index 8db69f5..5aee4a6 100644 --- a/src/services/api/index.js +++ b/src/services/api/index.js @@ -4,7 +4,7 @@ const express = require('express'); const subdomain = require('express-subdomain'); const cors = require('cors'); const APIMiddleware = require('../../middleware/api'); -const logger = require('../../../logger'); +const logger = require('../../logger'); const routes = require('./routes'); // Router to handle the subdomain restriction diff --git a/src/services/api/routes/v1/register.js b/src/services/api/routes/v1/register.js index 729bc41..860fad4 100644 --- a/src/services/api/routes/v1/register.js +++ b/src/services/api/routes/v1/register.js @@ -11,7 +11,7 @@ const { NEXAccount } = require('../../../../models/nex-account'); const database = require('../../../../database'); const cache = require('../../../../cache'); const util = require('../../../../util'); -const logger = require('../../../../../logger'); +const logger = require('../../../../logger'); const { config, disabledFeatures } = require('../../../../config-manager'); const PNID_VALID_CHARACTERS_REGEX = /^[\w\-\.]*$/gm; diff --git a/src/services/assets/index.js b/src/services/assets/index.js index 2059739..5061bf3 100644 --- a/src/services/assets/index.js +++ b/src/services/assets/index.js @@ -2,7 +2,7 @@ const express = require('express'); const subdomain = require('express-subdomain'); -const logger = require('../../../logger'); +const logger = require('../../logger'); const path = require('path'); // Router to handle the subdomain restriction diff --git a/src/services/conntest/index.js b/src/services/conntest/index.js index ebe2515..bd4b823 100644 --- a/src/services/conntest/index.js +++ b/src/services/conntest/index.js @@ -2,7 +2,7 @@ const express = require('express'); const subdomain = require('express-subdomain'); -const logger = require('../../../logger'); +const logger = require('../../logger'); // Router to handle the subdomain restriction const conntest = express.Router(); diff --git a/src/services/datastore/index.js b/src/services/datastore/index.js index ab263d2..a5803d1 100644 --- a/src/services/datastore/index.js +++ b/src/services/datastore/index.js @@ -1,6 +1,6 @@ const express = require('express'); const subdomain = require('express-subdomain'); -const logger = require('../../../logger'); +const logger = require('../../logger'); const routes = require('./routes'); // Router to handle the subdomain diff --git a/src/services/local-cdn/index.js b/src/services/local-cdn/index.js index b0e3985..ca8b894 100644 --- a/src/services/local-cdn/index.js +++ b/src/services/local-cdn/index.js @@ -1,6 +1,6 @@ const express = require('express'); const subdomain = require('express-subdomain'); -const logger = require('../../../logger'); +const logger = require('../../logger'); const { config, disabledFeatures } = require('../../config-manager'); if (!disabledFeatures.s3) { diff --git a/src/services/nasc/index.js b/src/services/nasc/index.js index 9f4f9f3..9266a81 100644 --- a/src/services/nasc/index.js +++ b/src/services/nasc/index.js @@ -3,7 +3,7 @@ const express = require('express'); const subdomain = require('express-subdomain'); const NASCMiddleware = require('../../middleware/nasc'); -const logger = require('../../../logger'); +const logger = require('../../logger'); const routes = require('./routes'); // Router to handle the subdomain restriction diff --git a/src/services/nnid/index.js b/src/services/nnid/index.js index 84f1d71..39334b6 100644 --- a/src/services/nnid/index.js +++ b/src/services/nnid/index.js @@ -5,7 +5,7 @@ const subdomain = require('express-subdomain'); const clientHeaderCheck = require('../../middleware/client-header'); const cemuMiddleware = require('../../middleware/cemu'); const pnidMiddleware = require('../../middleware/pnid'); -const logger = require('../../../logger'); +const logger = require('../../logger'); const routes = require('./routes'); // Router to handle the subdomain restriction diff --git a/src/services/nnid/routes/people.js b/src/services/nnid/routes/people.js index 7d1287a..6460877 100644 --- a/src/services/nnid/routes/people.js +++ b/src/services/nnid/routes/people.js @@ -9,7 +9,7 @@ const deviceCertificateMiddleware = require('../../../middleware/device-certific const ratelimit = require('../../../middleware/ratelimit'); const database = require('../../../database'); const util = require('../../../util'); -const logger = require('../../../../logger'); +const logger = require('../../../logger'); require('moment-timezone'); /** From e1649503908a2e16092e1d3eae3f02b869632d0a Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 28 Feb 2023 20:27:59 -0500 Subject: [PATCH 03/65] Make logger path configurable --- src/config-manager.js | 1 + src/logger.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config-manager.js b/src/config-manager.js index 954f2a4..83e9b45 100644 --- a/src/config-manager.js +++ b/src/config-manager.js @@ -72,6 +72,7 @@ function configure() { logger.info('Loading config from environment variable'); config = { + logger_path: process.env.PN_ACT_LOGGER_PATH, http: { port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT) }, diff --git a/src/logger.js b/src/logger.js index 07215de..3f61fb6 100644 --- a/src/logger.js +++ b/src/logger.js @@ -1,7 +1,9 @@ const fs = require('fs-extra'); require('colors'); -const root = __dirname; +const { config } = require('./config-manager'); + +const root = config.logger_path ? config.logger_path : `${__dirname}/..`; fs.ensureDirSync(`${root}/logs`); const streams = { From 6787361ee414188337495d89459a0512511d6327 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 28 Feb 2023 20:44:01 -0500 Subject: [PATCH 04/65] Remove unused modules --- package-lock.json | 448 +--------------------------------------------- package.json | 3 - 2 files changed, 2 insertions(+), 449 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79df13e..63f9f0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "account", - "version": "1.0.0", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "account", - "version": "1.0.0", + "version": "2.0.0", "license": "ISC", "dependencies": { "aws-sdk": "^2.978.0", @@ -17,10 +17,8 @@ "dotenv": "^16.0.3", "email-validator": "^2.0.4", "express": "^4.17.1", - "express-form-data": "^2.0.17", "express-rate-limit": "^5.3.0", "express-subdomain": "^1.0.5", - "formidable": "^1.2.2", "fs-extra": "^8.1.0", "got": "^11.8.2", "hcaptcha": "^0.1.0", @@ -35,7 +33,6 @@ "mongoose": "^5.8.3", "mongoose-unique-validator": "^2.0.3", "morgan": "^1.9.1", - "multer": "^1.4.3", "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", @@ -454,11 +451,6 @@ "node": ">=8" } }, - "node_modules/append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" - }, "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -547,14 +539,6 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/atob-lite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", @@ -803,18 +787,6 @@ "resolved": "https://registry.npmjs.org/buffer-to-uint8array/-/buffer-to-uint8array-1.1.0.tgz", "integrity": "sha512-JVTSbtA6YuOGdu5NL0ffizsBwuwbTXfV7OC91FhazMz9UKP/KlDS+Z7wuiSRClbnTQz52fJgVXI9YDXQRVl2sQ==" }, - "node_modules/busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", - "dependencies": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -970,84 +942,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/connect-multiparty": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/connect-multiparty/-/connect-multiparty-2.2.0.tgz", - "integrity": "sha512-zKcpA7cuXGEhuw9Pz7JmVCFmp85jzGLGm/iiagXTwyEAJp4ypLPtRS/V4IGuGb9KjjrgHBs6P/gDCpZHnFzksA==", - "dependencies": { - "http-errors": "~1.7.0", - "multiparty": "~4.2.1", - "on-finished": "~2.3.0", - "qs": "~6.5.2", - "type-is": "~1.6.16" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/connect-multiparty/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/connect-multiparty/node_modules/http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/connect-multiparty/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/connect-multiparty/node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/connect-multiparty/node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "node_modules/connect-multiparty/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/connect-multiparty/node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } - }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -1542,52 +1436,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express-form-data": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/express-form-data/-/express-form-data-2.0.19.tgz", - "integrity": "sha512-QWulRIYvZV/ZOuO0+SNpCs9Gl0st9SssYtm5Icfm17p2MU4HASLpd4K5w8fwnXB/lPPskecVSeqjVWi2SwIb1A==", - "dependencies": { - "connect-multiparty": "^2.2.0", - "fs-extra": "^9.1.0", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": ">=5.0.0" - } - }, - "node_modules/express-form-data/node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/express-form-data/node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/express-form-data/node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", - "engines": { - "node": ">= 10.0.0" - } - }, "node_modules/express-rate-limit": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", @@ -1715,15 +1563,6 @@ "node": ">= 0.12" } }, - "node_modules/formidable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", - "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", - "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", - "funding": { - "url": "https://ko-fi.com/tunnckoCore/commissions" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -2603,17 +2442,6 @@ "node": ">=8" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -2802,69 +2630,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/multer": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", - "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", - "deprecated": "Multer 1.x is affected by CVE-2022-24434. This is fixed in v1.4.4-lts.1 which drops support for versions of Node.js before 6. Please upgrade to at least Node.js 6 and version 1.4.4-lts.1 of Multer. If you need support for older versions of Node.js, we are open to accepting patches that would fix the CVE on the main 1.x release line, whilst maintaining compatibility with Node.js 0.10.", - "dependencies": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/multiparty": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz", - "integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==", - "dependencies": { - "http-errors": "~1.8.1", - "safe-buffer": "5.2.1", - "uid-safe": "2.1.5" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/multiparty/node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/multiparty/node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/multiparty/node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -3216,14 +2981,6 @@ "quote-stream": "bin/cmd.js" } }, - "node_modules/random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -3904,17 +3661,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "node_modules/uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "dependencies": { - "random-bytes": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -4491,11 +4237,6 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, - "append-field": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", - "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" - }, "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -4574,11 +4315,6 @@ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, - "at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==" - }, "atob-lite": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/atob-lite/-/atob-lite-2.0.0.tgz", @@ -4785,15 +4521,6 @@ "resolved": "https://registry.npmjs.org/buffer-to-uint8array/-/buffer-to-uint8array-1.1.0.tgz", "integrity": "sha512-JVTSbtA6YuOGdu5NL0ffizsBwuwbTXfV7OC91FhazMz9UKP/KlDS+Z7wuiSRClbnTQz52fJgVXI9YDXQRVl2sQ==" }, - "busboy": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", - "integrity": "sha512-InWFDomvlkEj+xWLBfU3AvnbVYqeTWmQopiW0tWWEy5yehYm2YkGEc59sUmw/4ty5Zj/b0WHGs1LgecuBSBGrg==", - "requires": { - "dicer": "0.2.5", - "readable-stream": "1.1.x" - } - }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -4918,65 +4645,6 @@ } } }, - "connect-multiparty": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/connect-multiparty/-/connect-multiparty-2.2.0.tgz", - "integrity": "sha512-zKcpA7cuXGEhuw9Pz7JmVCFmp85jzGLGm/iiagXTwyEAJp4ypLPtRS/V4IGuGb9KjjrgHBs6P/gDCpZHnFzksA==", - "requires": { - "http-errors": "~1.7.0", - "multiparty": "~4.2.1", - "on-finished": "~2.3.0", - "qs": "~6.5.2", - "type-is": "~1.6.16" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "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" - } - }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==" - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - } - } - }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", @@ -5375,43 +5043,6 @@ "vary": "~1.1.2" } }, - "express-form-data": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/express-form-data/-/express-form-data-2.0.19.tgz", - "integrity": "sha512-QWulRIYvZV/ZOuO0+SNpCs9Gl0st9SssYtm5Icfm17p2MU4HASLpd4K5w8fwnXB/lPPskecVSeqjVWi2SwIb1A==", - "requires": { - "connect-multiparty": "^2.2.0", - "fs-extra": "^9.1.0", - "signal-exit": "^3.0.7" - }, - "dependencies": { - "fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "requires": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - } - }, - "jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" - } - }, - "universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" - } - } - }, "express-rate-limit": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", @@ -5523,11 +5154,6 @@ "mime-types": "^2.1.12" } }, - "formidable": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", - "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==" - }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -6200,14 +5826,6 @@ } } }, - "mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "requires": { - "minimist": "^1.2.6" - } - }, "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -6346,55 +5964,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "multer": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz", - "integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==", - "requires": { - "append-field": "^1.0.0", - "busboy": "^0.2.11", - "concat-stream": "^1.5.2", - "mkdirp": "^0.5.4", - "object-assign": "^4.1.1", - "on-finished": "^2.3.0", - "type-is": "^1.6.4", - "xtend": "^4.0.0" - } - }, - "multiparty": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/multiparty/-/multiparty-4.2.3.tgz", - "integrity": "sha512-Ak6EUJZuhGS8hJ3c2fY6UW5MbkGUPMBEGd13djUzoY/BHqV/gTuFWtC6IuVA7A2+v3yjBS6c4or50xhzTQZImQ==", - "requires": { - "http-errors": "~1.8.1", - "safe-buffer": "5.2.1", - "uid-safe": "2.1.5" - }, - "dependencies": { - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" - }, - "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.1" - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==" - } - } - }, "mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -6653,11 +6222,6 @@ "through2": "^2.0.0" } }, - "random-bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==" - }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -7219,14 +6783,6 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, - "uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "requires": { - "random-bytes": "~1.0.0" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index bed4955..e6b5372 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,8 @@ "dotenv": "^16.0.3", "email-validator": "^2.0.4", "express": "^4.17.1", - "express-form-data": "^2.0.17", "express-rate-limit": "^5.3.0", "express-subdomain": "^1.0.5", - "formidable": "^1.2.2", "fs-extra": "^8.1.0", "got": "^11.8.2", "hcaptcha": "^0.1.0", @@ -46,7 +44,6 @@ "mongoose": "^5.8.3", "mongoose-unique-validator": "^2.0.3", "morgan": "^1.9.1", - "multer": "^1.4.3", "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", From 868a8ed9bbfbb49a6b1f67915a08506ccd8e06a5 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 28 Feb 2023 20:58:51 -0500 Subject: [PATCH 05/65] Pull logger path from env directly --- src/config-manager.js | 1 - src/logger.js | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/config-manager.js b/src/config-manager.js index 83e9b45..954f2a4 100644 --- a/src/config-manager.js +++ b/src/config-manager.js @@ -72,7 +72,6 @@ function configure() { logger.info('Loading config from environment variable'); config = { - logger_path: process.env.PN_ACT_LOGGER_PATH, http: { port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT) }, diff --git a/src/logger.js b/src/logger.js index 3f61fb6..3a925e2 100644 --- a/src/logger.js +++ b/src/logger.js @@ -1,9 +1,7 @@ const fs = require('fs-extra'); require('colors'); -const { config } = require('./config-manager'); - -const root = config.logger_path ? config.logger_path : `${__dirname}/..`; +const root = process.env.PN_ACT_LOGGER_PATH ? process.env.PN_ACT_LOGGER_PATH : `${__dirname}/..`; fs.ensureDirSync(`${root}/logs`); const streams = { From ff69ac3ceac4211e5c7c75b1baea5544fbf47a9f Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 28 Feb 2023 21:08:52 -0500 Subject: [PATCH 06/65] Added tsconfig and start of TypeScript migration --- package.json | 7 ++++++- tsconfig.json | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tsconfig.json diff --git a/package.json b/package.json index e6b5372..0385b45 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,14 @@ "name": "account", "version": "1.0.0", "description": "", - "main": "./src/server.js", + "main": "./dist/server.js", "scripts": { "lint": "./node_modules/.bin/eslint .", + "build": "npm run clean && tsc && npm run copy-static", + "clean": "rm -rf ./dist", + "copy-static": "npm run copy-assets && npm run copy-timezones", + "copy-assets": "cp -r ./src/assets ./dist/assets", + "copy-timezones": "cp ./src/services/nnid/timezones.json ./dist/services/nnid/timezones.json", "start": "node .", "start:dev": "NODE_ENV=development node ." }, diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..af34411 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "outDir": "./dist", + "allowJs": true, + "target": "es6", + "noEmitOnError": true + }, + "include": [ + "./src/**/*" + ] +} \ No newline at end of file From 0543bd45c843931bbd5c8173376d1efc3bffed96 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 1 Mar 2023 16:34:17 -0500 Subject: [PATCH 07/65] Enabled esModuleInterop in tsconfig --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index af34411..805bffc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "esModuleInterop": true, "outDir": "./dist", "allowJs": true, "target": "es6", From b4980e942d9f944af60a987e4f690b9dbdd77b7b Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 1 Mar 2023 16:36:21 -0500 Subject: [PATCH 08/65] Set moduleResolution to node in tsconfig --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index 805bffc..bdc34e9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "compilerOptions": { "esModuleInterop": true, + "moduleResolution": "node", "outDir": "./dist", "allowJs": true, "target": "es6", From bcbf403abaf4d6e758e14dfc2edb10535f7a04bb Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 1 Mar 2023 17:53:14 -0500 Subject: [PATCH 09/65] Set module to commonjs in tsconfig --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index bdc34e9..9fe2c15 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "module": "commonjs", "esModuleInterop": true, "moduleResolution": "node", "outDir": "./dist", From 68a0fa819319a25f3c2348c51b591fbcfa474b00 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 2 Mar 2023 19:29:09 -0500 Subject: [PATCH 10/65] Added es2021 lib to compilerOptions (needed for replaceAll) --- tsconfig.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 9fe2c15..a15797f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,8 +6,14 @@ "outDir": "./dist", "allowJs": true, "target": "es6", - "noEmitOnError": true + "noEmitOnError": true, + "lib": [ + "es2021" + ] }, + "lib": [ + "es6" + ], "include": [ "./src/**/*" ] From bf3e357bc1284a84df33aeef88be806c46876f4c Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 2 Mar 2023 19:37:17 -0500 Subject: [PATCH 11/65] Set tsconfig target to es2022 --- tsconfig.json | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index a15797f..ce05381 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,15 +5,9 @@ "moduleResolution": "node", "outDir": "./dist", "allowJs": true, - "target": "es6", - "noEmitOnError": true, - "lib": [ - "es2021" - ] + "target": "es2022", + "noEmitOnError": true }, - "lib": [ - "es6" - ], "include": [ "./src/**/*" ] From 8bb3d600c48ebe307ddf382ea3f3728ddfad3ce8 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 3 Mar 2023 00:28:08 -0500 Subject: [PATCH 12/65] Add types folder to ts includes --- tsconfig.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index ce05381..7e9987e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,7 +8,5 @@ "target": "es2022", "noEmitOnError": true }, - "include": [ - "./src/**/*" - ] + "include": ["src", "types"] } \ No newline at end of file From 84bf498d48f665656e8de85de5e11c3f67cb6029 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 3 Mar 2023 00:29:12 -0500 Subject: [PATCH 13/65] Enable "resolveJsonModule": true in tsconfig --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index 7e9987e..9d94299 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "resolveJsonModule": true, "module": "commonjs", "esModuleInterop": true, "moduleResolution": "node", From 3ef40c64cd53a8fceefe6ba93b07ce7b331bf531 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 3 Mar 2023 12:37:50 -0500 Subject: [PATCH 14/65] Updated packages --- package-lock.json | 490 ++++++++++++++++++++++++++++++++++------------ package.json | 11 +- 2 files changed, 367 insertions(+), 134 deletions(-) diff --git a/package-lock.json b/package-lock.json index 63f9f0b..1473949 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,19 @@ { "name": "account", - "version": "2.0.0", + "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "account", - "version": "2.0.0", + "version": "1.0.0", "license": "ISC", "dependencies": { "aws-sdk": "^2.978.0", "bcrypt": "^5.0.0", "colors": "^1.4.0", "cors": "^2.8.5", + "countries-and-timezones": "^3.4.1", "dicer": "^0.2.5", "dotenv": "^16.0.3", "email-validator": "^2.0.4", @@ -23,16 +24,16 @@ "got": "^11.8.2", "hcaptcha": "^0.1.0", "image-pixels": "^1.1.1", - "joi": "^17.6.1", + "joi": "^17.8.3", "kaitai-struct": "^0.9.0", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", "mii-js": "github:PretendoNetwork/mii-js", - "moment": "^2.24.0", - "moment-timezone": "^0.5.27", + "moment": "^2.29.4", "mongoose": "^5.8.3", "mongoose-unique-validator": "^2.0.3", "morgan": "^1.9.1", + "neat-config": "^1.0.0", "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", @@ -41,6 +42,11 @@ "xmlbuilder2": "0.0.4" }, "devDependencies": { + "@types/colors": "^1.2.1", + "@types/express": "^4.17.17", + "@types/fs-extra": "^11.0.1", + "@types/morgan": "^1.9.4", + "@types/node": "^18.14.4", "node-rsa": "^1.0.7", "prompt": "^1.0.0", "yesno": "^0.4.0" @@ -212,9 +218,9 @@ } }, "node_modules/@redis/client": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.5.tgz", - "integrity": "sha512-fuMnpDYSjT5JXR9rrCW1YWA4L8N/9/uS4ImT3ZEC/hcaQRI1D/9FvwjriRj1UvepIgzZXthFVKMNRzP/LNL7BQ==", + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.6.tgz", + "integrity": "sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==", "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -241,9 +247,9 @@ } }, "node_modules/@redis/search": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.1.tgz", - "integrity": "sha512-pqCXTc5e7wJJgUuJiC3hBgfoFRoPxYzwn0BEfKgejTM7M/9zP3IpUcqcjgfp8hF+LoV8rHZzcNTz7V+pEIY7LQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -296,6 +302,16 @@ "node": ">=10" } }, + "node_modules/@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, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, "node_modules/@types/bson": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", @@ -315,11 +331,72 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/colors": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/colors/-/colors-1.2.1.tgz", + "integrity": "sha512-7jNkpfN2lVO07nJ1RWzyMnNhH/I5N9iWuMPx9pedptxJ4MODf8rRV0lbJi6RakQ4sKQk231Fw4e2W9n3D7gZ3w==", + "deprecated": "This is a stub types definition. colors provides its own type definitions, so you don't need this installed.", + "dev": true, + "dependencies": { + "colors": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "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.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/fs-extra": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz", + "integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==", + "dev": true, + "dependencies": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "node_modules/@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, + "node_modules/@types/jsonfile": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", + "integrity": "sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -328,6 +405,12 @@ "@types/node": "*" } }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, "node_modules/@types/mongodb": { "version": "3.6.20", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", @@ -337,10 +420,31 @@ "@types/node": "*" } }, + "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": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==" + "version": "18.14.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.4.tgz", + "integrity": "sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==" + }, + "node_modules/@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/@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/@types/responselike": { "version": "1.0.0", @@ -350,6 +454,16 @@ "@types/node": "*" } }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -469,9 +583,9 @@ } }, "node_modules/are-we-there-yet/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.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -556,9 +670,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1313.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1313.0.tgz", - "integrity": "sha512-8GMdtV2Uch3HL2c6+P3lNZFTcg/fqq9L3EWYRLb6ljCZvWKTssjdkjSJFDyTReNgeiKV224YRPYQbKpOEz4flQ==", + "version": "2.1325.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1325.0.tgz", + "integrity": "sha512-ztg9HG5aoUHTprY+/eqjqb25E4joCgz+8ToxsP4OSKFQCtaBcF6my03j4e/J2j3fmpPifJnZSPMu4kV7DBj8WA==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -664,9 +778,9 @@ } }, "node_modules/bl/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -916,9 +1030,9 @@ } }, "node_modules/concat-stream/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -1001,6 +1115,15 @@ "node": ">= 0.10" } }, + "node_modules/countries-and-timezones": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/countries-and-timezones/-/countries-and-timezones-3.4.1.tgz", + "integrity": "sha512-INeHGCony4XUUR8iGL/lmt9s1Oi+n+gFHeJAMfbV5hJfYeDOB8JG1oxz5xFQu5oBZoRCJe/87k1Vzue9DoIauA==", + "engines": { + "node": ">=8.x", + "npm": ">=5.x" + } + }, "node_modules/cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -1164,9 +1287,9 @@ } }, "node_modules/duplexer2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2140,9 +2263,9 @@ } }, "node_modules/joi": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.1.tgz", - "integrity": "sha512-teoLhIvWE298R6AeJywcjR4sX2hHjB3/xJX4qPjg+gTg+c0mzUDsziYlqPmLomq9gVsfaMcgPaGc7VxtD/9StA==", + "version": "17.8.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.8.3.tgz", + "integrity": "sha512-q5Fn6Tj/jR8PfrLrx4fpGH4v9qM6o+vDUfD4/3vxxyg34OmKcNqYZ1qn2mpLza96S8tL0p0rIw2gOZX+/cTg9w==", "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -2412,9 +2535,9 @@ } }, "node_modules/minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", + "integrity": "sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==", "engines": { "node": ">=8" } @@ -2442,6 +2565,17 @@ "node": ">=8" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", @@ -2450,17 +2584,6 @@ "node": "*" } }, - "node_modules/moment-timezone": { - "version": "0.5.40", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.40.tgz", - "integrity": "sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg==", - "dependencies": { - "moment": ">= 2.9.0" - }, - "engines": { - "node": "*" - } - }, "node_modules/mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", @@ -2511,9 +2634,9 @@ } }, "node_modules/mongoose": { - "version": "5.13.15", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz", - "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==", + "version": "5.13.16", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.16.tgz", + "integrity": "sha512-kBNB+BfaQjn3Jjh1SfdZZub70pde9dI0sA8VN6AnnCOeK4TzbLDyB0lBmPBOajppm6U9orde5YfTRyyVa1U45w==", "dependencies": { "@types/bson": "1.x || 4.0.x", "@types/mongodb": "^3.5.27", @@ -2636,6 +2759,14 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/neat-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/neat-config/-/neat-config-1.0.0.tgz", + "integrity": "sha512-EKvHxsZ9yOUHWhx6MxxzbTDhNK0wiSbfaU42s2OnQuVgR+FwpswaiSm3xX7ST4TcN+rJiEw+GuhfK015vHKwrA==", + "dependencies": { + "joi": "^17.6.0" + } + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -3032,15 +3163,15 @@ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" }, "node_modules/redis": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.4.tgz", - "integrity": "sha512-wi2tgDdQ+Q8q+PR5FLRx4QvDiWaA+PoJbrzsyFqlClN5R4LplHqN3scs/aGjE//mbz++W19SgxiEnQ27jnCRaA==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.5.tgz", + "integrity": "sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==", "dependencies": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.5", + "@redis/client": "1.5.6", "@redis/graph": "1.1.0", "@redis/json": "1.0.4", - "@redis/search": "1.1.1", + "@redis/search": "1.1.2", "@redis/time-series": "1.0.4" } }, @@ -3406,9 +3537,9 @@ } }, "node_modules/static-module/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3518,17 +3649,6 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/tga": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/tga/-/tga-1.0.7.tgz", @@ -3551,9 +3671,9 @@ } }, "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4046,9 +4166,9 @@ "requires": {} }, "@redis/client": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.5.tgz", - "integrity": "sha512-fuMnpDYSjT5JXR9rrCW1YWA4L8N/9/uS4ImT3ZEC/hcaQRI1D/9FvwjriRj1UvepIgzZXthFVKMNRzP/LNL7BQ==", + "version": "1.5.6", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.6.tgz", + "integrity": "sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==", "requires": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -4068,9 +4188,9 @@ "requires": {} }, "@redis/search": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.1.tgz", - "integrity": "sha512-pqCXTc5e7wJJgUuJiC3hBgfoFRoPxYzwn0BEfKgejTM7M/9zP3IpUcqcjgfp8hF+LoV8rHZzcNTz7V+pEIY7LQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", "requires": {} }, "@redis/time-series": { @@ -4110,6 +4230,16 @@ "defer-to-connect": "^2.0.0" } }, + "@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/bson": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", @@ -4129,11 +4259,71 @@ "@types/responselike": "^1.0.0" } }, + "@types/colors": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/colors/-/colors-1.2.1.tgz", + "integrity": "sha512-7jNkpfN2lVO07nJ1RWzyMnNhH/I5N9iWuMPx9pedptxJ4MODf8rRV0lbJi6RakQ4sKQk231Fw4e2W9n3D7gZ3w==", + "dev": true, + "requires": { + "colors": "*" + } + }, + "@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/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/fs-extra": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.1.tgz", + "integrity": "sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==", + "dev": true, + "requires": { + "@types/jsonfile": "*", + "@types/node": "*" + } + }, "@types/http-cache-semantics": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, + "@types/jsonfile": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", + "integrity": "sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/keyv": { "version": "3.1.4", "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", @@ -4142,6 +4332,12 @@ "@types/node": "*" } }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, "@types/mongodb": { "version": "3.6.20", "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", @@ -4151,10 +4347,31 @@ "@types/node": "*" } }, + "@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": "18.13.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.13.0.tgz", - "integrity": "sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==" + "version": "18.14.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.4.tgz", + "integrity": "sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==" + }, + "@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/responselike": { "version": "1.0.0", @@ -4164,6 +4381,16 @@ "@types/node": "*" } }, + "@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -4252,9 +4479,9 @@ }, "dependencies": { "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.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.1.tgz", + "integrity": "sha512-+rQmrWMYGA90yenhTYsLWAsLsqVC8osOw6PKE1HDYiO0gdPeKe/xDHNzIAIn4C91YQ6oenEhfYqqc1883qHbjQ==", "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -4326,9 +4553,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "aws-sdk": { - "version": "2.1313.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1313.0.tgz", - "integrity": "sha512-8GMdtV2Uch3HL2c6+P3lNZFTcg/fqq9L3EWYRLb6ljCZvWKTssjdkjSJFDyTReNgeiKV224YRPYQbKpOEz4flQ==", + "version": "2.1325.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1325.0.tgz", + "integrity": "sha512-ztg9HG5aoUHTprY+/eqjqb25E4joCgz+8ToxsP4OSKFQCtaBcF6my03j4e/J2j3fmpPifJnZSPMu4kV7DBj8WA==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -4409,9 +4636,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4617,9 +4844,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -4692,6 +4919,11 @@ "vary": "^1" } }, + "countries-and-timezones": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/countries-and-timezones/-/countries-and-timezones-3.4.1.tgz", + "integrity": "sha512-INeHGCony4XUUR8iGL/lmt9s1Oi+n+gFHeJAMfbV5hJfYeDOB8JG1oxz5xFQu5oBZoRCJe/87k1Vzue9DoIauA==" + }, "cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -4811,9 +5043,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -5579,9 +5811,9 @@ "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" }, "joi": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.1.tgz", - "integrity": "sha512-teoLhIvWE298R6AeJywcjR4sX2hHjB3/xJX4qPjg+gTg+c0mzUDsziYlqPmLomq9gVsfaMcgPaGc7VxtD/9StA==", + "version": "17.8.3", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.8.3.tgz", + "integrity": "sha512-q5Fn6Tj/jR8PfrLrx4fpGH4v9qM6o+vDUfD4/3vxxyg34OmKcNqYZ1qn2mpLza96S8tL0p0rIw2gOZX+/cTg9w==", "requires": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -5803,9 +6035,9 @@ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "minipass": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz", - "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.4.tgz", + "integrity": "sha512-lwycX3cBMTvcejsHITUgYj6Gy6A7Nh4Q6h9NP4sTHY1ccJlC7yKzDmiShEHsJ16Jf1nKGDEaiHxiltsJEvk0nQ==" }, "minizlib": { "version": "2.1.2", @@ -5826,19 +6058,16 @@ } } }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + }, "moment": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, - "moment-timezone": { - "version": "0.5.40", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.40.tgz", - "integrity": "sha512-tWfmNkRYmBkPJz5mr9GVDn9vRlVZOTe6yqY92rFxiOdWXbjaR0+9LwQnZGGuNR63X456NqmEkbskte8tWL5ePg==", - "requires": { - "moment": ">= 2.9.0" - } - }, "mongodb": { "version": "3.7.3", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", @@ -5863,9 +6092,9 @@ } }, "mongoose": { - "version": "5.13.15", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.15.tgz", - "integrity": "sha512-cxp1Gbb8yUWkaEbajdhspSaKzAvsIvOtRlYD87GN/P2QEUhpd6bIvebi36T6M0tIVAMauNaK9SPA055N3PwF8Q==", + "version": "5.13.16", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.16.tgz", + "integrity": "sha512-kBNB+BfaQjn3Jjh1SfdZZub70pde9dI0sA8VN6AnnCOeK4TzbLDyB0lBmPBOajppm6U9orde5YfTRyyVa1U45w==", "requires": { "@types/bson": "1.x || 4.0.x", "@types/mongodb": "^3.5.27", @@ -5970,6 +6199,14 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "neat-config": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/neat-config/-/neat-config-1.0.0.tgz", + "integrity": "sha512-EKvHxsZ9yOUHWhx6MxxzbTDhNK0wiSbfaU42s2OnQuVgR+FwpswaiSm3xX7ST4TcN+rJiEw+GuhfK015vHKwrA==", + "requires": { + "joi": "^17.6.0" + } + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6266,15 +6503,15 @@ } }, "redis": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.4.tgz", - "integrity": "sha512-wi2tgDdQ+Q8q+PR5FLRx4QvDiWaA+PoJbrzsyFqlClN5R4LplHqN3scs/aGjE//mbz++W19SgxiEnQ27jnCRaA==", + "version": "4.6.5", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.5.tgz", + "integrity": "sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==", "requires": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.5", + "@redis/client": "1.5.6", "@redis/graph": "1.1.0", "@redis/json": "1.0.4", - "@redis/search": "1.1.1", + "@redis/search": "1.1.2", "@redis/time-series": "1.0.4" } }, @@ -6565,9 +6802,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -6658,13 +6895,6 @@ "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" - }, - "dependencies": { - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" - } } }, "tga": { @@ -6686,9 +6916,9 @@ }, "dependencies": { "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", diff --git a/package.json b/package.json index 0385b45..c4acc78 100644 --- a/package.json +++ b/package.json @@ -39,13 +39,11 @@ "got": "^11.8.2", "hcaptcha": "^0.1.0", "image-pixels": "^1.1.1", - "joi": "^17.6.1", - "kaitai-struct": "^0.9.0", + "joi": "^17.8.3", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", "mii-js": "github:PretendoNetwork/mii-js", - "moment": "^2.24.0", - "moment-timezone": "^0.5.27", + "moment": "^2.29.4", "mongoose": "^5.8.3", "mongoose-unique-validator": "^2.0.3", "morgan": "^1.9.1", @@ -57,6 +55,11 @@ "xmlbuilder2": "0.0.4" }, "devDependencies": { + "@types/colors": "^1.2.1", + "@types/express": "^4.17.17", + "@types/fs-extra": "^11.0.1", + "@types/morgan": "^1.9.4", + "@types/node": "^18.14.4", "node-rsa": "^1.0.7", "prompt": "^1.0.0", "yesno": "^0.4.0" From a75769a326948aaf3e14074d4d137439e8c8c866 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 3 Mar 2023 12:38:36 -0500 Subject: [PATCH 15/65] First steps to TypeScript --- src/{cache.js => cache.ts} | 57 ++--- src/{config-manager.js => config-manager.ts} | 76 ++----- src/{database.js => database.ts} | 67 +++--- src/{logger.js => logger.ts} | 8 +- src/{mailer.js => mailer.ts} | 37 +-- src/middleware/{api.js => api.ts} | 8 +- src/middleware/{cemu.js => cemu.ts} | 4 +- .../{client-header.js => client-header.ts} | 14 +- ...e-certificate.js => device-certificate.ts} | 6 +- src/middleware/{nasc.js => nasc.ts} | 17 +- src/middleware/{pnid.js => pnid.ts} | 8 +- src/middleware/{ratelimit.js => ratelimit.ts} | 6 +- .../{xml-parser.js => xml-parser.ts} | 8 +- src/mii.js | 214 ------------------ src/models/{device.js => device.ts} | 16 +- src/models/{nex-account.js => nex-account.ts} | 22 +- src/models/{pnid.js => pnid.ts} | 65 ++---- src/models/{server.js => server.ts} | 10 +- ...certificate.js => nintendo-certificate.ts} | 30 ++- src/{server.js => server.ts} | 34 +-- src/services/api/{index.js => index.ts} | 14 +- src/services/api/routes/index.js | 11 - src/services/api/routes/index.ts | 19 ++ .../v1/{connections.js => connections.ts} | 8 +- .../api/routes/v1/{email.js => email.ts} | 20 +- .../{forgotPassword.js => forgotPassword.ts} | 12 +- .../api/routes/v1/{login.js => login.ts} | 16 +- .../routes/v1/{register.js => register.ts} | 35 +-- .../v1/{resetPassword.js => resetPassword.ts} | 12 +- .../api/routes/v1/{user.js => user.ts} | 12 +- src/services/assets/{index.js => index.ts} | 10 +- src/services/conntest/{index.js => index.ts} | 8 +- src/services/datastore/{index.js => index.ts} | 10 +- src/services/datastore/routes/index.js | 3 - src/services/datastore/routes/index.ts | 5 + .../datastore/routes/{upload.js => upload.ts} | 16 +- src/services/local-cdn/index.js | 30 --- src/services/local-cdn/index.ts | 26 +++ .../local-cdn/routes/{get.js => get.ts} | 8 +- src/services/local-cdn/routes/index.js | 3 - src/services/local-cdn/routes/index.ts | 5 + src/services/nasc/{index.js => index.ts} | 12 +- src/services/nasc/routes/{ac.js => ac.ts} | 12 +- src/services/nasc/routes/index.js | 3 - src/services/nasc/routes/index.ts | 5 + src/services/nnid/{index.js => index.ts} | 16 +- src/services/nnid/routes/admin.js | 59 ----- src/services/nnid/routes/admin.ts | 88 +++++++ .../nnid/routes/{content.js => content.ts} | 14 +- .../nnid/routes/{devices.js => devices.ts} | 8 +- src/services/nnid/routes/index.js | 10 - src/services/nnid/routes/index.ts | 19 ++ src/services/nnid/routes/{miis.js => miis.ts} | 12 +- .../nnid/routes/{oauth.js => oauth.ts} | 16 +- .../nnid/routes/{people.js => people.ts} | 68 +++--- .../nnid/routes/{provider.js => provider.ts} | 22 +- .../nnid/routes/{support.js => support.ts} | 16 +- src/{util.js => util.ts} | 2 +- types/express.d.ts | 12 + types/mongoose/device-attribute.d.ts | 13 ++ types/mongoose/device.d.ts | 32 +++ types/mongoose/nex-account.d.ts | 23 ++ types/mongoose/pnid.d.ts | 81 +++++++ types/mongoose/server.d.ts | 19 ++ 64 files changed, 775 insertions(+), 777 deletions(-) rename src/{cache.js => cache.ts} (75%) rename src/{config-manager.js => config-manager.ts} (77%) rename src/{database.js => database.ts} (73%) rename src/{logger.js => logger.ts} (90%) rename src/{mailer.js => mailer.ts} (54%) rename src/middleware/{api.js => api.ts} (62%) rename src/middleware/{cemu.js => cemu.ts} (56%) rename src/middleware/{client-header.js => client-header.ts} (72%) rename src/middleware/{device-certificate.js => device-certificate.ts} (56%) rename src/middleware/{nasc.js => nasc.ts} (93%) rename src/middleware/{pnid.js => pnid.ts} (83%) rename src/middleware/{ratelimit.js => ratelimit.ts} (61%) rename src/middleware/{xml-parser.js => xml-parser.ts} (79%) delete mode 100644 src/mii.js rename src/models/{device.js => device.ts} (62%) rename src/models/{nex-account.js => nex-account.ts} (82%) rename src/models/{pnid.js => pnid.ts} (77%) rename src/models/{server.js => server.ts} (66%) rename src/{nintendo-certificate.js => nintendo-certificate.ts} (92%) rename src/{server.js => server.ts} (67%) rename src/services/api/{index.js => index.ts} (74%) delete mode 100644 src/services/api/routes/index.js create mode 100644 src/services/api/routes/index.ts rename src/services/api/routes/v1/{connections.js => connections.ts} (92%) rename src/services/api/routes/v1/{email.js => email.ts} (67%) rename src/services/api/routes/v1/{forgotPassword.js => forgotPassword.ts} (72%) rename src/services/api/routes/v1/{login.js => login.ts} (91%) rename src/services/api/routes/v1/{register.js => register.ts} (92%) rename src/services/api/routes/v1/{resetPassword.js => resetPassword.ts} (93%) rename src/services/api/routes/v1/{user.js => user.ts} (92%) rename src/services/assets/{index.js => index.ts} (68%) rename src/services/conntest/{index.js => index.ts} (80%) rename src/services/datastore/{index.js => index.ts} (66%) delete mode 100644 src/services/datastore/routes/index.js create mode 100644 src/services/datastore/routes/index.ts rename src/services/datastore/routes/{upload.js => upload.ts} (89%) delete mode 100644 src/services/local-cdn/index.js create mode 100644 src/services/local-cdn/index.ts rename src/services/local-cdn/routes/{get.js => get.ts} (65%) delete mode 100644 src/services/local-cdn/routes/index.js create mode 100644 src/services/local-cdn/routes/index.ts rename src/services/nasc/{index.js => index.ts} (62%) rename src/services/nasc/routes/{ac.js => ac.ts} (92%) delete mode 100644 src/services/nasc/routes/index.js create mode 100644 src/services/nasc/routes/index.ts rename src/services/nnid/{index.js => index.ts} (69%) delete mode 100644 src/services/nnid/routes/admin.js create mode 100644 src/services/nnid/routes/admin.ts rename src/services/nnid/routes/{content.js => content.ts} (92%) rename src/services/nnid/routes/{devices.js => devices.ts} (65%) delete mode 100644 src/services/nnid/routes/index.js create mode 100644 src/services/nnid/routes/index.ts rename src/services/nnid/routes/{miis.js => miis.ts} (87%) rename src/services/nnid/routes/{oauth.js => oauth.ts} (87%) rename src/services/nnid/routes/{people.js => people.ts} (82%) rename src/services/nnid/routes/{provider.js => provider.ts} (86%) rename src/services/nnid/routes/{support.js => support.ts} (88%) rename src/{util.js => util.ts} (96%) create mode 100644 types/express.d.ts create mode 100644 types/mongoose/device-attribute.d.ts create mode 100644 types/mongoose/device.d.ts create mode 100644 types/mongoose/nex-account.d.ts create mode 100644 types/mongoose/pnid.d.ts create mode 100644 types/mongoose/server.d.ts diff --git a/src/cache.js b/src/cache.ts similarity index 75% rename from src/cache.js rename to src/cache.ts index 6cd89e2..946209e 100644 --- a/src/cache.js +++ b/src/cache.ts @@ -1,6 +1,7 @@ -const fs = require('fs-extra'); -const redis = require('redis'); -const { config, disabledFeatures } = require('./config-manager'); +import fs from 'fs-extra'; +import redis from 'redis'; +import { config, disabledFeatures } from './config-manager'; + let client; const memoryCache = {}; @@ -9,7 +10,7 @@ const SERVICE_CERTS_BASE = `${__dirname}/../certs/service`; const NEX_CERTS_BASE = `${__dirname}/../certs/nex`; const LOCAL_CDN_BASE = `${__dirname}/../cdn`; -async function connect() { +export async function connect() { if (!disabledFeatures.redis) { client = redis.createClient(config.redis.client); client.on('error', (err) => console.log('Redis Client Error', err)); @@ -18,7 +19,7 @@ async function connect() { } } -async function setCachedFile(fileName, value) { +export async function setCachedFile(fileName, value) { if (disabledFeatures.redis) { memoryCache[fileName] = value; } else { @@ -26,7 +27,7 @@ async function setCachedFile(fileName, value) { } } -async function getCachedFile(fileName, encoding) { +export async function getCachedFile(fileName, encoding?) { let cachedFile; if (disabledFeatures.redis) { @@ -42,9 +43,9 @@ async function getCachedFile(fileName, encoding) { return cachedFile; } -// NEX server cache functions +// * NEX server cache functions -async function getNEXPublicKey(name, encoding) { +export async function getNEXPublicKey(name, encoding?) { let publicKey = await getCachedFile(`nex:${name}:public_key`, encoding); if (publicKey === null) { @@ -55,7 +56,7 @@ async function getNEXPublicKey(name, encoding) { return publicKey; } -async function getNEXPrivateKey(name, encoding) { +export async function getNEXPrivateKey(name, encoding?) { let privateKey = await getCachedFile(`nex:${name}:private_key`, encoding); if (privateKey === null) { @@ -66,7 +67,7 @@ async function getNEXPrivateKey(name, encoding) { return privateKey; } -async function getNEXSecretKey(name, encoding) { +export async function getNEXSecretKey(name, encoding?) { let secretKey = await getCachedFile(`nex:${name}:secret_key`, encoding); if (secretKey === null) { @@ -78,7 +79,7 @@ async function getNEXSecretKey(name, encoding) { return secretKey; } -async function getNEXAESKey(name, encoding) { +export async function getNEXAESKey(name, encoding?) { let aesKey = await getCachedFile(`nex:${name}:aes_key`, encoding); if (aesKey === null) { @@ -90,25 +91,25 @@ async function getNEXAESKey(name, encoding) { return aesKey; } -async function setNEXPublicKey(name, value) { +export async function setNEXPublicKey(name, value) { await setCachedFile(`nex:${name}:public_key`, value); } -async function setNEXPrivateKey(name, value) { +export async function setNEXPrivateKey(name, value) { await setCachedFile(`nex:${name}:private_key`, value); } -async function setNEXSecretKey(name, value) { +export async function setNEXSecretKey(name, value) { await setCachedFile(`nex:${name}:secret_key`, value); } -async function setNEXAESKey(name, value) { +export async function setNEXAESKey(name, value) { await setCachedFile(`nex:${name}:aes_key`, value); } -// 3rd party service cache functions +// * 3rd party service cache functions -async function getServicePublicKey(name, encoding) { +export async function getServicePublicKey(name, encoding?) { let publicKey = await getCachedFile(`service:${name}:public_key`, encoding); if (publicKey === null) { @@ -119,7 +120,7 @@ async function getServicePublicKey(name, encoding) { return publicKey; } -async function getServicePrivateKey(name, encoding) { +export async function getServicePrivateKey(name, encoding?) { let privateKey = await getCachedFile(`service:${name}:private_key`, encoding); if (privateKey === null) { @@ -130,7 +131,7 @@ async function getServicePrivateKey(name, encoding) { return privateKey; } -async function getServiceSecretKey(name, encoding) { +export async function getServiceSecretKey(name, encoding?) { let secretKey = await getCachedFile(`service:${name}:secret_key`, encoding); if (secretKey === null) { @@ -142,7 +143,7 @@ async function getServiceSecretKey(name, encoding) { return secretKey; } -async function getServiceAESKey(name, encoding) { +export async function getServiceAESKey(name, encoding?) { let aesKey = await getCachedFile(`service:${name}:aes_key`, encoding); if (aesKey === null) { @@ -154,25 +155,25 @@ async function getServiceAESKey(name, encoding) { return aesKey; } -async function setServicePublicKey(name, value) { +export async function setServicePublicKey(name, value) { await setCachedFile(`service:${name}:public_key`, value); } -async function setServicePrivateKey(name, value) { +export async function setServicePrivateKey(name, value) { await setCachedFile(`service:${name}:private_key`, value); } -async function setServiceSecretKey(name, value) { +export async function setServiceSecretKey(name, value) { await setCachedFile(`service:${name}:secret_key`, value); } -async function setServiceAESKey(name, value) { +export async function setServiceAESKey(name, value) { await setCachedFile(`service:${name}:aes_key`, value); } -// Local CDN cache functions +// * Local CDN cache functions -async function getLocalCDNFile(name, encoding) { +export async function getLocalCDNFile(name, encoding?) { let file = await getCachedFile(`local_cdn:${name}`, encoding); if (file === null) { @@ -185,11 +186,11 @@ async function getLocalCDNFile(name, encoding) { return file; } -async function setLocalCDNFile(name, value) { +export async function setLocalCDNFile(name, value) { await setCachedFile(`local_cdn:${name}`, value); } -module.exports = { +export default { connect, getNEXPublicKey, getNEXPrivateKey, diff --git a/src/config-manager.js b/src/config-manager.ts similarity index 77% rename from src/config-manager.js rename to src/config-manager.ts index 954f2a4..15a79d5 100644 --- a/src/config-manager.js +++ b/src/config-manager.ts @@ -1,58 +1,14 @@ -const fs = require('fs-extra'); -const get = require('lodash.get'); -const set = require('lodash.set'); -const logger = require('./logger'); +import fs from 'fs-extra'; +import get from 'lodash.get'; +import set from 'lodash.set'; +import dotenv from 'dotenv'; +import logger from './logger'; -require('dotenv').config(); +dotenv.config(); -/** - * @typedef {Object} Config - * @property {object} http HTTP server settings - * @property {number} http.port HTTP port the server will listen on - * @property {object} mongoose Mongose connection settings - * @property {string} mongoose.connection_string MongoDB connection string - * @property {object} mongoose.options MongoDB connection options - * @property {object} [redis] redis settings - * @property {string} [redis.client] redis client settings - * @property {string} [redis.client.url] redis server URL - * @property {object} [email] node-mailer client settings - * @property {string} [email.host] SMTP server address - * @property {number} [email.port] SMTP server port - * @property {boolean} [email.secure] Secure SMTP - * @property {string} [email.from] Email 'from' name/address - * @property {object} [email.auth] Email authentication settings - * @property {string} [email.auth.user] Email username - * @property {string} [email.auth.pass] Email password - * @property {object} [s3] s3 client settings - * @property {object} [s3.endpoint] s3 endpoint URL - * @property {string} [s3.key] s3 access key - * @property {string} [s3.secret] s3 access secret - * @property {object} [hcaptcha] hCaptcha settings - * @property {string} [hcaptcha.secret] hCaptcha secret - * @property {object} cdn CDN config settings - * @property {object} [cdn.subdomain] Subdomain used for serving CDN contents when s3 is disabled - * @property {string} [cdn.disk_path] Fully qualified file system path for storing and reading local CDN contents - * @property {string} cdn.base_url Base URL for CDN server - * @property {string} website_base Base URL for service website (used with emails) - */ +export let config: Record = {}; -/** - * @type {Config} - */ -let config = {}; - -/** - * @typedef {Object} DisabledFeatures - * @property {boolean} redis true if redis is disabled - * @property {boolean} email true if email sending is disabled - * @property {boolean} captcha true if captcha verification is disabled - * @property {boolean} s3 true if s3 services is disabled - */ - -/** - * @type {DisabledFeatures} - */ -const disabledFeatures = { +export const disabledFeatures = { redis: false, email: false, captcha: false, @@ -65,7 +21,7 @@ const requiredFields = [ ['cdn.base_url', 'PN_ACT_CONFIG_CDN_BASE_URL'] ]; -function configure() { +export function configure() { const usingEnv = process.env.PN_ACT_PREFER_ENV_CONFIG === 'true'; if (usingEnv) { @@ -129,22 +85,22 @@ function configure() { // * Check for required settings for (const requiredField of requiredFields) { - const [keyPath, env, convertType] = requiredField; + const [keyPath, envVarName, convertType] = requiredField; const configValue = get(config, keyPath); - const envValue = get(process.env, keyPath); + const envValue = get(process.env, envVarName); if (!configValue || (typeof configValue === 'string' && configValue.trim() === '')) { if (!envValue || envValue.trim() === '') { - logger.error(`Failed to locate required field ${keyPath}. Set ${keyPath} in config.json or the ${env} environment variable`); + logger.error(`Failed to locate required field ${keyPath}. Set ${keyPath} in config.json or the ${envVarName} environment variable`); process.exit(0); } else { - logger.info(`${keyPath} not found in config, using environment variable ${env}`); + logger.info(`${keyPath} not found in config, using environment variable ${envVarName}`); const newValue = envValue; - set(config, keyPath, convertType ? convertType(newValue) : newValue); + set(config, keyPath, convertType ? (convertType as Function)(newValue) : newValue); } } } @@ -324,11 +280,9 @@ function configure() { logger.warn(`s3 file storage disabled. Using disk-based file storage. Please ensure cdn.base_url config or PN_ACT_CONFIG_CDN_BASE env variable is set to point to this server with the subdomain being ${config.cdn.subdomain}`); } - - module.exports.config = config; } -module.exports = { +export default { configure, config, disabledFeatures diff --git a/src/database.js b/src/database.ts similarity index 73% rename from src/database.js rename to src/database.ts index 209b5ef..93bffff 100644 --- a/src/database.js +++ b/src/database.ts @@ -1,11 +1,12 @@ -const mongoose = require('mongoose'); -const bcrypt = require('bcrypt'); -const joi = require('joi'); -const util = require('./util'); -const { PNID } = require('./models/pnid'); -const { Server } = require('./models/server'); -const logger = require('./logger'); -const { config } = require('./config-manager'); +import mongoose from 'mongoose'; +import bcrypt from 'bcrypt'; +import joi from 'joi'; +import util from './util'; +import { PNID } from './models/pnid'; +import { Server } from './models/server'; +import logger from './logger'; +import { config } from './config-manager'; + const { connection_string, options } = config.mongoose; // TODO: Extend this later with more settings @@ -15,13 +16,11 @@ const discordConnectionSchema = joi.object({ let connection; -async function connect() { +export async function connect() { await mongoose.connect(connection_string, options); connection = mongoose.connection; connection.on('error', console.error.bind(console, 'connection error:')); - - module.exports.connection = connection; } function verifyConnected() { @@ -30,7 +29,7 @@ function verifyConnected() { } } -async function getUserByUsername(username) { +export async function getUserByUsername(username) { verifyConnected(); if (typeof username !== 'string') { @@ -44,7 +43,7 @@ async function getUserByUsername(username) { return user; } -async function getUserByPID(pid) { +export async function getUserByPID(pid) { verifyConnected(); const user = await PNID.findOne({ @@ -54,7 +53,7 @@ async function getUserByPID(pid) { return user; } -async function getUserByEmailAddress(email) { +export async function getUserByEmailAddress(email) { verifyConnected(); const user = await PNID.findOne({ @@ -64,17 +63,17 @@ async function getUserByEmailAddress(email) { return user; } -async function doesUserExist(username) { +export async function doesUserExist(username) { verifyConnected(); return !!await getUserByUsername(username); } -async function getUserBasic(token) { +export async function getUserBasic(token) { verifyConnected(); - // Wii U sends Basic auth as `username password`, where the password may not have spaces - // This is not to spec, but that is the consoles fault not ours + // * Wii U sends Basic auth as `username password`, where the password may not have spaces + // * This is not to spec, but that is the consoles fault not ours const [username, password] = Buffer.from(token, 'base64').toString().split(' '); const user = await getUserByUsername(username); @@ -91,7 +90,7 @@ async function getUserBasic(token) { return user; } -async function getUserBearer(token) { +export async function getUserBearer(token) { verifyConnected(); try { @@ -116,18 +115,19 @@ async function getUserBearer(token) { } } -async function getUserProfileJSONByPID(pid) { +export async function getUserProfileJSONByPID(pid) { verifyConnected(); const user = await getUserByPID(pid); - const device = user.get('devices')[0]; // Just grab the first device + const device = user.get('devices')[0]; // * Just grab the first device let device_attributes; if (device) { device_attributes = device.get('device_attributes').map(({name, value, created_date}) => { const deviceAttributeDocument = { name, - value + value, + created_date: '' }; if (created_date) { @@ -160,8 +160,9 @@ async function getUserProfileJSONByPID(pid) { primary: user.get('email.primary') ? 'Y' : 'N', reachable: user.get('email.reachable') ? 'Y' : 'N', type: 'DEFAULT', - updated_by: 'USER', // Can also be INTERNAL WS, don't know the difference - validated: user.get('email.validated') ? 'Y' : 'N' + updated_by: 'USER', // * Can also be INTERNAL WS, don't know the difference + validated: user.get('email.validated') ? 'Y' : 'N', + validated_date: '' }, mii: { status: 'COMPLETED', @@ -170,8 +171,8 @@ async function getUserProfileJSONByPID(pid) { mii_hash: user.get('mii.hash'), mii_images: { mii_image: { - // Images MUST be loaded over HTTPS or console ignores them - // Bunny CDN is the only CDN which seems to support TLS 1.0/1.1 (required) + // * Images MUST be loaded over HTTPS or console ignores them + // * Bunny CDN is the only CDN which seems to support TLS 1.0/1.1 (required) cached_url: `${config.cdn.base_url}/mii/${user.pid}/standard.tga`, id: user.get('mii.image_id'), url: `${config.cdn.base_url}/mii/${user.pid}/standard.tga`, @@ -208,13 +209,13 @@ function getServerByTitleId(titleId, accessMode) { }); } -async function addUserConnection(pnid, data, type) { +export async function addUserConnection(pnid, data, type) { if (type === 'discord') { return await addUserConnectionDiscord(pnid, data); } } -async function addUserConnectionDiscord(pnid, data) { +export async function addUserConnectionDiscord(pnid, data) { const valid = discordConnectionSchema.validate(data); if (valid.error) { @@ -237,14 +238,14 @@ async function addUserConnectionDiscord(pnid, data) { }; } -async function removeUserConnection(pnid, type) { - // Add more connections later? +export async function removeUserConnection(pnid, type) { + // * Add more connections later? if (type === 'discord') { return await removeUserConnectionDiscord(pnid); } } -async function removeUserConnectionDiscord(pnid) { +export async function removeUserConnectionDiscord(pnid) { await PNID.updateOne({ pid: pnid.get('pid') }, { $set: { 'connections.discord.id': '' @@ -257,7 +258,7 @@ async function removeUserConnectionDiscord(pnid) { }; } -module.exports = { +export default { connect, connection, getUserByUsername, @@ -270,5 +271,5 @@ module.exports = { getServer, getServerByTitleId, addUserConnection, - removeUserConnection, + removeUserConnection }; \ No newline at end of file diff --git a/src/logger.js b/src/logger.ts similarity index 90% rename from src/logger.js rename to src/logger.ts index 3a925e2..6d9cacf 100644 --- a/src/logger.js +++ b/src/logger.ts @@ -1,5 +1,7 @@ -const fs = require('fs-extra'); -require('colors'); +import fs from 'fs-extra'; +import colors from 'colors'; + +colors.enable(); const root = process.env.PN_ACT_LOGGER_PATH ? process.env.PN_ACT_LOGGER_PATH : `${__dirname}/..`; fs.ensureDirSync(`${root}/logs`); @@ -44,7 +46,7 @@ function info(input) { console.log(`${input}`.cyan.bold); } -module.exports = { +export default { success, error, warn, diff --git a/src/mailer.js b/src/mailer.ts similarity index 54% rename from src/mailer.js rename to src/mailer.ts index 7292f6e..6d2a878 100644 --- a/src/mailer.js +++ b/src/mailer.ts @@ -1,7 +1,8 @@ -const nodemailer = require('nodemailer'); -const { config, disabledFeatures } = require('./config-manager'); -const path = require('path'); -const fs = require("fs"); +import path from 'node:path'; +import fs from 'node:fs'; +import nodemailer from 'nodemailer'; +import { config, disabledFeatures } from './config-manager'; + const genericEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8'); const confirmationEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8'); @@ -11,30 +12,10 @@ if (!disabledFeatures.email) { transporter = nodemailer.createTransport(config.email); } -/** - @param {Object} options - @param {String} options.to The address of the recipient - @param {String} options.subject The subject of the email - - @param {String} options.username The username of the user (shown in the greeting) - @param {String} options.preview The preview text of the email (shown in the inbox by the email client) - @param {String} options.text The text version of the email - - @param {String} options.paragraph The main content of the email - - @param {Object} options.confirmation Whether or not the email is a confirmation email - @param {String} options.confirmation.href The link to the confirmation page - @param {String} options.confirmation.code The confirmation code - - @param {Object} options.link An object containing the link to be shown in the email - @param {String} options.link.href The URL of the link - @param {String} options.link.text The text of the link - -*/ -async function sendMail(options) { +export async function sendMail(options) { if (!disabledFeatures.email) { const { to, subject, username, paragraph, preview, text, link, confirmation } = options; - + let html = confirmation ? confirmationEmailTemplate : genericEmailTemplate; html = html.replace(/{{username}}/g, username); @@ -51,7 +32,7 @@ async function sendMail(options) { } await transporter.sendMail({ - from: config.email.from, + from: config.email.from, to, subject, text, @@ -60,6 +41,6 @@ async function sendMail(options) { } } -module.exports = { +export default { sendMail }; diff --git a/src/middleware/api.js b/src/middleware/api.ts similarity index 62% rename from src/middleware/api.js rename to src/middleware/api.ts index d6489d1..b8a3b3e 100644 --- a/src/middleware/api.js +++ b/src/middleware/api.ts @@ -1,7 +1,7 @@ -const xmlbuilder = require('xmlbuilder'); -const database = require('../database'); +import xmlbuilder from 'xmlbuilder'; +import database from '../database'; -async function APIMiddleware(request, response, next) { +export async function APIMiddleware(request, _response, next) { const { headers } = request; if (!headers.authorization || !(headers.authorization.startsWith('Bearer'))) { @@ -16,4 +16,4 @@ async function APIMiddleware(request, response, next) { return next(); } -module.exports = APIMiddleware; \ No newline at end of file +export default APIMiddleware; \ No newline at end of file diff --git a/src/middleware/cemu.js b/src/middleware/cemu.ts similarity index 56% rename from src/middleware/cemu.js rename to src/middleware/cemu.ts index c6e8441..22f3e73 100644 --- a/src/middleware/cemu.js +++ b/src/middleware/cemu.ts @@ -1,4 +1,4 @@ -async function CemuMiddleware(request, response, next) { +export async function CemuMiddleware(request, _response, next) { const subdomain = request.subdomains.reverse().join('.'); request.isCemu = subdomain === 'c.account'; @@ -6,4 +6,4 @@ async function CemuMiddleware(request, response, next) { return next(); } -module.exports = CemuMiddleware; \ No newline at end of file +export default CemuMiddleware; \ No newline at end of file diff --git a/src/middleware/client-header.js b/src/middleware/client-header.ts similarity index 72% rename from src/middleware/client-header.js rename to src/middleware/client-header.ts index 1999223..7f7a581 100644 --- a/src/middleware/client-header.js +++ b/src/middleware/client-header.ts @@ -1,14 +1,14 @@ -const xmlbuilder = require('xmlbuilder'); +import xmlbuilder from 'xmlbuilder'; const VALID_CLIENT_ID_SECRET_PAIRS = { - // 'Key' is the client ID, 'Value' is the client secret - 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // Possibly WiiU exclusive? - 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // Possibly 3DS exclusive? - 'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // Possibly 3DS exclusive? + // * 'Key' is the client ID, 'Value' is the client secret + 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // * Possibly WiiU exclusive? + 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // * Possibly 3DS exclusive? + 'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // * Possibly 3DS exclusive? }; -function nintendoClientHeaderCheck(request, response, next) { +export function nintendoClientHeaderCheck(request, response, next) { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime()); @@ -35,4 +35,4 @@ function nintendoClientHeaderCheck(request, response, next) { return next(); } -module.exports = nintendoClientHeaderCheck; \ No newline at end of file +export default nintendoClientHeaderCheck; \ No newline at end of file diff --git a/src/middleware/device-certificate.js b/src/middleware/device-certificate.ts similarity index 56% rename from src/middleware/device-certificate.js rename to src/middleware/device-certificate.ts index 7598091..70909d2 100644 --- a/src/middleware/device-certificate.js +++ b/src/middleware/device-certificate.ts @@ -1,6 +1,6 @@ -const NintendoCertificate = require('../nintendo-certificate'); +import NintendoCertificate from '../nintendo-certificate'; -async function deviceCertificateMiddleware(request, response, next) { +export async function deviceCertificateMiddleware(request, _response, next) { const { headers } = request; if (!headers['x-nintendo-device-cert']) { @@ -13,4 +13,4 @@ async function deviceCertificateMiddleware(request, response, next) { return next(); } -module.exports = deviceCertificateMiddleware; \ No newline at end of file +export default deviceCertificateMiddleware; \ No newline at end of file diff --git a/src/middleware/nasc.js b/src/middleware/nasc.ts similarity index 93% rename from src/middleware/nasc.js rename to src/middleware/nasc.ts index 4bb91a9..ece25bb 100644 --- a/src/middleware/nasc.js +++ b/src/middleware/nasc.ts @@ -1,11 +1,12 @@ -const crypto = require('crypto'); -const { Device } = require('../models/device'); -const { NEXAccount } = require('../models/nex-account'); -const util = require('../util'); -const database = require('../database'); -const NintendoCertificate = require('../nintendo-certificate'); +import crypto from 'node:crypto'; +import { Device } from '../models/device'; +import { NEXAccount } from '../models/nex-account'; +import util from '../util'; +import database from '../database'; +import NintendoCertificate from '../nintendo-certificate'; +import logger from '../logger'; -async function NASCMiddleware(request, response, next) { +export async function NASCMiddleware(request, response, next) { const requestParams = request.body; if (!requestParams.action || @@ -210,4 +211,4 @@ function validNintendoMACAddress(macAddress) { return MAC_REGEX.test(macAddress); } -module.exports = NASCMiddleware; \ No newline at end of file +export default NASCMiddleware; \ No newline at end of file diff --git a/src/middleware/pnid.js b/src/middleware/pnid.ts similarity index 83% rename from src/middleware/pnid.js rename to src/middleware/pnid.ts index d28d745..3cbc428 100644 --- a/src/middleware/pnid.js +++ b/src/middleware/pnid.ts @@ -1,7 +1,7 @@ -const xmlbuilder = require('xmlbuilder'); -const database = require('../database'); +import xmlbuilder from 'xmlbuilder'; +import database from '../database'; -async function PNIDMiddleware(request, response, next) { +export async function PNIDMiddleware(request, response, next) { const { headers } = request; if (!headers.authorization || !(headers.authorization.startsWith('Bearer') || headers.authorization.startsWith('Basic'))) { @@ -62,4 +62,4 @@ async function PNIDMiddleware(request, response, next) { return next(); } -module.exports = PNIDMiddleware; \ No newline at end of file +export default PNIDMiddleware; \ No newline at end of file diff --git a/src/middleware/ratelimit.js b/src/middleware/ratelimit.ts similarity index 61% rename from src/middleware/ratelimit.js rename to src/middleware/ratelimit.ts index 0951794..ef213a5 100644 --- a/src/middleware/ratelimit.js +++ b/src/middleware/ratelimit.ts @@ -1,7 +1,7 @@ -const crypto = require('crypto'); -const ratelimit = require('express-rate-limit'); +import crypto from 'node:crypto'; +import ratelimit from 'express-rate-limit'; -module.exports = ratelimit({ +export default ratelimit({ windowMs: 60 * 1000, max: 1, keyGenerator: request => { diff --git a/src/middleware/xml-parser.js b/src/middleware/xml-parser.ts similarity index 79% rename from src/middleware/xml-parser.js rename to src/middleware/xml-parser.ts index 323e045..b6cc5e2 100644 --- a/src/middleware/xml-parser.js +++ b/src/middleware/xml-parser.ts @@ -1,7 +1,7 @@ -const xmlbuilder = require('xmlbuilder'); -const { document: xmlParser } = require('xmlbuilder2'); +import xmlbuilder from 'xmlbuilder'; +import { document as xmlParser } from 'xmlbuilder2'; -function XMLMiddleware(request, response, next) { +export function XMLMiddleware(request, response, next) { if (request.method == 'POST' || request.method == 'PUT') { const headers = request.headers; let body = ''; @@ -50,4 +50,4 @@ function XMLMiddleware(request, response, next) { } } -module.exports = XMLMiddleware; \ No newline at end of file +export default XMLMiddleware; \ No newline at end of file diff --git a/src/mii.js b/src/mii.js deleted file mode 100644 index 437ae16..0000000 --- a/src/mii.js +++ /dev/null @@ -1,214 +0,0 @@ -const KaitaiStream = require('kaitai-struct/KaitaiStream'); - -class Mii extends KaitaiStream { - constructor(arrayBuffer, byteOffset) { - super(arrayBuffer, byteOffset); - - this.decode(); - } - - decode() { - // Decode raw data - // A lot of this goes unused - this.unknown1 = this.readU1(); - this.characterSet = this.readBitsIntBe(2); - this.regionLock = this.readBitsIntBe(2); - this.profanityFlag = this.readBitsIntBe(1) !== 0; - this.copying = this.readBitsIntBe(1) !== 0; - this.unknown2 = this.readBitsIntBe(2); - this.slotIndex = this.readBitsIntBe(4); - this.pageIndex = this.readBitsIntBe(4); - this.version = this.readBitsIntBe(4); - this.unknown3 = this.readBitsIntBe(4); - this.systemId = Array(8).fill().map(() => this.readU1()); - this.avatarId = Array(4).fill().map(() => this.readU1()); - this.clientId = Array(6).fill().map(() => this.readU1()); - this.padding = this.readU2le(); - this.miiMetaData = this.readU2le(); - this.miiName = Buffer.from(this.readBytes(20)).toString('utf16le'); - this.height = this.readU1(); - this.build = this.readU1(); - this.faceColor = this.readBitsIntBe(3); - this.faceType = this.readBitsIntBe(4); - this.mingle = this.readBitsIntBe(1) !== 0; - this.faceMakeup = this.readBitsIntBe(4); - this.faceWrinkles = this.readBitsIntBe(4); - this.alignToByte(); - this.hairType = this.readU1(); - this.unknown5 = this.readBitsIntBe(4); - this.hairFlip = this.readBitsIntBe(1) !== 0; - this.hairColor = this.readBitsIntBe(3); - this.alignToByte(); - this.eyeData = this.readU4le(); - this.eyebrowData = this.readU4le(); - this.noseData = this.readU2le(); - this.mouthData = this.readU2le(); - this.mouthData2 = this.readU2le(); - this.facialHairData = this.readU2le(); - this.glassesData = this.readU2le(); - this.moleData = this.readU2le(); - this.creatorName = Buffer.from(this.readBytes(20)).toString('utf16le'); - this.padding2 = this.readU2le(); - this.checksum = this.readU2le(); - - // Carve out more specific data from the above values - // TODO: read these bits directly instead of getting them later - - this.gender = (this.miiMetaData & 1); - this.birthMonth = ((this.miiMetaData >> 1) & 15); - this.birthDay = ((this.miiMetaData >> 5) & 31); - this.favoriteColor = ((this.miiMetaData >> 10) & 15); - this.favorite = ((this.miiMetaData >> 14) & 1); - - this.eyeType = (this.eyeData & 63); - this.eyeColor = ((this.eyeData >> 6) & 7); - this.eyeSize = ((this.eyeData >> 9) & 7); - this.eyeStretch = ((this.eyeData >> 13) & 7); - this.eyeRotation = ((this.eyeData >> 16) & 31); - this.eyeHorizontal = ((this.eyeData >> 21) & 15); - this.eyeVertical = ((this.eyeData >> 25) & 31); - - this.eyebrowType = (this.eyebrowData & 31); - this.eyebrowColor = ((this.eyebrowData >> 5) & 7); - this.eyebrowSize = ((this.eyebrowData >> 8) & 15); - this.eyebrowStretch = ((this.eyebrowData >> 12) & 7); - this.eyebrowRotation = ((this.eyebrowData >> 16) & 15); - this.eyebrowHorizontal = ((this.eyebrowData >> 21) & 15); - this.eyebrowVertical = ((this.eyebrowData >> 25) & 31); - - this.noseType = (this.noseData & 31); - this.noseSize = ((this.noseData >> 5) & 15); - this.noseVertical = ((this.noseData >> 9) & 31); - - - this.mouthType = (this.mouthData & 63); - this.mouthColor = ((this.mouthData >> 6) & 7); - this.mouthSize = ((this.mouthData >> 9) & 15); - this.mouthStretch = ((this.mouthData >> 13) & 7); - - this.mouthVertical = (this.mouthData2 & 31); - this.facialHairMustache = ((this.mouthData2 >> 5) & 7); - - this.facialHairType = (this.facialHairData & 7); - this.facialHairColor = ((this.facialHairData >> 3) & 7); - this.facialHairSize = ((this.facialHairData >> 6) & 15); - this.facialHairVertical = ((this.facialHairData >> 10) & 31); - - this.glassesType = (this.glassesData & 15); - this.glassesColor = (this.glassesData >> 4) & 7; - this.glassesSize = (this.glassesData >> 7) & 15; - this.glassesVertical = (this.glassesData >> 11) & 15; - - this.moleEnable = (this.moleData >> 15); - this.moleSize = ((this.moleData >> 1) & 15); - this.moleHorizontal = ((this.moleData >> 5) & 31); - this.moleVertical = ((this.moleData >> 10) & 31); - } - - toStudioMii() { - /* - Can also disable randomization with: - - let miiStudioData = Buffer.alloc(0x2F); - let next = 256; - - and removing "randomizer" and the "miiStudioData.writeUInt8(randomizer);" call - */ - const miiStudioData = Buffer.alloc(0x2F); - const randomizer = Math.floor(256 * Math.random()); - let next = randomizer; - let pos = 1; - - function encodeMiiPart(partValue) { - const encoded = (7 + (partValue ^ next)) % 256; - next = encoded; - - miiStudioData.writeUInt8(encoded, pos); - pos++; - } - - miiStudioData.writeUInt8(randomizer); - - if (this.facialHairColor === 0) { - encodeMiiPart(8); - } else { - encodeMiiPart(this.facialHairColor); - } - - encodeMiiPart(this.facialHairType); - encodeMiiPart(this.build); - encodeMiiPart(this.eyeStretch); - encodeMiiPart(this.eyeColor + 8); - encodeMiiPart(this.eyeRotation); - encodeMiiPart(this.eyeSize); - encodeMiiPart(this.eyeType); - encodeMiiPart(this.eyeHorizontal); - encodeMiiPart(this.eyeVertical); - encodeMiiPart(this.eyebrowStretch); - - if (this.eyebrowColor === 0) { - encodeMiiPart(8); - } else { - encodeMiiPart(this.eyebrowColor); - } - - encodeMiiPart(this.eyebrowRotation); - encodeMiiPart(this.eyebrowSize); - encodeMiiPart(this.eyebrowType); - encodeMiiPart(this.eyebrowHorizontal); - encodeMiiPart(this.eyebrowVertical); - encodeMiiPart(this.faceColor); - encodeMiiPart(this.faceMakeup); - encodeMiiPart(this.faceType); - encodeMiiPart(this.faceWrinkles); - encodeMiiPart(this.favoriteColor); - encodeMiiPart(this.gender); - - if (this.glassesColor == 0) { - encodeMiiPart(8); - } else if (this.glassesColor < 6) { - encodeMiiPart(this.glassesColor + 13); - } else { - encodeMiiPart(0); - } - - encodeMiiPart(this.glassesSize); - encodeMiiPart(this.glassesType); - encodeMiiPart(this.glassesVertical); - - if (this.hairColor == 0) { - encodeMiiPart(8); - } else { - encodeMiiPart(this.hairColor); - } - - encodeMiiPart(this.hairFlip ? 1 : 0); - encodeMiiPart(this.hairType); - encodeMiiPart(this.height); - encodeMiiPart(this.moleSize); - encodeMiiPart(this.moleEnable); - encodeMiiPart(this.moleHorizontal); - encodeMiiPart(this.moleVertical); - encodeMiiPart(this.mouthStretch); - - if (this.mouthColor < 4) { - encodeMiiPart(this.mouthColor + 19); - } else { - encodeMiiPart(0); - } - - encodeMiiPart(this.mouthSize); - encodeMiiPart(this.mouthType); - encodeMiiPart(this.mouthVertical); - encodeMiiPart(this.facialHairSize); - encodeMiiPart(this.facialHairMustache); - encodeMiiPart(this.facialHairVertical); - encodeMiiPart(this.noseSize); - encodeMiiPart(this.noseType); - encodeMiiPart(this.noseVertical); - - return miiStudioData; - } -} - -module.exports = Mii; \ No newline at end of file diff --git a/src/models/device.js b/src/models/device.ts similarity index 62% rename from src/models/device.js rename to src/models/device.ts index 00d667b..820a3f4 100644 --- a/src/models/device.js +++ b/src/models/device.ts @@ -1,14 +1,14 @@ -const { Schema, model } = require('mongoose'); +import { Schema, model } from 'mongoose'; -const DeviceAttributeSchema = new Schema({ +export const DeviceAttributeSchema = new Schema({ created_date: String, name: String, - value: String, + value: String }); -const DeviceAttribute = model('DeviceAttribute', DeviceAttributeSchema); +export const DeviceAttribute: IDeviceAttributeModel = model('DeviceAttribute', DeviceAttributeSchema); -const DeviceSchema = new Schema({ +export const DeviceSchema = new Schema({ is_emulator: { type: Boolean, default: false @@ -22,7 +22,7 @@ const DeviceSchema = new Schema({ 'ftr', // Nintendo 2DS 'ktr', // New Nintendo 3DS 'red', // New Nintendo 3DS XL - 'jan' // New Nintendo 2DS XL + 'jan' // New Nintendo 2DS XL ] }, device_id: Number, @@ -48,9 +48,9 @@ const DeviceSchema = new Schema({ } }); -const Device = model('Device', DeviceSchema); +export const Device: IDeviceModel = model('Device', DeviceSchema); -module.exports = { +export default { DeviceSchema, Device, DeviceAttributeSchema, diff --git a/src/models/nex-account.js b/src/models/nex-account.ts similarity index 82% rename from src/models/nex-account.js rename to src/models/nex-account.ts index fbffd69..6a4b509 100644 --- a/src/models/nex-account.js +++ b/src/models/nex-account.ts @@ -1,7 +1,7 @@ -const { Schema, model } = require('mongoose'); -const uniqueValidator = require('mongoose-unique-validator'); +import { Schema, model } from 'mongoose'; +import uniqueValidator from 'mongoose-unique-validator'; -const NEXAccountSchema = new Schema({ +export const NEXAccountSchema = new Schema({ device_type: { type: String, enum: [ @@ -23,7 +23,7 @@ const NEXAccountSchema = new Schema({ server_access_level: { type: String, default: 'prod' // everyone is in production by default - }, + } }); NEXAccountSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); @@ -44,9 +44,11 @@ NEXAccountSchema.methods.generatePID = async function () { const inuse = await NEXAccount.findOne({ pid }); - pid = (inuse ? await NEXAccount.generatePID() : pid); - - this.set('pid', pid); + if (inuse) { + await NEXAccount.generatePID(); + } else { + this.set('pid', pid); + } }; NEXAccountSchema.methods.generatePassword = function () { @@ -66,9 +68,9 @@ NEXAccountSchema.methods.generatePassword = function () { this.set('password', output.join('')); }; -const NEXAccount = model('NEXAccount', NEXAccountSchema); +export const NEXAccount: INEXAccountModel = model('NEXAccount', NEXAccountSchema); -module.exports = { +export default { NEXAccountSchema, - NEXAccount, + NEXAccount }; \ No newline at end of file diff --git a/src/models/pnid.js b/src/models/pnid.ts similarity index 77% rename from src/models/pnid.js rename to src/models/pnid.ts index 5cf0f99..73b0079 100644 --- a/src/models/pnid.js +++ b/src/models/pnid.ts @@ -1,15 +1,14 @@ -const { Schema, model } = require('mongoose'); -const uniqueValidator = require('mongoose-unique-validator'); -const bcrypt = require('bcrypt'); -const crypto = require('crypto'); -const imagePixels = require('image-pixels'); -const TGA = require('tga'); -const got = require('got'); -const util = require('../util'); -const { DeviceSchema } = require('./device'); -const Mii = require('mii-js'); +import crypto from 'node:crypto'; +import { Schema, model } from 'mongoose'; +import uniqueValidator from 'mongoose-unique-validator'; +import imagePixels from 'image-pixels'; +import TGA from 'tga'; +import got from 'got'; +import Mii from 'mii-js'; +import { DeviceSchema } from './device'; +import util from '../util'; -const PNIDSchema = new Schema({ +export const PNIDSchema = new Schema({ access_level: { type: Number, default: 0 // 0: standard, 1: tester, 2: mod?, 3: dev @@ -125,9 +124,11 @@ PNIDSchema.methods.generatePID = async function() { pid }); - pid = (inuse ? await PNID.generatePID() : pid); - - this.set('pid', pid); + if (inuse) { + await PNID.generatePID(); + } else { + this.set('pid', pid); + } }; PNIDSchema.methods.generateEmailValidationCode = async function() { @@ -145,33 +146,11 @@ PNIDSchema.methods.generateEmailValidationToken = async function() { 'identification.email_token': token }); - token = (inuse ? await PNID.generateEmailValidationToken() : token); - - this.set('identification.email_token', token); -}; - -PNIDSchema.methods.getDevice = async function(document) { - const devices = this.get('devices'); - - return devices.find(device => { - return ( - (device.device_id === document.device_id) && - (device.device_type === document.device_type) && - (device.serial === document.serial) - ); - }); -}; - -PNIDSchema.methods.addDevice = async function(device) { - this.devices.push(device); - - await this.save(); -}; - -PNIDSchema.methods.removeDevice = async function(device) { - this.devices = this.devices.filter(({ _id }) => _id !== device._id); - - await this.save(); + if (inuse) { + await PNID.generateEmailValidationToken(); + } else { + this.set('identification.email_token', token); + } }; PNIDSchema.methods.updateMii = async function({name, primary, data}) { @@ -231,9 +210,9 @@ PNIDSchema.methods.getServerMode = function () { return serverMode; }; -const PNID = model('PNID', PNIDSchema); +export const PNID: IPNIDModel = model('PNID', PNIDSchema); -module.exports = { +export default { PNIDSchema, PNID }; \ No newline at end of file diff --git a/src/models/server.js b/src/models/server.ts similarity index 66% rename from src/models/server.js rename to src/models/server.ts index 8b70a7a..e376aac 100644 --- a/src/models/server.js +++ b/src/models/server.ts @@ -1,7 +1,7 @@ -const { Schema, model } = require('mongoose'); -const uniqueValidator = require('mongoose-unique-validator'); +import { Schema, model } from 'mongoose'; +import uniqueValidator from 'mongoose-unique-validator'; -const ServerSchema = new Schema({ +export const ServerSchema = new Schema({ ip: String, // Example: 1.1.1.1 port: Number, // Example: 60000 service_name: String, // Example: friends @@ -15,9 +15,9 @@ const ServerSchema = new Schema({ ServerSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); -const Server = model('Server', ServerSchema); +export const Server: IServerModel = model('Server', ServerSchema); -module.exports = { +export default { ServerSchema, Server, }; \ No newline at end of file diff --git a/src/nintendo-certificate.js b/src/nintendo-certificate.ts similarity index 92% rename from src/nintendo-certificate.js rename to src/nintendo-certificate.ts index 6df33ee..5a35e85 100644 --- a/src/nintendo-certificate.js +++ b/src/nintendo-certificate.ts @@ -1,7 +1,5 @@ -// Parse Nintendo certificates - -const crypto = require('crypto'); -const NodeRSA = require('node-rsa'); +import crypto from 'node:crypto'; +import NodeRSA from 'node-rsa'; const WIIU_DEVICE_PUB_PEM = `-----BEGIN PUBLIC KEY----- MFIwEAYHKoZIzj0CAQYFK4EEABsDPgAEAP1WBBgs8XUJIQDDCK5IOZEbb5+h1TqV @@ -70,7 +68,19 @@ const SIGNATURE_SIZES = { } }; -class NintendoCertificate { +export class NintendoCertificate { + _certificate: Buffer; + _certificateBody: Buffer; + signatureType: number; + signature: Buffer; + issuer: string; + keyType: number; + certificateName: string; + ngKeyId: number; + publicKey: Buffer; + valid: boolean; + publicKeyData: Buffer; + constructor(certificate) { this._certificate = null; this._certificateBody = null; @@ -185,10 +195,10 @@ class NintendoCertificate { // https://github.com/Myriachan _verifySignatureECDSA() { const pem = this.issuer == 'Root-CA00000003-MS00000012' ? WIIU_DEVICE_PUB_PEM : CTR_DEVICE_PUB_PEM; - const key = crypto.createPublicKey({ - key: pem - }); - key.dsaEncoding = 'ieee-p1363'; + const key = { + key: pem, + dsaEncoding: 'ieee-p1363' as crypto.DSAEncoding + }; this.valid = crypto.verify('sha256', this._certificateBody, key, this.signature); } @@ -205,4 +215,4 @@ class NintendoCertificate { } } -module.exports = NintendoCertificate; \ No newline at end of file +export default NintendoCertificate; \ No newline at end of file diff --git a/src/server.js b/src/server.ts similarity index 67% rename from src/server.js rename to src/server.ts index a0b86cd..a373b69 100644 --- a/src/server.js +++ b/src/server.ts @@ -4,27 +4,27 @@ const configManager = require('./config-manager'); configManager.configure(); -const express = require('express'); -const morgan = require('morgan'); -const xmlparser = require('./middleware/xml-parser'); -const cache = require('./cache'); -const database = require('./database'); -const util = require('./util'); -const logger = require('./logger'); +import express from 'express'; +import morgan from 'morgan'; +import xmlparser from './middleware/xml-parser'; +import cache from './cache'; +import database from './database'; +import util from './util'; +import logger from './logger'; + +import conntest from './services/conntest'; +import nnid from './services/nnid'; +import nasc from './services/nasc'; +import datastore from './services/datastore'; +import api from './services/api'; +import localcdn from './services/local-cdn'; +import assets from './services/assets'; const { config } = configManager; const { http: { port } } = config; const app = express(); -const conntest = require('./services/conntest'); -const nnid = require('./services/nnid'); -const nasc = require('./services/nasc'); -const datastore = require('./services/datastore'); -const api = require('./services/api'); -const localcdn = require('./services/local-cdn'); -const assets = require('./services/assets'); - // START APPLICATION // Create router @@ -55,7 +55,7 @@ app.use((request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); response.status(404); response.send('0008Not Found'); @@ -63,7 +63,7 @@ app.use((request, response) => { // non-404 error handler logger.info('Creating non-404 status handler'); -app.use((error, request, response) => { +app.use((error, request, response, _next) => { const status = error.status || 500; const fullUrl = util.fullUrl(request); const deviceId = request.headers['X-Nintendo-Device-ID'] || 'Unknown'; diff --git a/src/services/api/index.js b/src/services/api/index.ts similarity index 74% rename from src/services/api/index.js rename to src/services/api/index.ts index 5aee4a6..56d7551 100644 --- a/src/services/api/index.js +++ b/src/services/api/index.ts @@ -1,11 +1,11 @@ // handles "api.nintendo.cc" endpoints -const express = require('express'); -const subdomain = require('express-subdomain'); -const cors = require('cors'); -const APIMiddleware = require('../../middleware/api'); -const logger = require('../../logger'); -const routes = require('./routes'); +import express from 'express'; +import subdomain from 'express-subdomain'; +import cors from 'cors'; +import APIMiddleware from '../../middleware/api'; +import routes from './routes'; +import logger from '../../logger'; // Router to handle the subdomain restriction const api = express.Router(); @@ -33,4 +33,4 @@ const router = express.Router(); logger.info('[USER API] Creating \'api\' subdomain'); router.use(subdomain('api', api)); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/index.js b/src/services/api/routes/index.js deleted file mode 100644 index 217a96d..0000000 --- a/src/services/api/routes/index.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - V1: { - CONNECTIONS: require('./v1/connections'), - EMAIL: require('./v1/email'), - FORGOT_PASSWORD: require('./v1/forgotPassword'), - LOGIN: require('./v1/login'), - REGISTER: require('./v1/register'), - RESET_PASSWORD: require('./v1/resetPassword'), - USER: require('./v1/user'), - } -}; \ No newline at end of file diff --git a/src/services/api/routes/index.ts b/src/services/api/routes/index.ts new file mode 100644 index 0000000..9956240 --- /dev/null +++ b/src/services/api/routes/index.ts @@ -0,0 +1,19 @@ +import connections_v1 from './v1/connections'; +import email_v1 from './v1/email'; +import forgotPassword_v1 from './v1/forgotPassword'; +import login_v1 from './v1/login'; +import register_v1 from './v1/register'; +import resetPassword_v1 from './v1/resetPassword'; +import user_v1 from './v1/user'; + +export default { + V1: { + CONNECTIONS: connections_v1, + EMAIL: email_v1, + FORGOT_PASSWORD: forgotPassword_v1, + LOGIN: login_v1, + REGISTER: register_v1, + RESET_PASSWORD: resetPassword_v1, + USER: user_v1 + } +}; \ No newline at end of file diff --git a/src/services/api/routes/v1/connections.js b/src/services/api/routes/v1/connections.ts similarity index 92% rename from src/services/api/routes/v1/connections.js rename to src/services/api/routes/v1/connections.ts index 76e41c7..58aea18 100644 --- a/src/services/api/routes/v1/connections.js +++ b/src/services/api/routes/v1/connections.ts @@ -1,5 +1,7 @@ -const router = require('express').Router(); -const database = require('../../../../database'); +import { Router } from 'express'; +import database from '../../../../database'; + +const router = Router(); const VALID_CONNECTION_TYPES = [ 'discord' @@ -74,4 +76,4 @@ router.delete('/remove/:type', async (request, response) => { response.status(result.status).json(result); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/v1/email.js b/src/services/api/routes/v1/email.ts similarity index 67% rename from src/services/api/routes/v1/email.js rename to src/services/api/routes/v1/email.ts index 561e651..22e38c6 100644 --- a/src/services/api/routes/v1/email.js +++ b/src/services/api/routes/v1/email.ts @@ -1,10 +1,18 @@ -const router = require('express').Router(); -const moment = require('moment'); -const { PNID } = require('../../../../models/pnid'); -const util = require('../../../../util'); +import { Router } from 'express'; +import moment from 'moment'; +import { PNID } from '../../../../models/pnid'; +import util from '../../../../util'; + +const router = Router(); router.get('/verify', async (request, response) => { - const { token } = request.query; + let token: string; + + if (Array.isArray(request.query.token)) { + token = request.query.token[0] as string; + } else { + token = request.query.token as string; + } if (!token || token.trim() == '') { return response.status(400).json({ @@ -39,4 +47,4 @@ router.get('/verify', async (request, response) => { response.status(200).send('Email validated. You may close this window'); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/v1/forgotPassword.js b/src/services/api/routes/v1/forgotPassword.ts similarity index 72% rename from src/services/api/routes/v1/forgotPassword.js rename to src/services/api/routes/v1/forgotPassword.ts index 7dd4948..3a46580 100644 --- a/src/services/api/routes/v1/forgotPassword.js +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -1,7 +1,9 @@ -const router = require('express').Router(); -const validator = require('validator'); -const database = require('../../../../database'); -const util = require('../../../../util'); +import { Router } from 'express'; +import validator from 'validator'; +import database from '../../../../database'; +import util from '../../../../util'; + +const router = Router(); router.post('/', async (request, response) => { const { body } = request; @@ -33,4 +35,4 @@ router.post('/', async (request, response) => { }); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/v1/login.js b/src/services/api/routes/v1/login.ts similarity index 91% rename from src/services/api/routes/v1/login.js rename to src/services/api/routes/v1/login.ts index e342ea5..7b63207 100644 --- a/src/services/api/routes/v1/login.js +++ b/src/services/api/routes/v1/login.ts @@ -1,9 +1,11 @@ -const router = require('express').Router(); -const bcrypt = require('bcrypt'); -const fs = require('fs-extra'); -const database = require('../../../../database'); -const cache = require('../../../../cache'); -const util = require('../../../../util'); +import { Router } from 'express'; +import bcrypt from 'bcrypt'; +import fs from 'fs-extra'; +import database from '../../../../database'; +import cache from '../../../../cache'; +import util from '../../../../util'; + +const router = Router(); /** * [POST] @@ -126,4 +128,4 @@ router.post('/', async (request, response) => { }); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/v1/register.js b/src/services/api/routes/v1/register.ts similarity index 92% rename from src/services/api/routes/v1/register.js rename to src/services/api/routes/v1/register.ts index 860fad4..8047a2c 100644 --- a/src/services/api/routes/v1/register.js +++ b/src/services/api/routes/v1/register.ts @@ -1,18 +1,21 @@ -const router = require('express').Router(); -const emailvalidator = require('email-validator'); -const fs = require('fs-extra'); -const moment = require('moment'); -const crypto = require('crypto'); -const hcaptcha = require('hcaptcha'); -const bcrypt = require('bcrypt'); -const Mii = require('mii-js'); -const { PNID } = require('../../../../models/pnid'); -const { NEXAccount } = require('../../../../models/nex-account'); -const database = require('../../../../database'); -const cache = require('../../../../cache'); -const util = require('../../../../util'); -const logger = require('../../../../logger'); -const { config, disabledFeatures } = require('../../../../config-manager'); + +import crypto from 'node:crypto'; +import { Router } from 'express'; +import emailvalidator from 'email-validator'; +import bcrypt from 'bcrypt'; +import fs from 'fs-extra'; +import moment from 'moment'; +import hcaptcha from 'hcaptcha'; +import Mii from 'mii-js'; +import database from '../../../../database'; +import cache from '../../../../cache'; +import util from '../../../../util'; +import logger from '../../../../logger'; +import { PNID } from '../../../../models/pnid'; +import { NEXAccount } from '../../../../models/nex-account'; +import { config, disabledFeatures } from '../../../../config-manager'; + +const router = Router(); const PNID_VALID_CHARACTERS_REGEX = /^[\w\-\.]*$/gm; const PNID_PUNCTUATION_START_REGEX = /^[\_\-\.]/gm; @@ -368,4 +371,4 @@ router.post('/', async (request, response) => { }); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/v1/resetPassword.js b/src/services/api/routes/v1/resetPassword.ts similarity index 93% rename from src/services/api/routes/v1/resetPassword.js rename to src/services/api/routes/v1/resetPassword.ts index 8afb3b1..e805e8d 100644 --- a/src/services/api/routes/v1/resetPassword.js +++ b/src/services/api/routes/v1/resetPassword.ts @@ -1,7 +1,9 @@ -const router = require('express').Router(); -const bcrypt = require('bcrypt'); -const { PNID } = require('../../../../models/pnid'); -const util = require('../../../../util'); +import { Router } from 'express'; +import bcrypt from 'bcrypt'; +import { PNID } from '../../../../models/pnid'; +import util from '../../../../util'; + +const router = Router(); // This sucks const PASSWORD_WORD_OR_NUMBER_REGEX = /(?=.*[a-zA-Z])(?=.*\d).*/; @@ -124,4 +126,4 @@ router.post('/', async (request, response) => { }); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/api/routes/v1/user.js b/src/services/api/routes/v1/user.ts similarity index 92% rename from src/services/api/routes/v1/user.js rename to src/services/api/routes/v1/user.ts index 7008548..1a6f89b 100644 --- a/src/services/api/routes/v1/user.js +++ b/src/services/api/routes/v1/user.ts @@ -1,7 +1,9 @@ -const router = require('express').Router(); -const joi = require('joi'); -const { PNID } = require('../../../../models/pnid'); -const { config } = require('../../../../config-manager'); +import { Router } from 'express'; +import joi from 'joi'; +import { PNID } from '../../../../models/pnid'; +import { config } from '../../../../config-manager'; + +const router = Router(); // TODO: Extend this later with more settings const userSchema = joi.object({ @@ -124,4 +126,4 @@ router.post('/', async (request, response) => { }); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/assets/index.js b/src/services/assets/index.ts similarity index 68% rename from src/services/assets/index.js rename to src/services/assets/index.ts index 5061bf3..b73a632 100644 --- a/src/services/assets/index.js +++ b/src/services/assets/index.ts @@ -1,9 +1,9 @@ // handles serving assets -const express = require('express'); -const subdomain = require('express-subdomain'); -const logger = require('../../logger'); -const path = require('path'); +import path from 'node:path'; +import express from 'express'; +import subdomain from 'express-subdomain'; +import logger from '../../logger'; // Router to handle the subdomain restriction const assets = express.Router(); @@ -19,4 +19,4 @@ const router = express.Router(); logger.info('[conntest] Creating \'assets\' subdomain'); router.use(subdomain('assets', assets)); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/conntest/index.js b/src/services/conntest/index.ts similarity index 80% rename from src/services/conntest/index.js rename to src/services/conntest/index.ts index bd4b823..1601858 100644 --- a/src/services/conntest/index.js +++ b/src/services/conntest/index.ts @@ -1,8 +1,8 @@ // handles conntest endpoints -const express = require('express'); -const subdomain = require('express-subdomain'); -const logger = require('../../logger'); +import express from 'express'; +import subdomain from 'express-subdomain'; +import logger from '../../logger'; // Router to handle the subdomain restriction const conntest = express.Router(); @@ -33,4 +33,4 @@ const router = express.Router(); logger.info('[conntest] Creating \'conntest\' subdomain'); router.use(subdomain('conntest', conntest)); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/datastore/index.js b/src/services/datastore/index.ts similarity index 66% rename from src/services/datastore/index.js rename to src/services/datastore/index.ts index a5803d1..7b670ea 100644 --- a/src/services/datastore/index.js +++ b/src/services/datastore/index.ts @@ -1,7 +1,7 @@ -const express = require('express'); -const subdomain = require('express-subdomain'); -const logger = require('../../logger'); -const routes = require('./routes'); +import express from 'express'; +import subdomain from 'express-subdomain'; +import routes from './routes'; +import logger from '../../logger'; // Router to handle the subdomain const datastore = express.Router(); @@ -17,4 +17,4 @@ const router = express.Router(); logger.info('[DATASTORE] Creating \'datastore\' subdomain'); router.use(subdomain('datastore', datastore)); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/datastore/routes/index.js b/src/services/datastore/routes/index.js deleted file mode 100644 index 34215ff..0000000 --- a/src/services/datastore/routes/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - UPLOAD: require('./upload.js'), -}; \ No newline at end of file diff --git a/src/services/datastore/routes/index.ts b/src/services/datastore/routes/index.ts new file mode 100644 index 0000000..7e54748 --- /dev/null +++ b/src/services/datastore/routes/index.ts @@ -0,0 +1,5 @@ +import upload from './upload'; + +export default { + UPLOAD: upload +}; \ No newline at end of file diff --git a/src/services/datastore/routes/upload.js b/src/services/datastore/routes/upload.ts similarity index 89% rename from src/services/datastore/routes/upload.js rename to src/services/datastore/routes/upload.ts index 18f13b6..595ce5d 100644 --- a/src/services/datastore/routes/upload.js +++ b/src/services/datastore/routes/upload.ts @@ -1,8 +1,10 @@ -const crypto = require('crypto'); -const router = require('express').Router(); -const Dicer = require('dicer'); -const fs = require('fs'); -const util = require('../../../util'); +import fs from 'node:fs'; +import crypto from 'node:crypto'; +import { Router } from 'express'; +import Dicer from 'dicer'; +import util from '../../../util'; + +const router = Router(); const signatureSecret = fs.readFileSync(`${__dirname}/../../../../certs/nex/datastore/secret.key`); @@ -66,9 +68,9 @@ router.post('/upload', multipartParser, async (request, response) => { if (hmac !== signature.toString()) { return response.sendStatus(400); } - + await util.uploadCDNAsset(bucket.toString(), key.toString(), file, acl.toString()); response.sendStatus(200); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/local-cdn/index.js b/src/services/local-cdn/index.js deleted file mode 100644 index ca8b894..0000000 --- a/src/services/local-cdn/index.js +++ /dev/null @@ -1,30 +0,0 @@ -const express = require('express'); -const subdomain = require('express-subdomain'); -const logger = require('../../logger'); -const { config, disabledFeatures } = require('../../config-manager'); - -if (!disabledFeatures.s3) { - // * s3 enabled, no need for this - - module.exports = express.Router(); - - return; -} - -const routes = require('./routes'); - -// Router to handle the subdomain -const localcdn = express.Router(); - -// Setup routes -logger.info('[LOCAL-CDN] Applying imported routes'); -localcdn.use(routes.GET); - -// Main router for endpoints -const router = express.Router(); - -// Create subdomains -logger.info(`[LOCAL-CDN] Creating '${config.cdn.subdomain}' subdomain`); -router.use(subdomain(config.cdn.subdomain, localcdn)); - -module.exports = router; \ No newline at end of file diff --git a/src/services/local-cdn/index.ts b/src/services/local-cdn/index.ts new file mode 100644 index 0000000..bf57e63 --- /dev/null +++ b/src/services/local-cdn/index.ts @@ -0,0 +1,26 @@ +import express from 'express'; +import subdomain from 'express-subdomain'; +import routes from './routes'; +import { config, disabledFeatures } from '../../config-manager'; +import logger from '../../logger'; + +const router = express.Router(); + +if (disabledFeatures.s3) { + // * s3 disabled, setup local CDN + + // * Router to handle the subdomain + const localcdn = express.Router(); + + // * Setup routes + logger.info('[LOCAL-CDN] Applying imported routes'); + localcdn.use(routes.GET); + + // * Create subdomains + logger.info(`[LOCAL-CDN] Creating '${config.cdn.subdomain}' subdomain`); + router.use(subdomain(config.cdn.subdomain, localcdn)); +} else { + logger.info('[LOCAL-CDN] s3 enabled, skipping local CDN'); +} + +export default router; \ No newline at end of file diff --git a/src/services/local-cdn/routes/get.js b/src/services/local-cdn/routes/get.ts similarity index 65% rename from src/services/local-cdn/routes/get.js rename to src/services/local-cdn/routes/get.ts index 7ae69b9..6dc45c7 100644 --- a/src/services/local-cdn/routes/get.js +++ b/src/services/local-cdn/routes/get.ts @@ -1,5 +1,7 @@ -const router = require('express').Router(); -const cache = require('../../../cache'); +import { Router } from 'express'; +import cache from '../../../cache'; + +const router = Router(); router.get('/*', async (request, response) => { const filePath = request.params[0]; @@ -13,4 +15,4 @@ router.get('/*', async (request, response) => { } }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/local-cdn/routes/index.js b/src/services/local-cdn/routes/index.js deleted file mode 100644 index 033fca1..0000000 --- a/src/services/local-cdn/routes/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - GET: require('./get.js'), -}; \ No newline at end of file diff --git a/src/services/local-cdn/routes/index.ts b/src/services/local-cdn/routes/index.ts new file mode 100644 index 0000000..d6b426e --- /dev/null +++ b/src/services/local-cdn/routes/index.ts @@ -0,0 +1,5 @@ +import get from './get'; + +export default { + GET: get, +}; \ No newline at end of file diff --git a/src/services/nasc/index.js b/src/services/nasc/index.ts similarity index 62% rename from src/services/nasc/index.js rename to src/services/nasc/index.ts index 9266a81..0b80c92 100644 --- a/src/services/nasc/index.js +++ b/src/services/nasc/index.ts @@ -1,10 +1,10 @@ // handles NASC endpoints -const express = require('express'); -const subdomain = require('express-subdomain'); -const NASCMiddleware = require('../../middleware/nasc'); -const logger = require('../../logger'); -const routes = require('./routes'); +import express from 'express'; +import subdomain from 'express-subdomain'; +import NASCMiddleware from '../../middleware/nasc'; +import routes from './routes'; +import logger from '../../logger'; // Router to handle the subdomain restriction const nasc = express.Router(); @@ -23,4 +23,4 @@ const router = express.Router(); logger.info('[NASC] Creating \'nasc\' subdomain'); router.use(subdomain('nasc', nasc)); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nasc/routes/ac.js b/src/services/nasc/routes/ac.ts similarity index 92% rename from src/services/nasc/routes/ac.js rename to src/services/nasc/routes/ac.ts index 66d08d4..d19c6c8 100644 --- a/src/services/nasc/routes/ac.js +++ b/src/services/nasc/routes/ac.ts @@ -1,8 +1,8 @@ -const fs = require('fs-extra'); -const express = require('express'); -const util = require('../../../util'); -const database = require('../../../database'); -const cache = require('../../../cache'); +import express from 'express'; +import fs from 'fs-extra'; +import util from '../../../util'; +import database from '../../../database'; +import cache from '../../../cache'; const router = express.Router(); @@ -103,4 +103,4 @@ async function processServiceTokenRequest(request) { return params; } -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nasc/routes/index.js b/src/services/nasc/routes/index.js deleted file mode 100644 index 971f25d..0000000 --- a/src/services/nasc/routes/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - AC: require('./ac') -}; \ No newline at end of file diff --git a/src/services/nasc/routes/index.ts b/src/services/nasc/routes/index.ts new file mode 100644 index 0000000..0399fd3 --- /dev/null +++ b/src/services/nasc/routes/index.ts @@ -0,0 +1,5 @@ +import ac from './ac'; + +export default { + AC: ac +}; \ No newline at end of file diff --git a/src/services/nnid/index.js b/src/services/nnid/index.ts similarity index 69% rename from src/services/nnid/index.js rename to src/services/nnid/index.ts index 39334b6..b0f8321 100644 --- a/src/services/nnid/index.js +++ b/src/services/nnid/index.ts @@ -1,12 +1,12 @@ // handles "account.nintendo.net" endpoints -const express = require('express'); -const subdomain = require('express-subdomain'); -const clientHeaderCheck = require('../../middleware/client-header'); -const cemuMiddleware = require('../../middleware/cemu'); -const pnidMiddleware = require('../../middleware/pnid'); -const logger = require('../../logger'); -const routes = require('./routes'); +import express from 'express'; +import subdomain from 'express-subdomain'; +import clientHeaderCheck from '../../middleware/client-header'; +import cemuMiddleware from '../../middleware/cemu'; +import pnidMiddleware from '../../middleware/pnid'; +import routes from './routes'; +import logger from '../../logger'; // Router to handle the subdomain restriction const nnid = express.Router(); @@ -37,4 +37,4 @@ router.use(subdomain('account', nnid)); logger.info('[NNID] Creating \'c.account\' subdomain'); router.use(subdomain('c.account', nnid)); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/admin.js b/src/services/nnid/routes/admin.js deleted file mode 100644 index be0b9f1..0000000 --- a/src/services/nnid/routes/admin.js +++ /dev/null @@ -1,59 +0,0 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); -const { PNID } = require('../../../models/pnid'); - -/** - * [GET] - * Replacement for: https://account.nintendo.net/v1/api/admin/mapped_ids - * Description: Maps between NNID usernames and PIDs - */ -router.get('/mapped_ids', async (request, response) => { - - let { input: inputList, input_type: inputType, output_type: outputType } = request.query; - inputList = inputList.split(','); - inputList = inputList.filter(input => input); // remove nulls - - if (inputType === 'user_id') { - inputType = 'usernameLower'; - inputList = inputList.map(name => name.toLowerCase()); - } - - if (outputType === 'user_id') { - outputType = 'username'; - } - - // This is slower than PNID.where() - // but it ensures that each input - // ALWAYS has an output and filters - // out unwanted input/output types - const results = []; - const allowedTypes = ['pid', 'user_id']; - - for (const input of inputList) { - const result = { - in_id: input, - out_id: '' - }; - - if (allowedTypes.includes(request.query.input_type) && allowedTypes.includes(request.query.output_type)) { - const query = {}; - query[inputType] = input; - - const searchResult = await PNID.findOne(query); - - if (searchResult) { - result.out_id = searchResult.get(outputType); - } - } - - results.push(result); - } - - response.send(xmlbuilder.create({ - mapped_ids: { - mapped_id: results - } - }).end()); -}); - -module.exports = router; \ No newline at end of file diff --git a/src/services/nnid/routes/admin.ts b/src/services/nnid/routes/admin.ts new file mode 100644 index 0000000..b28f243 --- /dev/null +++ b/src/services/nnid/routes/admin.ts @@ -0,0 +1,88 @@ +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import { PNID } from '../../../models/pnid'; + +const router = Router(); + +/** + * [GET] + * Replacement for: https://account.nintendo.net/v1/api/admin/mapped_ids + * Description: Maps between NNID usernames and PIDs + */ +router.get('/mapped_ids', async (request, response) => { + + let inputType: string; + let inputList: string[]; + let outputType: string; + let queryInput: string; + let queryOutput: string; + + if (Array.isArray(request.query.input_type)) { + inputType = request.query.input_type[0] as string; + } else { + inputType = request.query.input_type as string; + } + + if (Array.isArray(request.query.input)) { + inputList = request.query.input as string[]; + } else { + const input = request.query.input as string; + inputList = input.split(','); + } + + if (Array.isArray(request.query.output_type)) { + outputType = request.query.output_type[0] as string; + } else { + outputType = request.query.output_type as string; + } + + inputList = inputList.filter(input => input); // * Remove null inputs + + if (inputType === 'user_id') { + queryInput = 'usernameLower'; + inputList = inputList.map(name => name.toLowerCase()); + } else { + queryInput = 'pid'; + } + + if (outputType === 'user_id') { + queryOutput = 'username'; + } else { + queryOutput = 'pid'; + } + + // This is slower than PNID.where() + // but it ensures that each input + // ALWAYS has an output and filters + // out unwanted input/output types + const results = []; + const allowedTypes = ['pid', 'user_id']; + + for (const input of inputList) { + const result = { + in_id: input, + out_id: '' + }; + + if (allowedTypes.includes(inputType) && allowedTypes.includes(outputType)) { + const query = {}; + query[queryInput] = input; + + const searchResult = await PNID.findOne(query); + + if (searchResult) { + result.out_id = searchResult.get(queryOutput); + } + } + + results.push(result); + } + + response.send(xmlbuilder.create({ + mapped_ids: { + mapped_id: results + } + }).end()); +}); + +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/content.js b/src/services/nnid/routes/content.ts similarity index 92% rename from src/services/nnid/routes/content.js rename to src/services/nnid/routes/content.ts index e8b9d70..16a0c69 100644 --- a/src/services/nnid/routes/content.js +++ b/src/services/nnid/routes/content.ts @@ -1,6 +1,8 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); -const timezones = require('../timezones.json'); +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import timezones from '../timezones.json'; + +const router = Router(); /** * [GET] @@ -10,7 +12,7 @@ const timezones = require('../timezones.json'); router.get('/agreements/:type/:region/:version', (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); response.send(xmlbuilder.create({ agreements: { @@ -127,7 +129,7 @@ router.get('/agreements/:type/:region/:version', (request, response) => { router.get('/time_zones/:countryCode/:language', (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); /* // Old method. Crashes WiiU when sending a list with over 32 entries, but otherwise works @@ -159,4 +161,4 @@ router.get('/time_zones/:countryCode/:language', (request, response) => { }).end()); }); -module.exports = router; +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/devices.js b/src/services/nnid/routes/devices.ts similarity index 65% rename from src/services/nnid/routes/devices.js rename to src/services/nnid/routes/devices.ts index 4dd3e4e..ec6224e 100644 --- a/src/services/nnid/routes/devices.js +++ b/src/services/nnid/routes/devices.ts @@ -1,5 +1,7 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; + +const router = Router(); /** * [GET] @@ -12,4 +14,4 @@ router.get('/@current/status', async (request, response) => { }).end()); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/index.js b/src/services/nnid/routes/index.js deleted file mode 100644 index b5becf4..0000000 --- a/src/services/nnid/routes/index.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - ADMIN: require('./admin'), - CONTENT: require('./content'), - DEVICES: require('./devices'), - MIIS: require('./miis'), - OAUTH: require('./oauth'), - PEOPLE: require('./people'), - PROVIDER: require('./provider'), - SUPPORT: require('./support'), -}; \ No newline at end of file diff --git a/src/services/nnid/routes/index.ts b/src/services/nnid/routes/index.ts new file mode 100644 index 0000000..67e2938 --- /dev/null +++ b/src/services/nnid/routes/index.ts @@ -0,0 +1,19 @@ +import admin from './admin'; +import content from './content'; +import devices from './devices'; +import miis from './miis'; +import oauth from './oauth'; +import people from './people'; +import provider from './provider'; +import support from './support'; + +export default { + ADMIN: admin, + CONTENT: content, + DEVICES: devices, + MIIS: miis, + OAUTH: oauth, + PEOPLE: people, + PROVIDER: provider, + SUPPORT: support, +}; \ No newline at end of file diff --git a/src/services/nnid/routes/miis.js b/src/services/nnid/routes/miis.ts similarity index 87% rename from src/services/nnid/routes/miis.js rename to src/services/nnid/routes/miis.ts index 3c5603c..62e60df 100644 --- a/src/services/nnid/routes/miis.js +++ b/src/services/nnid/routes/miis.ts @@ -1,7 +1,9 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); -const { PNID } = require('../../../models/pnid'); -const { config } = require('../../../config-manager'); +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import { PNID } from '../../../models/pnid'; +import { config } from '../../../config-manager'; + +const router = Router(); /** * [GET] @@ -91,4 +93,4 @@ router.get('/', async (request, response) => { }).end()); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/oauth.js b/src/services/nnid/routes/oauth.ts similarity index 87% rename from src/services/nnid/routes/oauth.js rename to src/services/nnid/routes/oauth.ts index 21516ad..751a3b4 100644 --- a/src/services/nnid/routes/oauth.js +++ b/src/services/nnid/routes/oauth.ts @@ -1,9 +1,11 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); -const bcrypt = require('bcrypt'); -const fs = require('fs-extra'); -const database = require('../../../database'); -const util = require('../../../util'); +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import bcrypt from 'bcrypt'; +import fs from 'fs-extra'; +import database from '../../../database'; +import util from '../../../util'; + +const router = Router(); /** * [POST] @@ -117,4 +119,4 @@ router.post('/access_token/generate', async (request, response) => { }).end()); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/people.js b/src/services/nnid/routes/people.ts similarity index 82% rename from src/services/nnid/routes/people.js rename to src/services/nnid/routes/people.ts index 6460877..9eb06c5 100644 --- a/src/services/nnid/routes/people.js +++ b/src/services/nnid/routes/people.ts @@ -1,16 +1,18 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); -const moment = require('moment'); -const crypto = require('crypto'); -const bcrypt = require('bcrypt'); -const { PNID } = require('../../../models/pnid'); -const { NEXAccount } = require('../../../models/nex-account'); -const deviceCertificateMiddleware = require('../../../middleware/device-certificate'); -const ratelimit = require('../../../middleware/ratelimit'); -const database = require('../../../database'); -const util = require('../../../util'); -const logger = require('../../../logger'); -require('moment-timezone'); +import crypto from 'node:crypto'; +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import bcrypt from 'bcrypt'; +import moment from 'moment'; +import deviceCertificateMiddleware from '../../../middleware/device-certificate'; +import ratelimit from '../../../middleware/ratelimit'; +import database from '../../../database'; +import util from '../../../util'; +import { PNID } from '../../../models/pnid'; +import { NEXAccount } from '../../../models/nex-account'; +import logger from '../../../logger'; +import timezones from '../timezones.json'; + +const router = Router(); /** * [GET] @@ -102,6 +104,14 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons const primaryPasswordHash = util.nintendoPasswordHash(person.get('password'), nexAccount.get('pid')); const passwordHash = await bcrypt.hash(primaryPasswordHash, 10); + const countryCode = person.get('country'); + const language = person.get('language'); + const timezoneName = person.get('tz_name'); + + const regionLanguages = timezones[countryCode]; + const regionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; + const timezone = regionTimezones.find(tz => tz.area === timezoneName); + pnid = new PNID({ pid: nexAccount.get('pid'), creation_date: creationDate, @@ -111,8 +121,8 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons password: passwordHash, birthdate: person.get('birth_date'), gender: person.get('gender'), - country: person.get('country'), - language: person.get('language'), + country: countryCode, + language: language, email: { address: person.get('email').get('address').toLowerCase(), primary: person.get('email').get('primary') === 'Y', @@ -123,8 +133,8 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons }, region: person.get('region'), timezone: { - name: person.get('tz_name'), - offset: (moment.tz(person.get('tz_name')).utcOffset() * 60) + name: timezoneName, + offset: Number(timezone.utc_offset) }, mii: { name: person.get('mii').get('name'), @@ -190,7 +200,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons router.get('/@me/profile', async (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); const { pnid } = request; @@ -209,7 +219,7 @@ router.get('/@me/profile', async (request, response) => { router.post('/@me/devices', async (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); // We don't care about the device attributes // The console ignores them and PNIDs are not tied to consoles anyway @@ -232,7 +242,7 @@ router.post('/@me/devices', async (request, response) => { router.get('/@me/devices', async (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); const { pnid, headers } = request; @@ -265,7 +275,7 @@ router.get('/@me/devices', async (request, response) => { router.get('/@me/devices/owner', async (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', moment().add(5, 'h')); + response.set('X-Nintendo-Date', moment().add(5, 'h').toString()); const { pnid } = request; @@ -284,7 +294,7 @@ router.get('/@me/devices/owner', async (request, response) => { router.get('/@me/devices/status', async (request, response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', moment().add(5, 'h')); + response.set('X-Nintendo-Date', moment().add(5, 'h').toString()); response.send(xmlbuilder.create({ device: {} @@ -316,7 +326,7 @@ router.put('/@me/miis/@primary', async (request, response) => { */ router.put('/@me/devices/@current/inactivate', async (request, response) => { response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); const { pnid } = request; @@ -390,21 +400,27 @@ router.put('/@me', async (request, response) => { const gender = person.get('gender') ? person.get('gender') : pnid.get('gender'); const region = person.get('region') ? person.get('region') : pnid.get('region'); + const countryCode = person.get('country') ? person.get('country') : pnid.get('country'); + const language = person.get('language') ? person.get('language') : pnid.get('language'); const timezoneName = person.get('tz_name') ? person.get('tz_name') : pnid.get('timezone.name'); const marketingFlag = person.get('marketing_flag') ? person.get('marketing_flag') === 'Y' : pnid.get('flags.marketing'); const offDeviceFlag = person.get('off_device_flag') ? person.get('off_device_flag') === 'Y' : pnid.get('flags.off_device'); + const regionLanguages = timezones[countryCode]; + const regionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; + const timezone = regionTimezones.find(tz => tz.area === timezoneName); + if (person.get('password')) { const primaryPasswordHash = util.nintendoPasswordHash(person.get('password'), pnid.get('pid')); const passwordHash = await bcrypt.hash(primaryPasswordHash, 10); - + pnid.password = passwordHash; } pnid.gender = gender; pnid.region = region; pnid.timezone.name = timezoneName; - pnid.timezone.offset = (moment.tz(timezoneName).utcOffset() * 60); + pnid.timezone.offset = Number(timezone.utc_offset); pnid.timezone.marketing = marketingFlag; pnid.timezone.off_device = offDeviceFlag; @@ -493,4 +509,4 @@ router.put('/@me/emails/@primary', async (request, response) => { response.send(''); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/provider.js b/src/services/nnid/routes/provider.ts similarity index 86% rename from src/services/nnid/routes/provider.js rename to src/services/nnid/routes/provider.ts index 86fd9d1..a15de46 100644 --- a/src/services/nnid/routes/provider.js +++ b/src/services/nnid/routes/provider.ts @@ -1,10 +1,12 @@ -const router = require('express').Router(); -const xmlbuilder = require('xmlbuilder'); -const fs = require('fs-extra'); -const { NEXAccount } = require('../../../models/nex-account'); -const util = require('../../../util'); -const database = require('../../../database'); -const cache = require('../../../cache'); +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import fs from 'fs-extra'; +import database from '../../../database'; +import util from '../../../util'; +import cache from '../../../cache'; +import { NEXAccount } from '../../../models/nex-account'; + +const router = Router(); /** * [GET] @@ -14,7 +16,7 @@ const cache = require('../../../cache'); router.get('/service_token/@me', async (request, response) => { const { pnid } = request; - const titleId = request.headers['x-nintendo-title-id']; + const titleId = request.headers['x-nintendo-title-id'] as string; const serverAccessLevel = pnid.get('server_access_level'); const server = await database.getServerByTitleId(titleId, serverAccessLevel); @@ -110,7 +112,7 @@ router.get('/nex_token/@me', async (request, response) => { } const { service_name, service_type, ip, port, device } = server; - const titleId = request.headers['x-nintendo-title-id']; + const titleId = request.headers['x-nintendo-title-id'] as string; const cryptoPath = `${__dirname}/../../../../certs/${service_type}/${service_name}`; @@ -169,4 +171,4 @@ router.get('/nex_token/@me', async (request, response) => { }).end()); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/support.js b/src/services/nnid/routes/support.ts similarity index 88% rename from src/services/nnid/routes/support.js rename to src/services/nnid/routes/support.ts index d63fea3..f44d033 100644 --- a/src/services/nnid/routes/support.js +++ b/src/services/nnid/routes/support.ts @@ -1,9 +1,11 @@ -const router = require('express').Router(); -const dns = require('dns'); -const xmlbuilder = require('xmlbuilder'); -const moment = require('moment'); -const util = require('../../../util'); -const database = require('../../../database'); +import dns from 'node:dns'; +import { Router } from 'express'; +import xmlbuilder from 'xmlbuilder'; +import moment from 'moment'; +import database from '../../../database'; +import util from '../../../util'; + +const router = Router(); /** * [POST] @@ -145,4 +147,4 @@ router.get('/forgotten_password/:pid', async (request, response) => { response.status(200).send(''); }); -module.exports = router; \ No newline at end of file +export default router; \ No newline at end of file diff --git a/src/util.js b/src/util.ts similarity index 96% rename from src/util.js rename to src/util.ts index 0050b38..3494f67 100644 --- a/src/util.js +++ b/src/util.ts @@ -303,7 +303,7 @@ async function sendForgotPasswordEmail(pnid) { }); } -module.exports = { +export default { nintendoPasswordHash, nintendoBase64Decode, nintendoBase64Encode, diff --git a/types/express.d.ts b/types/express.d.ts new file mode 100644 index 0000000..ca16356 --- /dev/null +++ b/types/express.d.ts @@ -0,0 +1,12 @@ +import NintendoCertificate from '../src/nintendo-certificate' + +declare global { + namespace Express { + interface Request { + pnid?: IPNID; + isCemu?: boolean; + files?: Record; + certificate?: NintendoCertificate; + } + } +} \ No newline at end of file diff --git a/types/mongoose/device-attribute.d.ts b/types/mongoose/device-attribute.d.ts new file mode 100644 index 0000000..8be84dd --- /dev/null +++ b/types/mongoose/device-attribute.d.ts @@ -0,0 +1,13 @@ +import { Document, Model } from 'mongoose'; + +declare global { + interface IDeviceAttributeDocument extends Document { + created_date: string; + name: string; + value: string; + } + + interface IDeviceAttribute extends IDeviceAttributeDocument {} + + interface IDeviceAttributeModel extends Model {} +} \ No newline at end of file diff --git a/types/mongoose/device.d.ts b/types/mongoose/device.d.ts new file mode 100644 index 0000000..2303607 --- /dev/null +++ b/types/mongoose/device.d.ts @@ -0,0 +1,32 @@ +import { Document, Model } from 'mongoose'; +import { DeviceAttributeSchema } from '../../src/models/device'; + +type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan'; +type ACCESS_LEVEL = 0 | 1 | 2 | 3; +type SERVER_ACCESS_LEVEL = 'prod' | 'test' | 'dev'; + +declare global { + interface IDeviceDocument extends Document { + is_emulator: boolean; + model: MODEL; + device_id: number; + device_type: number; + serial: string; + device_attributes: typeof DeviceAttributeSchema[]; + soap: { + token: string; + account_id: number; + }, + // * 3DS-specific stuff + environment: string; + mac_hash: string; + fcdcert_hash: string; + linked_pids: number[]; + access_level: ACCESS_LEVEL; + server_access_level: SERVER_ACCESS_LEVEL; + } + + interface IDevice extends IDeviceDocument {} + + interface IDeviceModel extends Model {} +} \ No newline at end of file diff --git a/types/mongoose/nex-account.d.ts b/types/mongoose/nex-account.d.ts new file mode 100644 index 0000000..51ab37d --- /dev/null +++ b/types/mongoose/nex-account.d.ts @@ -0,0 +1,23 @@ +import { Document, Model } from 'mongoose'; + +type DEVICE = 'wiiu' | '3ds'; +type ACCESS_LEVEL = 0 | 1 | 2 | 3; + +declare global { + interface INEXAccountDocument extends Document { + device_type: DEVICE; + pid: number; + password: string; + owning_pid: number; + access_level: ACCESS_LEVEL; + server_access_level: string; + } + + interface INEXAccount extends INEXAccountDocument { + generatePID(): void; + } + + interface INEXAccountModel extends Model { + generatePID(): void; + } +} \ No newline at end of file diff --git a/types/mongoose/pnid.d.ts b/types/mongoose/pnid.d.ts new file mode 100644 index 0000000..145523b --- /dev/null +++ b/types/mongoose/pnid.d.ts @@ -0,0 +1,81 @@ +import { Document, Model } from 'mongoose'; +import { DeviceSchema } from '../../src/models/device'; + +declare global { + interface IPNIDDocument extends Document { + access_level: number; + server_access_level: string; + pid: number; + creation_date: string; + updated: string; + username: string; + usernameLower: string; + password: string; + birthdate: string; + gender: string; + country: string; + language: string; + email: { + address: string; + primary: boolean; + parent: boolean; + reachable: boolean; + validated: boolean; + validated_date: string; + id: number; + }; + region: number; + timezone: { + name: string; + offset: number; + marketing: boolean; + off_device: boolean; + }; + mii: { + name: string; + primary: boolean; + data: string; + id: number; + hash: string; + image_url: string; + image_id: number; + }; + flags: { + active: boolean; + marketing: boolean; + off_device: boolean; + }; + devices: typeof DeviceSchema[]; + identification: { // user identification tokens + email_code: string; + email_token: string; + access_token: { + value: string; + ttl: number; + }, + refresh_token: { + value: string; + ttl: number; + } + }; + connections: { + discord: { + id: string; + } + }; + } + + interface IPNID extends IPNIDDocument { + generatePID(): void; + generateEmailValidationCode(): void; + generateEmailValidationToken(): void; + updateMii(mii: { name: string, primary: boolean, data: Buffer}): void; + generateMiiImages(): void; + getServerMode(): string; + } + + interface IPNIDModel extends Model { + generatePID(): void; + generateEmailValidationToken(): void; + } +} \ No newline at end of file diff --git a/types/mongoose/server.d.ts b/types/mongoose/server.d.ts new file mode 100644 index 0000000..574f21e --- /dev/null +++ b/types/mongoose/server.d.ts @@ -0,0 +1,19 @@ +import { Document, Model } from 'mongoose'; + +declare global { + interface IServerDocument extends Document { + ip: string; // Example: 1.1.1.1 + port: Number; // Example: 60000 + service_name: string; // Example: friends + service_type: string; // Example: nex + game_server_id: string; // Example: 00003200 + title_ids: string[]; // Example: ["000500001018DB00", "000500001018DC00", "000500001018DD00"] + access_mode: string; // Example: prod + maintenance_mode: boolean; // Example: false + device: number; // Example: 1 (WiiU) + } + + interface IServer extends IServerDocument {} + + interface IServerModel extends Model {} +} \ No newline at end of file From 75de643ac5c59ef2b5e0a981f13a3be987977aed Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 3 Mar 2023 12:45:49 -0500 Subject: [PATCH 16/65] Bump version to 2.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c4acc78..1814e4b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "account", - "version": "1.0.0", + "version": "2.0.0", "description": "", "main": "./dist/server.js", "scripts": { From d05a1eed915c36ec346cef440bff3f4cf6c2e9e6 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 3 Mar 2023 20:59:05 -0500 Subject: [PATCH 17/65] Better typed Mongoose models --- package-lock.json | 621 +++++++++++---------------- package.json | 2 +- src/database.ts | 6 +- src/models/device.ts | 8 +- src/models/nex-account.ts | 14 +- src/models/pnid.ts | 32 +- src/models/server.ts | 4 +- src/services/api/routes/v1/user.ts | 64 +-- src/services/nnid/routes/people.ts | 2 +- types/express.d.ts | 3 +- types/mongoose/device-attribute.d.ts | 8 +- types/mongoose/device.d.ts | 8 +- types/mongoose/nex-account.d.ts | 13 +- types/mongoose/pnid.d.ts | 21 +- types/mongoose/server.d.ts | 6 +- 15 files changed, 341 insertions(+), 471 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1473949..c670965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,18 @@ { "name": "account", - "version": "1.0.0", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "account", - "version": "1.0.0", + "version": "2.0.0", "license": "ISC", "dependencies": { "aws-sdk": "^2.978.0", "bcrypt": "^5.0.0", "colors": "^1.4.0", "cors": "^2.8.5", - "countries-and-timezones": "^3.4.1", "dicer": "^0.2.5", "dotenv": "^16.0.3", "email-validator": "^2.0.4", @@ -25,15 +24,13 @@ "hcaptcha": "^0.1.0", "image-pixels": "^1.1.1", "joi": "^17.8.3", - "kaitai-struct": "^0.9.0", "lodash.get": "^4.4.2", "lodash.set": "^4.3.2", "mii-js": "github:PretendoNetwork/mii-js", "moment": "^2.29.4", - "mongoose": "^5.8.3", + "mongoose": "^7.0.0", "mongoose-unique-validator": "^2.0.3", "morgan": "^1.9.1", - "neat-config": "^1.0.0", "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", @@ -312,14 +309,6 @@ "@types/node": "*" } }, - "node_modules/@types/bson": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", - "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -411,15 +400,6 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, - "node_modules/@types/mongodb": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", - "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==", - "dependencies": { - "@types/bson": "*", - "@types/node": "*" - } - }, "node_modules/@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -464,6 +444,20 @@ "@types/node": "*" } }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -768,47 +762,6 @@ "resolved": "https://registry.npmjs.org/bit-buffer/-/bit-buffer-0.2.5.tgz", "integrity": "sha512-x1yGnmXvFg6e3DiyRztElbcn1bsCTFSoM/ncAzY62uE0JdTl5xlKJd0ooqLYoPbhdsnpehSIQrdIvclcZJYwiA==" }, - "node_modules/bl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", - "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "dependencies": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/bl/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/bl/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, "node_modules/bmp-js": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", @@ -861,11 +814,11 @@ } }, "node_modules/bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.0.1.tgz", + "integrity": "sha512-y09gBGusgHtinMon/GVbv1J6FrXhnr/+6hqLlSmEFzkz6PodqF6TxjyvfvY3AfO+oG1mgUtbC86xSbOlwvM62Q==", "engines": { - "node": ">=0.6.19" + "node": ">=14.20.1" } }, "node_modules/buffer": { @@ -1115,15 +1068,6 @@ "node": ">= 0.10" } }, - "node_modules/countries-and-timezones": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/countries-and-timezones/-/countries-and-timezones-3.4.1.tgz", - "integrity": "sha512-INeHGCony4XUUR8iGL/lmt9s1Oi+n+gFHeJAMfbV5hJfYeDOB8JG1oxz5xFQu5oBZoRCJe/87k1Vzue9DoIauA==", - "engines": { - "node": ">=8.x", - "npm": ">=5.x" - } - }, "node_modules/cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -1217,14 +1161,6 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, - "node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -2093,6 +2029,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -2326,15 +2267,13 @@ "node": ">=0.6.0" } }, - "node_modules/kaitai-struct": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/kaitai-struct/-/kaitai-struct-0.9.0.tgz", - "integrity": "sha512-mfoBu9+IGqaY3ykG1TyAy9omOAZWtheqESQOvo/HKIQVTz+gRPVCNBnhjbO+8wAQ77RD33wYvLBWmITuXIviQg==" - }, "node_modules/kareem": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", - "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } }, "node_modules/keyv": { "version": "4.5.2", @@ -2585,90 +2524,98 @@ } }, "node_modules/mongodb": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", - "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.1.0.tgz", + "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", "dependencies": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.1.8", - "safe-buffer": "^5.1.2" + "bson": "^5.0.1", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" }, "engines": { - "node": ">=4" + "node": ">=14.20.1" }, "optionalDependencies": { - "saslprep": "^1.0.0" + "saslprep": "^1.0.3" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.201.0", + "mongodb-client-encryption": "^2.3.0", + "snappy": "^7.2.2" }, "peerDependenciesMeta": { - "aws4": { - "optional": true - }, - "bson-ext": { - "optional": true - }, - "kerberos": { + "@aws-sdk/credential-providers": { "optional": true }, "mongodb-client-encryption": { "optional": true }, - "mongodb-extjson": { - "optional": true - }, "snappy": { "optional": true } } }, - "node_modules/mongodb/node_modules/optional-require": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", - "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", "dependencies": { - "require-at": "^1.0.6" + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" }, "engines": { - "node": ">=4" + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/mongoose": { - "version": "5.13.16", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.16.tgz", - "integrity": "sha512-kBNB+BfaQjn3Jjh1SfdZZub70pde9dI0sA8VN6AnnCOeK4TzbLDyB0lBmPBOajppm6U9orde5YfTRyyVa1U45w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.0.0.tgz", + "integrity": "sha512-U0YPURDld+k/nvvSG1mRClQSjZMRXwQKSU5yb9PslRnOmVz0UlBD7SjSnjUuGT0yk+7BH+kJNimsKqMxYAKkMA==", "dependencies": { - "@types/bson": "1.x || 4.0.x", - "@types/mongodb": "^3.5.27", - "bson": "^1.1.4", - "kareem": "2.3.2", - "mongodb": "3.7.3", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.8.4", - "mquery": "3.2.5", - "ms": "2.1.2", - "optional-require": "1.0.x", - "regexp-clone": "1.0.0", - "safe-buffer": "5.2.1", - "sift": "13.5.2", - "sliced": "1.0.1" + "bson": "^5.0.1", + "kareem": "2.5.1", + "mongodb": "5.1.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" }, "engines": { - "node": ">=4.0.0" + "node": ">=14.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/mongoose" } }, - "node_modules/mongoose-legacy-pluralize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==", - "peerDependencies": { - "mongoose": "*" - } - }, "node_modules/mongoose-unique-validator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/mongoose-unique-validator/-/mongoose-unique-validator-2.0.3.tgz", @@ -2682,9 +2629,9 @@ } }, "node_modules/mongoose/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/morgan": { "version": "1.10.0", @@ -2713,40 +2660,44 @@ } }, "node_modules/mpath": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz", - "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", "engines": { "node": ">=4.0.0" } }, "node_modules/mquery": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz", - "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", "dependencies": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "^1.0.0", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" + "debug": "4.x" }, "engines": { - "node": ">=4.0.0" + "node": ">=14.0.0" } }, "node_modules/mquery/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { - "ms": "2.0.0" + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/mquery/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/mquery/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/ms": { "version": "2.0.0", @@ -2759,14 +2710,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "node_modules/neat-config": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/neat-config/-/neat-config-1.0.0.tgz", - "integrity": "sha512-EKvHxsZ9yOUHWhx6MxxzbTDhNK0wiSbfaU42s2OnQuVgR+FwpswaiSm3xX7ST4TcN+rJiEw+GuhfK015vHKwrA==", - "dependencies": { - "joi": "^17.6.0" - } - }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -2913,14 +2856,6 @@ "wrappy": "1" } }, - "node_modules/optional-require": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", - "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==", - "engines": { - "node": ">=4" - } - }, "node_modules/optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -3175,11 +3110,6 @@ "@redis/time-series": "1.0.4" } }, - "node_modules/regexp-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", - "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" - }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -3228,14 +3158,6 @@ "uuid": "bin/uuid" } }, - "node_modules/require-at": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", - "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", - "engines": { - "node": ">=4" - } - }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -3436,19 +3358,36 @@ } }, "node_modules/sift": { - "version": "13.5.2", - "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", - "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, "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==" }, - "node_modules/sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==" + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } }, "node_modules/source-map": { "version": "0.6.1", @@ -4240,14 +4179,6 @@ "@types/node": "*" } }, - "@types/bson": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.5.tgz", - "integrity": "sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg==", - "requires": { - "@types/node": "*" - } - }, "@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -4338,15 +4269,6 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, - "@types/mongodb": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", - "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==", - "requires": { - "@types/bson": "*", - "@types/node": "*" - } - }, "@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -4391,6 +4313,20 @@ "@types/node": "*" } }, + "@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -4626,49 +4562,6 @@ "resolved": "https://registry.npmjs.org/bit-buffer/-/bit-buffer-0.2.5.tgz", "integrity": "sha512-x1yGnmXvFg6e3DiyRztElbcn1bsCTFSoM/ncAzY62uE0JdTl5xlKJd0ooqLYoPbhdsnpehSIQrdIvclcZJYwiA==" }, - "bl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", - "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, "bmp-js": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", @@ -4714,9 +4607,9 @@ } }, "bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/bson/-/bson-5.0.1.tgz", + "integrity": "sha512-y09gBGusgHtinMon/GVbv1J6FrXhnr/+6hqLlSmEFzkz6PodqF6TxjyvfvY3AfO+oG1mgUtbC86xSbOlwvM62Q==" }, "buffer": { "version": "4.9.2", @@ -4919,11 +4812,6 @@ "vary": "^1" } }, - "countries-and-timezones": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/countries-and-timezones/-/countries-and-timezones-3.4.1.tgz", - "integrity": "sha512-INeHGCony4XUUR8iGL/lmt9s1Oi+n+gFHeJAMfbV5hJfYeDOB8JG1oxz5xFQu5oBZoRCJe/87k1Vzue9DoIauA==" - }, "cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -4995,11 +4883,6 @@ "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, - "denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" - }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5703,6 +5586,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -5871,15 +5759,10 @@ "verror": "1.10.0" } }, - "kaitai-struct": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/kaitai-struct/-/kaitai-struct-0.9.0.tgz", - "integrity": "sha512-mfoBu9+IGqaY3ykG1TyAy9omOAZWtheqESQOvo/HKIQVTz+gRPVCNBnhjbO+8wAQ77RD33wYvLBWmITuXIviQg==" - }, "kareem": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.2.tgz", - "integrity": "sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ==" + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==" }, "keyv": { "version": "4.5.2", @@ -6069,62 +5952,70 @@ "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" }, "mongodb": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", - "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.1.0.tgz", + "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", "requires": { - "bl": "^2.2.1", - "bson": "^1.1.4", - "denque": "^1.4.1", - "optional-require": "^1.1.8", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "bson": "^5.0.1", + "mongodb-connection-string-url": "^2.6.0", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" }, "dependencies": { - "optional-require": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", - "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "requires": { - "require-at": "^1.0.6" + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } } } }, "mongoose": { - "version": "5.13.16", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.16.tgz", - "integrity": "sha512-kBNB+BfaQjn3Jjh1SfdZZub70pde9dI0sA8VN6AnnCOeK4TzbLDyB0lBmPBOajppm6U9orde5YfTRyyVa1U45w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.0.0.tgz", + "integrity": "sha512-U0YPURDld+k/nvvSG1mRClQSjZMRXwQKSU5yb9PslRnOmVz0UlBD7SjSnjUuGT0yk+7BH+kJNimsKqMxYAKkMA==", "requires": { - "@types/bson": "1.x || 4.0.x", - "@types/mongodb": "^3.5.27", - "bson": "^1.1.4", - "kareem": "2.3.2", - "mongodb": "3.7.3", - "mongoose-legacy-pluralize": "1.0.2", - "mpath": "0.8.4", - "mquery": "3.2.5", - "ms": "2.1.2", - "optional-require": "1.0.x", - "regexp-clone": "1.0.0", - "safe-buffer": "5.2.1", - "sift": "13.5.2", - "sliced": "1.0.1" + "bson": "^5.0.1", + "kareem": "2.5.1", + "mongodb": "5.1.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" }, "dependencies": { "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" } } }, - "mongoose-legacy-pluralize": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", - "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==", - "requires": {} - }, "mongoose-unique-validator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/mongoose-unique-validator/-/mongoose-unique-validator-2.0.3.tgz", @@ -6157,34 +6048,30 @@ } }, "mpath": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.8.4.tgz", - "integrity": "sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==" }, "mquery": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz", - "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", "requires": { - "bluebird": "3.5.1", - "debug": "3.1.0", - "regexp-clone": "^1.0.0", - "safe-buffer": "5.1.2", - "sliced": "1.0.1" + "debug": "4.x" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { - "ms": "2.0.0" + "ms": "2.1.2" } }, - "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==" + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" } } }, @@ -6199,14 +6086,6 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, - "neat-config": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/neat-config/-/neat-config-1.0.0.tgz", - "integrity": "sha512-EKvHxsZ9yOUHWhx6MxxzbTDhNK0wiSbfaU42s2OnQuVgR+FwpswaiSm3xX7ST4TcN+rJiEw+GuhfK015vHKwrA==", - "requires": { - "joi": "^17.6.0" - } - }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6309,11 +6188,6 @@ "wrappy": "1" } }, - "optional-require": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", - "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==" - }, "optionator": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", @@ -6515,11 +6389,6 @@ "@redis/time-series": "1.0.4" } }, - "regexp-clone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", - "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" - }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -6559,11 +6428,6 @@ } } }, - "require-at": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", - "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==" - }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -6716,19 +6580,28 @@ } }, "sift": { - "version": "13.5.2", - "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", - "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" }, "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==" }, - "sliced": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", - "integrity": "sha512-VZBmZP8WU3sMOZm1bdgTadsQbcscK0UM8oKxKVBs4XAhUo2Xxzm/OFMGBkPusxw9xL3Uy8LrzEqGqJhclsr0yA==" + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } }, "source-map": { "version": "0.6.1", diff --git a/package.json b/package.json index 1814e4b..a02b631 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "lodash.set": "^4.3.2", "mii-js": "github:PretendoNetwork/mii-js", "moment": "^2.29.4", - "mongoose": "^5.8.3", + "mongoose": "^7.0.0", "mongoose-unique-validator": "^2.0.3", "morgan": "^1.9.1", "nodemailer": "^6.4.2", diff --git a/src/database.ts b/src/database.ts index 93bffff..c5a47a9 100644 --- a/src/database.ts +++ b/src/database.ts @@ -38,7 +38,7 @@ export async function getUserByUsername(username) { const user = await PNID.findOne({ usernameLower: username.toLowerCase() - }); + }) as mongoose.HydratedDocument; return user; } @@ -48,7 +48,7 @@ export async function getUserByPID(pid) { const user = await PNID.findOne({ pid - }); + }) as mongoose.HydratedDocument; return user; } @@ -58,7 +58,7 @@ export async function getUserByEmailAddress(email) { const user = await PNID.findOne({ 'email.address': new RegExp(email, 'i') // * Ignore case - }); + }) as mongoose.HydratedDocument; return user; } diff --git a/src/models/device.ts b/src/models/device.ts index 820a3f4..22ac5c1 100644 --- a/src/models/device.ts +++ b/src/models/device.ts @@ -1,14 +1,14 @@ import { Schema, model } from 'mongoose'; -export const DeviceAttributeSchema = new Schema({ +export const DeviceAttributeSchema = new Schema({ created_date: String, name: String, value: String }); -export const DeviceAttribute: IDeviceAttributeModel = model('DeviceAttribute', DeviceAttributeSchema); +export const DeviceAttribute: DeviceAttributeModel = model('DeviceAttribute', DeviceAttributeSchema); -export const DeviceSchema = new Schema({ +export const DeviceSchema = new Schema({ is_emulator: { type: Boolean, default: false @@ -48,7 +48,7 @@ export const DeviceSchema = new Schema({ } }); -export const Device: IDeviceModel = model('Device', DeviceSchema); +export const Device: DeviceModel = model('Device', DeviceSchema); export default { DeviceSchema, diff --git a/src/models/nex-account.ts b/src/models/nex-account.ts index 6a4b509..cfbc818 100644 --- a/src/models/nex-account.ts +++ b/src/models/nex-account.ts @@ -1,7 +1,7 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; -export const NEXAccountSchema = new Schema({ +export const NEXAccountSchema = new Schema({ device_type: { type: String, enum: [ @@ -36,7 +36,7 @@ NEXAccountSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); https://account.nintendo.net/v1/api/admin/mapped_ids?input_type=pid&output_type=user_id&input=1799999999 returns `prodtest1` and the next few accounts counting down seem to be admin, service and internal test accounts */ -NEXAccountSchema.methods.generatePID = async function () { +NEXAccountSchema.method('generatePID', async function generatePID(): Promise { const min = 1000000000; // The console (WiiU) seems to not accept PIDs smaller than this const max = 1799999999; @@ -45,13 +45,13 @@ NEXAccountSchema.methods.generatePID = async function () { const inuse = await NEXAccount.findOne({ pid }); if (inuse) { - await NEXAccount.generatePID(); + await this.generatePID(); } else { this.set('pid', pid); } -}; +}); -NEXAccountSchema.methods.generatePassword = function () { +NEXAccountSchema.method('generatePassword', function generatePassword(): void { function character() { const offset = Math.floor(Math.random() * 62); if (offset < 10) return offset; @@ -66,9 +66,9 @@ NEXAccountSchema.methods.generatePassword = function () { } this.set('password', output.join('')); -}; +}); -export const NEXAccount: INEXAccountModel = model('NEXAccount', NEXAccountSchema); +export const NEXAccount: NEXAccountModel = model('NEXAccount', NEXAccountSchema); export default { NEXAccountSchema, diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 73b0079..4adc913 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -8,7 +8,7 @@ import Mii from 'mii-js'; import { DeviceSchema } from './device'; import util from '../util'; -export const PNIDSchema = new Schema({ +export const PNIDSchema = new Schema({ access_level: { type: Number, default: 0 // 0: standard, 1: tester, 2: mod?, 3: dev @@ -114,7 +114,7 @@ PNIDSchema.plugin(uniqueValidator, {message: '{PATH} already in use.'}); https://account.nintendo.net/v1/api/admin/mapped_ids?input_type=pid&output_type=user_id&input=1799999999 returns `prodtest1` and the next few accounts counting down seem to be admin, service and internal test accounts */ -PNIDSchema.methods.generatePID = async function() { +PNIDSchema.method('generatePID', async function generatePID(): Promise { const min = 1000000000; // The console (WiiU) seems to not accept PIDs smaller than this const max = 1799999999; @@ -125,21 +125,21 @@ PNIDSchema.methods.generatePID = async function() { }); if (inuse) { - await PNID.generatePID(); + await this.generatePID(); } else { this.set('pid', pid); } -}; +}); -PNIDSchema.methods.generateEmailValidationCode = async function() { +PNIDSchema.method('generateEmailValidationCode', async function generateEmailValidationCode(): Promise { // WiiU passes the PID along with the email code // Does not actually need to be unique to all users const code = Math.random().toFixed(6).split('.')[1]; // Dirty one-liner to generate numbers of 6 length and padded 0 this.set('identification.email_code', code); -}; +}); -PNIDSchema.methods.generateEmailValidationToken = async function() { +PNIDSchema.method('generateEmailValidationToken', async function generateEmailValidationToken(): Promise { let token = crypto.randomBytes(32).toString('hex'); const inuse = await PNID.findOne({ @@ -147,13 +147,13 @@ PNIDSchema.methods.generateEmailValidationToken = async function() { }); if (inuse) { - await PNID.generateEmailValidationToken(); + await this.generateEmailValidationToken(); } else { this.set('identification.email_token', token); } -}; +}); -PNIDSchema.methods.updateMii = async function({name, primary, data}) { +PNIDSchema.method('updateMii', async function updateMii({name, primary, data}): Promise { this.set('mii.name', name); this.set('mii.primary', primary === 'Y'); this.set('mii.data', data); @@ -164,9 +164,9 @@ PNIDSchema.methods.updateMii = async function({name, primary, data}) { await this.generateMiiImages(); await this.save(); -}; +}); -PNIDSchema.methods.generateMiiImages = async function() { +PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promise { const miiData = this.get('mii.data'); const mii = new Mii(Buffer.from(miiData, 'base64')); const miiStudioUrl = mii.studioUrl({ @@ -202,15 +202,15 @@ PNIDSchema.methods.generateMiiImages = async function() { }); const miiStudioBodyImageData = await got(miiStudioBodyUrl).buffer(); await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/body.png`, miiStudioBodyImageData, 'public-read'); -}; +}); -PNIDSchema.methods.getServerMode = function () { +PNIDSchema.method('getServerMode', function getServerMode(): string { const serverMode = this.get('server_mode') || 'prod'; return serverMode; -}; +}); -export const PNID: IPNIDModel = model('PNID', PNIDSchema); +export const PNID: PNIDModel = model('PNID', PNIDSchema); export default { PNIDSchema, diff --git a/src/models/server.ts b/src/models/server.ts index e376aac..b23dbe6 100644 --- a/src/models/server.ts +++ b/src/models/server.ts @@ -1,7 +1,7 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; -export const ServerSchema = new Schema({ +export const ServerSchema = new Schema({ ip: String, // Example: 1.1.1.1 port: Number, // Example: 60000 service_name: String, // Example: friends @@ -15,7 +15,7 @@ export const ServerSchema = new Schema({ ServerSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); -export const Server: IServerModel = model('Server', ServerSchema); +export const Server: ServerModel = model('Server', ServerSchema); export default { ServerSchema, diff --git a/src/services/api/routes/v1/user.ts b/src/services/api/routes/v1/user.ts index 1a6f89b..6f7a299 100644 --- a/src/services/api/routes/v1/user.ts +++ b/src/services/api/routes/v1/user.ts @@ -31,32 +31,32 @@ router.get('/', async (request, response) => { } return response.json({ - access_level: pnid.get('access_level'), - server_access_level: pnid.get('server_access_level'), - pid: pnid.get('pid'), - creation_date: pnid.get('creation_date'), - updated: pnid.get('updated'), - username: pnid.get('username'), - birthdate: pnid.get('birthdate'), - gender: pnid.get('gender'), - country: pnid.get('country'), + access_level: pnid.access_level, + server_access_level: pnid.server_access_level, + pid: pnid.pid, + creation_date: pnid.creation_date, + updated: pnid.updated, + username: pnid.username, + birthdate: pnid.birthdate, + gender: pnid.gender, + country: pnid.country, email: { - address: pnid.get('email.address'), + address: pnid.email.address, }, timezone: { - name: pnid.get('timezone.name') + name: pnid.timezone.name }, mii: { - data: pnid.get('mii.data'), - name: pnid.get('mii.name'), - image_url: `${config.cdn.base_url}/mii/${pnid.get('pid')}/normal_face.png` + data: pnid.mii.data, + name: pnid.mii.name, + image_url: `${config.cdn.base_url}/mii/${pnid.pid}/normal_face.png` }, flags: { - marketing: pnid.get('flags.marketing') + marketing: pnid.flags.marketing }, connections: { discord: { - id: pnid.get('connections.discord.id') + id: pnid.connections.discord.id } } }); @@ -95,32 +95,32 @@ router.post('/', async (request, response) => { await PNID.updateOne({ pid }, { $set: updateData }).exec(); return response.json({ - access_level: pnid.get('access_level'), - server_access_level: pnid.get('server_access_level'), - pid: pnid.get('pid'), - creation_date: pnid.get('creation_date'), - updated: pnid.get('updated'), - username: pnid.get('username'), - birthdate: pnid.get('birthdate'), - gender: pnid.get('gender'), - country: pnid.get('country'), + access_level: pnid.access_level, + server_access_level: pnid.server_access_level, + pid: pnid.pid, + creation_date: pnid.creation_date, + updated: pnid.updated, + username: pnid.username, + birthdate: pnid.birthdate, + gender: pnid.gender, + country: pnid.country, email: { - address: pnid.get('email.address'), + address: pnid.email.address, }, timezone: { - name: pnid.get('timezone.name') + name: pnid.timezone.name }, mii: { - data: pnid.get('mii.data'), - name: pnid.get('mii.name'), - image_url: `${config.cdn.base_url}/mii/${pnid.get('pid')}/normal_face.png` + data: pnid.mii.data, + name: pnid.mii.name, + image_url: `${config.cdn.base_url}/mii/${pnid.pid}/normal_face.png` }, flags: { - marketing: pnid.get('flags.marketing') + marketing: pnid.flags.marketing }, connections: { discord: { - id: pnid.get('connections.discord.id') + id: pnid.connections.discord.id } } }); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 9eb06c5..6c22374 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -227,7 +227,7 @@ router.post('/@me/devices', async (request, response) => { const { pnid } = request; - const person = await database.getUserProfileJSONByPID(pnid.get('pid')); + const person = await database.getUserProfileJSONByPID(pnid.pid); response.send(xmlbuilder.create({ person diff --git a/types/express.d.ts b/types/express.d.ts index ca16356..1dbe78b 100644 --- a/types/express.d.ts +++ b/types/express.d.ts @@ -1,9 +1,10 @@ +import { HydratedDocument } from 'mongoose'; import NintendoCertificate from '../src/nintendo-certificate' declare global { namespace Express { interface Request { - pnid?: IPNID; + pnid?: HydratedDocument; isCemu?: boolean; files?: Record; certificate?: NintendoCertificate; diff --git a/types/mongoose/device-attribute.d.ts b/types/mongoose/device-attribute.d.ts index 8be84dd..98a7de1 100644 --- a/types/mongoose/device-attribute.d.ts +++ b/types/mongoose/device-attribute.d.ts @@ -1,13 +1,13 @@ -import { Document, Model } from 'mongoose'; +import { Model } from 'mongoose'; declare global { - interface IDeviceAttributeDocument extends Document { + interface IDeviceAttribute { created_date: string; name: string; value: string; } - interface IDeviceAttribute extends IDeviceAttributeDocument {} + interface IDeviceAttributeMethods {} - interface IDeviceAttributeModel extends Model {} + interface DeviceAttributeModel extends Model {} } \ No newline at end of file diff --git a/types/mongoose/device.d.ts b/types/mongoose/device.d.ts index 2303607..786953b 100644 --- a/types/mongoose/device.d.ts +++ b/types/mongoose/device.d.ts @@ -1,4 +1,4 @@ -import { Document, Model } from 'mongoose'; +import { Model } from 'mongoose'; import { DeviceAttributeSchema } from '../../src/models/device'; type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan'; @@ -6,7 +6,7 @@ type ACCESS_LEVEL = 0 | 1 | 2 | 3; type SERVER_ACCESS_LEVEL = 'prod' | 'test' | 'dev'; declare global { - interface IDeviceDocument extends Document { + interface IDevice { is_emulator: boolean; model: MODEL; device_id: number; @@ -26,7 +26,7 @@ declare global { server_access_level: SERVER_ACCESS_LEVEL; } - interface IDevice extends IDeviceDocument {} + interface IDeviceMethods {} - interface IDeviceModel extends Model {} + interface DeviceModel extends Model {} } \ No newline at end of file diff --git a/types/mongoose/nex-account.d.ts b/types/mongoose/nex-account.d.ts index 51ab37d..e51119a 100644 --- a/types/mongoose/nex-account.d.ts +++ b/types/mongoose/nex-account.d.ts @@ -1,10 +1,10 @@ -import { Document, Model } from 'mongoose'; +import { Model } from 'mongoose'; type DEVICE = 'wiiu' | '3ds'; type ACCESS_LEVEL = 0 | 1 | 2 | 3; declare global { - interface INEXAccountDocument extends Document { + interface INEXAccount { device_type: DEVICE; pid: number; password: string; @@ -13,11 +13,10 @@ declare global { server_access_level: string; } - interface INEXAccount extends INEXAccountDocument { - generatePID(): void; + interface INEXAccountMethods { + generatePID(): Promise; + generatePassword(): void; } - interface INEXAccountModel extends Model { - generatePID(): void; - } + interface NEXAccountModel extends Model {} } \ No newline at end of file diff --git a/types/mongoose/pnid.d.ts b/types/mongoose/pnid.d.ts index 145523b..e0bea47 100644 --- a/types/mongoose/pnid.d.ts +++ b/types/mongoose/pnid.d.ts @@ -1,8 +1,8 @@ -import { Document, Model } from 'mongoose'; +import { Model } from 'mongoose'; import { DeviceSchema } from '../../src/models/device'; declare global { - interface IPNIDDocument extends Document { + interface IPNID { access_level: number; server_access_level: string; pid: number; @@ -65,17 +65,14 @@ declare global { }; } - interface IPNID extends IPNIDDocument { - generatePID(): void; - generateEmailValidationCode(): void; - generateEmailValidationToken(): void; - updateMii(mii: { name: string, primary: boolean, data: Buffer}): void; - generateMiiImages(): void; + interface IPNIDMethods { + generatePID(): Promise; + generateEmailValidationCode(): Promise; + generateEmailValidationToken(): Promise; + updateMii(mii: { name: string, primary: string, data: string}): Promise; + generateMiiImages(): Promise; getServerMode(): string; } - interface IPNIDModel extends Model { - generatePID(): void; - generateEmailValidationToken(): void; - } + interface PNIDModel extends Model {} } \ No newline at end of file diff --git a/types/mongoose/server.d.ts b/types/mongoose/server.d.ts index 574f21e..6261929 100644 --- a/types/mongoose/server.d.ts +++ b/types/mongoose/server.d.ts @@ -1,7 +1,7 @@ import { Document, Model } from 'mongoose'; declare global { - interface IServerDocument extends Document { + interface IServer { ip: string; // Example: 1.1.1.1 port: Number; // Example: 60000 service_name: string; // Example: friends @@ -13,7 +13,7 @@ declare global { device: number; // Example: 1 (WiiU) } - interface IServer extends IServerDocument {} + interface IServerMethods {} - interface IServerModel extends Model {} + interface ServerModel extends Model {} } \ No newline at end of file From 45a5fd986240adf764847a8116c2ac73052dca91 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 09:45:12 -0500 Subject: [PATCH 18/65] Add import aliases --- package.json | 2 +- src/cache.ts | 2 +- src/config-manager.ts | 2 +- src/database.ts | 10 ++++---- src/mailer.ts | 2 +- src/middleware/api.ts | 2 +- src/middleware/device-certificate.ts | 2 +- src/middleware/nasc.ts | 14 +++++------ src/middleware/pnid.ts | 2 +- src/models/pnid.ts | 4 +-- src/server.ts | 26 ++++++++++---------- src/services/api/index.ts | 6 ++--- src/services/api/routes/index.ts | 14 +++++------ src/services/api/routes/v1/connections.ts | 2 +- src/services/api/routes/v1/email.ts | 4 +-- src/services/api/routes/v1/forgotPassword.ts | 4 +-- src/services/api/routes/v1/login.ts | 6 ++--- src/services/api/routes/v1/register.ts | 14 +++++------ src/services/api/routes/v1/resetPassword.ts | 4 +-- src/services/api/routes/v1/user.ts | 4 +-- src/services/assets/index.ts | 2 +- src/services/conntest/index.ts | 2 +- src/services/datastore/index.ts | 4 +-- src/services/datastore/routes/index.ts | 2 +- src/services/datastore/routes/upload.ts | 2 +- src/services/local-cdn/index.ts | 6 ++--- src/services/local-cdn/routes/get.ts | 2 +- src/services/local-cdn/routes/index.ts | 2 +- src/services/nasc/index.ts | 6 ++--- src/services/nasc/routes/ac.ts | 6 ++--- src/services/nasc/routes/index.ts | 2 +- src/services/nnid/index.ts | 10 ++++---- src/services/nnid/routes/admin.ts | 2 +- src/services/nnid/routes/content.ts | 2 +- src/services/nnid/routes/index.ts | 16 ++++++------ src/services/nnid/routes/miis.ts | 4 +-- src/services/nnid/routes/oauth.ts | 4 +-- src/services/nnid/routes/people.ts | 16 ++++++------ src/services/nnid/routes/provider.ts | 12 ++++----- src/services/nnid/routes/support.ts | 4 +-- src/util.ts | 6 ++--- tsconfig.json | 8 ++++-- types/express.d.ts | 2 +- types/mongoose/device.d.ts | 2 +- types/mongoose/pnid.d.ts | 2 +- types/mongoose/server.d.ts | 2 +- 46 files changed, 129 insertions(+), 125 deletions(-) diff --git a/package.json b/package.json index a02b631..25f687b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "./dist/server.js", "scripts": { "lint": "./node_modules/.bin/eslint .", - "build": "npm run clean && tsc && npm run copy-static", + "build": "npm run clean && tsc && tsc-alias && npm run copy-static", "clean": "rm -rf ./dist", "copy-static": "npm run copy-assets && npm run copy-timezones", "copy-assets": "cp -r ./src/assets ./dist/assets", diff --git a/src/cache.ts b/src/cache.ts index 946209e..32a0e19 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -1,6 +1,6 @@ import fs from 'fs-extra'; import redis from 'redis'; -import { config, disabledFeatures } from './config-manager'; +import { config, disabledFeatures } from '@config-manager'; let client; diff --git a/src/config-manager.ts b/src/config-manager.ts index 15a79d5..9509604 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -2,7 +2,7 @@ import fs from 'fs-extra'; import get from 'lodash.get'; import set from 'lodash.set'; import dotenv from 'dotenv'; -import logger from './logger'; +import logger from '@logger'; dotenv.config(); diff --git a/src/database.ts b/src/database.ts index c5a47a9..5d6025a 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1,11 +1,11 @@ import mongoose from 'mongoose'; import bcrypt from 'bcrypt'; import joi from 'joi'; -import util from './util'; -import { PNID } from './models/pnid'; -import { Server } from './models/server'; -import logger from './logger'; -import { config } from './config-manager'; +import util from '@util'; +import { PNID } from '@models/pnid'; +import { Server } from '@models/server'; +import logger from '@logger'; +import { config } from '@config-manager'; const { connection_string, options } = config.mongoose; diff --git a/src/mailer.ts b/src/mailer.ts index 6d2a878..6acbb86 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import fs from 'node:fs'; import nodemailer from 'nodemailer'; -import { config, disabledFeatures } from './config-manager'; +import { config, disabledFeatures } from '@config-manager'; const genericEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8'); const confirmationEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8'); diff --git a/src/middleware/api.ts b/src/middleware/api.ts index b8a3b3e..3edfbfa 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -1,5 +1,5 @@ import xmlbuilder from 'xmlbuilder'; -import database from '../database'; +import database from '@database'; export async function APIMiddleware(request, _response, next) { const { headers } = request; diff --git a/src/middleware/device-certificate.ts b/src/middleware/device-certificate.ts index 70909d2..b78c0ec 100644 --- a/src/middleware/device-certificate.ts +++ b/src/middleware/device-certificate.ts @@ -1,4 +1,4 @@ -import NintendoCertificate from '../nintendo-certificate'; +import NintendoCertificate from '@nintendo-certificate'; export async function deviceCertificateMiddleware(request, _response, next) { const { headers } = request; diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index ece25bb..b6903fb 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -1,10 +1,10 @@ import crypto from 'node:crypto'; -import { Device } from '../models/device'; -import { NEXAccount } from '../models/nex-account'; -import util from '../util'; -import database from '../database'; -import NintendoCertificate from '../nintendo-certificate'; -import logger from '../logger'; +import { Device } from '@models/device'; +import { NEXAccount } from '@models/nex-account'; +import util from '@util'; +import database from '@database'; +import NintendoCertificate from '@nintendo-certificate'; +import logger from '@logger'; export async function NASCMiddleware(request, response, next) { const requestParams = request.body; @@ -50,7 +50,7 @@ export async function NASCMiddleware(request, response, next) { } const cert = new NintendoCertificate(fcdcert); - + if (!cert.valid) { return response.status(200).send(util.nascError('121')); } diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index 3cbc428..fbe89ab 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -1,5 +1,5 @@ import xmlbuilder from 'xmlbuilder'; -import database from '../database'; +import database from '@database'; export async function PNIDMiddleware(request, response, next) { const { headers } = request; diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 4adc913..6934d8d 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -5,8 +5,8 @@ import imagePixels from 'image-pixels'; import TGA from 'tga'; import got from 'got'; import Mii from 'mii-js'; -import { DeviceSchema } from './device'; -import util from '../util'; +import { DeviceSchema } from '@models/device'; +import util from '@util'; export const PNIDSchema = new Schema({ access_level: { diff --git a/src/server.ts b/src/server.ts index a373b69..3762318 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,24 +1,24 @@ process.title = 'Pretendo - Account'; -const configManager = require('./config-manager'); +const configManager = require('@config-manager'); configManager.configure(); import express from 'express'; import morgan from 'morgan'; -import xmlparser from './middleware/xml-parser'; -import cache from './cache'; -import database from './database'; -import util from './util'; -import logger from './logger'; +import xmlparser from '@middleware/xml-parser'; +import cache from '@cache'; +import database from '@database'; +import util from '@util'; +import logger from '@logger'; -import conntest from './services/conntest'; -import nnid from './services/nnid'; -import nasc from './services/nasc'; -import datastore from './services/datastore'; -import api from './services/api'; -import localcdn from './services/local-cdn'; -import assets from './services/assets'; +import conntest from '@services/conntest'; +import nnid from '@services/nnid'; +import nasc from '@services/nasc'; +import datastore from '@services/datastore'; +import api from '@services/api'; +import localcdn from '@services/local-cdn'; +import assets from '@services/assets'; const { config } = configManager; diff --git a/src/services/api/index.ts b/src/services/api/index.ts index 56d7551..3f79071 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -3,9 +3,9 @@ import express from 'express'; import subdomain from 'express-subdomain'; import cors from 'cors'; -import APIMiddleware from '../../middleware/api'; -import routes from './routes'; -import logger from '../../logger'; +import APIMiddleware from '@middleware/api'; +import routes from '@services/api/routes'; +import logger from '@logger'; // Router to handle the subdomain restriction const api = express.Router(); diff --git a/src/services/api/routes/index.ts b/src/services/api/routes/index.ts index 9956240..4b0f452 100644 --- a/src/services/api/routes/index.ts +++ b/src/services/api/routes/index.ts @@ -1,10 +1,10 @@ -import connections_v1 from './v1/connections'; -import email_v1 from './v1/email'; -import forgotPassword_v1 from './v1/forgotPassword'; -import login_v1 from './v1/login'; -import register_v1 from './v1/register'; -import resetPassword_v1 from './v1/resetPassword'; -import user_v1 from './v1/user'; +import connections_v1 from '@services/api/routes/v1/connections'; +import email_v1 from '@services/api/routes/v1/email'; +import forgotPassword_v1 from '@services/api/routes/v1/forgotPassword'; +import login_v1 from '@services/api/routes/v1/login'; +import register_v1 from '@services/api/routes/v1/register'; +import resetPassword_v1 from '@services/api/routes/v1/resetPassword'; +import user_v1 from '@services/api/routes/v1/user'; export default { V1: { diff --git a/src/services/api/routes/v1/connections.ts b/src/services/api/routes/v1/connections.ts index 58aea18..a15924e 100644 --- a/src/services/api/routes/v1/connections.ts +++ b/src/services/api/routes/v1/connections.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import database from '../../../../database'; +import database from '@database'; const router = Router(); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index 22e38c6..7c33101 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import moment from 'moment'; -import { PNID } from '../../../../models/pnid'; -import util from '../../../../util'; +import { PNID } from '@models/pnid'; +import util from '@util'; const router = Router(); diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index 3a46580..9634663 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import validator from 'validator'; -import database from '../../../../database'; -import util from '../../../../util'; +import database from '@database'; +import util from '@util'; const router = Router(); diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index 7b63207..c925030 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -1,9 +1,9 @@ import { Router } from 'express'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import database from '../../../../database'; -import cache from '../../../../cache'; -import util from '../../../../util'; +import database from '@database'; +import cache from '@cache'; +import util from '@util'; const router = Router(); diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 8047a2c..017092f 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -7,13 +7,13 @@ import fs from 'fs-extra'; import moment from 'moment'; import hcaptcha from 'hcaptcha'; import Mii from 'mii-js'; -import database from '../../../../database'; -import cache from '../../../../cache'; -import util from '../../../../util'; -import logger from '../../../../logger'; -import { PNID } from '../../../../models/pnid'; -import { NEXAccount } from '../../../../models/nex-account'; -import { config, disabledFeatures } from '../../../../config-manager'; +import database from '@database'; +import cache from '@cache'; +import util from '@util'; +import logger from '@logger'; +import { PNID } from '@models/pnid'; +import { NEXAccount } from '@models/nex-account'; +import { config, disabledFeatures } from '@config-manager'; const router = Router(); diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index e805e8d..8642439 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import bcrypt from 'bcrypt'; -import { PNID } from '../../../../models/pnid'; -import util from '../../../../util'; +import { PNID } from '@models/pnid'; +import util from '@util'; const router = Router(); diff --git a/src/services/api/routes/v1/user.ts b/src/services/api/routes/v1/user.ts index 6f7a299..6e5d4fa 100644 --- a/src/services/api/routes/v1/user.ts +++ b/src/services/api/routes/v1/user.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import joi from 'joi'; -import { PNID } from '../../../../models/pnid'; -import { config } from '../../../../config-manager'; +import { PNID } from '@models/pnid'; +import { config } from '@config-manager'; const router = Router(); diff --git a/src/services/assets/index.ts b/src/services/assets/index.ts index b73a632..d00a3f7 100644 --- a/src/services/assets/index.ts +++ b/src/services/assets/index.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import express from 'express'; import subdomain from 'express-subdomain'; -import logger from '../../logger'; +import logger from '@logger'; // Router to handle the subdomain restriction const assets = express.Router(); diff --git a/src/services/conntest/index.ts b/src/services/conntest/index.ts index 1601858..73b8545 100644 --- a/src/services/conntest/index.ts +++ b/src/services/conntest/index.ts @@ -2,7 +2,7 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import logger from '../../logger'; +import logger from '@logger'; // Router to handle the subdomain restriction const conntest = express.Router(); diff --git a/src/services/datastore/index.ts b/src/services/datastore/index.ts index 7b670ea..c493f1d 100644 --- a/src/services/datastore/index.ts +++ b/src/services/datastore/index.ts @@ -1,7 +1,7 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import routes from './routes'; -import logger from '../../logger'; +import routes from '@services/datastore/routes'; +import logger from '@logger'; // Router to handle the subdomain const datastore = express.Router(); diff --git a/src/services/datastore/routes/index.ts b/src/services/datastore/routes/index.ts index 7e54748..de121ba 100644 --- a/src/services/datastore/routes/index.ts +++ b/src/services/datastore/routes/index.ts @@ -1,4 +1,4 @@ -import upload from './upload'; +import upload from '@services/datastore/routes/upload'; export default { UPLOAD: upload diff --git a/src/services/datastore/routes/upload.ts b/src/services/datastore/routes/upload.ts index 595ce5d..118b7e5 100644 --- a/src/services/datastore/routes/upload.ts +++ b/src/services/datastore/routes/upload.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import crypto from 'node:crypto'; import { Router } from 'express'; import Dicer from 'dicer'; -import util from '../../../util'; +import util from '@util'; const router = Router(); diff --git a/src/services/local-cdn/index.ts b/src/services/local-cdn/index.ts index bf57e63..507924a 100644 --- a/src/services/local-cdn/index.ts +++ b/src/services/local-cdn/index.ts @@ -1,8 +1,8 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import routes from './routes'; -import { config, disabledFeatures } from '../../config-manager'; -import logger from '../../logger'; +import routes from '@services/local-cdn/routes'; +import { config, disabledFeatures } from '@config-manager'; +import logger from '@logger'; const router = express.Router(); diff --git a/src/services/local-cdn/routes/get.ts b/src/services/local-cdn/routes/get.ts index 6dc45c7..fd70a25 100644 --- a/src/services/local-cdn/routes/get.ts +++ b/src/services/local-cdn/routes/get.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import cache from '../../../cache'; +import cache from '@cache'; const router = Router(); diff --git a/src/services/local-cdn/routes/index.ts b/src/services/local-cdn/routes/index.ts index d6b426e..8f02619 100644 --- a/src/services/local-cdn/routes/index.ts +++ b/src/services/local-cdn/routes/index.ts @@ -1,4 +1,4 @@ -import get from './get'; +import get from '@services/local-cdn/routes/get'; export default { GET: get, diff --git a/src/services/nasc/index.ts b/src/services/nasc/index.ts index 0b80c92..5ddf5e9 100644 --- a/src/services/nasc/index.ts +++ b/src/services/nasc/index.ts @@ -2,9 +2,9 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import NASCMiddleware from '../../middleware/nasc'; -import routes from './routes'; -import logger from '../../logger'; +import NASCMiddleware from '@middleware/nasc'; +import routes from '@services/nasc/routes'; +import logger from '@logger'; // Router to handle the subdomain restriction const nasc = express.Router(); diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index d19c6c8..1351dfd 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -1,8 +1,8 @@ import express from 'express'; import fs from 'fs-extra'; -import util from '../../../util'; -import database from '../../../database'; -import cache from '../../../cache'; +import util from '@util'; +import database from '@database'; +import cache from '@cache'; const router = express.Router(); diff --git a/src/services/nasc/routes/index.ts b/src/services/nasc/routes/index.ts index 0399fd3..1f3ab33 100644 --- a/src/services/nasc/routes/index.ts +++ b/src/services/nasc/routes/index.ts @@ -1,4 +1,4 @@ -import ac from './ac'; +import ac from '@services/nasc/routes/ac'; export default { AC: ac diff --git a/src/services/nnid/index.ts b/src/services/nnid/index.ts index b0f8321..0f24f01 100644 --- a/src/services/nnid/index.ts +++ b/src/services/nnid/index.ts @@ -2,11 +2,11 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import clientHeaderCheck from '../../middleware/client-header'; -import cemuMiddleware from '../../middleware/cemu'; -import pnidMiddleware from '../../middleware/pnid'; -import routes from './routes'; -import logger from '../../logger'; +import clientHeaderCheck from '@middleware/client-header'; +import cemuMiddleware from '@middleware/cemu'; +import pnidMiddleware from '@middleware/pnid'; +import routes from '@services/nnid/routes'; +import logger from '@logger'; // Router to handle the subdomain restriction const nnid = express.Router(); diff --git a/src/services/nnid/routes/admin.ts b/src/services/nnid/routes/admin.ts index b28f243..2c92dbb 100644 --- a/src/services/nnid/routes/admin.ts +++ b/src/services/nnid/routes/admin.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; -import { PNID } from '../../../models/pnid'; +import { PNID } from '@models/pnid'; const router = Router(); diff --git a/src/services/nnid/routes/content.ts b/src/services/nnid/routes/content.ts index 16a0c69..9a31d61 100644 --- a/src/services/nnid/routes/content.ts +++ b/src/services/nnid/routes/content.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; -import timezones from '../timezones.json'; +import timezones from '@services/nnid/timezones.json'; const router = Router(); diff --git a/src/services/nnid/routes/index.ts b/src/services/nnid/routes/index.ts index 67e2938..4fb9855 100644 --- a/src/services/nnid/routes/index.ts +++ b/src/services/nnid/routes/index.ts @@ -1,11 +1,11 @@ -import admin from './admin'; -import content from './content'; -import devices from './devices'; -import miis from './miis'; -import oauth from './oauth'; -import people from './people'; -import provider from './provider'; -import support from './support'; +import admin from '@services/nnid/routes/admin'; +import content from '@services/nnid/routes/content'; +import devices from '@services/nnid/routes/devices'; +import miis from '@services/nnid/routes/miis'; +import oauth from '@services/nnid/routes/oauth'; +import people from '@services/nnid/routes/people'; +import provider from '@services/nnid/routes/provider'; +import support from '@services/nnid/routes/support'; export default { ADMIN: admin, diff --git a/src/services/nnid/routes/miis.ts b/src/services/nnid/routes/miis.ts index 62e60df..502bc16 100644 --- a/src/services/nnid/routes/miis.ts +++ b/src/services/nnid/routes/miis.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; -import { PNID } from '../../../models/pnid'; -import { config } from '../../../config-manager'; +import { PNID } from '@models/pnid'; +import { config } from '@config-manager'; const router = Router(); diff --git a/src/services/nnid/routes/oauth.ts b/src/services/nnid/routes/oauth.ts index 751a3b4..b3db6a2 100644 --- a/src/services/nnid/routes/oauth.ts +++ b/src/services/nnid/routes/oauth.ts @@ -2,8 +2,8 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import database from '../../../database'; -import util from '../../../util'; +import database from '@database'; +import util from '@util'; const router = Router(); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 6c22374..9f0ca9f 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -3,14 +3,14 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import moment from 'moment'; -import deviceCertificateMiddleware from '../../../middleware/device-certificate'; -import ratelimit from '../../../middleware/ratelimit'; -import database from '../../../database'; -import util from '../../../util'; -import { PNID } from '../../../models/pnid'; -import { NEXAccount } from '../../../models/nex-account'; -import logger from '../../../logger'; -import timezones from '../timezones.json'; +import deviceCertificateMiddleware from '@middleware/device-certificate'; +import ratelimit from '@middleware/ratelimit'; +import database from '@database'; +import util from '@util'; +import { PNID } from '@models/pnid'; +import { NEXAccount } from '@models/nex-account'; +import logger from '@logger'; +import timezones from '@services/nnid/timezones.json'; const router = Router(); diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index a15de46..9fba2bb 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -1,10 +1,10 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import fs from 'fs-extra'; -import database from '../../../database'; -import util from '../../../util'; -import cache from '../../../cache'; -import { NEXAccount } from '../../../models/nex-account'; +import database from '@database'; +import util from '@util'; +import cache from '@cache'; +import { NEXAccount } from '@models/nex-account'; const router = Router(); @@ -33,7 +33,7 @@ router.get('/service_token/@me', async (request, response) => { const { service_name, service_type, device } = server; - const cryptoPath = `${__dirname}/../../../../certs/${service_type}/${service_name}`; + const cryptoPath = `${__dirname}/@../certs/${service_type}/${service_name}`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -114,7 +114,7 @@ router.get('/nex_token/@me', async (request, response) => { const { service_name, service_type, ip, port, device } = server; const titleId = request.headers['x-nintendo-title-id'] as string; - const cryptoPath = `${__dirname}/../../../../certs/${service_type}/${service_name}`; + const cryptoPath = `${__dirname}/@../certs/${service_type}/${service_name}`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index f44d033..4c1bb1f 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -2,8 +2,8 @@ import dns from 'node:dns'; import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import moment from 'moment'; -import database from '../../../database'; -import util from '../../../util'; +import database from '@database'; +import util from '@util'; const router = Router(); diff --git a/src/util.ts b/src/util.ts index 3494f67..fd36a02 100644 --- a/src/util.ts +++ b/src/util.ts @@ -3,9 +3,9 @@ const path = require('path'); const NodeRSA = require('node-rsa'); const aws = require('aws-sdk'); const fs = require('fs-extra'); -const mailer = require('./mailer'); -const cache = require('./cache'); -const { config, disabledFeatures } = require('./config-manager'); +const mailer = require('@mailer'); +const cache = require('@cache'); +const { config, disabledFeatures } = require('@config-manager'); let s3; diff --git a/tsconfig.json b/tsconfig.json index 9d94299..a3d9165 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,10 +4,14 @@ "module": "commonjs", "esModuleInterop": true, "moduleResolution": "node", - "outDir": "./dist", + "baseUrl": "src", + "outDir": "dist", "allowJs": true, "target": "es2022", - "noEmitOnError": true + "noEmitOnError": true, + "paths": { + "@*": ["./*"] + } }, "include": ["src", "types"] } \ No newline at end of file diff --git a/types/express.d.ts b/types/express.d.ts index 1dbe78b..e5f87dd 100644 --- a/types/express.d.ts +++ b/types/express.d.ts @@ -1,5 +1,5 @@ import { HydratedDocument } from 'mongoose'; -import NintendoCertificate from '../src/nintendo-certificate' +import NintendoCertificate from '@nintendo-certificate'; declare global { namespace Express { diff --git a/types/mongoose/device.d.ts b/types/mongoose/device.d.ts index 786953b..90b723d 100644 --- a/types/mongoose/device.d.ts +++ b/types/mongoose/device.d.ts @@ -1,5 +1,5 @@ import { Model } from 'mongoose'; -import { DeviceAttributeSchema } from '../../src/models/device'; +import { DeviceAttributeSchema } from '@models/device'; type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan'; type ACCESS_LEVEL = 0 | 1 | 2 | 3; diff --git a/types/mongoose/pnid.d.ts b/types/mongoose/pnid.d.ts index e0bea47..b7f9441 100644 --- a/types/mongoose/pnid.d.ts +++ b/types/mongoose/pnid.d.ts @@ -1,5 +1,5 @@ import { Model } from 'mongoose'; -import { DeviceSchema } from '../../src/models/device'; +import { DeviceSchema } from '@models/device'; declare global { interface IPNID { diff --git a/types/mongoose/server.d.ts b/types/mongoose/server.d.ts index 6261929..11cfb4e 100644 --- a/types/mongoose/server.d.ts +++ b/types/mongoose/server.d.ts @@ -1,4 +1,4 @@ -import { Document, Model } from 'mongoose'; +import { Model } from 'mongoose'; declare global { interface IServer { From a836f67b47cdf1d1afe8524d69a8c32f4be89a29 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 10:03:06 -0500 Subject: [PATCH 19/65] Bump mongoose to 7 and use mongoose-unique-validator fork --- package-lock.json | 209 ++++++++++++++++++++++++---------------------- package.json | 2 +- 2 files changed, 111 insertions(+), 100 deletions(-) diff --git a/package-lock.json b/package-lock.json index c670965..6e0a7ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "mii-js": "github:PretendoNetwork/mii-js", "moment": "^2.29.4", "mongoose": "^7.0.0", - "mongoose-unique-validator": "^2.0.3", + "mongoose-unique-validator": "github:stenneepro/mongoose-unique-validator#bump/mongoose7", "morgan": "^1.9.1", "nodemailer": "^6.4.2", "redis": "^4.3.1", @@ -410,9 +410,9 @@ } }, "node_modules/@types/node": { - "version": "18.14.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.4.tgz", - "integrity": "sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==" + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -664,9 +664,9 @@ } }, "node_modules/aws-sdk": { - "version": "2.1325.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1325.0.tgz", - "integrity": "sha512-ztg9HG5aoUHTprY+/eqjqb25E4joCgz+8ToxsP4OSKFQCtaBcF6my03j4e/J2j3fmpPifJnZSPMu4kV7DBj8WA==", + "version": "2.1328.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1328.0.tgz", + "integrity": "sha512-ud8ieE+hGX/cWHkQ9kMxQw6w+onbv71PDrcPmP2j8cmYv5IPlM5Zh8/tpsmXApLYDmQMuZ3TtssiB1KmoSbzgA==", "dependencies": { "buffer": "4.9.2", "events": "1.1.1", @@ -2311,6 +2311,11 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "node_modules/lodash.set": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", @@ -2564,37 +2569,6 @@ "whatwg-url": "^11.0.0" } }, - "node_modules/mongodb-connection-string-url/node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "engines": { - "node": ">=12" - } - }, - "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/mongoose": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.0.0.tgz", @@ -2617,15 +2591,16 @@ } }, "node_modules/mongoose-unique-validator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mongoose-unique-validator/-/mongoose-unique-validator-2.0.3.tgz", - "integrity": "sha512-3/8pmvAC1acBZS6eWKAWQUiZBlARE1wyWtjga4iQ2wDJeOfRlIKmAvTNHSZXKaAf7RCRUd7wh7as6yWAOrjpQg==", + "version": "3.1.0", + "resolved": "git+ssh://git@github.com/stenneepro/mongoose-unique-validator.git#1cd976b70ddd8e8e65fed1d9a387677713a8d177", + "license": "MIT", "dependencies": { "lodash.foreach": "^4.1.0", - "lodash.get": "^4.0.2" + "lodash.get": "^4.0.2", + "lodash.merge": "^4.6.2" }, "peerDependencies": { - "mongoose": "^5.2.1" + "mongoose": "^7.0.0" } }, "node_modules/mongoose/node_modules/ms": { @@ -2747,6 +2722,25 @@ } } }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-rsa": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", @@ -3667,9 +3661,15 @@ } }, "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } }, "node_modules/tunnel-agent": { "version": "0.6.0", @@ -3826,17 +3826,23 @@ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" }, "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } }, "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/which-typed-array": { @@ -4279,9 +4285,9 @@ } }, "@types/node": { - "version": "18.14.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.4.tgz", - "integrity": "sha512-VhCw7I7qO2X49+jaKcAUwi3rR+hbxT5VcYF493+Z5kMLI0DL568b7JI4IDJaxWFH0D/xwmGJNoXisyX+w7GH/g==" + "version": "18.14.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", + "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" }, "@types/qs": { "version": "6.9.7", @@ -4489,9 +4495,9 @@ "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" }, "aws-sdk": { - "version": "2.1325.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1325.0.tgz", - "integrity": "sha512-ztg9HG5aoUHTprY+/eqjqb25E4joCgz+8ToxsP4OSKFQCtaBcF6my03j4e/J2j3fmpPifJnZSPMu4kV7DBj8WA==", + "version": "2.1328.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1328.0.tgz", + "integrity": "sha512-ud8ieE+hGX/cWHkQ9kMxQw6w+onbv71PDrcPmP2j8cmYv5IPlM5Zh8/tpsmXApLYDmQMuZ3TtssiB1KmoSbzgA==", "requires": { "buffer": "4.9.2", "events": "1.1.1", @@ -5797,6 +5803,11 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" + }, "lodash.set": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", @@ -5969,30 +5980,6 @@ "requires": { "@types/whatwg-url": "^8.2.1", "whatwg-url": "^11.0.0" - }, - "dependencies": { - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "requires": { - "punycode": "^2.1.1" - } - }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" - }, - "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - } - } } }, "mongoose": { @@ -6017,12 +6004,12 @@ } }, "mongoose-unique-validator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/mongoose-unique-validator/-/mongoose-unique-validator-2.0.3.tgz", - "integrity": "sha512-3/8pmvAC1acBZS6eWKAWQUiZBlARE1wyWtjga4iQ2wDJeOfRlIKmAvTNHSZXKaAf7RCRUd7wh7as6yWAOrjpQg==", + "version": "git+ssh://git@github.com/stenneepro/mongoose-unique-validator.git#1cd976b70ddd8e8e65fed1d9a387677713a8d177", + "from": "mongoose-unique-validator@https://github.com/stenneepro/mongoose-unique-validator.git#bump/mongoose7", "requires": { "lodash.foreach": "^4.1.0", - "lodash.get": "^4.0.2" + "lodash.get": "^4.0.2", + "lodash.merge": "^4.6.2" } }, "morgan": { @@ -6107,6 +6094,27 @@ "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "requires": { "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } } }, "node-rsa": { @@ -6842,9 +6850,12 @@ } }, "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } }, "tunnel-agent": { "version": "0.6.0", @@ -6975,17 +6986,17 @@ } }, "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" }, "whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } }, "which-typed-array": { diff --git a/package.json b/package.json index 25f687b..b03b646 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "mii-js": "github:PretendoNetwork/mii-js", "moment": "^2.29.4", "mongoose": "^7.0.0", - "mongoose-unique-validator": "^2.0.3", + "mongoose-unique-validator": "github:stenneepro/mongoose-unique-validator#bump/mongoose7", "morgan": "^1.9.1", "nodemailer": "^6.4.2", "redis": "^4.3.1", From 706435ed7af7dbbe76586112f1c22e5d1779a489 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 10:41:27 -0500 Subject: [PATCH 20/65] Fixed cryptoPath checks in provider NNID endpoint --- src/services/nnid/routes/provider.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 9fba2bb..64ac262 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -31,9 +31,9 @@ router.get('/service_token/@me', async (request, response) => { }).end()); } - const { service_name, service_type, device } = server; + const { service_name, device } = server; - const cryptoPath = `${__dirname}/@../certs/${service_type}/${service_name}`; + const cryptoPath = `${__dirname}/../../../../certs/service/${service_name}`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -111,10 +111,10 @@ router.get('/nex_token/@me', async (request, response) => { }).end()); } - const { service_name, service_type, ip, port, device } = server; + const { service_name, ip, port, device } = server; const titleId = request.headers['x-nintendo-title-id'] as string; - const cryptoPath = `${__dirname}/@../certs/${service_type}/${service_name}`; + const cryptoPath = `${__dirname}/../../../../certs/nex/${service_name}`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys From c73b820342ac310e0b62f628ab9095211ac98342 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 10:42:13 -0500 Subject: [PATCH 21/65] Removed PNID.deleteOne from deletion endpoint. Does not actually delete a NNID --- src/services/nnid/routes/people.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 9f0ca9f..f00a66f 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -370,8 +370,6 @@ router.put('/@me/deletion', async (request, response) => { }).end()); } - await PNID.deleteOne({ pid: pnid.get('pid') }); - response.send(''); }); From 6f570f6c2bf51de1124db4743be32021e03f8d49 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 11:29:48 -0500 Subject: [PATCH 22/65] Disable id virtual getter on mongoose documents --- src/models/pnid.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 6934d8d..988e428 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -102,7 +102,7 @@ export const PNIDSchema = new Schema({ id: String } } -}); +}, { id: false }); PNIDSchema.plugin(uniqueValidator, {message: '{PATH} already in use.'}); From 66f6dfc5df21a7600dd6e1d8b3d6cc9b00781554 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 12:41:53 -0500 Subject: [PATCH 23/65] Return DB connection from function --- src/database.ts | 12 ++++++++---- src/middleware/nasc.ts | 2 +- src/services/api/routes/v1/register.ts | 2 +- src/services/nnid/routes/people.ts | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/database.ts b/src/database.ts index 5d6025a..13fa7be 100644 --- a/src/database.ts +++ b/src/database.ts @@ -14,17 +14,21 @@ const discordConnectionSchema = joi.object({ id: joi.string() }); -let connection; +let _connection; export async function connect() { await mongoose.connect(connection_string, options); - connection = mongoose.connection; - connection.on('error', console.error.bind(console, 'connection error:')); + _connection = mongoose.connection; + _connection.on('error', console.error.bind(console, 'connection error:')); +} + +export function connection() { + return _connection; } function verifyConnected() { - if (!connection) { + if (!connection()) { throw new Error('Cannot make database requets without being connected'); } } diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index b6903fb..778dbdd 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -111,7 +111,7 @@ export async function NASCMiddleware(request, response, next) { if (password && !pid && !pidHmac) { // Register new user - const session = await database.connection.startSession(); + const session = await database.connection().startSession(); await session.startTransaction(); try { diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 017092f..50d291c 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -229,7 +229,7 @@ router.post('/', async (request, response) => { let pnid; let nexAccount; - const session = await database.connection.startSession(); + const session = await database.connection().startSession(); await session.startTransaction(); try { diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index f00a66f..440852a 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -81,7 +81,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons let pnid; let nexAccount; - const session = await database.connection.startSession(); + const session = await database.connection().startSession(); await session.startTransaction(); try { From ffc4e783a8f197b88d703d96b5c90662746e77cd Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 15:48:08 -0500 Subject: [PATCH 24/65] Removed unused variables from NASC --- src/services/nasc/routes/ac.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 1351dfd..5308627 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -1,5 +1,4 @@ import express from 'express'; -import fs from 'fs-extra'; import util from '@util'; import database from '@database'; import cache from '@cache'; @@ -29,7 +28,7 @@ router.post('/', async (request, response) => { }); /** - * + * * @param {express.Request} request */ async function processLoginRequest(request) { @@ -53,8 +52,6 @@ async function processLoginRequest(request) { const { service_name, ip, port } = server; - const cryptoPath = `${__dirname}/../../../../certs/nex/${service_name}`; - const publicKey = await cache.getNEXPublicKey(service_name); const secretKey = await cache.getNEXSecretKey(service_name); From 498d3838a342f9afaa8e41efebe8e03ecdcc1c7a Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 15:51:28 -0500 Subject: [PATCH 25/65] Added nexUser to express.Request type --- src/middleware/nasc.ts | 3 ++- types/express.d.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 778dbdd..53252a8 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -1,4 +1,5 @@ import crypto from 'node:crypto'; +import { HydratedDocument } from 'mongoose'; import { Device } from '@models/device'; import { NEXAccount } from '@models/nex-account'; import util from '@util'; @@ -161,7 +162,7 @@ export async function NASCMiddleware(request, response, next) { } } - const nexUser = await NEXAccount.findOne({ pid }); + const nexUser = await NEXAccount.findOne({ pid }) as HydratedDocument; if (!nexUser || nexUser.get('access_level') < 0) { return response.status(200).send(util.nascError('102')); diff --git a/types/express.d.ts b/types/express.d.ts index e5f87dd..1e3c92a 100644 --- a/types/express.d.ts +++ b/types/express.d.ts @@ -5,6 +5,7 @@ declare global { namespace Express { interface Request { pnid?: HydratedDocument; + nexUser?: HydratedDocument; isCemu?: boolean; files?: Record; certificate?: NintendoCertificate; From 55c9bff86245f10f27454dc9af0e4701a96b211a Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 16:01:01 -0500 Subject: [PATCH 26/65] Replaced jsdoc with TS types --- src/services/nasc/routes/ac.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 5308627..0545682 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -27,11 +27,7 @@ router.post('/', async (request, response) => { response.status(200).send(responseData.toString()); }); -/** - * - * @param {express.Request} request - */ -async function processLoginRequest(request) { +async function processLoginRequest(request: express.Request) { const requestParams = request.body; const titleID = util.nintendoBase64Decode(requestParams.titleid).toString(); const { nexUser } = request; @@ -83,11 +79,7 @@ async function processLoginRequest(request) { return params; } -/** - * - * @param {express.Request} request - */ -async function processServiceTokenRequest(request) { +async function processServiceTokenRequest(request: express.Request) { const params = new URLSearchParams({ retry: util.nintendoBase64Encode('0'), returncd: util.nintendoBase64Encode('007'), From e438253d3b775257044a3c2d04e5ba77c489fb17 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 20:25:01 -0500 Subject: [PATCH 27/65] Moved types folder into src and changed alias root to @/ --- src/cache.ts | 2 +- src/config-manager.ts | 2 +- src/database.ts | 11 +-- src/mailer.ts | 2 +- src/middleware/api.ts | 2 +- src/middleware/device-certificate.ts | 2 +- src/middleware/nasc.ts | 13 ++-- src/middleware/pnid.ts | 2 +- src/models/device.ts | 2 + src/models/nex-account.ts | 1 + src/models/pnid.ts | 5 +- src/models/server.ts | 1 + src/server.ts | 24 +++--- src/services/api/index.ts | 6 +- src/services/api/routes/index.ts | 14 ++-- src/services/api/routes/v1/connections.ts | 2 +- src/services/api/routes/v1/email.ts | 4 +- src/services/api/routes/v1/forgotPassword.ts | 4 +- src/services/api/routes/v1/login.ts | 6 +- src/services/api/routes/v1/register.ts | 14 ++-- src/services/api/routes/v1/resetPassword.ts | 4 +- src/services/api/routes/v1/user.ts | 4 +- src/services/assets/index.ts | 2 +- src/services/conntest/index.ts | 2 +- src/services/datastore/index.ts | 4 +- src/services/datastore/routes/index.ts | 2 +- src/services/datastore/routes/upload.ts | 2 +- src/services/local-cdn/index.ts | 6 +- src/services/local-cdn/routes/get.ts | 2 +- src/services/local-cdn/routes/index.ts | 2 +- src/services/nasc/index.ts | 6 +- src/services/nasc/routes/ac.ts | 6 +- src/services/nasc/routes/index.ts | 2 +- src/services/nnid/index.ts | 10 +-- src/services/nnid/routes/admin.ts | 2 +- src/services/nnid/routes/content.ts | 2 +- src/services/nnid/routes/index.ts | 16 ++-- src/services/nnid/routes/miis.ts | 4 +- src/services/nnid/routes/oauth.ts | 4 +- src/services/nnid/routes/people.ts | 16 ++-- src/services/nnid/routes/provider.ts | 8 +- src/services/nnid/routes/support.ts | 4 +- {types => src/types}/express.d.ts | 4 +- src/types/mongoose/device-attribute.ts | 11 +++ src/types/mongoose/device.ts | 30 ++++++++ src/types/mongoose/nex-account.ts | 20 +++++ src/types/mongoose/pnid.ts | 76 +++++++++++++++++++ src/types/mongoose/server.ts | 17 +++++ src/util.ts | 15 ++-- tsconfig.json | 4 +- types/mongoose/device-attribute.d.ts | 13 ---- types/mongoose/device.d.ts | 32 -------- types/mongoose/nex-account.d.ts | 22 ------ types/mongoose/pnid.d.ts | 78 -------------------- types/mongoose/server.d.ts | 19 ----- 55 files changed, 284 insertions(+), 286 deletions(-) rename {types => src/types}/express.d.ts (61%) create mode 100644 src/types/mongoose/device-attribute.ts create mode 100644 src/types/mongoose/device.ts create mode 100644 src/types/mongoose/nex-account.ts create mode 100644 src/types/mongoose/pnid.ts create mode 100644 src/types/mongoose/server.ts delete mode 100644 types/mongoose/device-attribute.d.ts delete mode 100644 types/mongoose/device.d.ts delete mode 100644 types/mongoose/nex-account.d.ts delete mode 100644 types/mongoose/pnid.d.ts delete mode 100644 types/mongoose/server.d.ts diff --git a/src/cache.ts b/src/cache.ts index 32a0e19..5049b67 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -1,6 +1,6 @@ import fs from 'fs-extra'; import redis from 'redis'; -import { config, disabledFeatures } from '@config-manager'; +import { config, disabledFeatures } from '@/config-manager'; let client; diff --git a/src/config-manager.ts b/src/config-manager.ts index 9509604..37bc0c2 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -2,7 +2,7 @@ import fs from 'fs-extra'; import get from 'lodash.get'; import set from 'lodash.set'; import dotenv from 'dotenv'; -import logger from '@logger'; +import logger from '@/logger'; dotenv.config(); diff --git a/src/database.ts b/src/database.ts index 13fa7be..dc3a31b 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1,11 +1,12 @@ import mongoose from 'mongoose'; import bcrypt from 'bcrypt'; import joi from 'joi'; -import util from '@util'; -import { PNID } from '@models/pnid'; -import { Server } from '@models/server'; -import logger from '@logger'; -import { config } from '@config-manager'; +import util from '@/util'; +import { PNID } from '@/models/pnid'; +import { Server } from '@/models/server'; +import logger from '@/logger'; +import { config } from '@/config-manager'; +import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; const { connection_string, options } = config.mongoose; diff --git a/src/mailer.ts b/src/mailer.ts index 6acbb86..c39d039 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -1,7 +1,7 @@ import path from 'node:path'; import fs from 'node:fs'; import nodemailer from 'nodemailer'; -import { config, disabledFeatures } from '@config-manager'; +import { config, disabledFeatures } from '@/config-manager'; const genericEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8'); const confirmationEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8'); diff --git a/src/middleware/api.ts b/src/middleware/api.ts index 3edfbfa..cbf942d 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -1,5 +1,5 @@ import xmlbuilder from 'xmlbuilder'; -import database from '@database'; +import database from '@/database'; export async function APIMiddleware(request, _response, next) { const { headers } = request; diff --git a/src/middleware/device-certificate.ts b/src/middleware/device-certificate.ts index b78c0ec..dc4dcfa 100644 --- a/src/middleware/device-certificate.ts +++ b/src/middleware/device-certificate.ts @@ -1,4 +1,4 @@ -import NintendoCertificate from '@nintendo-certificate'; +import NintendoCertificate from '@/nintendo-certificate'; export async function deviceCertificateMiddleware(request, _response, next) { const { headers } = request; diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 53252a8..b718024 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -1,11 +1,12 @@ import crypto from 'node:crypto'; import { HydratedDocument } from 'mongoose'; -import { Device } from '@models/device'; -import { NEXAccount } from '@models/nex-account'; -import util from '@util'; -import database from '@database'; -import NintendoCertificate from '@nintendo-certificate'; -import logger from '@logger'; +import { Device } from '@/models/device'; +import { NEXAccount } from '@/models/nex-account'; +import util from '@/util'; +import database from '@/database'; +import NintendoCertificate from '@/nintendo-certificate'; +import logger from '@/logger'; +import { INEXAccount, INEXAccountMethods } from '@/types/mongoose/nex-account'; export async function NASCMiddleware(request, response, next) { const requestParams = request.body; diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index fbe89ab..604b7de 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -1,5 +1,5 @@ import xmlbuilder from 'xmlbuilder'; -import database from '@database'; +import database from '@/database'; export async function PNIDMiddleware(request, response, next) { const { headers } = request; diff --git a/src/models/device.ts b/src/models/device.ts index 22ac5c1..d23c120 100644 --- a/src/models/device.ts +++ b/src/models/device.ts @@ -1,4 +1,6 @@ import { Schema, model } from 'mongoose'; +import { IDeviceAttribute, IDeviceAttributeMethods, DeviceAttributeModel } from '@/types/mongoose/device-attribute'; +import { IDevice, IDeviceMethods, DeviceModel } from '@/types/mongoose/device'; export const DeviceAttributeSchema = new Schema({ created_date: String, diff --git a/src/models/nex-account.ts b/src/models/nex-account.ts index cfbc818..2683a4f 100644 --- a/src/models/nex-account.ts +++ b/src/models/nex-account.ts @@ -1,5 +1,6 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; +import { INEXAccount, INEXAccountMethods, NEXAccountModel } from '@/types/mongoose/nex-account'; export const NEXAccountSchema = new Schema({ device_type: { diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 988e428..3ccdd2d 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -5,8 +5,9 @@ import imagePixels from 'image-pixels'; import TGA from 'tga'; import got from 'got'; import Mii from 'mii-js'; -import { DeviceSchema } from '@models/device'; -import util from '@util'; +import { DeviceSchema } from '@/models/device'; +import util from '@/util'; +import { IPNID, IPNIDMethods, PNIDModel } from '@/types/mongoose/pnid'; export const PNIDSchema = new Schema({ access_level: { diff --git a/src/models/server.ts b/src/models/server.ts index b23dbe6..229142c 100644 --- a/src/models/server.ts +++ b/src/models/server.ts @@ -1,5 +1,6 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; +import { IServer, IServerMethods, ServerModel } from '@/types/mongoose/server'; export const ServerSchema = new Schema({ ip: String, // Example: 1.1.1.1 diff --git a/src/server.ts b/src/server.ts index 3762318..3869de0 100644 --- a/src/server.ts +++ b/src/server.ts @@ -6,19 +6,19 @@ configManager.configure(); import express from 'express'; import morgan from 'morgan'; -import xmlparser from '@middleware/xml-parser'; -import cache from '@cache'; -import database from '@database'; -import util from '@util'; -import logger from '@logger'; +import xmlparser from '@/middleware/xml-parser'; +import cache from '@/cache'; +import database from '@/database'; +import util from '@/util'; +import logger from '@/logger'; -import conntest from '@services/conntest'; -import nnid from '@services/nnid'; -import nasc from '@services/nasc'; -import datastore from '@services/datastore'; -import api from '@services/api'; -import localcdn from '@services/local-cdn'; -import assets from '@services/assets'; +import conntest from '@/services/conntest'; +import nnid from '@/services/nnid'; +import nasc from '@/services/nasc'; +import datastore from '@/services/datastore'; +import api from '@/services/api'; +import localcdn from '@/services/local-cdn'; +import assets from '@/services/assets'; const { config } = configManager; diff --git a/src/services/api/index.ts b/src/services/api/index.ts index 3f79071..0d8a952 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -3,9 +3,9 @@ import express from 'express'; import subdomain from 'express-subdomain'; import cors from 'cors'; -import APIMiddleware from '@middleware/api'; -import routes from '@services/api/routes'; -import logger from '@logger'; +import APIMiddleware from '@/middleware/api'; +import routes from '@/services/api/routes'; +import logger from '@/logger'; // Router to handle the subdomain restriction const api = express.Router(); diff --git a/src/services/api/routes/index.ts b/src/services/api/routes/index.ts index 4b0f452..61691f2 100644 --- a/src/services/api/routes/index.ts +++ b/src/services/api/routes/index.ts @@ -1,10 +1,10 @@ -import connections_v1 from '@services/api/routes/v1/connections'; -import email_v1 from '@services/api/routes/v1/email'; -import forgotPassword_v1 from '@services/api/routes/v1/forgotPassword'; -import login_v1 from '@services/api/routes/v1/login'; -import register_v1 from '@services/api/routes/v1/register'; -import resetPassword_v1 from '@services/api/routes/v1/resetPassword'; -import user_v1 from '@services/api/routes/v1/user'; +import connections_v1 from '@/services/api/routes/v1/connections'; +import email_v1 from '@/services/api/routes/v1/email'; +import forgotPassword_v1 from '@/services/api/routes/v1/forgotPassword'; +import login_v1 from '@/services/api/routes/v1/login'; +import register_v1 from '@/services/api/routes/v1/register'; +import resetPassword_v1 from '@/services/api/routes/v1/resetPassword'; +import user_v1 from '@/services/api/routes/v1/user'; export default { V1: { diff --git a/src/services/api/routes/v1/connections.ts b/src/services/api/routes/v1/connections.ts index a15924e..4ec11c5 100644 --- a/src/services/api/routes/v1/connections.ts +++ b/src/services/api/routes/v1/connections.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import database from '@database'; +import database from '@/database'; const router = Router(); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index 7c33101..1f28f18 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import moment from 'moment'; -import { PNID } from '@models/pnid'; -import util from '@util'; +import { PNID } from '@/models/pnid'; +import util from '@/util'; const router = Router(); diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index 9634663..eb926b4 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import validator from 'validator'; -import database from '@database'; -import util from '@util'; +import database from '@/database'; +import util from '@/util'; const router = Router(); diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index c925030..e6c8c1f 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -1,9 +1,9 @@ import { Router } from 'express'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import database from '@database'; -import cache from '@cache'; -import util from '@util'; +import database from '@/database'; +import cache from '@/cache'; +import util from '@/util'; const router = Router(); diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 50d291c..95f79d4 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -7,13 +7,13 @@ import fs from 'fs-extra'; import moment from 'moment'; import hcaptcha from 'hcaptcha'; import Mii from 'mii-js'; -import database from '@database'; -import cache from '@cache'; -import util from '@util'; -import logger from '@logger'; -import { PNID } from '@models/pnid'; -import { NEXAccount } from '@models/nex-account'; -import { config, disabledFeatures } from '@config-manager'; +import database from '@/database'; +import cache from '@/cache'; +import util from '@/util'; +import logger from '@/logger'; +import { PNID } from '@/models/pnid'; +import { NEXAccount } from '@/models/nex-account'; +import { config, disabledFeatures } from '@/config-manager'; const router = Router(); diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 8642439..3f9a823 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import bcrypt from 'bcrypt'; -import { PNID } from '@models/pnid'; -import util from '@util'; +import { PNID } from '@/models/pnid'; +import util from '@/util'; const router = Router(); diff --git a/src/services/api/routes/v1/user.ts b/src/services/api/routes/v1/user.ts index 6e5d4fa..2ce5fae 100644 --- a/src/services/api/routes/v1/user.ts +++ b/src/services/api/routes/v1/user.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import joi from 'joi'; -import { PNID } from '@models/pnid'; -import { config } from '@config-manager'; +import { PNID } from '@/models/pnid'; +import { config } from '@/config-manager'; const router = Router(); diff --git a/src/services/assets/index.ts b/src/services/assets/index.ts index d00a3f7..dc77afb 100644 --- a/src/services/assets/index.ts +++ b/src/services/assets/index.ts @@ -3,7 +3,7 @@ import path from 'node:path'; import express from 'express'; import subdomain from 'express-subdomain'; -import logger from '@logger'; +import logger from '@/logger'; // Router to handle the subdomain restriction const assets = express.Router(); diff --git a/src/services/conntest/index.ts b/src/services/conntest/index.ts index 73b8545..8033849 100644 --- a/src/services/conntest/index.ts +++ b/src/services/conntest/index.ts @@ -2,7 +2,7 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import logger from '@logger'; +import logger from '@/logger'; // Router to handle the subdomain restriction const conntest = express.Router(); diff --git a/src/services/datastore/index.ts b/src/services/datastore/index.ts index c493f1d..6969988 100644 --- a/src/services/datastore/index.ts +++ b/src/services/datastore/index.ts @@ -1,7 +1,7 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import routes from '@services/datastore/routes'; -import logger from '@logger'; +import routes from '@/services/datastore/routes'; +import logger from '@/logger'; // Router to handle the subdomain const datastore = express.Router(); diff --git a/src/services/datastore/routes/index.ts b/src/services/datastore/routes/index.ts index de121ba..5e00989 100644 --- a/src/services/datastore/routes/index.ts +++ b/src/services/datastore/routes/index.ts @@ -1,4 +1,4 @@ -import upload from '@services/datastore/routes/upload'; +import upload from '@/services/datastore/routes/upload'; export default { UPLOAD: upload diff --git a/src/services/datastore/routes/upload.ts b/src/services/datastore/routes/upload.ts index 118b7e5..a17c15d 100644 --- a/src/services/datastore/routes/upload.ts +++ b/src/services/datastore/routes/upload.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import crypto from 'node:crypto'; import { Router } from 'express'; import Dicer from 'dicer'; -import util from '@util'; +import util from '@/util'; const router = Router(); diff --git a/src/services/local-cdn/index.ts b/src/services/local-cdn/index.ts index 507924a..e8891ac 100644 --- a/src/services/local-cdn/index.ts +++ b/src/services/local-cdn/index.ts @@ -1,8 +1,8 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import routes from '@services/local-cdn/routes'; -import { config, disabledFeatures } from '@config-manager'; -import logger from '@logger'; +import routes from '@/services/local-cdn/routes'; +import { config, disabledFeatures } from '@/config-manager'; +import logger from '@/logger'; const router = express.Router(); diff --git a/src/services/local-cdn/routes/get.ts b/src/services/local-cdn/routes/get.ts index fd70a25..7a68dc8 100644 --- a/src/services/local-cdn/routes/get.ts +++ b/src/services/local-cdn/routes/get.ts @@ -1,5 +1,5 @@ import { Router } from 'express'; -import cache from '@cache'; +import cache from '@/cache'; const router = Router(); diff --git a/src/services/local-cdn/routes/index.ts b/src/services/local-cdn/routes/index.ts index 8f02619..5038ab4 100644 --- a/src/services/local-cdn/routes/index.ts +++ b/src/services/local-cdn/routes/index.ts @@ -1,4 +1,4 @@ -import get from '@services/local-cdn/routes/get'; +import get from '@/services/local-cdn/routes/get'; export default { GET: get, diff --git a/src/services/nasc/index.ts b/src/services/nasc/index.ts index 5ddf5e9..a55de55 100644 --- a/src/services/nasc/index.ts +++ b/src/services/nasc/index.ts @@ -2,9 +2,9 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import NASCMiddleware from '@middleware/nasc'; -import routes from '@services/nasc/routes'; -import logger from '@logger'; +import NASCMiddleware from '@/middleware/nasc'; +import routes from '@/services/nasc/routes'; +import logger from '@/logger'; // Router to handle the subdomain restriction const nasc = express.Router(); diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 0545682..f468f1a 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -1,7 +1,7 @@ import express from 'express'; -import util from '@util'; -import database from '@database'; -import cache from '@cache'; +import util from '@/util'; +import database from '@/database'; +import cache from '@/cache'; const router = express.Router(); diff --git a/src/services/nasc/routes/index.ts b/src/services/nasc/routes/index.ts index 1f3ab33..e8dfff6 100644 --- a/src/services/nasc/routes/index.ts +++ b/src/services/nasc/routes/index.ts @@ -1,4 +1,4 @@ -import ac from '@services/nasc/routes/ac'; +import ac from '@/services/nasc/routes/ac'; export default { AC: ac diff --git a/src/services/nnid/index.ts b/src/services/nnid/index.ts index 0f24f01..9c9cdd3 100644 --- a/src/services/nnid/index.ts +++ b/src/services/nnid/index.ts @@ -2,11 +2,11 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import clientHeaderCheck from '@middleware/client-header'; -import cemuMiddleware from '@middleware/cemu'; -import pnidMiddleware from '@middleware/pnid'; -import routes from '@services/nnid/routes'; -import logger from '@logger'; +import clientHeaderCheck from '@/middleware/client-header'; +import cemuMiddleware from '@/middleware/cemu'; +import pnidMiddleware from '@/middleware/pnid'; +import routes from '@/services/nnid/routes'; +import logger from '@/logger'; // Router to handle the subdomain restriction const nnid = express.Router(); diff --git a/src/services/nnid/routes/admin.ts b/src/services/nnid/routes/admin.ts index 2c92dbb..115b5ab 100644 --- a/src/services/nnid/routes/admin.ts +++ b/src/services/nnid/routes/admin.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; -import { PNID } from '@models/pnid'; +import { PNID } from '@/models/pnid'; const router = Router(); diff --git a/src/services/nnid/routes/content.ts b/src/services/nnid/routes/content.ts index 9a31d61..92f4701 100644 --- a/src/services/nnid/routes/content.ts +++ b/src/services/nnid/routes/content.ts @@ -1,6 +1,6 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; -import timezones from '@services/nnid/timezones.json'; +import timezones from '@/services/nnid/timezones.json'; const router = Router(); diff --git a/src/services/nnid/routes/index.ts b/src/services/nnid/routes/index.ts index 4fb9855..7510b1f 100644 --- a/src/services/nnid/routes/index.ts +++ b/src/services/nnid/routes/index.ts @@ -1,11 +1,11 @@ -import admin from '@services/nnid/routes/admin'; -import content from '@services/nnid/routes/content'; -import devices from '@services/nnid/routes/devices'; -import miis from '@services/nnid/routes/miis'; -import oauth from '@services/nnid/routes/oauth'; -import people from '@services/nnid/routes/people'; -import provider from '@services/nnid/routes/provider'; -import support from '@services/nnid/routes/support'; +import admin from '@/services/nnid/routes/admin'; +import content from '@/services/nnid/routes/content'; +import devices from '@/services/nnid/routes/devices'; +import miis from '@/services/nnid/routes/miis'; +import oauth from '@/services/nnid/routes/oauth'; +import people from '@/services/nnid/routes/people'; +import provider from '@/services/nnid/routes/provider'; +import support from '@/services/nnid/routes/support'; export default { ADMIN: admin, diff --git a/src/services/nnid/routes/miis.ts b/src/services/nnid/routes/miis.ts index 502bc16..7219ed4 100644 --- a/src/services/nnid/routes/miis.ts +++ b/src/services/nnid/routes/miis.ts @@ -1,7 +1,7 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; -import { PNID } from '@models/pnid'; -import { config } from '@config-manager'; +import { PNID } from '@/models/pnid'; +import { config } from '@/config-manager'; const router = Router(); diff --git a/src/services/nnid/routes/oauth.ts b/src/services/nnid/routes/oauth.ts index b3db6a2..ab1ca40 100644 --- a/src/services/nnid/routes/oauth.ts +++ b/src/services/nnid/routes/oauth.ts @@ -2,8 +2,8 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import database from '@database'; -import util from '@util'; +import database from '@/database'; +import util from '@/util'; const router = Router(); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 440852a..8733e00 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -3,14 +3,14 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import moment from 'moment'; -import deviceCertificateMiddleware from '@middleware/device-certificate'; -import ratelimit from '@middleware/ratelimit'; -import database from '@database'; -import util from '@util'; -import { PNID } from '@models/pnid'; -import { NEXAccount } from '@models/nex-account'; -import logger from '@logger'; -import timezones from '@services/nnid/timezones.json'; +import deviceCertificateMiddleware from '@/middleware/device-certificate'; +import ratelimit from '@/middleware/ratelimit'; +import database from '@/database'; +import util from '@/util'; +import { PNID } from '@/models/pnid'; +import { NEXAccount } from '@/models/nex-account'; +import logger from '@/logger'; +import timezones from '@/services/nnid/timezones.json'; const router = Router(); diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 64ac262..804839a 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -1,10 +1,10 @@ import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import fs from 'fs-extra'; -import database from '@database'; -import util from '@util'; -import cache from '@cache'; -import { NEXAccount } from '@models/nex-account'; +import database from '@/database'; +import util from '@/util'; +import cache from '@/cache'; +import { NEXAccount } from '@/models/nex-account'; const router = Router(); diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index 4c1bb1f..b07bcff 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -2,8 +2,8 @@ import dns from 'node:dns'; import { Router } from 'express'; import xmlbuilder from 'xmlbuilder'; import moment from 'moment'; -import database from '@database'; -import util from '@util'; +import database from '@/database'; +import util from '@/util'; const router = Router(); diff --git a/types/express.d.ts b/src/types/express.d.ts similarity index 61% rename from types/express.d.ts rename to src/types/express.d.ts index 1e3c92a..e6669ab 100644 --- a/types/express.d.ts +++ b/src/types/express.d.ts @@ -1,5 +1,7 @@ import { HydratedDocument } from 'mongoose'; -import NintendoCertificate from '@nintendo-certificate'; +import NintendoCertificate from '@/nintendo-certificate'; +import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; +import { INEXAccount, INEXAccountMethods } from '@/types/mongoose/nex-account'; declare global { namespace Express { diff --git a/src/types/mongoose/device-attribute.ts b/src/types/mongoose/device-attribute.ts new file mode 100644 index 0000000..2c5a2bf --- /dev/null +++ b/src/types/mongoose/device-attribute.ts @@ -0,0 +1,11 @@ +import { Model } from 'mongoose'; + +export interface IDeviceAttribute { + created_date: string; + name: string; + value: string; +} + +export interface IDeviceAttributeMethods {} + +export interface DeviceAttributeModel extends Model {} \ No newline at end of file diff --git a/src/types/mongoose/device.ts b/src/types/mongoose/device.ts new file mode 100644 index 0000000..9fe4ba3 --- /dev/null +++ b/src/types/mongoose/device.ts @@ -0,0 +1,30 @@ +import { Model } from 'mongoose'; +import { DeviceAttributeSchema } from '@/models/device'; + +type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan'; +type ACCESS_LEVEL = 0 | 1 | 2 | 3; +type SERVER_ACCESS_LEVEL = 'prod' | 'test' | 'dev'; + +export interface IDevice { + is_emulator: boolean; + model: MODEL; + device_id: number; + device_type: number; + serial: string; + device_attributes: typeof DeviceAttributeSchema[]; + soap: { + token: string; + account_id: number; + }, + // * 3DS-specific stuff + environment: string; + mac_hash: string; + fcdcert_hash: string; + linked_pids: number[]; + access_level: ACCESS_LEVEL; + server_access_level: SERVER_ACCESS_LEVEL; +} + +export interface IDeviceMethods {} + +export interface DeviceModel extends Model {} \ No newline at end of file diff --git a/src/types/mongoose/nex-account.ts b/src/types/mongoose/nex-account.ts new file mode 100644 index 0000000..b109527 --- /dev/null +++ b/src/types/mongoose/nex-account.ts @@ -0,0 +1,20 @@ +import { Model } from 'mongoose'; + +type DEVICE = 'wiiu' | '3ds'; +type ACCESS_LEVEL = 0 | 1 | 2 | 3; + +export interface INEXAccount { + device_type: DEVICE; + pid: number; + password: string; + owning_pid: number; + access_level: ACCESS_LEVEL; + server_access_level: string; +} + +export interface INEXAccountMethods { + generatePID(): Promise; + generatePassword(): void; +} + +export interface NEXAccountModel extends Model {} \ No newline at end of file diff --git a/src/types/mongoose/pnid.ts b/src/types/mongoose/pnid.ts new file mode 100644 index 0000000..e52f064 --- /dev/null +++ b/src/types/mongoose/pnid.ts @@ -0,0 +1,76 @@ +import { Model } from 'mongoose'; +import { DeviceSchema } from '@/models/device'; + +export interface IPNID { + access_level: number; + server_access_level: string; + pid: number; + creation_date: string; + updated: string; + username: string; + usernameLower: string; + password: string; + birthdate: string; + gender: string; + country: string; + language: string; + email: { + address: string; + primary: boolean; + parent: boolean; + reachable: boolean; + validated: boolean; + validated_date: string; + id: number; + }; + region: number; + timezone: { + name: string; + offset: number; + marketing: boolean; + off_device: boolean; + }; + mii: { + name: string; + primary: boolean; + data: string; + id: number; + hash: string; + image_url: string; + image_id: number; + }; + flags: { + active: boolean; + marketing: boolean; + off_device: boolean; + }; + devices: typeof DeviceSchema[]; + identification: { // user identification tokens + email_code: string; + email_token: string; + access_token: { + value: string; + ttl: number; + }, + refresh_token: { + value: string; + ttl: number; + } + }; + connections: { + discord: { + id: string; + } + }; +} + +export interface IPNIDMethods { + generatePID(): Promise; + generateEmailValidationCode(): Promise; + generateEmailValidationToken(): Promise; + updateMii(mii: { name: string, primary: string, data: string}): Promise; + generateMiiImages(): Promise; + getServerMode(): string; +} + +export interface PNIDModel extends Model {} \ No newline at end of file diff --git a/src/types/mongoose/server.ts b/src/types/mongoose/server.ts new file mode 100644 index 0000000..f25198e --- /dev/null +++ b/src/types/mongoose/server.ts @@ -0,0 +1,17 @@ +import { Model } from 'mongoose'; + +export interface IServer { + ip: string; // Example: 1.1.1.1 + port: Number; // Example: 60000 + service_name: string; // Example: friends + service_type: string; // Example: nex + game_server_id: string; // Example: 00003200 + title_ids: string[]; // Example: ["000500001018DB00", "000500001018DC00", "000500001018DD00"] + access_mode: string; // Example: prod + maintenance_mode: boolean; // Example: false + device: number; // Example: 1 (WiiU) +} + +export interface IServerMethods {} + +export interface ServerModel extends Model {} \ No newline at end of file diff --git a/src/util.ts b/src/util.ts index fd36a02..d3aaef3 100644 --- a/src/util.ts +++ b/src/util.ts @@ -3,9 +3,9 @@ const path = require('path'); const NodeRSA = require('node-rsa'); const aws = require('aws-sdk'); const fs = require('fs-extra'); -const mailer = require('@mailer'); -const cache = require('@cache'); -const { config, disabledFeatures } = require('@config-manager'); +const mailer = require('@/mailer'); +const cache = require('@/cache'); +const { config, disabledFeatures } = require('@/config-manager'); let s3; @@ -17,7 +17,7 @@ if (!disabledFeatures.s3) { }); } -function nintendoPasswordHash(password, pid) { +function nintendoPasswordHash(password: string, pid: number): string { const pidBuffer = Buffer.alloc(4); pidBuffer.writeUInt32LE(pid); @@ -31,18 +31,17 @@ function nintendoPasswordHash(password, pid) { return hashed; } -function nintendoBase64Decode(encoded) { +function nintendoBase64Decode(encoded: string): Buffer { encoded = encoded.replaceAll('.', '+').replaceAll('-', '/').replaceAll('*', '='); return Buffer.from(encoded, 'base64'); } -function nintendoBase64Encode(decoded) { +function nintendoBase64Encode(decoded: string | Buffer): string { const encoded = Buffer.from(decoded).toString('base64'); return encoded.replaceAll('+', '.').replaceAll('/', '-').replaceAll('=', '*'); } -async function generateToken(cryptoOptions, tokenOptions) { - +async function generateToken(cryptoOptions, tokenOptions): Promise { // Access and refresh tokens use a different format since they must be much smaller // They take no extra crypto options if (!cryptoOptions) { diff --git a/tsconfig.json b/tsconfig.json index a3d9165..16ad818 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,8 +10,8 @@ "target": "es2022", "noEmitOnError": true, "paths": { - "@*": ["./*"] + "@/*": ["./*"] } }, - "include": ["src", "types"] + "include": ["src"] } \ No newline at end of file diff --git a/types/mongoose/device-attribute.d.ts b/types/mongoose/device-attribute.d.ts deleted file mode 100644 index 98a7de1..0000000 --- a/types/mongoose/device-attribute.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Model } from 'mongoose'; - -declare global { - interface IDeviceAttribute { - created_date: string; - name: string; - value: string; - } - - interface IDeviceAttributeMethods {} - - interface DeviceAttributeModel extends Model {} -} \ No newline at end of file diff --git a/types/mongoose/device.d.ts b/types/mongoose/device.d.ts deleted file mode 100644 index 90b723d..0000000 --- a/types/mongoose/device.d.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Model } from 'mongoose'; -import { DeviceAttributeSchema } from '@models/device'; - -type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan'; -type ACCESS_LEVEL = 0 | 1 | 2 | 3; -type SERVER_ACCESS_LEVEL = 'prod' | 'test' | 'dev'; - -declare global { - interface IDevice { - is_emulator: boolean; - model: MODEL; - device_id: number; - device_type: number; - serial: string; - device_attributes: typeof DeviceAttributeSchema[]; - soap: { - token: string; - account_id: number; - }, - // * 3DS-specific stuff - environment: string; - mac_hash: string; - fcdcert_hash: string; - linked_pids: number[]; - access_level: ACCESS_LEVEL; - server_access_level: SERVER_ACCESS_LEVEL; - } - - interface IDeviceMethods {} - - interface DeviceModel extends Model {} -} \ No newline at end of file diff --git a/types/mongoose/nex-account.d.ts b/types/mongoose/nex-account.d.ts deleted file mode 100644 index e51119a..0000000 --- a/types/mongoose/nex-account.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Model } from 'mongoose'; - -type DEVICE = 'wiiu' | '3ds'; -type ACCESS_LEVEL = 0 | 1 | 2 | 3; - -declare global { - interface INEXAccount { - device_type: DEVICE; - pid: number; - password: string; - owning_pid: number; - access_level: ACCESS_LEVEL; - server_access_level: string; - } - - interface INEXAccountMethods { - generatePID(): Promise; - generatePassword(): void; - } - - interface NEXAccountModel extends Model {} -} \ No newline at end of file diff --git a/types/mongoose/pnid.d.ts b/types/mongoose/pnid.d.ts deleted file mode 100644 index b7f9441..0000000 --- a/types/mongoose/pnid.d.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { Model } from 'mongoose'; -import { DeviceSchema } from '@models/device'; - -declare global { - interface IPNID { - access_level: number; - server_access_level: string; - pid: number; - creation_date: string; - updated: string; - username: string; - usernameLower: string; - password: string; - birthdate: string; - gender: string; - country: string; - language: string; - email: { - address: string; - primary: boolean; - parent: boolean; - reachable: boolean; - validated: boolean; - validated_date: string; - id: number; - }; - region: number; - timezone: { - name: string; - offset: number; - marketing: boolean; - off_device: boolean; - }; - mii: { - name: string; - primary: boolean; - data: string; - id: number; - hash: string; - image_url: string; - image_id: number; - }; - flags: { - active: boolean; - marketing: boolean; - off_device: boolean; - }; - devices: typeof DeviceSchema[]; - identification: { // user identification tokens - email_code: string; - email_token: string; - access_token: { - value: string; - ttl: number; - }, - refresh_token: { - value: string; - ttl: number; - } - }; - connections: { - discord: { - id: string; - } - }; - } - - interface IPNIDMethods { - generatePID(): Promise; - generateEmailValidationCode(): Promise; - generateEmailValidationToken(): Promise; - updateMii(mii: { name: string, primary: string, data: string}): Promise; - generateMiiImages(): Promise; - getServerMode(): string; - } - - interface PNIDModel extends Model {} -} \ No newline at end of file diff --git a/types/mongoose/server.d.ts b/types/mongoose/server.d.ts deleted file mode 100644 index 11cfb4e..0000000 --- a/types/mongoose/server.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Model } from 'mongoose'; - -declare global { - interface IServer { - ip: string; // Example: 1.1.1.1 - port: Number; // Example: 60000 - service_name: string; // Example: friends - service_type: string; // Example: nex - game_server_id: string; // Example: 00003200 - title_ids: string[]; // Example: ["000500001018DB00", "000500001018DC00", "000500001018DD00"] - access_mode: string; // Example: prod - maintenance_mode: boolean; // Example: false - device: number; // Example: 1 (WiiU) - } - - interface IServerMethods {} - - interface ServerModel extends Model {} -} \ No newline at end of file From bfba5a025968ecb21a4876f809e91b786b6ca131 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 4 Mar 2023 22:50:43 -0500 Subject: [PATCH 28/65] Migrate to TS imports in util.ts (forgot, oops) --- src/util.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/util.ts b/src/util.ts index d3aaef3..e383f93 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,11 +1,11 @@ -const crypto = require('crypto'); -const path = require('path'); -const NodeRSA = require('node-rsa'); -const aws = require('aws-sdk'); -const fs = require('fs-extra'); -const mailer = require('@/mailer'); -const cache = require('@/cache'); -const { config, disabledFeatures } = require('@/config-manager'); +import crypto from 'node:crypto'; +import path from 'node:path'; +import NodeRSA from 'node-rsa'; +import aws from 'aws-sdk'; +import fs from 'fs-extra'; +import mailer from '@/mailer'; +import cache from '@/cache'; +import { config, disabledFeatures } from '@/config-manager'; let s3; From d23a8b7c212690819f67c4efa2ffbafdb9c54c6d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 5 Mar 2023 20:14:31 -0500 Subject: [PATCH 29/65] Remade config manager. Removed JSON file support --- src/config-manager.ts | 394 +++++++++++++------------------------ src/types/common/config.ts | 47 +++++ 2 files changed, 181 insertions(+), 260 deletions(-) create mode 100644 src/types/common/config.ts diff --git a/src/config-manager.ts b/src/config-manager.ts index 37bc0c2..db16603 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -1,289 +1,163 @@ import fs from 'fs-extra'; -import get from 'lodash.get'; -import set from 'lodash.set'; +import mongoose from 'mongoose'; import dotenv from 'dotenv'; import logger from '@/logger'; +import { Config, DisabledFeatures } from '@/types/common/config'; dotenv.config(); -export let config: Record = {}; - -export const disabledFeatures = { +export const disabledFeatures: DisabledFeatures = { redis: false, email: false, captcha: false, s3: false }; -const requiredFields = [ - ['http.port', 'PN_ACT_CONFIG_HTTP_PORT', Number], - ['mongoose.connection_string', 'PN_ACT_CONFIG_MONGO_CONNECTION_STRING'], - ['cdn.base_url', 'PN_ACT_CONFIG_CDN_BASE_URL'] -]; +logger.info('Loading config'); -export function configure() { - const usingEnv = process.env.PN_ACT_PREFER_ENV_CONFIG === 'true'; +let mongooseConnectOptions: mongoose.ConnectOptions; - if (usingEnv) { - logger.info('Loading config from environment variable'); +if (process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH) { + mongooseConnectOptions = fs.readJSONSync(process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH); +} - config = { - http: { - port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT) - }, - mongoose: { - connection_string: process.env.PN_ACT_CONFIG_MONGO_CONNECTION_STRING, - options: Object.keys(process.env) - .filter(key => key.startsWith('PN_ACT_CONFIG_MONGOOSE_OPTION_')) - .reduce((obj, key) => { - obj[key.split('_').pop()] = process.env[key]; - return obj; - }, {}) - }, - redis: { - client: { - url: process.env.PN_ACT_CONFIG_REDIS_URL - } - }, - email: { - host: process.env.PN_ACT_CONFIG_EMAIL_HOST, - port: Number(process.env.PN_ACT_CONFIG_EMAIL_PORT), - secure: Boolean(process.env.PN_ACT_CONFIG_EMAIL_SECURE), - auth: { - user: process.env.PN_ACT_CONFIG_EMAIL_USERNAME, - pass: process.env.PN_ACT_CONFIG_EMAIL_PASSWORD - }, - from: process.env.PN_ACT_CONFIG_EMAIL_FROM - }, - s3: { - endpoint: process.env.PN_ACT_CONFIG_S3_ENDPOINT, - key: process.env.PN_ACT_CONFIG_S3_ACCESS_KEY, - secret: process.env.PN_ACT_CONFIG_S3_ACCESS_SECRET - }, - hcaptcha: { - secret: process.env.PN_ACT_CONFIG_HCAPTCHA_SECRET - }, - cdn: { - subdomain: process.env.PN_ACT_CONFIG_CDN_SUBDOMAIN, - disk_path: process.env.PN_ACT_CONFIG_CDN_DISK_PATH, - base_url: process.env.PN_ACT_CONFIG_CDN_BASE_URL - }, - website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE - }; - } else { - logger.info('Loading config from config.json'); - - if (!fs.pathExistsSync(`${__dirname}/../config.json`)) { - logger.error('Failed to locate config.json file'); - process.exit(0); +export const config: Config = { + http: { + port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT) + }, + mongoose: { + connection_string: process.env.PN_ACT_CONFIG_MONGO_CONNECTION_STRING, + options: mongooseConnectOptions + }, + redis: { + client: { + url: process.env.PN_ACT_CONFIG_REDIS_URL } + }, + email: { + host: process.env.PN_ACT_CONFIG_EMAIL_HOST, + port: Number(process.env.PN_ACT_CONFIG_EMAIL_PORT), + secure: Boolean(process.env.PN_ACT_CONFIG_EMAIL_SECURE), + auth: { + user: process.env.PN_ACT_CONFIG_EMAIL_USERNAME, + pass: process.env.PN_ACT_CONFIG_EMAIL_PASSWORD + }, + from: process.env.PN_ACT_CONFIG_EMAIL_FROM + }, + s3: { + endpoint: process.env.PN_ACT_CONFIG_S3_ENDPOINT, + key: process.env.PN_ACT_CONFIG_S3_ACCESS_KEY, + secret: process.env.PN_ACT_CONFIG_S3_ACCESS_SECRET + }, + hcaptcha: { + secret: process.env.PN_ACT_CONFIG_HCAPTCHA_SECRET + }, + cdn: { + subdomain: process.env.PN_ACT_CONFIG_CDN_SUBDOMAIN, + disk_path: process.env.PN_ACT_CONFIG_CDN_DISK_PATH, + base_url: process.env.PN_ACT_CONFIG_CDN_BASE_URL + }, + website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE +}; - config = require(`${__dirname}/../config.json`); +logger.info('Config loaded, checking integrity'); + +if (!config.http.port) { + logger.error('Failed to find HTTP port. Set the PN_ACT_CONFIG_HTTP_PORT environment variable'); + process.exit(0); +} + +if (!config.mongoose.connection_string) { + logger.error('Failed to find MongoDB connection string. Set the PN_ACT_CONFIG_MONGO_CONNECTION_STRING environment variable'); + process.exit(0); +} + +if (!config.cdn.base_url) { + logger.error('Failed to find asset CDN base URL. Set the PN_ACT_CONFIG_CDN_BASE_URL environment variable'); + process.exit(0); +} + +if (!config.redis.client.url) { + logger.warn('Failed to find Redis connection url. Disabling feature and using in-memory cache. To enable feature set the PN_ACT_CONFIG_REDIS_URL environment variable'); + disabledFeatures.redis = true; +} + +if (!config.email.host) { + logger.warn('Failed to find email SMTP host. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_HOST environment variable'); + disabledFeatures.email = true; +} + +if (!config.email.port) { + logger.warn('Failed to find email SMTP port. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PORT environment variable'); + disabledFeatures.email = true; +} + +if (config.email.secure === undefined) { + logger.warn('Failed to find email SMTP secure flag. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_SECURE environment variable'); + disabledFeatures.email = true; +} + +if (!config.email.auth.user) { + logger.warn('Failed to find email account username. Disabling feature. To enable feature set the auth.user environment variable'); + disabledFeatures.email = true; +} + +if (!config.email.auth.pass) { + logger.warn('Failed to find email account password. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PASSWORD environment variable'); + disabledFeatures.email = true; +} + +if (!config.email.from) { + logger.warn('Failed to find email from config. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_FROM environment variable'); + disabledFeatures.email = true; +} + +if (!disabledFeatures.email) { + if (!config.website_base) { + logger.error('Email sending is enabled and no website base was configured. Set the PN_ACT_CONFIG_WEBSITE_BASE environment variable'); + process.exit(0); + } +} + +if (!config.hcaptcha.secret) { + logger.warn('Failed to find captcha secret config. Disabling feature. To enable feature set the PN_ACT_CONFIG_HCAPTCHA_SECRET environment variable'); + disabledFeatures.captcha = true; +} + +if (!config.s3.endpoint) { + logger.warn('Failed to find s3 endpoint config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ENDPOINT environment variable'); + disabledFeatures.s3 = true; +} + +if (!config.s3.key) { + logger.warn('Failed to find s3 access key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_KEY environment variable'); + disabledFeatures.s3 = true; +} + +if (!config.s3.secret) { + logger.warn('Failed to find s3 secret key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_SECRET environment variable'); + disabledFeatures.s3 = true; +} + +if (disabledFeatures.s3) { + if (!config.cdn.subdomain) { + logger.error('s3 file storage is disabled and no CDN subdomain was set. Set the PN_ACT_CONFIG_CDN_SUBDOMAIN environment variable'); + process.exit(0); } - logger.info('Config loaded, checking integrity'); - - // * Check for required settings - for (const requiredField of requiredFields) { - const [keyPath, envVarName, convertType] = requiredField; - - const configValue = get(config, keyPath); - const envValue = get(process.env, envVarName); - - if (!configValue || (typeof configValue === 'string' && configValue.trim() === '')) { - if (!envValue || envValue.trim() === '') { - logger.error(`Failed to locate required field ${keyPath}. Set ${keyPath} in config.json or the ${envVarName} environment variable`); - - process.exit(0); - } else { - logger.info(`${keyPath} not found in config, using environment variable ${envVarName}`); - - const newValue = envValue; - - set(config, keyPath, convertType ? (convertType as Function)(newValue) : newValue); - } - } + if (!config.cdn.disk_path) { + logger.error('s3 file storage is disabled and no CDN disk path was set. Set the PN_ACT_CONFIG_CDN_DISK_PATH environment variable'); + process.exit(0); } - // * Check for optional settings + logger.warn(`s3 file storage disabled. Using disk-based file storage. Please ensure cdn.base_url config or PN_ACT_CONFIG_CDN_BASE env variable is set to point to this server with the subdomain being ${config.cdn.subdomain}`); - const redisCheck = get(config, 'redis.client.url'); - - if (!redisCheck || redisCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find Redis connection url. Disabling feature and using in-memory cache. To enable feature set the PN_ACT_CONFIG_REDIS_URL environment variable'); - - } else { - logger.warn('Failed to find Redis connection url. Disabling feature and using in-memory cache. To enable feature set redis.client.url in your config.json'); - - } - - disabledFeatures.redis = true; - } - - const emailHostCheck = get(config, 'email.host'); - - if (!emailHostCheck || emailHostCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find email SMTP host. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_HOST environment variable'); - } else { - logger.warn('Failed to find email SMTP host. Disabling feature. To enable feature set email.host in your config.json'); - } - - - disabledFeatures.email = true; - } - - const emailPortCheck = get(config, 'email.port'); - - if (!emailPortCheck) { - if (usingEnv) { - logger.warn('Failed to find email SMTP port. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PORT environment variable'); - } else { - logger.warn('Failed to find email SMTP port. Disabling feature. To enable feature set email.port in your config.json'); - } - - disabledFeatures.email = true; - } - - const emailSecureCheck = get(config, 'email.secure'); - - if (emailSecureCheck === undefined) { - if (usingEnv) { - logger.warn('Failed to find email SMTP secure flag. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_SECURE environment variable'); - } else { - - logger.warn('Failed to find email SMTP secure flag. Disabling feature. To enable feature set email.secure in your config.json'); - } - - disabledFeatures.email = true; - } - - const emailUsernameCheck = get(config, 'email.auth.user'); - - if (!emailUsernameCheck || emailUsernameCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find email account username. Disabling feature. To enable feature set the auth.user environment variable'); - } else { - - logger.warn('Failed to find email account username. Disabling feature. To enable feature set email.auth.user in your config.json'); - } - - disabledFeatures.email = true; - } - - const emailPasswordCheck = get(config, 'email.auth.pass'); - - if (!emailPasswordCheck || emailPasswordCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find email account password. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PASSWORD environment variable'); - } else { - - logger.warn('Failed to find email account password. Disabling feature. To enable feature set email.auth.pass in your config.json'); - } - - disabledFeatures.email = true; - } - - const emailFromCheck = get(config, 'email.from'); - - if (!emailFromCheck || emailFromCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find email from config. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_FROM environment variable'); - } else { - - logger.warn('Failed to find email from config. Disabling feature. To enable feature set email.from in your config.json'); - } - - disabledFeatures.email = true; - } - - if (!disabledFeatures.email) { - const websiteBaseCheck = get(config, 'website_base'); - - if (!websiteBaseCheck || websiteBaseCheck.trim() === '') { - if (usingEnv) { - logger.error('Email sending is enabled and no website base was configured. Set the PN_ACT_CONFIG_WEBSITE_BASE environment variable'); - } else { - logger.error('Email sending is enabled and no website base was configured. Set website_base in your config.json'); - } - - process.exit(0); - } - } - - const captchaSecretCheck = get(config, 'hcaptcha.secret'); - - if (!captchaSecretCheck || captchaSecretCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find captcha secret config. Disabling feature. To enable feature set the PN_ACT_CONFIG_HCAPTCHA_SECRET environment variable'); - } else { - logger.warn('Failed to find captcha secret config. Disabling feature. To enable feature set hcaptcha.secret in your config.json'); - } - - disabledFeatures.captcha = true; - } - - const s3EndpointCheck = get(config, 's3.endpoint'); - - if (!s3EndpointCheck || s3EndpointCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find s3 endpoint config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ENDPOINT environment variable'); - } else { - logger.warn('Failed to find s3 endpoint config. Disabling feature. To enable feature set s3.endpoint in your config.json'); - } - - disabledFeatures.s3 = true; - } else { - } - - const s3AccessKeyCheck = get(config, 's3.key'); - - if (!s3AccessKeyCheck || s3AccessKeyCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find s3 access key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_KEY environment variable'); - } else { - logger.warn('Failed to find s3 access key config. Disabling feature. To enable feature set s3.key in your config.json'); - } - - disabledFeatures.s3 = true; - } - - const s3SecretKeyCheck = get(config, 's3.secret'); - - if (!s3SecretKeyCheck || s3SecretKeyCheck.trim() === '') { - if (usingEnv) { - logger.warn('Failed to find s3 secret key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_SECRET environment variable'); - } else { - logger.warn('Failed to find s3 secret key config. Disabling feature. To enable feature set s3.secret in your config.json'); - } - - disabledFeatures.s3 = true; - } - - if (disabledFeatures.s3) { - const cdnSubdomainCheck = get(config, 'cdn.subdomain'); - - if (!cdnSubdomainCheck || cdnSubdomainCheck.trim() === '') { - if (usingEnv) { - logger.error('s3 file storage is disabled and no CDN subdomain was set. Set the PN_ACT_CONFIG_CDN_SUBDOMAIN environment variable'); - } else { - logger.error('s3 file storage is disabled and no CDN subdomain was set. Set cdn.subdomain in your config.json'); - } - - process.exit(0); - } - - if (disabledFeatures.redis) { - logger.warn('Both s3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable s3 if you\'re running a production server.'); - } - - logger.warn(`s3 file storage disabled. Using disk-based file storage. Please ensure cdn.base_url config or PN_ACT_CONFIG_CDN_BASE env variable is set to point to this server with the subdomain being ${config.cdn.subdomain}`); + if (disabledFeatures.redis) { + logger.warn('Both s3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable s3 if you\'re running a production server.'); } } export default { - configure, config, disabledFeatures }; \ No newline at end of file diff --git a/src/types/common/config.ts b/src/types/common/config.ts new file mode 100644 index 0000000..ed3fbb2 --- /dev/null +++ b/src/types/common/config.ts @@ -0,0 +1,47 @@ +import mongoose from 'mongoose'; + +export interface Config { + http: { + port: number; + }; + mongoose: { + connection_string: string; + options: mongoose.ConnectOptions; + }; + redis: { + client: { + url: string; + } + }; + email: { + host: string; + port: number; + secure: boolean; + auth: { + user: string; + pass: string; + }; + from: string; + }; + s3: { + endpoint: string; + key: string; + secret: string; + }; + hcaptcha: { + secret: string; + }; + cdn: { + subdomain: string; + disk_path: string; + base_url: string; + }; + website_base: string; +}; + +export interface DisabledFeatures { + redis: boolean; + email: boolean; + captcha: boolean; + s3: boolean +} \ No newline at end of file From 9fafca77fd5e6a7684671bc9830d9e10a168120d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 6 Mar 2023 21:01:15 -0500 Subject: [PATCH 30/65] Typed literally everything and eslint is happy --- .eslintignore | 1 + .eslintrc.json | 19 +- package-lock.json | 2590 ++++++++++++++++- package.json | 13 +- src/cache.ts | 100 +- src/database.ts | 143 +- src/logger.ts | 20 +- src/mailer.ts | 13 +- src/middleware/api.ts | 13 +- src/middleware/cemu.ts | 6 +- src/middleware/client-header.ts | 22 +- src/middleware/device-certificate.ts | 8 +- src/middleware/nasc.ts | 82 +- src/middleware/pnid.ts | 26 +- src/middleware/ratelimit.ts | 5 +- src/middleware/xml-parser.ts | 18 +- src/nintendo-certificate.ts | 33 +- src/server.ts | 26 +- src/services/api/index.ts | 4 +- src/services/api/routes/v1/connections.ts | 27 +- src/services/api/routes/v1/email.ts | 19 +- src/services/api/routes/v1/forgotPassword.ts | 12 +- src/services/api/routes/v1/login.ts | 52 +- src/services/api/routes/v1/register.ts | 79 +- src/services/api/routes/v1/resetPassword.ts | 33 +- src/services/api/routes/v1/user.ts | 27 +- src/services/assets/index.ts | 4 +- src/services/conntest/index.ts | 6 +- src/services/datastore/index.ts | 4 +- src/services/datastore/routes/upload.ts | 65 +- src/services/local-cdn/index.ts | 4 +- src/services/local-cdn/routes/get.ts | 10 +- src/services/nasc/index.ts | 4 +- src/services/nasc/routes/ac.ts | 51 +- src/services/nnid/routes/admin.ts | 44 +- src/services/nnid/routes/content.ts | 17 +- src/services/nnid/routes/devices.ts | 7 +- src/services/nnid/routes/miis.ts | 149 +- src/services/nnid/routes/oauth.ts | 29 +- src/services/nnid/routes/people.ts | 155 +- src/services/nnid/routes/provider.ts | 65 +- src/services/nnid/routes/support.ts | 34 +- src/types/common/config.ts | 2 +- src/types/common/crypto-options.ts | 4 + src/types/common/mailer-options.ts | 16 + src/types/common/signature-size.ts | 4 + src/types/common/token-options.ts | 8 + src/types/common/token.ts | 8 + src/types/common/yes-no-bool-string.ts | 1 + src/types/express.d.ts | 9 +- src/types/mongoose/device-attribute.ts | 6 +- src/types/mongoose/device.ts | 14 +- src/types/mongoose/nex-account.ts | 8 +- src/types/mongoose/pnid.ts | 14 +- src/types/mongoose/server.ts | 10 +- src/types/services/api/connection-data.ts | 4 + src/types/services/api/connection-response.ts | 5 + .../services/api/discord-connection-data.ts | 3 + src/types/services/api/update-user-request.ts | 7 + src/types/services/nasc/request-params.ts | 11 + src/types/services/nnid/person.ts | 44 + src/types/services/nnid/pnid-profile.ts | 53 + src/types/services/nnid/region-languages.ts | 5 + src/types/services/nnid/region-timezones.ts | 9 + src/util.ts | 181 +- tsconfig.json | 6 +- 66 files changed, 3673 insertions(+), 798 deletions(-) create mode 100644 src/types/common/crypto-options.ts create mode 100644 src/types/common/mailer-options.ts create mode 100644 src/types/common/signature-size.ts create mode 100644 src/types/common/token-options.ts create mode 100644 src/types/common/token.ts create mode 100644 src/types/common/yes-no-bool-string.ts create mode 100644 src/types/services/api/connection-data.ts create mode 100644 src/types/services/api/connection-response.ts create mode 100644 src/types/services/api/discord-connection-data.ts create mode 100644 src/types/services/api/update-user-request.ts create mode 100644 src/types/services/nasc/request-params.ts create mode 100644 src/types/services/nnid/person.ts create mode 100644 src/types/services/nnid/pnid-profile.ts create mode 100644 src/types/services/nnid/region-languages.ts create mode 100644 src/types/services/nnid/region-timezones.ts diff --git a/.eslintignore b/.eslintignore index e69de29..53c37a1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -0,0 +1 @@ +dist \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index c7da300..d66114d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,13 +4,17 @@ "commonjs": true, "es6": true }, - "parserOptions": { - "ecmaVersion": 2020 - }, + "parser": "@typescript-eslint/parser", "globals": { "BigInt": true }, - "extends": "eslint:recommended", + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "plugins": [ + "@typescript-eslint" + ], "rules": { "require-atomic-updates": "warn", "no-case-declarations": "off", @@ -20,6 +24,13 @@ "no-global-assign": "off", "prefer-const": "error", "no-var": "error", + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "no-extra-semi": "off", + "@typescript-eslint/no-extra-semi": "error", + "@typescript-eslint/no-empty-interface": "warn", + "@typescript-eslint/no-inferrable-types": "off", + "@typescript-eslint/explicit-function-return-type": "error", "one-var": [ "error", "never" diff --git a/package-lock.json b/package-lock.json index 6e0a7ce..612c092 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,13 +24,12 @@ "hcaptcha": "^0.1.0", "image-pixels": "^1.1.1", "joi": "^17.8.3", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", "mii-js": "github:PretendoNetwork/mii-js", "moment": "^2.29.4", "mongoose": "^7.0.0", "mongoose-unique-validator": "github:stenneepro/mongoose-unique-validator#bump/mongoose7", "morgan": "^1.9.1", + "node-rsa": "^1.0.7", "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", @@ -39,13 +38,19 @@ "xmlbuilder2": "0.0.4" }, "devDependencies": { - "@types/colors": "^1.2.1", + "@hcaptcha/types": "^1.0.3", + "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", "@types/morgan": "^1.9.4", "@types/node": "^18.14.4", - "node-rsa": "^1.0.7", + "@types/node-rsa": "^1.1.1", + "@types/nodemailer": "^6.4.7", + "@typescript-eslint/eslint-plugin": "^5.54.1", + "@typescript-eslint/parser": "^5.54.1", + "eslint": "^8.35.0", "prompt": "^1.0.0", + "typescript": "^4.9.5", "yesno": "^0.4.0" } }, @@ -58,6 +63,61 @@ "node": ">=0.1.90" } }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", + "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", + "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -71,6 +131,68 @@ "@hapi/hoek": "^9.0.0" } }, + "node_modules/@hcaptcha/types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.3.tgz", + "integrity": "sha512-1mbU6eSGawRrqeahRrOzZo/SVLI6oZ5/azuBpSyVrRRR96CnS3fOVDWfzxpngfxKD0/I9Rwu6c/3ITqD8rXeTQ==", + "dev": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", @@ -90,6 +212,41 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@oozcitak/dom": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-0.0.11.tgz", @@ -320,16 +477,6 @@ "@types/responselike": "^1.0.0" } }, - "node_modules/@types/colors": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/colors/-/colors-1.2.1.tgz", - "integrity": "sha512-7jNkpfN2lVO07nJ1RWzyMnNhH/I5N9iWuMPx9pedptxJ4MODf8rRV0lbJi6RakQ4sKQk231Fw4e2W9n3D7gZ3w==", - "deprecated": "This is a stub types definition. colors provides its own type definitions, so you don't need this installed.", - "dev": true, - "dependencies": { - "colors": "*" - } - }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -339,6 +486,15 @@ "@types/node": "*" } }, + "node_modules/@types/dicer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@types/dicer/-/dicer-0.2.2.tgz", + "integrity": "sha512-UPLqCYey+jn5Mf57KFDwxD/7VZYDsbYUi3iyTehLFVjlbvl/JcUTPaot8uKNYLO0EoZpey+rC/s5AF3VxfeC2Q==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/express": { "version": "4.17.17", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", @@ -377,6 +533,12 @@ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "node_modules/@types/jsonfile": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", @@ -414,6 +576,24 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" }, + "node_modules/@types/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-itzxtaBgk4OMbrCawVCvas934waMZWjW17v7EYgFVlfYS/cl0/P7KZdojWCq9SDJMI5cnLQLUP8ayhVCTY8TEg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/nodemailer": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.7.tgz", + "integrity": "sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -434,6 +614,12 @@ "@types/node": "*" } }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "node_modules/@types/serve-static": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", @@ -458,6 +644,299 @@ "@types/webidl-conversions": "*" } }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz", + "integrity": "sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/type-utils": "5.54.1", + "@typescript-eslint/utils": "5.54.1", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.1.tgz", + "integrity": "sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz", + "integrity": "sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz", + "integrity": "sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.54.1", + "@typescript-eslint/utils": "5.54.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.1.tgz", + "integrity": "sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz", + "integrity": "sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.1.tgz", + "integrity": "sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz", + "integrity": "sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.54.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -486,6 +965,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/acorn-node": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", @@ -559,6 +1047,21 @@ "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/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -597,6 +1100,12 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "node_modules/arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", @@ -615,6 +1124,15 @@ "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/arraybuffer-to-string": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/arraybuffer-to-string/-/arraybuffer-to-string-1.0.2.tgz", @@ -799,6 +1317,18 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/brfs": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz", @@ -899,11 +1429,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, + "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/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -936,6 +1491,24 @@ "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/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -1068,6 +1641,20 @@ "node": ">= 0.10" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -1198,6 +1785,30 @@ "node": ">=0.8.0" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -1375,6 +1986,18 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/escodegen": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", @@ -1396,6 +2019,224 @@ "source-map": "~0.6.1" } }, + "node_modules/eslint": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", + "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^2.0.0", + "@eslint/js": "8.35.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1408,6 +2249,48 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -1545,6 +2428,34 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/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, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "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", @@ -1555,6 +2466,27 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/file-type": { "version": "10.11.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", @@ -1563,6 +2495,18 @@ "node": ">=6" } }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -1580,6 +2524,41 @@ "node": ">= 0.8" } }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "node_modules/flatten-vertex-data": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", @@ -1769,6 +2748,53 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -1809,6 +2835,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -1841,6 +2873,15 @@ "node": ">= 0.4.0" } }, + "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/has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -1971,6 +3012,15 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/image-pixels": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/image-pixels/-/image-pixels-1.1.1.tgz", @@ -2015,6 +3065,31 @@ "node": ">=6" } }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2122,6 +3197,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "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", @@ -2144,6 +3228,36 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/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": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-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-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -2190,6 +3304,12 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -2220,6 +3340,28 @@ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz", "integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==" }, + "node_modules/js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -2240,6 +3382,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -2295,6 +3443,21 @@ "node": ">= 0.8.0" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2316,11 +3479,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "node_modules/lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==" - }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -2405,6 +3563,15 @@ "node": ">=0.10.0" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -2413,6 +3580,19 @@ "node": ">= 0.6" } }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mii-js": { "version": "1.0.4", "resolved": "git+ssh://git@github.com/PretendoNetwork/mii-js.git#5d8eb8013514a13b0df6eb4a5bfd8b5a63fb9861", @@ -2685,6 +3865,18 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -2745,7 +3937,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", - "dev": true, "dependencies": { "asn1": "^0.2.4" } @@ -2874,6 +4065,48 @@ "node": ">=8" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-rect": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parse-rect/-/parse-rect-1.2.0.tgz", @@ -2890,6 +4123,15 @@ "node": ">= 0.8" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -2898,6 +4140,15 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -2908,6 +4159,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -2918,6 +4178,18 @@ "resolved": "https://registry.npmjs.org/pick-by-alias/-/pick-by-alias-1.2.0.tgz", "integrity": "sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw==" }, + "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" + } + }, "node_modules/pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -3017,6 +4289,26 @@ "node": ">=0.4.x" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + } + ] + }, "node_modules/quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -3104,6 +4396,18 @@ "@redis/time-series": "1.0.4" } }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -3173,6 +4477,15 @@ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", @@ -3189,6 +4502,16 @@ "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz", "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg==" }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/revalidator": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", @@ -3212,6 +4535,29 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -3338,6 +4684,27 @@ "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -3361,6 +4728,15 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -3555,6 +4931,30 @@ "node": ">=8" } }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -3582,6 +4982,12 @@ "node": ">=10" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "node_modules/tga": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/tga/-/tga-1.0.7.tgz", @@ -3640,6 +5046,18 @@ "string-to-arraybuffer": "^1.0.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, + "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", @@ -3671,6 +5089,27 @@ "node": ">=12" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -3703,6 +5142,18 @@ "node": ">= 0.8.0" } }, + "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", @@ -3720,6 +5171,19 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -3845,6 +5309,21 @@ "node": ">=12" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/which-typed-array": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", @@ -3976,6 +5455,18 @@ "resolved": "https://registry.npmjs.org/yesno/-/yesno-0.4.0.tgz", "integrity": "sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==", "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } }, "dependencies": { @@ -3985,6 +5476,46 @@ "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true }, + "@eslint/eslintrc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", + "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", + "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", + "dev": true + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -3998,6 +5529,52 @@ "@hapi/hoek": "^9.0.0" } }, + "@hcaptcha/types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@hcaptcha/types/-/types-1.0.3.tgz", + "integrity": "sha512-1mbU6eSGawRrqeahRrOzZo/SVLI6oZ5/azuBpSyVrRRR96CnS3fOVDWfzxpngfxKD0/I9Rwu6c/3ITqD8rXeTQ==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@mapbox/node-pre-gyp": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.10.tgz", @@ -4014,6 +5591,32 @@ "tar": "^6.1.11" } }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, "@oozcitak/dom": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-0.0.11.tgz", @@ -4196,15 +5799,6 @@ "@types/responselike": "^1.0.0" } }, - "@types/colors": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/colors/-/colors-1.2.1.tgz", - "integrity": "sha512-7jNkpfN2lVO07nJ1RWzyMnNhH/I5N9iWuMPx9pedptxJ4MODf8rRV0lbJi6RakQ4sKQk231Fw4e2W9n3D7gZ3w==", - "dev": true, - "requires": { - "colors": "*" - } - }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -4214,6 +5808,15 @@ "@types/node": "*" } }, + "@types/dicer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@types/dicer/-/dicer-0.2.2.tgz", + "integrity": "sha512-UPLqCYey+jn5Mf57KFDwxD/7VZYDsbYUi3iyTehLFVjlbvl/JcUTPaot8uKNYLO0EoZpey+rC/s5AF3VxfeC2Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/express": { "version": "4.17.17", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", @@ -4252,6 +5855,12 @@ "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, "@types/jsonfile": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/@types/jsonfile/-/jsonfile-6.1.1.tgz", @@ -4289,6 +5898,24 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", "integrity": "sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA==" }, + "@types/node-rsa": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/node-rsa/-/node-rsa-1.1.1.tgz", + "integrity": "sha512-itzxtaBgk4OMbrCawVCvas934waMZWjW17v7EYgFVlfYS/cl0/P7KZdojWCq9SDJMI5cnLQLUP8ayhVCTY8TEg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/nodemailer": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.7.tgz", + "integrity": "sha512-f5qCBGAn/f0qtRcd4SEn88c8Fp3Swct1731X4ryPKqS61/A3LmmzN8zaEz7hneJvpjFbUUgY7lru/B/7ODTazg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -4309,6 +5936,12 @@ "@types/node": "*" } }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, "@types/serve-static": { "version": "1.15.1", "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", @@ -4333,6 +5966,185 @@ "@types/webidl-conversions": "*" } }, + "@typescript-eslint/eslint-plugin": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.1.tgz", + "integrity": "sha512-a2RQAkosH3d3ZIV08s3DcL/mcGc2M/UC528VkPULFxR9VnVPT8pBu0IyBAJJmVsCmhVfwQX1v6q+QGnmSe1bew==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/type-utils": "5.54.1", + "@typescript-eslint/utils": "5.54.1", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.1.tgz", + "integrity": "sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz", + "integrity": "sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.54.1.tgz", + "integrity": "sha512-WREHsTz0GqVYLIbzIZYbmUUr95DKEKIXZNH57W3s+4bVnuF1TKe2jH8ZNH8rO1CeMY3U4j4UQeqPNkHMiGem3g==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.54.1", + "@typescript-eslint/utils": "5.54.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/types": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.54.1.tgz", + "integrity": "sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz", + "integrity": "sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/visitor-keys": "5.54.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.54.1.tgz", + "integrity": "sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.54.1", + "@typescript-eslint/types": "5.54.1", + "@typescript-eslint/typescript-estree": "5.54.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.54.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz", + "integrity": "sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.54.1", + "eslint-visitor-keys": "^3.3.0" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -4352,6 +6164,13 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, "acorn-node": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", @@ -4406,6 +6225,15 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, + "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" + } + }, "aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", @@ -4440,6 +6268,12 @@ } } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", @@ -4455,6 +6289,12 @@ "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==" }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "arraybuffer-to-string": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/arraybuffer-to-string/-/arraybuffer-to-string-1.0.2.tgz", @@ -4601,6 +6441,15 @@ "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" + } + }, "brfs": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/brfs/-/brfs-2.0.2.tgz", @@ -4680,11 +6529,27 @@ "get-intrinsic": "^1.0.2" } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" }, + "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" + } + }, "chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -4708,6 +6573,21 @@ "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 + }, "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -4818,6 +6698,17 @@ "vary": "^1" } }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, "cycle": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", @@ -4913,6 +6804,24 @@ "streamsearch": "0.1.2" } }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "dotenv": { "version": "16.0.3", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.3.tgz", @@ -5075,6 +6984,12 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, "escodegen": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", @@ -5087,11 +7002,209 @@ "source-map": "~0.6.1" } }, + "eslint": { + "version": "8.35.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", + "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^2.0.0", + "@eslint/js": "8.35.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + } + } + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + }, + "espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + } + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", @@ -5210,6 +7323,30 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "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" + } + } + } + }, "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", @@ -5220,11 +7357,38 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "file-type": { "version": "10.11.0", "resolved": "https://registry.npmjs.org/file-type/-/file-type-10.11.0.tgz", "integrity": "sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw==" }, + "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", @@ -5239,6 +7403,32 @@ "unpipe": "~1.0.0" } }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, "flatten-vertex-data": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flatten-vertex-data/-/flatten-vertex-data-1.0.2.tgz", @@ -5388,6 +7578,38 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -5419,6 +7641,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -5441,6 +7669,12 @@ "function-bind": "^1.1.1" } }, + "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 + }, "has-symbols": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", @@ -5537,6 +7771,12 @@ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, "image-pixels": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/image-pixels/-/image-pixels-1.1.1.tgz", @@ -5578,6 +7818,22 @@ "file-type": "^10.9.0" } }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -5644,6 +7900,12 @@ "has": "^1.0.3" } }, + "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", @@ -5657,6 +7919,27 @@ "has-tostringtag": "^1.0.0" } }, + "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-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-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", @@ -5694,6 +7977,12 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -5721,6 +8010,21 @@ "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.3.7.tgz", "integrity": "sha512-9IXdWudL61npZjvLuVe/ktHiA41iE8qFyLB+4VDTblEsWBzeg8WQTlktdUK4CdncUqtUgUg0bbOmTE2bKBKaBQ==" }, + "js-sdsl": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", + "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -5741,6 +8045,12 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -5787,6 +8097,15 @@ "type-check": "~0.3.2" } }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -5808,11 +8127,6 @@ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, - "lodash.set": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", - "integrity": "sha512-4hNPN5jlm/N/HLMCO43v8BXKq9Z7QdAGc/VGrRD61w8gN9g/6jF9A4L1pbUgBLCffi0w9VsXfTOij5x8iTyFvg==" - }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -5880,11 +8194,27 @@ } } }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, "mii-js": { "version": "git+ssh://git@github.com/PretendoNetwork/mii-js.git#5d8eb8013514a13b0df6eb4a5bfd8b5a63fb9861", "from": "mii-js@github:PretendoNetwork/mii-js", @@ -6005,7 +8335,7 @@ }, "mongoose-unique-validator": { "version": "git+ssh://git@github.com/stenneepro/mongoose-unique-validator.git#1cd976b70ddd8e8e65fed1d9a387677713a8d177", - "from": "mongoose-unique-validator@https://github.com/stenneepro/mongoose-unique-validator.git#bump/mongoose7", + "from": "mongoose-unique-validator@github:stenneepro/mongoose-unique-validator#bump/mongoose7", "requires": { "lodash.foreach": "^4.1.0", "lodash.get": "^4.0.2", @@ -6073,6 +8403,18 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6121,7 +8463,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/node-rsa/-/node-rsa-1.1.1.tgz", "integrity": "sha512-Jd4cvbJMryN21r5HgxQOpMEqv+ooke/korixNNK3mGqfGJmy0M77WDDzo/05969+OkMy3XW1UuZsSmW9KQm7Fw==", - "dev": true, "requires": { "asn1": "^0.2.4" } @@ -6214,6 +8555,33 @@ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parse-rect": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/parse-rect/-/parse-rect-1.2.0.tgz", @@ -6227,11 +8595,23 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", @@ -6242,6 +8622,12 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", @@ -6252,6 +8638,12 @@ "resolved": "https://registry.npmjs.org/pick-by-alias/-/pick-by-alias-1.2.0.tgz", "integrity": "sha512-ESj2+eBxhGrcA1azgHs7lARG5+5iLakc/6nlfbpjcLl00HuuUOIuORhYXN4D1HfvMSKuVtFQjAlnwi1JHEeDIw==" }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, "pngjs": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", @@ -6326,6 +8718,12 @@ "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "quick-lru": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", @@ -6397,6 +8795,12 @@ "@redis/time-series": "1.0.4" } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -6451,6 +8855,12 @@ "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "responselike": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", @@ -6464,6 +8874,12 @@ "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz", "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg==" }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "revalidator": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", @@ -6478,6 +8894,15 @@ "glob": "^7.1.3" } }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -6577,6 +9002,21 @@ "resolved": "https://registry.npmjs.org/shallow-copy/-/shallow-copy-0.0.1.tgz", "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==" }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -6597,6 +9037,12 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -6760,6 +9206,21 @@ "ansi-regex": "^5.0.1" } }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "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" + } + }, "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -6778,6 +9239,12 @@ "yallist": "^4.0.0" } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "tga": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/tga/-/tga-1.0.7.tgz", @@ -6835,6 +9302,15 @@ "string-to-arraybuffer": "^1.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", @@ -6857,6 +9333,21 @@ "punycode": "^2.1.1" } }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -6883,6 +9374,12 @@ "prelude-ls": "~1.1.2" } }, + "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", @@ -6897,6 +9394,12 @@ "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -6999,6 +9502,15 @@ "webidl-conversions": "^7.0.0" } }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, "which-typed-array": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", @@ -7107,6 +9619,12 @@ "resolved": "https://registry.npmjs.org/yesno/-/yesno-0.4.0.tgz", "integrity": "sha512-tdBxmHvbXPBKYIg81bMCB7bVeDmHkRzk5rVJyYYXurwKkHq/MCd8rz4HSJUP7hW0H2NlXiq8IFiWvYKEHhlotA==", "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true } } } diff --git a/package.json b/package.json index b03b646..f97be5c 100644 --- a/package.json +++ b/package.json @@ -40,13 +40,12 @@ "hcaptcha": "^0.1.0", "image-pixels": "^1.1.1", "joi": "^17.8.3", - "lodash.get": "^4.4.2", - "lodash.set": "^4.3.2", "mii-js": "github:PretendoNetwork/mii-js", "moment": "^2.29.4", "mongoose": "^7.0.0", "mongoose-unique-validator": "github:stenneepro/mongoose-unique-validator#bump/mongoose7", "morgan": "^1.9.1", + "node-rsa": "^1.0.7", "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", @@ -55,13 +54,19 @@ "xmlbuilder2": "0.0.4" }, "devDependencies": { - "@types/colors": "^1.2.1", + "@hcaptcha/types": "^1.0.3", + "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", "@types/morgan": "^1.9.4", "@types/node": "^18.14.4", - "node-rsa": "^1.0.7", + "@types/node-rsa": "^1.1.1", + "@types/nodemailer": "^6.4.7", + "@typescript-eslint/eslint-plugin": "^5.54.1", + "@typescript-eslint/parser": "^5.54.1", + "eslint": "^8.35.0", "prompt": "^1.0.0", + "typescript": "^4.9.5", "yesno": "^0.4.0" } } diff --git a/src/cache.ts b/src/cache.ts index 5049b67..7da86d2 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -2,15 +2,15 @@ import fs from 'fs-extra'; import redis from 'redis'; import { config, disabledFeatures } from '@/config-manager'; -let client; +let client: redis.RedisClientType; -const memoryCache = {}; +const memoryCache: { [key: string]: Buffer } = {}; -const SERVICE_CERTS_BASE = `${__dirname}/../certs/service`; -const NEX_CERTS_BASE = `${__dirname}/../certs/nex`; -const LOCAL_CDN_BASE = `${__dirname}/../cdn`; +const SERVICE_CERTS_BASE: string = `${__dirname}/../certs/service`; +const NEX_CERTS_BASE: string = `${__dirname}/../certs/nex`; +const LOCAL_CDN_BASE: string = `${__dirname}/../cdn`; -export async function connect() { +export async function connect(): Promise { if (!disabledFeatures.redis) { client = redis.createClient(config.redis.client); client.on('error', (err) => console.log('Redis Client Error', err)); @@ -19,7 +19,7 @@ export async function connect() { } } -export async function setCachedFile(fileName, value) { +export async function setCachedFile(fileName: string, value: Buffer): Promise { if (disabledFeatures.redis) { memoryCache[fileName] = value; } else { @@ -27,17 +27,16 @@ export async function setCachedFile(fileName, value) { } } -export async function getCachedFile(fileName, encoding?) { - let cachedFile; +export async function getCachedFile(fileName: string, encoding?: BufferEncoding): Promise { + let cachedFile: Buffer; if (disabledFeatures.redis) { cachedFile = memoryCache[fileName] || null; } else { - cachedFile = await client.get(fileName); - } - - if (cachedFile !== null) { - cachedFile = Buffer.from(cachedFile, encoding); + const redisValue: string = await client.get(fileName); + if (redisValue) { + cachedFile = Buffer.from(redisValue, encoding); + } } return cachedFile; @@ -45,33 +44,33 @@ export async function getCachedFile(fileName, encoding?) { // * NEX server cache functions -export async function getNEXPublicKey(name, encoding?) { - let publicKey = await getCachedFile(`nex:${name}:public_key`, encoding); +export async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise { + let publicKey: Buffer = await getCachedFile(`nex:${name}:public_key`, encoding); if (publicKey === null) { - publicKey = await fs.readFile(`${NEX_CERTS_BASE}/${name}/public.pem`, { encoding }); + publicKey = await fs.readFile(`${NEX_CERTS_BASE}/${name}/public.pem`); await setNEXPublicKey(name, publicKey); } return publicKey; } -export async function getNEXPrivateKey(name, encoding?) { - let privateKey = await getCachedFile(`nex:${name}:private_key`, encoding); +export async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promise { + let privateKey: Buffer = await getCachedFile(`nex:${name}:private_key`, encoding); if (privateKey === null) { - privateKey = await fs.readFile(`${NEX_CERTS_BASE}/${name}/private.pem`, { encoding }); + privateKey = await fs.readFile(`${NEX_CERTS_BASE}/${name}/private.pem`); await setNEXPrivateKey(name, privateKey); } return privateKey; } -export async function getNEXSecretKey(name, encoding?) { - let secretKey = await getCachedFile(`nex:${name}:secret_key`, encoding); +export async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise { + let secretKey: Buffer = await getCachedFile(`nex:${name}:secret_key`, encoding); if (secretKey === null) { - const fileBuffer = await fs.readFile(`${NEX_CERTS_BASE}/${name}/secret.key`, { encoding: 'utf8' }); + const fileBuffer: string = await fs.readFile(`${NEX_CERTS_BASE}/${name}/secret.key`, { encoding: 'utf8' }); secretKey = Buffer.from(fileBuffer, encoding); await setNEXSecretKey(name, secretKey); } @@ -79,11 +78,11 @@ export async function getNEXSecretKey(name, encoding?) { return secretKey; } -export async function getNEXAESKey(name, encoding?) { - let aesKey = await getCachedFile(`nex:${name}:aes_key`, encoding); +export async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { + let aesKey: Buffer = await getCachedFile(`nex:${name}:aes_key`, encoding); if (aesKey === null) { - const fileBuffer = await fs.readFile(`${NEX_CERTS_BASE}/${name}/aes.key`, { encoding: 'utf8' }); + const fileBuffer: string = await fs.readFile(`${NEX_CERTS_BASE}/${name}/aes.key`, { encoding: 'utf8' }); aesKey = Buffer.from(fileBuffer, encoding); await setNEXAESKey(name, aesKey); } @@ -91,51 +90,51 @@ export async function getNEXAESKey(name, encoding?) { return aesKey; } -export async function setNEXPublicKey(name, value) { +export async function setNEXPublicKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:public_key`, value); } -export async function setNEXPrivateKey(name, value) { +export async function setNEXPrivateKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:private_key`, value); } -export async function setNEXSecretKey(name, value) { +export async function setNEXSecretKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:secret_key`, value); } -export async function setNEXAESKey(name, value) { +export async function setNEXAESKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:aes_key`, value); } // * 3rd party service cache functions -export async function getServicePublicKey(name, encoding?) { - let publicKey = await getCachedFile(`service:${name}:public_key`, encoding); +export async function getServicePublicKey(name: string, encoding?: BufferEncoding): Promise { + let publicKey: Buffer = await getCachedFile(`service:${name}:public_key`, encoding); if (publicKey === null) { - publicKey = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/public.pem`, { encoding }); + publicKey = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/public.pem`); await setServicePublicKey(name, publicKey); } return publicKey; } -export async function getServicePrivateKey(name, encoding?) { - let privateKey = await getCachedFile(`service:${name}:private_key`, encoding); +export async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Promise { + let privateKey: Buffer = await getCachedFile(`service:${name}:private_key`, encoding); if (privateKey === null) { - privateKey = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/private.pem`, { encoding }); + privateKey = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/private.pem`); await setServicePrivateKey(name, privateKey); } return privateKey; } -export async function getServiceSecretKey(name, encoding?) { - let secretKey = await getCachedFile(`service:${name}:secret_key`, encoding); +export async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Promise { + let secretKey: Buffer = await getCachedFile(`service:${name}:secret_key`, encoding); if (secretKey === null) { - const fileBuffer = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/secret.key`, { encoding: 'utf8' }); + const fileBuffer: string = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/secret.key`, { encoding: 'utf8' }); secretKey = Buffer.from(fileBuffer, encoding); await setServiceSecretKey(name, secretKey); } @@ -143,11 +142,11 @@ export async function getServiceSecretKey(name, encoding?) { return secretKey; } -export async function getServiceAESKey(name, encoding?) { - let aesKey = await getCachedFile(`service:${name}:aes_key`, encoding); +export async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promise { + let aesKey: Buffer = await getCachedFile(`service:${name}:aes_key`, encoding); if (aesKey === null) { - const fileBuffer = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/aes.key`, { encoding: 'utf8' }); + const fileBuffer: string = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/aes.key`, { encoding: 'utf8' }); aesKey = Buffer.from(fileBuffer, encoding); await setServiceAESKey(name, aesKey); } @@ -155,30 +154,31 @@ export async function getServiceAESKey(name, encoding?) { return aesKey; } -export async function setServicePublicKey(name, value) { +export async function setServicePublicKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:public_key`, value); } -export async function setServicePrivateKey(name, value) { +export async function setServicePrivateKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:private_key`, value); } -export async function setServiceSecretKey(name, value) { +export async function setServiceSecretKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:secret_key`, value); } -export async function setServiceAESKey(name, value) { +export async function setServiceAESKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:aes_key`, value); } // * Local CDN cache functions -export async function getLocalCDNFile(name, encoding?) { - let file = await getCachedFile(`local_cdn:${name}`, encoding); +export async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise { + let file: Buffer = await getCachedFile(`local_cdn:${name}`, encoding); if (file === null) { if (await fs.pathExists(`${LOCAL_CDN_BASE}/${name}`)) { - file = await fs.readFile(`${LOCAL_CDN_BASE}/${name}`, { encoding }); + const fileBuffer: string = await fs.readFile(`${LOCAL_CDN_BASE}/${name}`, { encoding }); + file = Buffer.from(fileBuffer); await setLocalCDNFile(name, file); } } @@ -186,7 +186,7 @@ export async function getLocalCDNFile(name, encoding?) { return file; } -export async function setLocalCDNFile(name, value) { +export async function setLocalCDNFile(name: string, value: Buffer): Promise { await setCachedFile(`local_cdn:${name}`, value); } diff --git a/src/database.ts b/src/database.ts index dc3a31b..0bd36bb 100644 --- a/src/database.ts +++ b/src/database.ts @@ -6,87 +6,94 @@ import { PNID } from '@/models/pnid'; import { Server } from '@/models/server'; import logger from '@/logger'; import { config } from '@/config-manager'; -import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; +import { HydratedDeviceDocument } from '@/types/mongoose/device'; +import { HydratedServerDocument } from '@/types/mongoose/server'; +import { Token } from '@/types/common/token'; +import { PNIDProfile } from '@/types/services/nnid/pnid-profile'; +import { ConnectionData } from '@/types/services/api/connection-data'; +import { ConnectionResponse } from '@/types/services/api/connection-response'; +import { DiscordConnectionData } from '@/types/services/api/discord-connection-data'; -const { connection_string, options } = config.mongoose; +const connection_string: string = config.mongoose.connection_string; +const options: mongoose.ConnectOptions = config.mongoose.options; // TODO: Extend this later with more settings -const discordConnectionSchema = joi.object({ +const discordConnectionSchema: joi.ObjectSchema = joi.object({ id: joi.string() }); -let _connection; +let _connection: mongoose.Connection; -export async function connect() { +export async function connect(): Promise { await mongoose.connect(connection_string, options); _connection = mongoose.connection; _connection.on('error', console.error.bind(console, 'connection error:')); } -export function connection() { +export function connection(): mongoose.Connection { return _connection; } -function verifyConnected() { +function verifyConnected(): void { if (!connection()) { throw new Error('Cannot make database requets without being connected'); } } -export async function getUserByUsername(username) { +export async function getUserByUsername(username: string): Promise { verifyConnected(); if (typeof username !== 'string') { return null; } - const user = await PNID.findOne({ + return await PNID.findOne({ usernameLower: username.toLowerCase() - }) as mongoose.HydratedDocument; - - return user; + }) as HydratedPNIDDocument; } -export async function getUserByPID(pid) { +export async function getUserByPID(pid: number): Promise { verifyConnected(); - const user = await PNID.findOne({ + return await PNID.findOne({ pid - }) as mongoose.HydratedDocument; - - return user; + }) as HydratedPNIDDocument; } -export async function getUserByEmailAddress(email) { +export async function getUserByEmailAddress(email: string): Promise { verifyConnected(); - const user = await PNID.findOne({ + return await PNID.findOne({ 'email.address': new RegExp(email, 'i') // * Ignore case - }) as mongoose.HydratedDocument; - - return user; + }) as HydratedPNIDDocument; } -export async function doesUserExist(username) { +export async function doesUserExist(username: string): Promise { verifyConnected(); return !!await getUserByUsername(username); } -export async function getUserBasic(token) { +export async function getUserBasic(token: string): Promise { verifyConnected(); // * Wii U sends Basic auth as `username password`, where the password may not have spaces // * This is not to spec, but that is the consoles fault not ours - const [username, password] = Buffer.from(token, 'base64').toString().split(' '); - const user = await getUserByUsername(username); + const decoded: string = Buffer.from(token, 'base64').toString(); + const parts: string[] = decoded.split(' '); + + const username: string = parts[0]; + const password: string = parts[1]; + + const user: HydratedPNIDDocument = await getUserByUsername(username); if (!user) { return null; } - const hashedPassword = util.nintendoPasswordHash(password, user.pid); + const hashedPassword: string = util.nintendoPasswordHash(password, user.pid); if (!bcrypt.compareSync(hashedPassword, user.password)) { return null; @@ -95,17 +102,17 @@ export async function getUserBasic(token) { return user; } -export async function getUserBearer(token) { +export async function getUserBearer(token: string): Promise { verifyConnected(); try { - const decryptedToken = await util.decryptToken(Buffer.from(token, 'base64')); - const unpackedToken = util.unpackToken(decryptedToken); + const decryptedToken: Buffer = await util.decryptToken(Buffer.from(token, 'base64')); + const unpackedToken: Token = util.unpackToken(decryptedToken); - const user = await getUserByPID(unpackedToken.pid); + const user: HydratedPNIDDocument = await getUserByPID(unpackedToken.pid); if (user) { - const expireTime = Math.floor((Number(unpackedToken.expire_time) / 1000)); + const expireTime: number = Math.floor((Number(unpackedToken.expire_time) / 1000)); if (Math.floor(Date.now() / 1000) > expireTime) { return null; @@ -113,40 +120,38 @@ export async function getUserBearer(token) { } return user; - } catch (error) { + } catch (error: any) { // TODO: Handle error logger.error(error); return null; } } -export async function getUserProfileJSONByPID(pid) { +export async function getUserProfileJSONByPID(pid: number): Promise { verifyConnected(); - const user = await getUserByPID(pid); - const device = user.get('devices')[0]; // * Just grab the first device - let device_attributes; + const user: HydratedPNIDDocument = await getUserByPID(pid); + const device: HydratedDeviceDocument = user.get('devices')[0]; // * Just grab the first device + let device_attributes: [{ + device_attribute: { + name: string; + value: string; + created_date: string; + }; + }]; if (device) { - device_attributes = device.get('device_attributes').map(({name, value, created_date}) => { - const deviceAttributeDocument = { + device_attributes = device.get('device_attributes').map(({name, value, created_date}) => ({ + device_attribute: { name, value, - created_date: '' - }; - - if (created_date) { - deviceAttributeDocument.created_date = created_date; + created_date: created_date ? created_date : '' } - - return { - device_attribute: deviceAttributeDocument - }; - }); + })); } - const userObject = { - //accounts: {}, We need to figure this out, no idea what these values mean or what they do + return { + //accounts: {}, // * We need to figure this out, no idea what these values mean or what they do active_flag: user.get('flags.active') ? 'Y' : 'N', birth_date: user.get('birthdate'), country: user.get('country'), @@ -167,7 +172,7 @@ export async function getUserProfileJSONByPID(pid) { type: 'DEFAULT', updated_by: 'USER', // * Can also be INTERNAL WS, don't know the difference validated: user.get('email.validated') ? 'Y' : 'N', - validated_date: '' + validated_date: user.get('email.validated') ? user.get('email.validated_date') : '' }, mii: { status: 'COMPLETED', @@ -192,39 +197,33 @@ export async function getUserProfileJSONByPID(pid) { user_id: user.get('username'), utc_offset: user.get('timezone.offset') }; - - if (user.get('email.validated')) { - userObject.email.validated_date = user.get('email.validated_date'); - } - - return userObject; } -function getServer(gameServerId, accessMode) { - return Server.findOne({ +export async function getServer(gameServerId: string, accessMode: string): Promise { + return await Server.findOne({ game_server_id: gameServerId, - access_mode: accessMode, + access_mode: accessMode }); } -function getServerByTitleId(titleId, accessMode) { - return Server.findOne({ +export async function getServerByTitleId(titleId: string, accessMode: string): Promise { + return await Server.findOne({ title_ids: titleId, - access_mode: accessMode, + access_mode: accessMode }); } -export async function addUserConnection(pnid, data, type) { +export async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { if (type === 'discord') { return await addUserConnectionDiscord(pnid, data); } } -export async function addUserConnectionDiscord(pnid, data) { - const valid = discordConnectionSchema.validate(data); +export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { + const valid: joi.ValidationResult = discordConnectionSchema.validate(data); if (valid.error) { - return { + return { app: 'api', status: 400, error: 'Invalid or missing connection data' @@ -237,27 +236,27 @@ export async function addUserConnectionDiscord(pnid, data) { } }); - return { + return { app: 'api', status: 200 }; } -export async function removeUserConnection(pnid, type) { +export async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { // * Add more connections later? if (type === 'discord') { return await removeUserConnectionDiscord(pnid); } } -export async function removeUserConnectionDiscord(pnid) { +export async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { await PNID.updateOne({ pid: pnid.get('pid') }, { $set: { 'connections.discord.id': '' } }); - return { + return { app: 'api', status: 200 }; diff --git a/src/logger.ts b/src/logger.ts index 6d9cacf..64435a2 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -3,10 +3,10 @@ import colors from 'colors'; colors.enable(); -const root = process.env.PN_ACT_LOGGER_PATH ? process.env.PN_ACT_LOGGER_PATH : `${__dirname}/..`; +const root: string = process.env.PN_ACT_LOGGER_PATH ? process.env.PN_ACT_LOGGER_PATH : `${__dirname}/..`; fs.ensureDirSync(`${root}/logs`); -const streams = { +const streams: { [key: string]: fs.WriteStream } = { latest: fs.createWriteStream(`${root}/logs/latest.log`), success: fs.createWriteStream(`${root}/logs/success.log`), error: fs.createWriteStream(`${root}/logs/error.log`), @@ -14,32 +14,32 @@ const streams = { info: fs.createWriteStream(`${root}/logs/info.log`) }; -function success(input) { - const time = new Date(); +function success(input: string): void { + const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [SUCCESS]: ${input}`; streams.success.write(`${input}\n`); console.log(`${input}`.green.bold); } -function error(input) { - const time = new Date(); +function error(input: string): void { + const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [ERROR]: ${input}`; streams.error.write(`${input}\n`); console.log(`${input}`.red.bold); } -function warn(input) { - const time = new Date(); +function warn(input: string): void { + const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [WARN]: ${input}`; streams.warn.write(`${input}\n`); console.log(`${input}`.yellow.bold); } -function info(input) { - const time = new Date(); +function info(input: string): void { + const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [INFO]: ${input}`; streams.info.write(`${input}\n`); diff --git a/src/mailer.ts b/src/mailer.ts index c39d039..fd39b85 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -2,21 +2,22 @@ import path from 'node:path'; import fs from 'node:fs'; import nodemailer from 'nodemailer'; import { config, disabledFeatures } from '@/config-manager'; +import { MailerOptions } from '@/types/common/mailer-options'; -const genericEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8'); -const confirmationEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8'); +const genericEmailTemplate: string = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8'); +const confirmationEmailTemplate: string = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8'); -let transporter; +let transporter: nodemailer.Transporter; if (!disabledFeatures.email) { transporter = nodemailer.createTransport(config.email); } -export async function sendMail(options) { +export async function sendMail(options: MailerOptions): Promise { if (!disabledFeatures.email) { const { to, subject, username, paragraph, preview, text, link, confirmation } = options; - let html = confirmation ? confirmationEmailTemplate : genericEmailTemplate; + let html: string = confirmation ? confirmationEmailTemplate : genericEmailTemplate; html = html.replace(/{{username}}/g, username); html = html.replace(/{{paragraph}}/g, paragraph); @@ -27,7 +28,7 @@ export async function sendMail(options) { if (link) { const { href, text } = link; - const button = ` ${text}` + const button: string = ` ${text}` html = html.replace(//g, button); } diff --git a/src/middleware/api.ts b/src/middleware/api.ts index cbf942d..67edf9d 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -1,15 +1,16 @@ -import xmlbuilder from 'xmlbuilder'; +import express from 'express'; import database from '@/database'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -export async function APIMiddleware(request, _response, next) { - const { headers } = request; +export async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { + const authHeader: string = request.headers.authorization; - if (!headers.authorization || !(headers.authorization.startsWith('Bearer'))) { + if (!authHeader || !(authHeader.startsWith('Bearer'))) { return next(); } - const token = headers.authorization.split(' ')[1]; - const user = await database.getUserBearer(token); + const token: string = authHeader.split(' ')[1]; + const user: HydratedPNIDDocument = await database.getUserBearer(token); request.pnid = user; diff --git a/src/middleware/cemu.ts b/src/middleware/cemu.ts index 22f3e73..029e861 100644 --- a/src/middleware/cemu.ts +++ b/src/middleware/cemu.ts @@ -1,5 +1,7 @@ -export async function CemuMiddleware(request, _response, next) { - const subdomain = request.subdomains.reverse().join('.'); +import express from 'express'; + +export function CemuMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { + const subdomain: string = request.subdomains.reverse().join('.'); request.isCemu = subdomain === 'c.account'; diff --git a/src/middleware/client-header.ts b/src/middleware/client-header.ts index 7f7a581..1353c89 100644 --- a/src/middleware/client-header.ts +++ b/src/middleware/client-header.ts @@ -1,6 +1,7 @@ +import express from 'express'; import xmlbuilder from 'xmlbuilder'; -const VALID_CLIENT_ID_SECRET_PAIRS = { +const VALID_CLIENT_ID_SECRET_PAIRS: { [key: string]: string } = { // * 'Key' is the client ID, 'Value' is the client secret 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // * Possibly WiiU exclusive? 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // * Possibly 3DS exclusive? @@ -8,20 +9,21 @@ const VALID_CLIENT_ID_SECRET_PAIRS = { }; -export function nintendoClientHeaderCheck(request, response, next) { +export function nintendoClientHeaderCheck(request: express.Request, response: express.Response, next: express.NextFunction): void { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('X-Nintendo-Date', new Date().getTime().toString()); - const {headers} = request; + const clientId: string = request.headers['x-nintendo-client-id'] as string; + const clientSecret: string = request.headers['x-nintendo-client-secret'] as string; if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + !clientId || + !clientSecret || + !VALID_CLIENT_ID_SECRET_PAIRS[clientId] || + clientSecret !== VALID_CLIENT_ID_SECRET_PAIRS[clientId] ) { - return response.send(xmlbuilder.create({ + response.send(xmlbuilder.create({ errors: { error: { cause: 'client_id', @@ -30,6 +32,8 @@ export function nintendoClientHeaderCheck(request, response, next) { } } }).end()); + + return; } return next(); diff --git a/src/middleware/device-certificate.ts b/src/middleware/device-certificate.ts index dc4dcfa..7cc95a7 100644 --- a/src/middleware/device-certificate.ts +++ b/src/middleware/device-certificate.ts @@ -1,13 +1,13 @@ +import express from 'express'; import NintendoCertificate from '@/nintendo-certificate'; -export async function deviceCertificateMiddleware(request, _response, next) { - const { headers } = request; +export function deviceCertificateMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { + const certificate: string = request.headers['x-nintendo-device-cert'] as string; - if (!headers['x-nintendo-device-cert']) { + if (!certificate) { return next(); } - const certificate = headers['x-nintendo-device-cert']; request.certificate = new NintendoCertificate(certificate); return next(); diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index b718024..c3e5da6 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -1,15 +1,18 @@ import crypto from 'node:crypto'; -import { HydratedDocument } from 'mongoose'; +import express from 'express'; +import mongoose from 'mongoose'; import { Device } from '@/models/device'; import { NEXAccount } from '@/models/nex-account'; import util from '@/util'; import database from '@/database'; import NintendoCertificate from '@/nintendo-certificate'; import logger from '@/logger'; -import { INEXAccount, INEXAccountMethods } from '@/types/mongoose/nex-account'; +import { NASCRequestParams } from '@/types/services/nasc/request-params'; +import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; +import { HydratedDeviceDocument } from '@/types/mongoose/device'; -export async function NASCMiddleware(request, response, next) { - const requestParams = request.body; +export async function NASCMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { + const requestParams: NASCRequestParams = request.body; if (!requestParams.action || !requestParams.fcdcert || @@ -18,25 +21,26 @@ export async function NASCMiddleware(request, response, next) { !requestParams.titleid || !requestParams.servertype ) { - return response.status(200).send(util.nascError('null')); // This is what Nintendo sends + response.status(200).send(util.nascError('null')); // This is what Nintendo sends + return; } - const action = util.nintendoBase64Decode(requestParams.action).toString(); - const fcdcert = util.nintendoBase64Decode(requestParams.fcdcert); - const serialNumber = util.nintendoBase64Decode(requestParams.csnum).toString(); - const macAddress = util.nintendoBase64Decode(requestParams.macadr).toString(); - const titleID = util.nintendoBase64Decode(requestParams.titleid).toString(); - const environment = util.nintendoBase64Decode(requestParams.servertype).toString(); + const action: string = util.nintendoBase64Decode(requestParams.action).toString(); + const fcdcert: Buffer = util.nintendoBase64Decode(requestParams.fcdcert); + const serialNumber: string = util.nintendoBase64Decode(requestParams.csnum).toString(); + const macAddress: string = util.nintendoBase64Decode(requestParams.macadr).toString(); + const titleID: string = util.nintendoBase64Decode(requestParams.titleid).toString(); + const environment: string = util.nintendoBase64Decode(requestParams.servertype).toString(); - const macAddressHash = crypto.createHash('sha256').update(macAddress).digest('base64'); - const fcdcertHash = crypto.createHash('sha256').update(fcdcert).digest('base64'); + const macAddressHash: string = crypto.createHash('sha256').update(macAddress).digest('base64'); + const fcdcertHash: string = crypto.createHash('sha256').update(fcdcert).digest('base64'); - let pid; - let pidHmac; - let password; + let pid: number; + let pidHmac: string; + let password: string; if (requestParams.userid) { - pid = util.nintendoBase64Decode(requestParams.userid).toString(); + pid = Number(util.nintendoBase64Decode(requestParams.userid).toString()); } if (requestParams.uidhmac) { @@ -48,20 +52,23 @@ export async function NASCMiddleware(request, response, next) { } if (action !== 'LOGIN' && action !== 'SVCLOC') { - return response.status(200).send(util.nascError('null')); // This is what Nintendo sends + response.status(200).send(util.nascError('null')); // This is what Nintendo sends + return; } - const cert = new NintendoCertificate(fcdcert); + const cert: NintendoCertificate = new NintendoCertificate(fcdcert); if (!cert.valid) { - return response.status(200).send(util.nascError('121')); + response.status(200).send(util.nascError('121')); + return; } if (!validNintendoMACAddress(macAddress)) { - return response.status(200).send(util.nascError('null')); + response.status(200).send(util.nascError('null')); + return; } - let model; + let model: string; switch (serialNumber[0]) { case 'C': model = 'ctr'; @@ -84,10 +91,11 @@ export async function NASCMiddleware(request, response, next) { } if (!model) { - return response.status(200).send(util.nascError('null')); + response.status(200).send(util.nascError('null')); + return; } - let device = await Device.findOne({ + let device: HydratedDeviceDocument = await Device.findOne({ model, serial: serialNumber, environment, @@ -97,14 +105,16 @@ export async function NASCMiddleware(request, response, next) { if (device) { if (device.get('access_level') < 0) { - return response.status(200).send(util.nascError('102')); + response.status(200).send(util.nascError('102')); + return; } if (pid) { const linkedPIDs = device.get('linked_pids'); if (!linkedPIDs.includes(pid)) { - return response.status(200).send(util.nascError('102')); + response.status(200).send(util.nascError('102')); + return; } } } @@ -113,12 +123,12 @@ export async function NASCMiddleware(request, response, next) { if (password && !pid && !pidHmac) { // Register new user - const session = await database.connection().startSession(); + const session: mongoose.ClientSession = await database.connection().startSession(); await session.startTransaction(); try { // Create new NEX account - const nexAccount = await new NEXAccount({ + const nexAccount: HydratedNEXAccountDocument = await new NEXAccount({ device_type: '3ds', password }); @@ -127,7 +137,7 @@ export async function NASCMiddleware(request, response, next) { await nexAccount.save({ session }); - pid = nexAccount.get('pid'); + pid = Number(nexAccount.get('pid')); // Set password @@ -154,7 +164,8 @@ export async function NASCMiddleware(request, response, next) { await session.abortTransaction(); // 3DS expects 200 even on error - return response.status(200).send(util.nascError('102')); + response.status(200).send(util.nascError('102')); + return; } finally { // * This runs regardless of failure // * Returning on catch will not prevent this from running @@ -163,10 +174,11 @@ export async function NASCMiddleware(request, response, next) { } } - const nexUser = await NEXAccount.findOne({ pid }) as HydratedDocument; + const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ pid }); if (!nexUser || nexUser.get('access_level') < 0) { - return response.status(200).send(util.nascError('102')); + response.status(200).send(util.nascError('102')); + return; } request.nexUser = nexUser; @@ -176,7 +188,7 @@ export async function NASCMiddleware(request, response, next) { // https://www.adminsub.net/mac-address-finder/nintendo // Saves us from doing an OUI lookup each time -const NINTENDO_VENDER_OUIS = [ +const NINTENDO_VENDER_OUIS: string[] = [ 'ECC40D', 'E84ECE', 'E0F6B5', 'E0E751', 'E00C7F', 'DC68EB', 'D86BF7', 'D4F057', 'CCFB65', 'CC9E00', 'B8AE6E', 'B88AEC', 'B87826', 'A4C0E1', 'A45C27', 'A438CC', '9CE635', '98E8FA', @@ -202,10 +214,10 @@ const NINTENDO_VENDER_OUIS = [ ]; // TODO: Make something better -const MAC_REGEX = /^[0-9a-fA-F]{12}$/; +const MAC_REGEX: RegExp = /^[0-9a-fA-F]{12}$/; // Maybe should later parse more data out -function validNintendoMACAddress(macAddress) { +function validNintendoMACAddress(macAddress: string): boolean { if (!NINTENDO_VENDER_OUIS.includes(macAddress.substring(0, 6).toUpperCase())) { return false; } diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index 604b7de..0f8b323 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -1,15 +1,19 @@ +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import database from '@/database'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -export async function PNIDMiddleware(request, response, next) { - const { headers } = request; +export async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { + const authHeader: string = request.headers.authorization; - if (!headers.authorization || !(headers.authorization.startsWith('Bearer') || headers.authorization.startsWith('Basic'))) { + if (!authHeader || !(authHeader.startsWith('Bearer') || authHeader.startsWith('Basic'))) { return next(); } - let [type, token] = headers.authorization.split(' '); - let user; + const parts: string[] = authHeader.split(' '); + const type: string = parts[0]; + let token: string = parts[1]; + let user: HydratedPNIDDocument; if (request.isCemu) { token = Buffer.from(token, 'hex').toString('base64'); @@ -25,7 +29,7 @@ export async function PNIDMiddleware(request, response, next) { response.status(401); if (type === 'Bearer') { - return response.send(xmlbuilder.create({ + response.send(xmlbuilder.create({ errors: { error: { cause: 'access_token', @@ -34,9 +38,11 @@ export async function PNIDMiddleware(request, response, next) { } } }).end()); + + return; } - return response.send(xmlbuilder.create({ + response.send(xmlbuilder.create({ errors: { error: { code: '1105', @@ -44,10 +50,12 @@ export async function PNIDMiddleware(request, response, next) { } } }).end()); + + return; } if (user.get('access_level') < 0) { - return response.status(400).send(xmlbuilder.create({ + response.status(400).send(xmlbuilder.create({ errors: { error: { code: '0122', @@ -55,6 +63,8 @@ export async function PNIDMiddleware(request, response, next) { } } }).end()); + + return; } request.pnid = user; diff --git a/src/middleware/ratelimit.ts b/src/middleware/ratelimit.ts index ef213a5..e6909f2 100644 --- a/src/middleware/ratelimit.ts +++ b/src/middleware/ratelimit.ts @@ -1,11 +1,12 @@ import crypto from 'node:crypto'; +import express from 'express'; import ratelimit from 'express-rate-limit'; export default ratelimit({ windowMs: 60 * 1000, max: 1, - keyGenerator: request => { - const data = request.headers['x-nintendo-device-cert']; + keyGenerator: (request: express.Request) => { + const data: string = request.headers['x-nintendo-device-cert'] as string; return crypto.createHash('md5').update(data).digest('hex'); } }); \ No newline at end of file diff --git a/src/middleware/xml-parser.ts b/src/middleware/xml-parser.ts index b6cc5e2..f89b7f5 100644 --- a/src/middleware/xml-parser.ts +++ b/src/middleware/xml-parser.ts @@ -1,27 +1,29 @@ +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { document as xmlParser } from 'xmlbuilder2'; -export function XMLMiddleware(request, response, next) { +export function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void { if (request.method == 'POST' || request.method == 'PUT') { - const headers = request.headers; - let body = ''; + const contentType: string = request.headers['content-type']; + const contentLength: string = request.headers['content-length']; + let body: string = ''; if ( - !headers['content-type'] || - !headers['content-type'].toLowerCase().includes('xml') + !contentType || + !contentType.toLowerCase().includes('xml') ) { return next(); } if ( - !headers['content-length'] || - parseInt(headers['content-length']) === 0 + !contentLength || + parseInt(contentLength) === 0 ) { return next(); } request.setEncoding('utf-8'); - request.on('data', (chunk) => { + request.on('data', (chunk: string) => { body += chunk; }); diff --git a/src/nintendo-certificate.ts b/src/nintendo-certificate.ts index 5a35e85..07b93f8 100644 --- a/src/nintendo-certificate.ts +++ b/src/nintendo-certificate.ts @@ -1,5 +1,6 @@ import crypto from 'node:crypto'; import NodeRSA from 'node-rsa'; +import { SignatureSize } from '@/types/common/signature-size'; const WIIU_DEVICE_PUB_PEM = `-----BEGIN PUBLIC KEY----- MFIwEAYHKoZIzj0CAQYFK4EEABsDPgAEAP1WBBgs8XUJIQDDCK5IOZEbb5+h1TqV @@ -40,29 +41,31 @@ const CTR_LFCS_B_PUB = Buffer.from([ 0xAF, 0x07, 0xEB, 0x9C, 0xBF, 0xA9, 0xC9 ]); + + // Signature options -const SIGNATURE_SIZES = { - RSA_4096_SHA1: { +const SIGNATURE_SIZES: { [key: string]: SignatureSize } = { + RSA_4096_SHA1: { SIZE: 0x200, PADDING_SIZE: 0x3C }, - RSA_2048_SHA1: { + RSA_2048_SHA1: { SIZE: 0x100, PADDING_SIZE: 0x3C }, - ELLIPTIC_CURVE_SHA1: { + ELLIPTIC_CURVE_SHA1: { SIZE: 0x3C, PADDING_SIZE: 0x40 }, - RSA_4096_SHA256: { + RSA_4096_SHA256: { SIZE: 0x200, PADDING_SIZE: 0x3C }, - RSA_2048_SHA256: { + RSA_2048_SHA256: { SIZE: 0x100, PADDING_SIZE: 0x3C }, - ECDSA_SHA256: { + ECDSA_SHA256: { SIZE: 0x3C, PADDING_SIZE: 0x40 } @@ -81,7 +84,7 @@ export class NintendoCertificate { valid: boolean; publicKeyData: Buffer; - constructor(certificate) { + constructor(certificate: string | Buffer) { this._certificate = null; this._certificateBody = null; this.signatureType = null; @@ -116,7 +119,7 @@ export class NintendoCertificate { // Assume regular certificate this.signatureType = this._certificate.readUInt32BE(0x00); - const signatureTypeSizes = this._signatureTypeSizes(this.signatureType); + const signatureTypeSizes: SignatureSize = this._signatureTypeSizes(this.signatureType); this._certificateBody = this._certificate.subarray(0x4 + signatureTypeSizes.SIZE + signatureTypeSizes.PADDING_SIZE); @@ -129,7 +132,7 @@ export class NintendoCertificate { } } - _signatureTypeSizes(signatureType) { + _signatureTypeSizes(signatureType: number): SignatureSize { switch (signatureType) { case 0x10000: return SIGNATURE_SIZES.RSA_4096_SHA1; @@ -168,7 +171,7 @@ export class NintendoCertificate { } _verifySignatureRSA4096() { - const publicKey = new NodeRSA(); + const publicKey: NodeRSA = new NodeRSA(); publicKey.importKey({ n: this.publicKeyData.subarray(0x0, 0x200), @@ -179,7 +182,7 @@ export class NintendoCertificate { } _verifySignatureRSA2048() { - const publicKey = new NodeRSA(); + const publicKey: NodeRSA = new NodeRSA(); publicKey.importKey({ n: this.publicKeyData.subarray(0x0, 0x100), @@ -194,8 +197,8 @@ export class NintendoCertificate { // from bytes to PEM! // https://github.com/Myriachan _verifySignatureECDSA() { - const pem = this.issuer == 'Root-CA00000003-MS00000012' ? WIIU_DEVICE_PUB_PEM : CTR_DEVICE_PUB_PEM; - const key = { + const pem: string = this.issuer == 'Root-CA00000003-MS00000012' ? WIIU_DEVICE_PUB_PEM : CTR_DEVICE_PUB_PEM; + const key: crypto.VerifyPublicKeyInput = { key: pem, dsaEncoding: 'ieee-p1363' as crypto.DSAEncoding }; @@ -204,7 +207,7 @@ export class NintendoCertificate { } _verifySignatureLFCS() { - const publicKey = new NodeRSA(); + const publicKey: NodeRSA = new NodeRSA(); publicKey.importKey({ n: CTR_LFCS_B_PUB, diff --git a/src/server.ts b/src/server.ts index 3869de0..1d3710f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,8 +1,8 @@ process.title = 'Pretendo - Account'; - -const configManager = require('@config-manager'); - -configManager.configure(); +process.on('uncaughtException', (err, origin) => { + console.log(err); + console.log(origin); +}); import express from 'express'; import morgan from 'morgan'; @@ -20,7 +20,7 @@ import api from '@/services/api'; import localcdn from '@/services/local-cdn'; import assets from '@/services/assets'; -const { config } = configManager; +import { config } from '@/config-manager'; const { http: { port } } = config; const app = express(); @@ -47,9 +47,9 @@ app.use(assets); // 404 handler logger.info('Creating 404 status handler'); -app.use((request, response) => { - const fullUrl = util.fullUrl(request); - const deviceId = request.headers['X-Nintendo-Device-ID'] || 'Unknown'; +app.use((request: express.Request, response: express.Response) => { + const fullUrl: string = util.fullUrl(request); + const deviceId: string = request.headers['X-Nintendo-Device-ID'] as string || 'Unknown'; logger.warn(`HTTP 404 at ${fullUrl} from ${deviceId}`); @@ -63,10 +63,10 @@ app.use((request, response) => { // non-404 error handler logger.info('Creating non-404 status handler'); -app.use((error, request, response, _next) => { - const status = error.status || 500; - const fullUrl = util.fullUrl(request); - const deviceId = request.headers['X-Nintendo-Device-ID'] || 'Unknown'; +app.use((error: any, request: express.Request, response: express.Response, _next: express.NextFunction) => { + const status: number = error.status || 500; + const fullUrl: string = util.fullUrl(request); + const deviceId: string = request.headers['X-Nintendo-Device-ID'] as string || 'Unknown'; logger.warn(`HTTP ${status} at ${fullUrl} from ${deviceId}: ${error.message}`); @@ -78,7 +78,7 @@ app.use((error, request, response, _next) => { }); }); -async function main() { +async function main(): Promise { // Starts the server logger.info('Starting server'); diff --git a/src/services/api/index.ts b/src/services/api/index.ts index 0d8a952..df383af 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -8,7 +8,7 @@ import routes from '@/services/api/routes'; import logger from '@/logger'; // Router to handle the subdomain restriction -const api = express.Router(); +const api: express.Router = express.Router(); logger.info('[USER API] Importing middleware'); api.use(APIMiddleware); @@ -27,7 +27,7 @@ api.use('/v1/user', routes.V1.USER); // Main router for endpoints -const router = express.Router(); +const router: express.Router = express.Router(); // Create subdomains logger.info('[USER API] Creating \'api\' subdomain'); diff --git a/src/services/api/routes/v1/connections.ts b/src/services/api/routes/v1/connections.ts index 4ec11c5..1a307e6 100644 --- a/src/services/api/routes/v1/connections.ts +++ b/src/services/api/routes/v1/connections.ts @@ -1,9 +1,12 @@ -import { Router } from 'express'; +import express from 'express'; import database from '@/database'; +import { ConnectionData } from '@/types/services/api/connection-data'; +import { ConnectionResponse } from '@/types/services/api/connection-response'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); -const VALID_CONNECTION_TYPES = [ +const VALID_CONNECTION_TYPES: string[] = [ 'discord' ]; @@ -12,10 +15,10 @@ const VALID_CONNECTION_TYPES = [ * Implementation of for: https://api.pretendo.cc/v1/connections/add/TYPE * Description: Adds an account connection to the users PNID */ -router.post('/add/:type', async (request, response) => { - const { body, pnid } = request; - const { type } = request.params; - const { data } = body; +router.post('/add/:type', async (request: express.Request, response: express.Response) => { + const data: ConnectionData = request.body?.data; + const pnid: HydratedPNIDDocument = request.pnid; + const type: string = request.params.type; if (!pnid) { return response.status(400).json({ @@ -41,7 +44,7 @@ router.post('/add/:type', async (request, response) => { }); } - const result = await database.addUserConnection(pnid, data, type); + const result: ConnectionResponse = await database.addUserConnection(pnid, data, type); response.status(result.status).json(result); }); @@ -51,9 +54,9 @@ router.post('/add/:type', async (request, response) => { * Implementation of for: https://api.pretendo.cc/v1/connections/remove/TYPE * Description: Removes an account connection from the users PNID */ -router.delete('/remove/:type', async (request, response) => { - const { pnid } = request; - const { type } = request.params; +router.delete('/remove/:type', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; + const type: string = request.params.type; if (!pnid) { return response.status(400).json({ @@ -71,7 +74,7 @@ router.delete('/remove/:type', async (request, response) => { }); } - const result = await database.removeUserConnection(pnid, type); + const result: ConnectionResponse = await database.removeUserConnection(pnid, type); response.status(result.status).json(result); }); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index 1f28f18..308bc84 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -1,18 +1,13 @@ -import { Router } from 'express'; +import express from 'express'; import moment from 'moment'; import { PNID } from '@/models/pnid'; import util from '@/util'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); -router.get('/verify', async (request, response) => { - let token: string; - - if (Array.isArray(request.query.token)) { - token = request.query.token[0] as string; - } else { - token = request.query.token as string; - } +router.get('/verify', async (request: express.Request, response: express.Response) => { + let token: string = request.query.token as string; if (!token || token.trim() == '') { return response.status(400).json({ @@ -22,7 +17,7 @@ router.get('/verify', async (request, response) => { }); } - const pnid = await PNID.findOne({ + const pnid: HydratedPNIDDocument = await PNID.findOne({ 'identification.email_token': token }); @@ -34,7 +29,7 @@ router.get('/verify', async (request, response) => { }); } - const validatedDate = moment().format('YYYY-MM-DDTHH:MM:SS'); + const validatedDate: string = moment().format('YYYY-MM-DDTHH:MM:SS'); pnid.set('email.reachable', true); pnid.set('email.validated', true); diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index eb926b4..24148ba 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -1,13 +1,13 @@ -import { Router } from 'express'; +import express from 'express'; import validator from 'validator'; import database from '@/database'; import util from '@/util'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); -router.post('/', async (request, response) => { - const { body } = request; - const { input } = body; +router.post('/', async (request: express.Request, response: express.Response) => { + const input: string = request.body?.input; if (!input || input.trim() === '') { return response.status(400).json({ @@ -17,7 +17,7 @@ router.post('/', async (request, response) => { }); } - let pnid; + let pnid: HydratedPNIDDocument; if (validator.isEmail(input)) { pnid = await database.getUserByEmailAddress(input); diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index e6c8c1f..4aa098a 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -1,11 +1,14 @@ -import { Router } from 'express'; +import express from 'express'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; import database from '@/database'; import cache from '@/cache'; import util from '@/util'; +import { CryptoOptions } from '@/types/common/crypto-options'; +import { TokenOptions } from '@/types/common/token-options'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); /** * [POST] @@ -13,11 +16,13 @@ const router = Router(); * Description: Generates an access token for an API user * TODO: Replace this with a more robust OAuth2 implementation */ -router.post('/', async (request, response) => { - const { body } = request; - const { grant_type, username, password, refresh_token } = body; +router.post('/', async (request: express.Request, response: express.Response) => { + const grantType: string = request.body?.grantType; + const username: string = request.body?.username; + const password: string = request.body?.password; + const refreshToken: string = request.body?.refresh_token; - if (!['password', 'refresh_token'].includes(grant_type)) { + if (!['password', 'refresh_token'].includes(grantType)) { return response.status(400).json({ app: 'api', status: 400, @@ -25,7 +30,7 @@ router.post('/', async (request, response) => { }); } - if (grant_type === 'password' && (!username || username.trim() === '')) { + if (grantType === 'password' && (!username || username.trim() === '')) { return response.status(400).json({ app: 'api', status: 400, @@ -33,7 +38,7 @@ router.post('/', async (request, response) => { }); } - if (grant_type === 'password' && (!password || password.trim() === '')) { + if (grantType === 'password' && (!password || password.trim() === '')) { return response.status(400).json({ app: 'api', status: 400, @@ -41,7 +46,7 @@ router.post('/', async (request, response) => { }); } - if (grant_type === 'refresh_token' && (!refresh_token || refresh_token.trim() === '')) { + if (grantType === 'refresh_token' && (!refreshToken || refreshToken.trim() === '')) { return response.status(400).json({ app: 'api', status: 400, @@ -49,9 +54,11 @@ router.post('/', async (request, response) => { }); } - let pnid; - if (grant_type === 'password') { + let pnid: HydratedPNIDDocument; + + if (grantType === 'password') { pnid = await database.getUserByUsername(username); + if (!pnid) { return response.status(400).json({ app: 'api', @@ -60,7 +67,7 @@ router.post('/', async (request, response) => { }); } - const hashedPassword = util.nintendoPasswordHash(password, pnid.get('pid')); + const hashedPassword: string = util.nintendoPasswordHash(password, pnid.get('pid')); if (!pnid || !bcrypt.compareSync(hashedPassword, pnid.password)) { return response.status(400).json({ @@ -70,7 +77,8 @@ router.post('/', async (request, response) => { }); } } else { - pnid = await database.getUserBearer(refresh_token); + pnid = await database.getUserBearer(refreshToken); + if (!pnid) { return response.status(400).json({ app: 'api', @@ -80,7 +88,7 @@ router.post('/', async (request, response) => { } } - const cryptoPath = `${__dirname}/../../../../../certs/service/account`; + const cryptoPath: string = `${__dirname}/../../../../../certs/service/account`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -91,15 +99,15 @@ router.post('/', async (request, response) => { }); } - const publicKey = await cache.getServicePublicKey('account'); - const secretKey = await cache.getServiceSecretKey('account'); + const publicKey: Buffer = await cache.getServicePublicKey('account'); + const secretKey: Buffer = await cache.getServiceSecretKey('account'); - const cryptoOptions = { + const cryptoOptions: CryptoOptions = { public_key: publicKey, hmac_secret: secretKey }; - const accessTokenOptions = { + const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, pid: pnid.get('pid'), @@ -108,7 +116,7 @@ router.post('/', async (request, response) => { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const refreshTokenOptions = { + const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, pid: pnid.get('pid'), @@ -117,14 +125,14 @@ router.post('/', async (request, response) => { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken = await util.generateToken(cryptoOptions, accessTokenOptions); - const refreshToken = await util.generateToken(cryptoOptions, refreshTokenOptions); + const accessToken: string = await util.generateToken(cryptoOptions, accessTokenOptions); + const newRefreshToken: string = await util.generateToken(cryptoOptions, refreshTokenOptions); response.json({ access_token: accessToken, token_type: 'Bearer', expires_in: 3600, - refresh_token: refreshToken + refresh_token: newRefreshToken }); }); diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 95f79d4..7712d29 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -1,12 +1,13 @@ import crypto from 'node:crypto'; -import { Router } from 'express'; +import express from 'express'; import emailvalidator from 'email-validator'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; import moment from 'moment'; import hcaptcha from 'hcaptcha'; import Mii from 'mii-js'; +import mongoose from 'mongoose'; import database from '@/database'; import cache from '@/cache'; import util from '@/util'; @@ -14,36 +15,38 @@ import logger from '@/logger'; import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; import { config, disabledFeatures } from '@/config-manager'; +import { CryptoOptions } from '@/types/common/crypto-options'; +import { TokenOptions } from '@/types/common/token-options'; +import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); -const PNID_VALID_CHARACTERS_REGEX = /^[\w\-\.]*$/gm; -const PNID_PUNCTUATION_START_REGEX = /^[\_\-\.]/gm; -const PNID_PUNCTUATION_END_REGEX = /[\_\-\.]$/gm; -const PNID_PUNCTUATION_DUPLICATE_REGEX = /[\_\-\.]{2,}/gm; +const PNID_VALID_CHARACTERS_REGEX: RegExp = /^[\w\-\.]*$/gm; +const PNID_PUNCTUATION_START_REGEX: RegExp = /^[\_\-\.]/gm; +const PNID_PUNCTUATION_END_REGEX: RegExp = /[\_\-\.]$/gm; +const PNID_PUNCTUATION_DUPLICATE_REGEX: RegExp = /[\_\-\.]{2,}/gm; // This sucks -const PASSWORD_WORD_OR_NUMBER_REGEX = /(?=.*[a-zA-Z])(?=.*\d).*/; -const PASSWORD_WORD_OR_PUNCTUATION_REGEX = /(?=.*[a-zA-Z])(?=.*[\_\-\.]).*/; -const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX = /(?=.*\d)(?=.*[\_\-\.]).*/; -const PASSWORD_REPEATED_CHARACTER_REGEX = /(.)\1\1/; +const PASSWORD_WORD_OR_NUMBER_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*\d).*/; +const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[\_\-\.]).*/; +const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[\_\-\.]).*/; +const PASSWORD_REPEATED_CHARACTER_REGEX: RegExp = /(.)\1\1/; -const DEFAULT_MII_DATA = Buffer.from('AwAAQOlVognnx0GC2/uogAOzuI0n2QAAAEBEAGUAZgBhAHUAbAB0AAAAAAAAAEBAAAAhAQJoRBgmNEYUgRIXaA0AACkAUkhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGm9', 'base64'); +const DEFAULT_MII_DATA: Buffer = Buffer.from('AwAAQOlVognnx0GC2/uogAOzuI0n2QAAAEBEAGUAZgBhAHUAbAB0AAAAAAAAAEBAAAAhAQJoRBgmNEYUgRIXaA0AACkAUkhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGm9', 'base64'); /** * [POST] * Implementation of: https://api.pretendo.cc/v1/register * Description: Creates a new user PNID */ -router.post('/', async (request, response) => { - const { body } = request; - - const email = body.email?.trim(); - const username = body.username?.trim(); - const miiName = body.mii_name?.trim(); - const password = body.password?.trim(); - const passwordConfirm = body.password_confirm?.trim(); - const hCaptchaResponse = body.hCaptchaResponse?.trim(); +router.post('/', async (request: express.Request, response: express.Response) => { + const email: string = request.body.email?.trim(); + const username: string = request.body.username?.trim(); + const miiName: string = request.body.mii_name?.trim(); + const password: string = request.body.password?.trim(); + const passwordConfirm: string = request.body.password_confirm?.trim(); + const hCaptchaResponse: string = request.body.hCaptchaResponse?.trim(); if (!disabledFeatures.captcha) { if (!hCaptchaResponse || hCaptchaResponse === '') { @@ -54,7 +57,7 @@ router.post('/', async (request, response) => { }); } - const captchaVerify = await hcaptcha.verify(config.hcaptcha.secret, hCaptchaResponse); + const captchaVerify: VerifyResponse = await hcaptcha.verify(config.hcaptcha.secret, hCaptchaResponse); if (!captchaVerify.success) { return response.status(400).json({ @@ -138,7 +141,7 @@ router.post('/', async (request, response) => { }); } - const userExists = await database.doesUserExist(username); + const userExists: boolean = await database.doesUserExist(username); if (userExists) { return response.status(400).json({ @@ -212,7 +215,7 @@ router.post('/', async (request, response) => { }); } - const miiNameBuffer = Buffer.from(miiName, 'utf16le'); // UTF8 to UTF16 + const miiNameBuffer: Buffer = Buffer.from(miiName, 'utf16le'); // UTF8 to UTF16 if (miiNameBuffer.length > 0x14) { return response.status(400).json({ @@ -222,14 +225,14 @@ router.post('/', async (request, response) => { }); } - const mii = new Mii(DEFAULT_MII_DATA); + const mii: Mii = new Mii(DEFAULT_MII_DATA); mii.miiName = miiName; - const creationDate = moment().format('YYYY-MM-DDTHH:MM:SS'); - let pnid; - let nexAccount; + const creationDate: string = moment().format('YYYY-MM-DDTHH:MM:SS'); + let pnid: HydratedPNIDDocument; + let nexAccount: HydratedNEXAccountDocument; - const session = await database.connection().startSession(); + const session: mongoose.ClientSession = await database.connection().startSession(); await session.startTransaction(); try { @@ -251,8 +254,8 @@ router.post('/', async (request, response) => { await nexAccount.save({ session }); - const primaryPasswordHash = util.nintendoPasswordHash(password, nexAccount.get('pid')); - const passwordHash = await bcrypt.hash(primaryPasswordHash, 10); + const primaryPasswordHash: string = util.nintendoPasswordHash(password, nexAccount.get('pid')); + const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid = new PNID({ pid: nexAccount.get('pid'), @@ -323,7 +326,7 @@ router.post('/', async (request, response) => { await util.sendConfirmationEmail(pnid); - const cryptoPath = `${__dirname}/../../../../../certs/service/account`; + const cryptoPath: string = `${__dirname}/../../../../../certs/service/account`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -334,15 +337,15 @@ router.post('/', async (request, response) => { }); } - const publicKey = await cache.getServicePublicKey('account'); - const secretKey = await cache.getServiceSecretKey('account'); + const publicKey: Buffer = await cache.getServicePublicKey('account'); + const secretKey: Buffer = await cache.getServiceSecretKey('account'); - const cryptoOptions = { + const cryptoOptions: CryptoOptions = { public_key: publicKey, hmac_secret: secretKey }; - const accessTokenOptions = { + const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, pid: pnid.get('pid'), @@ -351,7 +354,7 @@ router.post('/', async (request, response) => { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const refreshTokenOptions = { + const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, pid: pnid.get('pid'), @@ -360,8 +363,8 @@ router.post('/', async (request, response) => { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken = await util.generateToken(cryptoOptions, accessTokenOptions); - const refreshToken = await util.generateToken(cryptoOptions, refreshTokenOptions); + const accessToken: string = await util.generateToken(cryptoOptions, accessTokenOptions); + const refreshToken: string = await util.generateToken(cryptoOptions, refreshTokenOptions); response.json({ access_token: accessToken, diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 3f9a823..8f570b5 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -1,21 +1,22 @@ -import { Router } from 'express'; +import express from 'express'; import bcrypt from 'bcrypt'; import { PNID } from '@/models/pnid'; import util from '@/util'; +import { Token } from '@/types/common/token'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); // This sucks -const PASSWORD_WORD_OR_NUMBER_REGEX = /(?=.*[a-zA-Z])(?=.*\d).*/; -const PASSWORD_WORD_OR_PUNCTUATION_REGEX = /(?=.*[a-zA-Z])(?=.*[\_\-\.]).*/; -const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX = /(?=.*\d)(?=.*[\_\-\.]).*/; -const PASSWORD_REPEATED_CHARACTER_REGEX = /(.)\1\1/; +const PASSWORD_WORD_OR_NUMBER_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*\d).*/; +const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[\_\-\.]).*/; +const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[\_\-\.]).*/; +const PASSWORD_REPEATED_CHARACTER_REGEX: RegExp = /(.)\1\1/; -router.post('/', async (request, response) => { - const { body } = request; - const password = body.password?.trim(); - const passwordConfirm = body.password_confirm?.trim(); - const token = body.token?.trim(); +router.post('/', async (request: express.Request, response: express.Response) => { + const password: string = request.body.password?.trim(); + const passwordConfirm: string = request.body.password_confirm?.trim(); + const token: string = request.body.token?.trim(); if (!token || token === '') { return response.status(400).json({ @@ -25,9 +26,9 @@ router.post('/', async (request, response) => { }); } - let unpackedToken; + let unpackedToken: Token; try { - const decryptedToken = await util.decryptToken(Buffer.from(token, 'base64')); + const decryptedToken: Buffer = await util.decryptToken(Buffer.from(token, 'base64')); unpackedToken = util.unpackToken(decryptedToken); } catch (error) { console.log(error); @@ -46,7 +47,7 @@ router.post('/', async (request, response) => { }); } - const pnid = await PNID.findOne({ pid: unpackedToken.pid }); + const pnid: HydratedPNIDDocument = await PNID.findOne({ pid: unpackedToken.pid }); if (!pnid) { return response.status(400).json({ @@ -113,8 +114,8 @@ router.post('/', async (request, response) => { }); } - const primaryPasswordHash = util.nintendoPasswordHash(password, pnid.get('pid')); - const passwordHash = await bcrypt.hash(primaryPasswordHash, 10); + const primaryPasswordHash: string = util.nintendoPasswordHash(password, pnid.get('pid')); + const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; diff --git a/src/services/api/routes/v1/user.ts b/src/services/api/routes/v1/user.ts index 2ce5fae..ef03c25 100644 --- a/src/services/api/routes/v1/user.ts +++ b/src/services/api/routes/v1/user.ts @@ -1,12 +1,14 @@ -import { Router } from 'express'; +import express from 'express'; import joi from 'joi'; import { PNID } from '@/models/pnid'; import { config } from '@/config-manager'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; +import { UpdateUserRequest } from '@/types/services/api/update-user-request'; -const router = Router(); +const router: express.Router = express.Router(); // TODO: Extend this later with more settings -const userSchema = joi.object({ +const userSchema: joi.ObjectSchema = joi.object({ mii: joi.object({ name: joi.string(), primary: joi.string(), @@ -19,8 +21,8 @@ const userSchema = joi.object({ * Implementation of for: https://api.pretendo.cc/v1/user * Description: Gets PNID details about the current user */ -router.get('/', async (request, response) => { - const { pnid } = request; +router.get('/', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; if (!pnid) { return response.status(400).json({ @@ -67,8 +69,9 @@ router.get('/', async (request, response) => { * Implementation of for: https://api.pretendo.cc/v1/user * Description: Updates PNID certain details about the current user */ -router.post('/', async (request, response) => { - const { body, pnid } = request; +router.post('/', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; + const updateUserRequest: UpdateUserRequest = request.body; if (!pnid) { return response.status(400).json({ @@ -78,7 +81,7 @@ router.post('/', async (request, response) => { }); } - const valid = userSchema.validate(body); + const valid: joi.ValidationResult = userSchema.validate(updateUserRequest); if (valid.error) { return response.status(400).json({ @@ -88,11 +91,13 @@ router.post('/', async (request, response) => { }); } - const { pid } = pnid; + // TODO - Make this do something - const updateData = {}; + //const pid: number = pnid.pid; - await PNID.updateOne({ pid }, { $set: updateData }).exec(); + //const updateData = {}; + + //await PNID.updateOne({ pid }, { $set: updateData }).exec(); return response.json({ access_level: pnid.access_level, diff --git a/src/services/assets/index.ts b/src/services/assets/index.ts index dc77afb..f40cd56 100644 --- a/src/services/assets/index.ts +++ b/src/services/assets/index.ts @@ -6,14 +6,14 @@ import subdomain from 'express-subdomain'; import logger from '@/logger'; // Router to handle the subdomain restriction -const assets = express.Router(); +const assets: express.Router = express.Router(); // Setup public folder logger.info('[assets] Setting up public folder'); assets.use(express.static(path.join(__dirname, '../../assets'))); // Main router for endpoints -const router = express.Router(); +const router: express.Router = express.Router(); // Create subdomains logger.info('[conntest] Creating \'assets\' subdomain'); diff --git a/src/services/conntest/index.ts b/src/services/conntest/index.ts index 8033849..610cdda 100644 --- a/src/services/conntest/index.ts +++ b/src/services/conntest/index.ts @@ -5,11 +5,11 @@ import subdomain from 'express-subdomain'; import logger from '@/logger'; // Router to handle the subdomain restriction -const conntest = express.Router(); +const conntest: express.Router = express.Router(); // Setup route logger.info('[conntest] Applying imported routes'); -conntest.get('/', async (request, response) => { +conntest.get('/', async (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/html'); response.set('X-Organization', 'Nintendo'); @@ -27,7 +27,7 @@ This is test.html page }); // Main router for endpoints -const router = express.Router(); +const router: express.Router = express.Router(); // Create subdomains logger.info('[conntest] Creating \'conntest\' subdomain'); diff --git a/src/services/datastore/index.ts b/src/services/datastore/index.ts index 6969988..a06640d 100644 --- a/src/services/datastore/index.ts +++ b/src/services/datastore/index.ts @@ -4,14 +4,14 @@ import routes from '@/services/datastore/routes'; import logger from '@/logger'; // Router to handle the subdomain -const datastore = express.Router(); +const datastore: express.Router = express.Router(); // Setup routes logger.info('[DATASTORE] Applying imported routes'); datastore.use(routes.UPLOAD); // Main router for endpoints -const router = express.Router(); +const router: express.Router = express.Router(); // Create subdomains logger.info('[DATASTORE] Creating \'datastore\' subdomain'); diff --git a/src/services/datastore/routes/upload.ts b/src/services/datastore/routes/upload.ts index a17c15d..5b47857 100644 --- a/src/services/datastore/routes/upload.ts +++ b/src/services/datastore/routes/upload.ts @@ -1,30 +1,35 @@ import fs from 'node:fs'; import crypto from 'node:crypto'; -import { Router } from 'express'; +import express from 'express'; import Dicer from 'dicer'; import util from '@/util'; -const router = Router(); +const router: express.Router = express.Router(); -const signatureSecret = fs.readFileSync(`${__dirname}/../../../../certs/nex/datastore/secret.key`); +const signatureSecret: Buffer = fs.readFileSync(`${__dirname}/../../../../certs/nex/datastore/secret.key`); -function multipartParser(request, response, next) { - const RE_BOUNDARY = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i; - const RE_FILE_NAME = /name="(.*)"/; - const boundary = RE_BOUNDARY.exec(request.header('content-type')); - const dicer = new Dicer({ boundary: boundary[1] || boundary[2] }); - const files = {}; +function multipartParser(request: express.Request, response: express.Response, next: express.NextFunction) { + const RE_BOUNDARY: RegExp = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i; + const RE_FILE_NAME: RegExp = /name="(.*)"/; - dicer.on('part', part => { - let fileBuffer = Buffer.alloc(0); - let fileName = ''; + const boundary: RegExpExecArray = RE_BOUNDARY.exec(request.header('content-type')); + const dicer: Dicer = new Dicer({ boundary: boundary[1] || boundary[2] }); + const files: { [key: string]: Buffer } = {}; + + dicer.on('part', (part: Dicer.PartStream) => { + let fileBuffer: Buffer = Buffer.alloc(0); + let fileName: string = ''; part.on('header', header => { fileName = RE_FILE_NAME.exec(header['content-disposition'][0])[1]; }); - part.on('data', data => { - fileBuffer = Buffer.concat([fileBuffer, data]); + part.on('data', (data: Buffer | string) => { + if (data instanceof String) { + data = Buffer.from(data); + } + + fileBuffer = Buffer.concat([fileBuffer, data as Buffer]); }); part.on('end', () => { @@ -40,36 +45,34 @@ function multipartParser(request, response, next) { request.pipe(dicer); } -router.post('/upload', multipartParser, async (request, response) => { - const { - bucket, // Space name - key, // path - file, // the file content - acl, // S3 ACL - pid, // uploading user PID - date, // upload time - signature, // data signature - } = request.files; +router.post('/upload', multipartParser, async (request: express.Request, response: express.Response) => { + const bucket: string = request.files.bucket.toString(); + const key: string = request.files.key.toString(); + const file: Buffer = request.files.file; + const acl: string = request.files.acl.toString(); + const pid: string = request.files.pid.toString(); + const date: string = request.files.date.toString(); + const signature: string = request.files.signature.toString(); // Signatures only good for 1 minute - const minute = 1000 * 60; - const minuteAgo = Date.now() - minute; + const minute: number = 1000 * 60; + const minuteAgo: number = Date.now() - minute; if (Number(date) < Math.floor(minuteAgo / 1000)) { return response.sendStatus(400); } - const data = pid.toString() + bucket.toString() + key.toString() + date.toString(); + const data: string = `${pid}${bucket}${key}${date}`; - const hmac = crypto.createHmac('sha256', signatureSecret).update(data).digest('hex'); + const hmac: string = crypto.createHmac('sha256', signatureSecret).update(data).digest('hex'); - console.log(hmac, signature.toString()); + console.log(hmac, signature); - if (hmac !== signature.toString()) { + if (hmac !== signature) { return response.sendStatus(400); } - await util.uploadCDNAsset(bucket.toString(), key.toString(), file, acl.toString()); + await util.uploadCDNAsset(bucket, key, file, acl); response.sendStatus(200); }); diff --git a/src/services/local-cdn/index.ts b/src/services/local-cdn/index.ts index e8891ac..9f9fe3f 100644 --- a/src/services/local-cdn/index.ts +++ b/src/services/local-cdn/index.ts @@ -4,13 +4,13 @@ import routes from '@/services/local-cdn/routes'; import { config, disabledFeatures } from '@/config-manager'; import logger from '@/logger'; -const router = express.Router(); +const router: express.Router = express.Router(); if (disabledFeatures.s3) { // * s3 disabled, setup local CDN // * Router to handle the subdomain - const localcdn = express.Router(); + const localcdn: express.Router = express.Router(); // * Setup routes logger.info('[LOCAL-CDN] Applying imported routes'); diff --git a/src/services/local-cdn/routes/get.ts b/src/services/local-cdn/routes/get.ts index 7a68dc8..1492c13 100644 --- a/src/services/local-cdn/routes/get.ts +++ b/src/services/local-cdn/routes/get.ts @@ -1,12 +1,12 @@ -import { Router } from 'express'; +import express from 'express'; import cache from '@/cache'; -const router = Router(); +const router: express.Router = express.Router(); -router.get('/*', async (request, response) => { - const filePath = request.params[0]; +router.get('/*', async (request: express.Request, response: express.Response) => { + const filePath: string = request.params[0] as string; - const file = await cache.getLocalCDNFile(filePath); + const file: Buffer = await cache.getLocalCDNFile(filePath); if (file) { response.send(file); diff --git a/src/services/nasc/index.ts b/src/services/nasc/index.ts index a55de55..38f1d60 100644 --- a/src/services/nasc/index.ts +++ b/src/services/nasc/index.ts @@ -7,7 +7,7 @@ import routes from '@/services/nasc/routes'; import logger from '@/logger'; // Router to handle the subdomain restriction -const nasc = express.Router(); +const nasc: express.Router = express.Router(); logger.info('[NASC] Importing middleware'); nasc.use(NASCMiddleware); @@ -17,7 +17,7 @@ logger.info('[NASC] Applying imported routes'); nasc.use('/ac', routes.AC); // Main router for endpoints -const router = express.Router(); +const router: express.Router = express.Router(); // Create subdomains logger.info('[NASC] Creating \'nasc\' subdomain'); diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index f468f1a..6e4589a 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -2,18 +2,23 @@ import express from 'express'; import util from '@/util'; import database from '@/database'; import cache from '@/cache'; +import { CryptoOptions } from '@/types/common/crypto-options'; +import { TokenOptions } from '@/types/common/token-options'; +import { NASCRequestParams } from '@/types/services/nasc/request-params'; +import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; +import { HydratedServerDocument } from '@/types/mongoose/server'; -const router = express.Router(); +const router: express.Router = express.Router(); /** * [POST] * Replacement for: https://nasc.nintendowifi.net/ac * Description: Gets a NEX server address and token */ -router.post('/', async (request, response) => { - const requestParams = request.body; - const action = util.nintendoBase64Decode(requestParams.action).toString(); - let responseData; +router.post('/', async (request: express.Request, response: express.Response) => { + const requestParams: NASCRequestParams = request.body; + const action: string = util.nintendoBase64Decode(requestParams.action).toString(); + let responseData: URLSearchParams; switch (action) { case 'LOGIN': @@ -27,36 +32,38 @@ router.post('/', async (request, response) => { response.status(200).send(responseData.toString()); }); -async function processLoginRequest(request: express.Request) { - const requestParams = request.body; - const titleID = util.nintendoBase64Decode(requestParams.titleid).toString(); - const { nexUser } = request; +async function processLoginRequest(request: express.Request): Promise { + const requestParams: NASCRequestParams = request.body; + const titleID: string = util.nintendoBase64Decode(requestParams.titleid).toString(); + const nexUser: HydratedNEXAccountDocument = request.nexUser; // TODO: REMOVE AFTER PUBLIC LAUNCH // LET EVERYONE IN THE `test` FRIENDS SERVER // THAT WAY EVERYONE CAN GET AN ASSIGNED PID - let serverAccessLevel = 'test'; + let serverAccessLevel: string = 'test'; if (titleID !== '0004013000003202') { serverAccessLevel = nexUser.get('server_access_level'); } - const server = await database.getServerByTitleId(titleID, serverAccessLevel); + const server: HydratedServerDocument = await database.getServerByTitleId(titleID, serverAccessLevel); if (!server || !server.service_name || !server.ip || !server.port) { return util.nascError('110'); } - const { service_name, ip, port } = server; + const serverName: string = server.service_name; + const ip: string = server.ip; + const port: number = server.port; - const publicKey = await cache.getNEXPublicKey(service_name); - const secretKey = await cache.getNEXSecretKey(service_name); + const publicKey: Buffer = await cache.getNEXPublicKey(serverName); + const secretKey: Buffer = await cache.getNEXSecretKey(serverName); - const cryptoOptions = { + const cryptoOptions: CryptoOptions = { public_key: publicKey, hmac_secret: secretKey }; - const tokenOptions = { + const tokenOptions: TokenOptions = { system_type: 0x2, // 3DS token_type: 0x3, // nex token, pid: nexUser.get('pid'), @@ -65,22 +72,20 @@ async function processLoginRequest(request: express.Request) { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let nexToken = await util.generateToken(cryptoOptions, tokenOptions); + let nexToken: string = await util.generateToken(cryptoOptions, tokenOptions); nexToken = util.nintendoBase64Encode(Buffer.from(nexToken, 'base64')); - const params = new URLSearchParams({ + return new URLSearchParams({ locator: util.nintendoBase64Encode(`${ip}:${port}`), retry: util.nintendoBase64Encode('0'), returncd: util.nintendoBase64Encode('001'), token: nexToken, datetime: util.nintendoBase64Encode(Date.now().toString()), }); - - return params; } -async function processServiceTokenRequest(request: express.Request) { - const params = new URLSearchParams({ +async function processServiceTokenRequest(_request: express.Request): Promise { + return new URLSearchParams({ retry: util.nintendoBase64Encode('0'), returncd: util.nintendoBase64Encode('007'), servicetoken: util.nintendoBase64Encode(Buffer.alloc(64).toString()), // hard coded for now @@ -88,8 +93,6 @@ async function processServiceTokenRequest(request: express.Request) { svchost: util.nintendoBase64Encode('n/a'), datetime: util.nintendoBase64Encode(Date.now().toString()), }); - - return params; } export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/admin.ts b/src/services/nnid/routes/admin.ts index 115b5ab..11bc7d6 100644 --- a/src/services/nnid/routes/admin.ts +++ b/src/services/nnid/routes/admin.ts @@ -1,28 +1,22 @@ -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { PNID } from '@/models/pnid'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); /** * [GET] * Replacement for: https://account.nintendo.net/v1/api/admin/mapped_ids * Description: Maps between NNID usernames and PIDs */ -router.get('/mapped_ids', async (request, response) => { - - let inputType: string; +router.get('/mapped_ids', async (request: express.Request, response: express.Response) => { + const inputType: string = request.query.input_type as string; + const outputType: string = request.query.output_type as string; let inputList: string[]; - let outputType: string; let queryInput: string; let queryOutput: string; - if (Array.isArray(request.query.input_type)) { - inputType = request.query.input_type[0] as string; - } else { - inputType = request.query.input_type as string; - } - if (Array.isArray(request.query.input)) { inputList = request.query.input as string[]; } else { @@ -30,12 +24,6 @@ router.get('/mapped_ids', async (request, response) => { inputList = input.split(','); } - if (Array.isArray(request.query.output_type)) { - outputType = request.query.output_type[0] as string; - } else { - outputType = request.query.output_type as string; - } - inputList = inputList.filter(input => input); // * Remove null inputs if (inputType === 'user_id') { @@ -55,20 +43,30 @@ router.get('/mapped_ids', async (request, response) => { // but it ensures that each input // ALWAYS has an output and filters // out unwanted input/output types - const results = []; - const allowedTypes = ['pid', 'user_id']; + const results: { + in_id: string; + out_id: string; + }[] = []; + const allowedTypes: string[] = ['pid', 'user_id']; for (const input of inputList) { - const result = { + const result: { + in_id: string; + out_id: string; + } = { in_id: input, out_id: '' }; if (allowedTypes.includes(inputType) && allowedTypes.includes(outputType)) { - const query = {}; + const query: { + usernameLower?: string; + pid?: number; + } = {}; + query[queryInput] = input; - const searchResult = await PNID.findOne(query); + const searchResult: HydratedPNIDDocument = await PNID.findOne(query); if (searchResult) { result.out_id = searchResult.get(queryOutput); diff --git a/src/services/nnid/routes/content.ts b/src/services/nnid/routes/content.ts index 92f4701..5d45aa6 100644 --- a/src/services/nnid/routes/content.ts +++ b/src/services/nnid/routes/content.ts @@ -1,15 +1,17 @@ -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import timezones from '@/services/nnid/timezones.json'; +import { RegionLanguages } from '@/types/services/nnid/region-languages'; +import { RegionTimezones } from '@/types/services/nnid/region-timezones'; -const router = Router(); +const router: express.Router = express.Router(); /** * [GET] * Replacement for: https://account.nintendo.net/v1/api/content/agreements/TYPE/REGION/VERSION * Description: Sends the client requested agreement */ -router.get('/agreements/:type/:region/:version', (request, response) => { +router.get('/agreements/:type/:region/:version', (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); @@ -126,7 +128,7 @@ router.get('/agreements/:type/:region/:version', (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/content/time_zones/COUNTRY/LANGUAGE * Description: Sends the client the requested timezones */ -router.get('/time_zones/:countryCode/:language', (request, response) => { +router.get('/time_zones/:countryCode/:language', (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); @@ -149,10 +151,11 @@ router.get('/time_zones/:countryCode/:language', (request, response) => { }); */ - const { countryCode, language } = request.params; + const countryCode: string = request.params.countryCode; + const language: string = request.params.language; - const regionLanguages = timezones[countryCode]; - const regionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; + const regionLanguages: RegionLanguages = timezones[countryCode]; + const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; response.send(xmlbuilder.create({ timezones: { diff --git a/src/services/nnid/routes/devices.ts b/src/services/nnid/routes/devices.ts index ec6224e..3626fb1 100644 --- a/src/services/nnid/routes/devices.ts +++ b/src/services/nnid/routes/devices.ts @@ -1,14 +1,15 @@ -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; -const router = Router(); +const router: express.Router = express.Router(); /** * [GET] * Replacement for: https://account.nintendo.net/v1/api/devices/@current/status * Description: Unknown use */ -router.get('/@current/status', async (request, response) => { +router.get('/@current/status', async (request: express.Request, response: express.Response) => { + // TODO - Finish this response.send(xmlbuilder.create({ device: '' }).end()); diff --git a/src/services/nnid/routes/miis.ts b/src/services/nnid/routes/miis.ts index 7219ed4..368cb9e 100644 --- a/src/services/nnid/routes/miis.ts +++ b/src/services/nnid/routes/miis.ts @@ -1,81 +1,110 @@ -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { PNID } from '@/models/pnid'; import { config } from '@/config-manager'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; +import { YesNoBoolString } from '@/types/common/yes-no-bool-string'; -const router = Router(); +const router: express.Router = express.Router(); /** * [GET] - * Replacement for: https://account.pretendo.cc/v1/api/miis + * Replacement for: https://account.nintendo.net/v1/api/miis * Description: Returns a list of NNID miis */ -router.get('/', async (request, response) => { +router.get('/', async (request: express.Request, response: express.Response) => { + let pids: number[]; - const { pids } = request.query; + if (Array.isArray(request.query.pids)) { + pids = request.query.pids.map(pid => Number(pid)); + } else { + const input = request.query.pids as string; + pids = input.split(',').map(pid => Number(pid)); + } - const results = await PNID.where('pid', pids); - const miis = []; + const results: HydratedPNIDDocument[] = await PNID.where('pid', pids); + const miis: { + data: string; + id: number; + images: { + image: { + cached_url: string; + id: number; + url: string; + type: string; + }[] + }; + name: string; + pid: number; + primary: YesNoBoolString; + user_id: string; + }[] = []; for (const user of results) { - const { mii } = user; - - const miiImages = [ - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, - type: 'standard' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/frustrated.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/frustrated.png`, - type: 'frustrated_face' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/smile_open_mouth.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/smile_open_mouth.png`, - type: 'happy_face' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/wink_left.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/wink_left.png`, - type: 'like_face' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, - type: 'normal_face' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/sorrow.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/sorrow.png`, - type: 'puzzled_face' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/surprised_open_mouth.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/surprised_open_mouth.png`, - type: 'surprised_face' - }, - { - cached_url: `${config.cdn.base_url}/mii/${user.pid}/body.png`, - id: mii.id, - url: `${config.cdn.base_url}/mii/${user.pid}/body.png`, - type: 'whole_body' - } - ]; + const mii: { + name: string; + primary: boolean; + data: string; + id: number; + hash: string; + image_url: string; + image_id: number; + } = user.mii; miis.push({ data: mii.data.replace(/(\r\n|\n|\r)/gm, ''), id: mii.id, images: { - image: miiImages + image: [ + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, + type: 'standard' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/frustrated.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/frustrated.png`, + type: 'frustrated_face' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/smile_open_mouth.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/smile_open_mouth.png`, + type: 'happy_face' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/wink_left.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/wink_left.png`, + type: 'like_face' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/normal_face.png`, + type: 'normal_face' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/sorrow.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/sorrow.png`, + type: 'puzzled_face' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/surprised_open_mouth.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/surprised_open_mouth.png`, + type: 'surprised_face' + }, + { + cached_url: `${config.cdn.base_url}/mii/${user.pid}/body.png`, + id: mii.id, + url: `${config.cdn.base_url}/mii/${user.pid}/body.png`, + type: 'whole_body' + } + ] }, name: mii.name, pid: user.pid, diff --git a/src/services/nnid/routes/oauth.ts b/src/services/nnid/routes/oauth.ts index ab1ca40..800cad5 100644 --- a/src/services/nnid/routes/oauth.ts +++ b/src/services/nnid/routes/oauth.ts @@ -1,22 +1,25 @@ -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; import database from '@/database'; import util from '@/util'; +import { TokenOptions } from '@/types/common/token-options'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); /** * [POST] * Replacement for: https://account.nintendo.net/v1/api/oauth20/access_token/generate * Description: Generates an access token for a user */ -router.post('/access_token/generate', async (request, response) => { - const { body } = request; - const { grant_type, user_id, password } = body; +router.post('/access_token/generate', async (request: express.Request, response: express.Response) => { + const grantType: string = request.body?.grant_type; + const username: string = request.body?.user_id; + const password: string = request.body?.password; - if (!['password', 'refresh_token'].includes(grant_type)) { + if (!['password', 'refresh_token'].includes(grantType)) { response.status(400); return response.send(xmlbuilder.create({ error: { @@ -27,7 +30,7 @@ router.post('/access_token/generate', async (request, response) => { }).end()); } - if (!user_id || user_id.trim() === '') { + if (!username || username.trim() === '') { response.status(400); return response.send(xmlbuilder.create({ error: { @@ -49,7 +52,7 @@ router.post('/access_token/generate', async (request, response) => { }).end()); } - const pnid = await database.getUserByUsername(user_id); + const pnid: HydratedPNIDDocument = await database.getUserByUsername(username); if (!pnid || !await bcrypt.compare(password, pnid.password)) { response.status(400); @@ -72,7 +75,7 @@ router.post('/access_token/generate', async (request, response) => { }).end()); } - const cryptoPath = `${__dirname}/../../../../certs/service/account`; + const cryptoPath: string = `${__dirname}/../../../../certs/service/account`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -86,22 +89,22 @@ router.post('/access_token/generate', async (request, response) => { }).end()); } - const accessTokenOptions = { + const accessTokenOptions: TokenOptions = { system_type: 0x1, // WiiU token_type: 0x1, // OAuth Access, pid: pnid.get('pid'), expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const refreshTokenOptions = { + const refreshTokenOptions: TokenOptions = { system_type: 0x1, // WiiU token_type: 0x2, // OAuth Refresh, pid: pnid.get('pid'), expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let accessToken = await util.generateToken(null, accessTokenOptions); - let refreshToken = await util.generateToken(null, refreshTokenOptions); + let accessToken: string = await util.generateToken(null, accessTokenOptions); + let refreshToken: string = await util.generateToken(null, refreshTokenOptions); if (request.isCemu) { accessToken = Buffer.from(accessToken, 'base64').toString('hex'); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 8733e00..9c508f2 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -1,8 +1,9 @@ import crypto from 'node:crypto'; -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import moment from 'moment'; +import mongoose from 'mongoose'; import deviceCertificateMiddleware from '@/middleware/device-certificate'; import ratelimit from '@/middleware/ratelimit'; import database from '@/database'; @@ -11,18 +12,24 @@ import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; import logger from '@/logger'; import timezones from '@/services/nnid/timezones.json'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; +import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; +import { RegionLanguages } from '@/types/services/nnid/region-languages'; +import { RegionTimezone, RegionTimezones } from '@/types/services/nnid/region-timezones'; +import { Person } from '@/types/services/nnid/person'; +import { PNIDProfile } from '@/types/services/nnid/pnid-profile'; -const router = Router(); +const router: express.Router = express.Router(); /** * [GET] * Replacement for: https://account.nintendo.net/v1/api/people/:USERNAME * Description: Checks if a username is in use */ -router.get('/:username', async (request, response) => { - const { username } = request.params; +router.get('/:username', async (request: express.Request, response: express.Response) => { + const username: string = request.params.username; - const userExists = await database.doesUserExist(username); + const userExists: boolean = await database.doesUserExist(username); if (userExists) { response.status(400); @@ -46,7 +53,7 @@ router.get('/:username', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people * Description: Registers a new NNID */ -router.post('/', ratelimit, deviceCertificateMiddleware, async (request, response) => { +router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express.Request, response: express.Response) => { if (!request.certificate.valid) { // TODO: Change this to a different error response.status(400); @@ -60,9 +67,10 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons }).end()); } - const person = request.body.get('person'); + // * request.body is a Map, as is request.body.person + const person: Person = request.body.get('person'); - const userExists = await database.doesUserExist(person.get('user_id')); + const userExists: boolean = await database.doesUserExist(person.get('user_id')); if (userExists) { response.status(400); @@ -77,11 +85,11 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons }).end()); } - const creationDate = moment().format('YYYY-MM-DDTHH:MM:SS'); - let pnid; - let nexAccount; + const creationDate: string = moment().format('YYYY-MM-DDTHH:MM:SS'); + let pnid: HydratedPNIDDocument; + let nexAccount: HydratedNEXAccountDocument; - const session = await database.connection().startSession(); + const session: mongoose.ClientSession = await database.connection().startSession(); await session.startTransaction(); try { @@ -101,16 +109,16 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons await nexAccount.save({ session }); - const primaryPasswordHash = util.nintendoPasswordHash(person.get('password'), nexAccount.get('pid')); - const passwordHash = await bcrypt.hash(primaryPasswordHash, 10); + const primaryPasswordHash: string = util.nintendoPasswordHash(person.get('password'), nexAccount.get('pid')); + const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); - const countryCode = person.get('country'); - const language = person.get('language'); - const timezoneName = person.get('tz_name'); + const countryCode: string = person.get('country'); + const language: string = person.get('language'); + const timezoneName: string = person.get('tz_name'); - const regionLanguages = timezones[countryCode]; - const regionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; - const timezone = regionTimezones.find(tz => tz.area === timezoneName); + const regionLanguages: RegionLanguages = timezones[countryCode]; + const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; + const timezone: RegionTimezone = regionTimezones.find(tz => tz.area === timezoneName); pnid = new PNID({ pid: nexAccount.get('pid'), @@ -197,14 +205,14 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons * Replacement for: https://account.nintendo.net/v1/api/people/@me/profile * Description: Gets a users profile */ -router.get('/@me/profile', async (request, response) => { +router.get('/@me/profile', async (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - const { pnid } = request; + const pnid: HydratedPNIDDocument = request.pnid; - const person = await database.getUserProfileJSONByPID(pnid.get('pid')); + const person: PNIDProfile = await database.getUserProfileJSONByPID(pnid.get('pid')); response.send(xmlbuilder.create({ person @@ -216,7 +224,7 @@ router.get('/@me/profile', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/devices * Description: Gets user profile, seems to be the same as https://account.nintendo.net/v1/api/people/@me/profile */ -router.post('/@me/devices', async (request, response) => { +router.post('/@me/devices', async (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); @@ -225,9 +233,11 @@ router.post('/@me/devices', async (request, response) => { // The console ignores them and PNIDs are not tied to consoles anyway // So the server also ignores them and does not save the ones posted here - const { pnid } = request; + // TODO - CHANGE THIS. WE NEED TO SAVE CONSOLE DETAILS !!! - const person = await database.getUserProfileJSONByPID(pnid.pid); + const pnid: HydratedPNIDDocument = request.pnid; + + const person: PNIDProfile = await database.getUserProfileJSONByPID(pnid.pid); response.send(xmlbuilder.create({ person @@ -239,26 +249,32 @@ router.post('/@me/devices', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/devices * Description: Returns only user devices */ -router.get('/@me/devices', async (request, response) => { +router.get('/@me/devices', async (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - const { pnid, headers } = request; + const pnid: HydratedPNIDDocument = request.pnid; + const deviceId: string = request.headers['x-nintendo-device-id'] as string; + const acceptLanguage: string = request.headers['accept-language'] as string; + const platformId: string = request.headers['x-nintendo-platform-id'] as string; + const region: string = request.headers['x-nintendo-region'] as string; + const serialNumber: string = request.headers['x-nintendo-serial-number'] as string; + const systemVersion: string = request.headers['x-nintendo-system-version'] as string; response.send(xmlbuilder.create({ devices: [ { device: { - device_id: headers['x-nintendo-device-id'], - language: headers['accept-language'], + device_id: deviceId, + language: acceptLanguage, updated: moment().format('YYYY-MM-DDTHH:MM:SS'), pid: pnid.get('pid'), - platform_id: headers['x-nintendo-platform-id'], - region: headers['x-nintendo-region'], - serial_number: headers['x-nintendo-serial-number'], + platform_id: platformId, + region: region, + serial_number: serialNumber, status: 'ACTIVE', - system_version: headers['x-nintendo-system-version'], + system_version: systemVersion, type: 'RETAIL', updated_by: 'USER' } @@ -272,14 +288,14 @@ router.get('/@me/devices', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/devices/owner * Description: Gets user profile, seems to be the same as https://account.nintendo.net/v1/api/people/@me/profile */ -router.get('/@me/devices/owner', async (request, response) => { +router.get('/@me/devices/owner', async (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', moment().add(5, 'h').toString()); - const { pnid } = request; + const pnid: HydratedPNIDDocument = request.pnid; - const person = await database.getUserProfileJSONByPID(pnid.get('pid')); + const person: PNIDProfile = await database.getUserProfileJSONByPID(pnid.get('pid')); response.send(xmlbuilder.create({ person @@ -291,7 +307,7 @@ router.get('/@me/devices/owner', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/devices/status * Description: Unknown use */ -router.get('/@me/devices/status', async (request, response) => { +router.get('/@me/devices/status', async (_request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', moment().add(5, 'h').toString()); @@ -307,12 +323,15 @@ router.get('/@me/devices/status', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/miis/@primary * Description: Updates a users Mii */ -router.put('/@me/miis/@primary', async (request, response) => { - const { pnid } = request; +router.put('/@me/miis/@primary', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; - const mii = request.body.get('mii'); + // TODO - Make this more strictly typed? + const mii: Map = request.body.get('mii'); - const [name, primary, data] = [mii.get('name'), mii.get('primary'), mii.get('data')]; + const name: string = mii.get('name'); + const primary: string = mii.get('primary'); + const data: string = mii.get('data'); await pnid.updateMii({ name, primary, data }); @@ -324,11 +343,11 @@ router.put('/@me/miis/@primary', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/devices/@current/inactivate * Description: Deactivates a user from a console */ -router.put('/@me/devices/@current/inactivate', async (request, response) => { +router.put('/@me/devices/@current/inactivate', async (request: express.Request, response: express.Response) => { response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - const { pnid } = request; + const pnid: HydratedPNIDDocument = request.pnid; if (!pnid) { response.status(400); @@ -353,8 +372,8 @@ router.put('/@me/devices/@current/inactivate', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/deletion * Description: Deletes a NNID */ -router.put('/@me/deletion', async (request, response) => { - const { pnid } = request; +router.put('/@me/deletion', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; if (!pnid) { response.status(400); @@ -378,9 +397,9 @@ router.put('/@me/deletion', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/ * Description: Updates a PNIDs account details */ -router.put('/@me', async (request, response) => { - const { pnid } = request; - const person = request.body.get('person'); +router.put('/@me', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; + const person: Person = request.body.get('person'); if (!pnid) { response.status(400); @@ -396,27 +415,27 @@ router.put('/@me', async (request, response) => { }).end()); } - const gender = person.get('gender') ? person.get('gender') : pnid.get('gender'); - const region = person.get('region') ? person.get('region') : pnid.get('region'); - const countryCode = person.get('country') ? person.get('country') : pnid.get('country'); - const language = person.get('language') ? person.get('language') : pnid.get('language'); - const timezoneName = person.get('tz_name') ? person.get('tz_name') : pnid.get('timezone.name'); - const marketingFlag = person.get('marketing_flag') ? person.get('marketing_flag') === 'Y' : pnid.get('flags.marketing'); - const offDeviceFlag = person.get('off_device_flag') ? person.get('off_device_flag') === 'Y' : pnid.get('flags.off_device'); + const gender: string = person.get('gender') ? person.get('gender') : pnid.get('gender'); + const region: string = person.get('region') ? person.get('region') : pnid.get('region'); + const countryCode: string = person.get('country') ? person.get('country') : pnid.get('country'); + const language: string = person.get('language') ? person.get('language') : pnid.get('language'); + const timezoneName: string = person.get('tz_name') ? person.get('tz_name') : pnid.get('timezone.name'); + const marketingFlag: boolean = person.get('marketing_flag') ? person.get('marketing_flag') === 'Y' : pnid.get('flags.marketing'); + const offDeviceFlag: boolean = person.get('off_device_flag') ? person.get('off_device_flag') === 'Y' : pnid.get('flags.off_device'); - const regionLanguages = timezones[countryCode]; - const regionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; - const timezone = regionTimezones.find(tz => tz.area === timezoneName); + const regionLanguages: RegionLanguages = timezones[countryCode]; + const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; + const timezone: RegionTimezone = regionTimezones.find(tz => tz.area === timezoneName); if (person.get('password')) { - const primaryPasswordHash = util.nintendoPasswordHash(person.get('password'), pnid.get('pid')); - const passwordHash = await bcrypt.hash(primaryPasswordHash, 10); + const primaryPasswordHash: string = util.nintendoPasswordHash(person.get('password'), pnid.get('pid')); + const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; } pnid.gender = gender; - pnid.region = region; + pnid.region = Number(region); pnid.timezone.name = timezoneName; pnid.timezone.offset = Number(timezone.utc_offset); pnid.timezone.marketing = marketingFlag; @@ -432,8 +451,8 @@ router.put('/@me', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/emails/ * Description: Gets a list (why?) of PNID emails */ -router.get('/@me/emails', async (request, response) => { - const { pnid } = request; +router.get('/@me/emails', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; if (!pnid) { response.status(400); @@ -473,9 +492,11 @@ router.get('/@me/emails', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/people/@me/emails/@primary * Description: Updates a users email address */ -router.put('/@me/emails/@primary', async (request, response) => { - const { pnid } = request; - const email = request.body.get('email'); +router.put('/@me/emails/@primary', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; + + // TODO - Make this more strictly typed? + const email: Map = request.body.get('email'); if (!pnid) { response.status(400); diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 804839a..ca1de25 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -1,24 +1,29 @@ -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import fs from 'fs-extra'; import database from '@/database'; import util from '@/util'; import cache from '@/cache'; import { NEXAccount } from '@/models/nex-account'; +import { CryptoOptions } from '@/types/common/crypto-options'; +import { TokenOptions } from '@/types/common/token-options'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; +import { HydratedServerDocument } from '@/types/mongoose/server'; +import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; -const router = Router(); +const router: express.Router = express.Router(); /** * [GET] * Replacement for: https://account.nintendo.net/v1/api/provider/service_token/@me * Description: Gets a service token */ -router.get('/service_token/@me', async (request, response) => { - const { pnid } = request; +router.get('/service_token/@me', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; - const titleId = request.headers['x-nintendo-title-id'] as string; - const serverAccessLevel = pnid.get('server_access_level'); - const server = await database.getServerByTitleId(titleId, serverAccessLevel); + const titleId: string = request.headers['x-nintendo-title-id'] as string; + const serverAccessLevel: string = pnid.get('server_access_level'); + const server: HydratedServerDocument = await database.getServerByTitleId(titleId, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ @@ -31,9 +36,10 @@ router.get('/service_token/@me', async (request, response) => { }).end()); } - const { service_name, device } = server; + const serverName: string = server.service_name; + const device: number = server.device; - const cryptoPath = `${__dirname}/../../../../certs/service/${service_name}`; + const cryptoPath: string = `${__dirname}/../../../../certs/service/${serverName}`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -47,15 +53,15 @@ router.get('/service_token/@me', async (request, response) => { }).end()); } - const publicKey = await cache.getServicePublicKey(service_name); - const secretKey = await cache.getServiceSecretKey(service_name); + const publicKey: Buffer = await cache.getServicePublicKey(serverName); + const secretKey: Buffer = await cache.getServiceSecretKey(serverName); - const cryptoOptions = { + const cryptoOptions: CryptoOptions = { public_key: publicKey, hmac_secret: secretKey }; - const tokenOptions = { + const tokenOptions: TokenOptions = { system_type: device, token_type: 0x4, // service token, pid: pnid.get('pid'), @@ -64,7 +70,7 @@ router.get('/service_token/@me', async (request, response) => { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let serviceToken = await util.generateToken(cryptoOptions, tokenOptions); + let serviceToken: string = await util.generateToken(cryptoOptions, tokenOptions); if (request.isCemu) { serviceToken = Buffer.from(serviceToken, 'base64').toString('hex'); @@ -82,9 +88,9 @@ router.get('/service_token/@me', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/provider/nex_token/@me * Description: Gets a NEX server address and token */ -router.get('/nex_token/@me', async (request, response) => { - const { game_server_id: gameServerID } = request.query; - const { pnid } = request; +router.get('/nex_token/@me', async (request: express.Request, response: express.Response) => { + const pnid: HydratedPNIDDocument = request.pnid; + const gameServerID: string = request.query.game_server_id as string; if (!gameServerID) { return response.send(xmlbuilder.create({ @@ -97,8 +103,8 @@ router.get('/nex_token/@me', async (request, response) => { }).end()); } - const serverAccessLevel = pnid.get('server_access_level'); - const server = await database.getServer(gameServerID, serverAccessLevel); + const serverAccessLevel: string = pnid.get('server_access_level'); + const server: HydratedServerDocument = await database.getServer(gameServerID, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ @@ -111,10 +117,13 @@ router.get('/nex_token/@me', async (request, response) => { }).end()); } - const { service_name, ip, port, device } = server; - const titleId = request.headers['x-nintendo-title-id'] as string; + const serverName: string = server.service_name; + const ip: string = server.ip; + const port: number = server.port; + const device: number = server.device; + const titleId: string = request.headers['x-nintendo-title-id'] as string; - const cryptoPath = `${__dirname}/../../../../certs/nex/${service_name}`; + const cryptoPath: string = `${__dirname}/../../../../certs/nex/${serverName}`; if (!await fs.pathExists(cryptoPath)) { // Need to generate keys @@ -128,15 +137,15 @@ router.get('/nex_token/@me', async (request, response) => { }).end()); } - const publicKey = await cache.getNEXPublicKey(service_name); - const secretKey= await cache.getNEXSecretKey(service_name); + const publicKey: Buffer = await cache.getNEXPublicKey(serverName); + const secretKey: Buffer = await cache.getNEXSecretKey(serverName); - const cryptoOptions = { + const cryptoOptions: CryptoOptions = { public_key: publicKey, hmac_secret: secretKey }; - const tokenOptions = { + const tokenOptions: TokenOptions = { system_type: device, token_type: 0x3, // nex token, pid: pnid.get('pid'), @@ -145,7 +154,7 @@ router.get('/nex_token/@me', async (request, response) => { expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const nexUser = await NEXAccount.findOne({ + const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ owning_pid: pnid.get('pid') }); @@ -154,7 +163,7 @@ router.get('/nex_token/@me', async (request, response) => { return response.send('0008Not Found'); } - let nexToken = await util.generateToken(cryptoOptions, tokenOptions); + let nexToken: string = await util.generateToken(cryptoOptions, tokenOptions); if (request.isCemu) { nexToken = Buffer.from(nexToken, 'base64').toString('hex'); diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index b07bcff..edfe201 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -1,19 +1,20 @@ import dns from 'node:dns'; -import { Router } from 'express'; +import express from 'express'; import xmlbuilder from 'xmlbuilder'; import moment from 'moment'; import database from '@/database'; import util from '@/util'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -const router = Router(); +const router: express.Router = express.Router(); /** * [POST] * Replacement for: https://account.nintendo.net/v1/api/support/validate/email * Description: Verifies a provided email address is valid */ -router.post('/validate/email', async (request, response) => { - const { email } = request.body; +router.post('/validate/email', async (request: express.Request, response: express.Response) => { + const email: string = request.body; if (!email) { return response.send(xmlbuilder.create({ @@ -27,9 +28,9 @@ router.post('/validate/email', async (request, response) => { }).end()); } - const domain = email.split('@')[1]; + const domain: string = email.split('@')[1]; - dns.resolveMx(domain, (error) => { + dns.resolveMx(domain, (error: NodeJS.ErrnoException) => { if (error) { return response.send(xmlbuilder.create({ errors: { @@ -51,10 +52,11 @@ router.post('/validate/email', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/support/email_confirmation/:pid/:code * Description: Verifies a users email via 6 digit code */ -router.put('/email_confirmation/:pid/:code', async (request, response) => { - const { pid, code } = request.params; +router.put('/email_confirmation/:pid/:code', async (request: express.Request, response: express.Response) => { + const code: string = request.params.code; + const pid: number = Number(request.params.pid); - const pnid = await database.getUserByPID(pid); + const pnid: HydratedPNIDDocument = await database.getUserByPID(pid); if (!pnid) { return response.status(400).send(xmlbuilder.create({ @@ -78,7 +80,7 @@ router.put('/email_confirmation/:pid/:code', async (request, response) => { }).end()); } - const validatedDate = moment().format('YYYY-MM-DDTHH:MM:SS'); + const validatedDate: string = moment().format('YYYY-MM-DDTHH:MM:SS'); pnid.set('email.reachable', true); pnid.set('email.validated', true); @@ -96,10 +98,10 @@ router.put('/email_confirmation/:pid/:code', async (request, response) => { * Replacement for: https://account.nintendo.net/v1/api/support/resend_confirmation * Description: Resends a users confirmation email */ -router.get('/resend_confirmation', async (request, response) => { - const pid = request.headers['x-nintendo-pid']; +router.get('/resend_confirmation', async (request: express.Request, response: express.Response) => { + const pid: number = Number(request.headers['x-nintendo-pid']); - const pnid = await database.getUserByPID(pid); + const pnid: HydratedPNIDDocument = await database.getUserByPID(pid); if (!pnid) { // TODO - Unsure if this is the right error @@ -124,10 +126,10 @@ router.get('/resend_confirmation', async (request, response) => { * Description: Sends the user a password reset email * NOTE: On NN this was a temp password that expired after 24 hours. We do not do that */ -router.get('/forgotten_password/:pid', async (request, response) => { - const { pid } = request.params; +router.get('/forgotten_password/:pid', async (request: express.Request, response: express.Response) => { + const pid: number = Number(request.params.pid); - const pnid = await database.getUserByPID(pid); + const pnid: HydratedPNIDDocument = await database.getUserByPID(pid); if (!pnid) { // TODO - Better errors diff --git a/src/types/common/config.ts b/src/types/common/config.ts index ed3fbb2..4ce668d 100644 --- a/src/types/common/config.ts +++ b/src/types/common/config.ts @@ -37,7 +37,7 @@ export interface Config { base_url: string; }; website_base: string; -}; +} export interface DisabledFeatures { redis: boolean; diff --git a/src/types/common/crypto-options.ts b/src/types/common/crypto-options.ts new file mode 100644 index 0000000..d4a5918 --- /dev/null +++ b/src/types/common/crypto-options.ts @@ -0,0 +1,4 @@ +export interface CryptoOptions { + public_key: Buffer; + hmac_secret: Buffer; +}; \ No newline at end of file diff --git a/src/types/common/mailer-options.ts b/src/types/common/mailer-options.ts new file mode 100644 index 0000000..277cf33 --- /dev/null +++ b/src/types/common/mailer-options.ts @@ -0,0 +1,16 @@ +export interface MailerOptions { + to: string; + subject: string; + username: string; + paragraph?: string; + preview?: string; + text: string; + link?: { + href: string; + text: string; + }; + confirmation?: { + href: string; + code: string; + }; +}; \ No newline at end of file diff --git a/src/types/common/signature-size.ts b/src/types/common/signature-size.ts new file mode 100644 index 0000000..3fe755e --- /dev/null +++ b/src/types/common/signature-size.ts @@ -0,0 +1,4 @@ +export interface SignatureSize { + SIZE: number; + PADDING_SIZE: number; +}; \ No newline at end of file diff --git a/src/types/common/token-options.ts b/src/types/common/token-options.ts new file mode 100644 index 0000000..4a9bb15 --- /dev/null +++ b/src/types/common/token-options.ts @@ -0,0 +1,8 @@ +export interface TokenOptions { + system_type: number; + token_type: number; + pid: number; + access_level?: number; + title_id?: bigint; + expire_time: bigint; +}; \ No newline at end of file diff --git a/src/types/common/token.ts b/src/types/common/token.ts new file mode 100644 index 0000000..84673c2 --- /dev/null +++ b/src/types/common/token.ts @@ -0,0 +1,8 @@ +export interface Token { + system_type: number; + token_type: number; + pid: number; + access_level?: number; + title_id?: bigint; + expire_time: bigint; +}; \ No newline at end of file diff --git a/src/types/common/yes-no-bool-string.ts b/src/types/common/yes-no-bool-string.ts new file mode 100644 index 0000000..474aa6e --- /dev/null +++ b/src/types/common/yes-no-bool-string.ts @@ -0,0 +1 @@ +export type YesNoBoolString = 'Y' | 'N'; \ No newline at end of file diff --git a/src/types/express.d.ts b/src/types/express.d.ts index e6669ab..26882cb 100644 --- a/src/types/express.d.ts +++ b/src/types/express.d.ts @@ -1,13 +1,12 @@ -import { HydratedDocument } from 'mongoose'; import NintendoCertificate from '@/nintendo-certificate'; -import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; -import { INEXAccount, INEXAccountMethods } from '@/types/mongoose/nex-account'; +import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; +import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; declare global { namespace Express { interface Request { - pnid?: HydratedDocument; - nexUser?: HydratedDocument; + pnid?: HydratedPNIDDocument; + nexUser?: HydratedNEXAccountDocument; isCemu?: boolean; files?: Record; certificate?: NintendoCertificate; diff --git a/src/types/mongoose/device-attribute.ts b/src/types/mongoose/device-attribute.ts index 2c5a2bf..d77c3d8 100644 --- a/src/types/mongoose/device-attribute.ts +++ b/src/types/mongoose/device-attribute.ts @@ -1,11 +1,13 @@ import { Model } from 'mongoose'; export interface IDeviceAttribute { - created_date: string; + created_date?: string; name: string; value: string; } export interface IDeviceAttributeMethods {} -export interface DeviceAttributeModel extends Model {} \ No newline at end of file +export interface IDeviceAttributeQueryHelpers {} + +export interface DeviceAttributeModel extends Model {} \ No newline at end of file diff --git a/src/types/mongoose/device.ts b/src/types/mongoose/device.ts index 9fe4ba3..d9dcb1f 100644 --- a/src/types/mongoose/device.ts +++ b/src/types/mongoose/device.ts @@ -1,5 +1,5 @@ -import { Model } from 'mongoose'; -import { DeviceAttributeSchema } from '@/models/device'; +import { Model, Types, HydratedDocument } from 'mongoose'; +import { IDeviceAttribute } from '@/types/mongoose/device-attribute'; type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan'; type ACCESS_LEVEL = 0 | 1 | 2 | 3; @@ -11,11 +11,11 @@ export interface IDevice { device_id: number; device_type: number; serial: string; - device_attributes: typeof DeviceAttributeSchema[]; + device_attributes: Types.DocumentArray; soap: { token: string; account_id: number; - }, + }; // * 3DS-specific stuff environment: string; mac_hash: string; @@ -27,4 +27,8 @@ export interface IDevice { export interface IDeviceMethods {} -export interface DeviceModel extends Model {} \ No newline at end of file +export interface IDeviceQueryHelpers {} + +export interface DeviceModel extends Model {} + +export type HydratedDeviceDocument = HydratedDocument \ No newline at end of file diff --git a/src/types/mongoose/nex-account.ts b/src/types/mongoose/nex-account.ts index b109527..fadc1bb 100644 --- a/src/types/mongoose/nex-account.ts +++ b/src/types/mongoose/nex-account.ts @@ -1,4 +1,4 @@ -import { Model } from 'mongoose'; +import { Model, HydratedDocument } from 'mongoose'; type DEVICE = 'wiiu' | '3ds'; type ACCESS_LEVEL = 0 | 1 | 2 | 3; @@ -17,4 +17,8 @@ export interface INEXAccountMethods { generatePassword(): void; } -export interface NEXAccountModel extends Model {} \ No newline at end of file +export interface INEXAccountQueryHelpers {} + +export interface NEXAccountModel extends Model {} + +export type HydratedNEXAccountDocument = HydratedDocument \ No newline at end of file diff --git a/src/types/mongoose/pnid.ts b/src/types/mongoose/pnid.ts index e52f064..8f87458 100644 --- a/src/types/mongoose/pnid.ts +++ b/src/types/mongoose/pnid.ts @@ -1,5 +1,5 @@ -import { Model } from 'mongoose'; -import { DeviceSchema } from '@/models/device'; +import { Model, Types, HydratedDocument } from 'mongoose'; +import { IDevice } from '@/types/mongoose/device'; export interface IPNID { access_level: number; @@ -44,14 +44,14 @@ export interface IPNID { marketing: boolean; off_device: boolean; }; - devices: typeof DeviceSchema[]; + devices: Types.DocumentArray; identification: { // user identification tokens email_code: string; email_token: string; access_token: { value: string; ttl: number; - }, + }; refresh_token: { value: string; ttl: number; @@ -73,4 +73,8 @@ export interface IPNIDMethods { getServerMode(): string; } -export interface PNIDModel extends Model {} \ No newline at end of file +export interface IPNIDQueryHelpers {} + +export interface PNIDModel extends Model {} + +export type HydratedPNIDDocument = HydratedDocument \ No newline at end of file diff --git a/src/types/mongoose/server.ts b/src/types/mongoose/server.ts index f25198e..65865d2 100644 --- a/src/types/mongoose/server.ts +++ b/src/types/mongoose/server.ts @@ -1,8 +1,8 @@ -import { Model } from 'mongoose'; +import { Model, HydratedDocument } from 'mongoose'; export interface IServer { ip: string; // Example: 1.1.1.1 - port: Number; // Example: 60000 + port: number; // Example: 60000 service_name: string; // Example: friends service_type: string; // Example: nex game_server_id: string; // Example: 00003200 @@ -14,4 +14,8 @@ export interface IServer { export interface IServerMethods {} -export interface ServerModel extends Model {} \ No newline at end of file +export interface IServerQueryHelpers {} + +export interface ServerModel extends Model {} + +export type HydratedServerDocument = HydratedDocument \ No newline at end of file diff --git a/src/types/services/api/connection-data.ts b/src/types/services/api/connection-data.ts new file mode 100644 index 0000000..54fe992 --- /dev/null +++ b/src/types/services/api/connection-data.ts @@ -0,0 +1,4 @@ +import { DiscordConnectionData } from '@/types/services/api/discord-connection-data'; + +// TODO - This will be a union of all ConnectionData types when more connections are added +export type ConnectionData = DiscordConnectionData; \ No newline at end of file diff --git a/src/types/services/api/connection-response.ts b/src/types/services/api/connection-response.ts new file mode 100644 index 0000000..6baa9b0 --- /dev/null +++ b/src/types/services/api/connection-response.ts @@ -0,0 +1,5 @@ +export interface ConnectionResponse { + app: string; + status: number; + error?: string; +} \ No newline at end of file diff --git a/src/types/services/api/discord-connection-data.ts b/src/types/services/api/discord-connection-data.ts new file mode 100644 index 0000000..b9ed367 --- /dev/null +++ b/src/types/services/api/discord-connection-data.ts @@ -0,0 +1,3 @@ +export interface DiscordConnectionData { + id: string; +}; \ No newline at end of file diff --git a/src/types/services/api/update-user-request.ts b/src/types/services/api/update-user-request.ts new file mode 100644 index 0000000..a525e98 --- /dev/null +++ b/src/types/services/api/update-user-request.ts @@ -0,0 +1,7 @@ +export interface UpdateUserRequest { + mii?: { + name: string; + primary: string; + data: string; + } +} \ No newline at end of file diff --git a/src/types/services/nasc/request-params.ts b/src/types/services/nasc/request-params.ts new file mode 100644 index 0000000..aafcda6 --- /dev/null +++ b/src/types/services/nasc/request-params.ts @@ -0,0 +1,11 @@ +export interface NASCRequestParams { + action: string; + fcdcert: string; + csnum: string; + macadr: string; + titleid: string; + servertype: string; + userid?: string; + uidhmac?: string; + passwd?: string; +} \ No newline at end of file diff --git a/src/types/services/nnid/person.ts b/src/types/services/nnid/person.ts new file mode 100644 index 0000000..9da3757 --- /dev/null +++ b/src/types/services/nnid/person.ts @@ -0,0 +1,44 @@ +import { YesNoBoolString } from '@/types/common/yes-no-bool-string'; +import { IDeviceAttribute } from '@/types/mongoose/device-attribute'; + +// TODO - Change this Map type to something more strongly typed +export interface Person extends Map { + birth_date: string; + user_id: string; + password: string; + country: string; + language: string; + tz_name: string; + agreement: { + agreement_date: string; + country: string; + location: string; + type: string; + version: string; + }; + email: { + address: string; + owned: YesNoBoolString; + parent: YesNoBoolString; + primary: YesNoBoolString; + validated: YesNoBoolString; + type: string; + }; + mii: { + name: string; + primary: YesNoBoolString; + data: string; + }; + parental_consent: { + scope: string; + consent_date: string; + approval_id: string; + }; + gender: string; + region: string; + marketing_flag: YesNoBoolString; + device_attributes: { + device_attribute: IDeviceAttribute[] + }; + off_device_flag: YesNoBoolString; +} \ No newline at end of file diff --git a/src/types/services/nnid/pnid-profile.ts b/src/types/services/nnid/pnid-profile.ts new file mode 100644 index 0000000..ac95915 --- /dev/null +++ b/src/types/services/nnid/pnid-profile.ts @@ -0,0 +1,53 @@ +import { YesNoBoolString } from '@/types/common/yes-no-bool-string'; + +export interface PNIDProfile { + //accounts: {}; // * We need to figure this out; no idea what these values mean or what they do + active_flag: YesNoBoolString; + birth_date: string; + country: string; + create_date: string; + device_attributes: [{ + device_attribute: { + name: string; + value: string; + created_date: string; + }; + }]; + gender: string; + language: string; + updated: string; + marketing_flag: YesNoBoolString; + off_device_flag: YesNoBoolString; + pid: number; + email: { + address: string; + id: string; + parent: YesNoBoolString; + primary: YesNoBoolString; + reachable: YesNoBoolString; + type: 'DEFAULT'; + updated_by: 'USER'; // * Can also be INTERNAL WS; don't know the difference + validated: YesNoBoolString; + validated_date: string; + }; + mii: { + status: 'COMPLETED'; + data: string; + id: number; + mii_hash: string; + mii_images: { + mii_image: { + cached_url: string; + id: string; + url: string; + type: 'standard'; + } + }; + name: string; + primary: YesNoBoolString; + }; + region: number; + tz_name: string; + user_id: string; + utc_offset: number; +} \ No newline at end of file diff --git a/src/types/services/nnid/region-languages.ts b/src/types/services/nnid/region-languages.ts new file mode 100644 index 0000000..e25307d --- /dev/null +++ b/src/types/services/nnid/region-languages.ts @@ -0,0 +1,5 @@ +import { RegionTimezones } from '@/types/services/nnid/region-timezones'; + +export interface RegionLanguages { + [myKey: string]: RegionTimezones +} \ No newline at end of file diff --git a/src/types/services/nnid/region-timezones.ts b/src/types/services/nnid/region-timezones.ts new file mode 100644 index 0000000..c904aaa --- /dev/null +++ b/src/types/services/nnid/region-timezones.ts @@ -0,0 +1,9 @@ +export interface RegionTimezone { + area: string; + language: string; + name: string; + utc_offset: string; + order: string; +} + +export type RegionTimezones = RegionTimezone[]; \ No newline at end of file diff --git a/src/util.ts b/src/util.ts index e383f93..eaec4c4 100644 --- a/src/util.ts +++ b/src/util.ts @@ -3,11 +3,18 @@ import path from 'node:path'; import NodeRSA from 'node-rsa'; import aws from 'aws-sdk'; import fs from 'fs-extra'; +import express from 'express'; +import mongoose from 'mongoose'; import mailer from '@/mailer'; import cache from '@/cache'; import { config, disabledFeatures } from '@/config-manager'; +import { CryptoOptions } from '@/types/common/crypto-options'; +import { TokenOptions } from '@/types/common/token-options'; +import { Token } from '@/types/common/token'; +import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; +import { MailerOptions } from '@/types/common/mailer-options'; -let s3; +let s3: aws.S3; if (!disabledFeatures.s3) { s3 = new aws.S3({ @@ -18,17 +25,16 @@ if (!disabledFeatures.s3) { } function nintendoPasswordHash(password: string, pid: number): string { - const pidBuffer = Buffer.alloc(4); + const pidBuffer: Buffer = Buffer.alloc(4); pidBuffer.writeUInt32LE(pid); - const unpacked = Buffer.concat([ + const unpacked: Buffer = Buffer.concat([ pidBuffer, Buffer.from('\x02\x65\x43\x46'), Buffer.from(password) ]); - const hashed = crypto.createHash('sha256').update(unpacked).digest().toString('hex'); - return hashed; + return crypto.createHash('sha256').update(unpacked).digest().toString('hex'); } function nintendoBase64Decode(encoded: string): Buffer { @@ -37,41 +43,42 @@ function nintendoBase64Decode(encoded: string): Buffer { } function nintendoBase64Encode(decoded: string | Buffer): string { - const encoded = Buffer.from(decoded).toString('base64'); + const encoded: string = Buffer.from(decoded).toString('base64'); return encoded.replaceAll('+', '.').replaceAll('/', '-').replaceAll('=', '*'); } -async function generateToken(cryptoOptions, tokenOptions): Promise { +async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: TokenOptions): Promise { // Access and refresh tokens use a different format since they must be much smaller // They take no extra crypto options if (!cryptoOptions) { - const aesKey = await cache.getServiceAESKey('account', 'hex'); + const aesKey: Buffer = await cache.getServiceAESKey('account', 'hex'); - const dataBuffer = Buffer.alloc(1 + 1 + 4 + 8); + const dataBuffer: Buffer = Buffer.alloc(1 + 1 + 4 + 8); dataBuffer.writeUInt8(tokenOptions.system_type, 0x0); dataBuffer.writeUInt8(tokenOptions.token_type, 0x1); dataBuffer.writeUInt32LE(tokenOptions.pid, 0x2); dataBuffer.writeBigUInt64LE(tokenOptions.expire_time, 0x6); - const iv = Buffer.alloc(16); - const cipher = crypto.createCipheriv('aes-128-cbc', aesKey, iv); + const iv: Buffer = Buffer.alloc(16); + const cipher: crypto.Cipher = crypto.createCipheriv('aes-128-cbc', aesKey, iv); - let encryptedBody = cipher.update(dataBuffer); + let encryptedBody: Buffer = cipher.update(dataBuffer); encryptedBody = Buffer.concat([encryptedBody, cipher.final()]); return encryptedBody.toString('base64'); } - const publicKey = new NodeRSA(cryptoOptions.public_key, 'pkcs8-public-pem', { + const publicKey: NodeRSA = new NodeRSA(cryptoOptions.public_key, 'pkcs8-public-pem', { environment: 'browser', encryptionScheme: { - 'hash': 'sha256', + scheme: 'pkcs1_oaep', + hash: 'sha256' } }); // Create the buffer containing the token data - const dataBuffer = Buffer.alloc(1 + 1 + 4 + 1 + 8 + 8); + const dataBuffer: Buffer = Buffer.alloc(1 + 1 + 4 + 1 + 8 + 8); dataBuffer.writeUInt8(tokenOptions.system_type, 0x0); dataBuffer.writeUInt8(tokenOptions.token_type, 0x1); @@ -81,8 +88,8 @@ async function generateToken(cryptoOptions, tokenOptions): Promise { dataBuffer.writeBigUInt64LE(tokenOptions.expire_time, 0xF); // Calculate the signature of the token body - const hmac = crypto.createHmac('sha1', cryptoOptions.hmac_secret).update(dataBuffer); - const signature = hmac.digest(); + const hmac: crypto.Hmac = crypto.createHmac('sha1', cryptoOptions.hmac_secret).update(dataBuffer); + const signature: Buffer = hmac.digest(); // You can thank the 3DS for the shit thats about to happen with the AES IV // The 3DS only allows for strings up to 255 characters in NEX @@ -90,35 +97,37 @@ async function generateToken(cryptoOptions, tokenOptions): Promise { // I am sorry, and have already asked every God I could think of for forgiveness // Generate random AES key - const key = crypto.randomBytes(16); + const key: Buffer = crypto.randomBytes(16); // Encrypt the AES key with RSA public key - const encryptedKey = publicKey.encrypt(key); + const encryptedKey: Buffer = publicKey.encrypt(key); // Take two random points in the RSA encrypted key - const point1 = ~~((encryptedKey.length - 8) * Math.random()); - const point2 = ~~((encryptedKey.length - 8) * Math.random()); + const point1: number = ~~((encryptedKey.length - 8) * Math.random()); + const point2: number = ~~((encryptedKey.length - 8) * Math.random()); // Build an IV from each of the two points - const iv = Buffer.concat([ + const iv: Buffer = Buffer.concat([ Buffer.from(encryptedKey.subarray(point1, point1 + 8)), Buffer.from(encryptedKey.subarray(point2, point2 + 8)) ]); - const cipher = crypto.createCipheriv('aes-128-cbc', key, iv); + const cipher: crypto.Cipher = crypto.createCipheriv('aes-128-cbc', key, iv); // Encrypt the token body with AES - let encryptedBody = cipher.update(dataBuffer); - encryptedBody = Buffer.concat([encryptedBody, cipher.final()]); + const encryptedBody: Buffer = Buffer.concat([ + cipher.update(dataBuffer), + cipher.final() + ]); // Create crypto config token section - const cryptoConfig = Buffer.concat([ + const cryptoConfig: Buffer = Buffer.concat([ encryptedKey, Buffer.from([point1, point2]) ]); // Build the token - const token = Buffer.concat([ + const token: Buffer = Buffer.concat([ cryptoConfig, signature, encryptedBody @@ -127,54 +136,59 @@ async function generateToken(cryptoOptions, tokenOptions): Promise { return token.toString('base64'); // Encode to base64 for transport } -async function decryptToken(token) { +async function decryptToken(token: Buffer): Promise { // Access and refresh tokens use a different format since they must be much smaller // Assume a small length means access or refresh token if (token.length <= 32) { - const aesKey = await cache.getServiceAESKey('account', 'hex'); + const aesKey: Buffer = await cache.getServiceAESKey('account', 'hex'); - const iv = Buffer.alloc(16); + const iv: Buffer = Buffer.alloc(16); - const decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv); + const decipher: crypto.Decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv); - let decryptedBody = decipher.update(token); - decryptedBody = Buffer.concat([decryptedBody, decipher.final()]); + const decryptedBody: Buffer = Buffer.concat([ + decipher.update(token), + decipher.final() + ]); return decryptedBody; } - const privateKeyBytes = await cache.getServicePrivateKey('account'); - const secretKey = await cache.getServiceSecretKey('account'); + const privateKeyBytes: Buffer = await cache.getServicePrivateKey('account'); + const secretKey: Buffer = await cache.getServiceSecretKey('account'); - const privateKey = new NodeRSA(privateKeyBytes, 'pkcs1-private-pem', { + const privateKey: NodeRSA = new NodeRSA(privateKeyBytes, 'pkcs1-private-pem', { environment: 'browser', encryptionScheme: { - 'hash': 'sha256', + scheme: 'pkcs1_oaep', + hash: 'sha256' } }); - const cryptoConfig = token.subarray(0, 0x82); - const signature = token.subarray(0x82, 0x96); - const encryptedBody = token.subarray(0x96); + const cryptoConfig: Buffer = token.subarray(0, 0x82); + const signature: Buffer = token.subarray(0x82, 0x96); + const encryptedBody: Buffer = token.subarray(0x96); - const encryptedAESKey = cryptoConfig.subarray(0, 128); - const point1 = cryptoConfig.readInt8(0x80); - const point2 = cryptoConfig.readInt8(0x81); + const encryptedAESKey: Buffer = cryptoConfig.subarray(0, 128); + const point1: number = cryptoConfig.readInt8(0x80); + const point2: number = cryptoConfig.readInt8(0x81); - const iv = Buffer.concat([ + const iv: Buffer = Buffer.concat([ Buffer.from(encryptedAESKey.subarray(point1, point1 + 8)), Buffer.from(encryptedAESKey.subarray(point2, point2 + 8)) ]); - const decryptedAESKey = privateKey.decrypt(encryptedAESKey); + const decryptedAESKey: Buffer = privateKey.decrypt(encryptedAESKey); - const decipher = crypto.createDecipheriv('aes-128-cbc', decryptedAESKey, iv); + const decipher: crypto.Decipher = crypto.createDecipheriv('aes-128-cbc', decryptedAESKey, iv); - let decryptedBody = decipher.update(encryptedBody); - decryptedBody = Buffer.concat([decryptedBody, decipher.final()]); + const decryptedBody: Buffer = Buffer.concat([ + decipher.update(encryptedBody), + decipher.final() + ]); - const hmac = crypto.createHmac('sha1', secretKey).update(decryptedBody); - const calculatedSignature = hmac.digest(); + const hmac: crypto.Hmac = crypto.createHmac('sha1', secretKey).update(decryptedBody); + const calculatedSignature: Buffer = hmac.digest(); if (!signature.equals(calculatedSignature)) { console.log('Token signature did not match'); @@ -184,9 +198,9 @@ async function decryptToken(token) { return decryptedBody; } -function unpackToken(token) { +function unpackToken(token: Buffer): Token { if (token.length <= 14) { - return { + return { system_type: token.readUInt8(0x0), token_type: token.readUInt8(0x1), pid: token.readUInt32LE(0x2), @@ -194,7 +208,7 @@ function unpackToken(token) { }; } - return { + return { system_type: token.readUInt8(0x0), token_type: token.readUInt8(0x1), pid: token.readUInt32LE(0x2), @@ -204,49 +218,45 @@ function unpackToken(token) { }; } -function fullUrl(request) { - const protocol = request.protocol; - const host = request.host; - const opath = request.originalUrl; +function fullUrl(request: express.Request): string { + const protocol: string = request.protocol; + const host: string = request.host; + const opath: string = request.originalUrl; return `${protocol}://${host}${opath}`; } -async function uploadCDNAsset(bucket, key, data, acl) { +async function uploadCDNAsset(bucket: string, key: string, data: Buffer, acl: string): Promise { if (disabledFeatures.s3) { await writeLocalCDNFile(key, data); } else { - const awsPutParams = { + await s3.putObject({ Body: data, Key: key, Bucket: bucket, ACL: acl - }; - - await s3.putObject(awsPutParams).promise(); + }).promise(); } } -async function writeLocalCDNFile(key, data) { - const filePath = config.cdn.disk_path; - const folder = path.dirname(filePath); +async function writeLocalCDNFile(key: string, data: Buffer): Promise { + const filePath: string = config.cdn.disk_path; + const folder: string = path.dirname(filePath); await fs.ensureDir(folder); await fs.writeFile(filePath, data); } -function nascError(errorCode) { - const params = new URLSearchParams({ +function nascError(errorCode: string): URLSearchParams { + return new URLSearchParams({ retry: nintendoBase64Encode('1'), returncd: errorCode == 'null' ? errorCode : nintendoBase64Encode(errorCode), datetime: nintendoBase64Encode(Date.now().toString()), }); - - return params; } -async function sendConfirmationEmail(pnid) { - await mailer.sendMail({ +async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { + const options: MailerOptions = { to: pnid.get('email.address'), subject: '[Pretendo Network] Please confirm your email address', username: pnid.get('username'), @@ -255,30 +265,33 @@ async function sendConfirmationEmail(pnid) { code: pnid.get('identification.email_code') }, text: `Hello ${pnid.get('username')}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.get('identification.email_code')}` - }); + }; + await mailer.sendMail(options); } -async function sendEmailConfirmedEmail(pnid) { - await mailer.sendMail({ +async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument): Promise { + const options: MailerOptions = { to: pnid.get('email.address'), subject: '[Pretendo Network] Email address confirmed', username: pnid.get('username'), paragraph: 'your email address has been confirmed. We hope you have fun on Pretendo Network!', text: `Dear ${pnid.get('username')}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` - }); + }; + + await mailer.sendMail(options); } -async function sendForgotPasswordEmail(pnid) { - const publicKey = await cache.getServicePublicKey('account'); - const secretKey = await cache.getServiceSecretKey('account'); +async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument): Promise { + const publicKey: Buffer = await cache.getServicePublicKey('account'); + const secretKey: Buffer = await cache.getServiceSecretKey('account'); - const cryptoOptions = { + const cryptoOptions: CryptoOptions = { public_key: publicKey, hmac_secret: secretKey }; - const tokenOptions = { + const tokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x5, // Password reset pid: pnid.get('pid'), @@ -287,9 +300,9 @@ async function sendForgotPasswordEmail(pnid) { expire_time: BigInt(Date.now() + (24 * 60 * 60 * 1000)) // Only valid for 24 hours }; - const passwordResetToken = await generateToken(cryptoOptions, tokenOptions); + const passwordResetToken: string = await generateToken(cryptoOptions, tokenOptions); - await mailer.sendMail({ + const mailerOptions: MailerOptions = { to: pnid.get('email.address'), subject: '[Pretendo Network] Forgot Password', username: pnid.get('username'), @@ -299,7 +312,9 @@ async function sendForgotPasswordEmail(pnid) { href: `${config.website_base}/account/reset-password?token=${encodeURIComponent(passwordResetToken)}` }, text: `Dear ${pnid.get('username')}, a password reset has been requested from this account. \r\n\r\nIf you did not request the password reset, please ignore this email. \r\nIf you did request this password reset, please click the link to reset your password: ${config.website_base}/account/reset-password?token=${encodeURIComponent(passwordResetToken)}` - }); + }; + + await mailer.sendMail(mailerOptions); } export default { diff --git a/tsconfig.json b/tsconfig.json index 16ad818..e8db98d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,7 +11,11 @@ "noEmitOnError": true, "paths": { "@/*": ["./*"] - } + }, + "typeRoots": [ + "node_modules/@types", + "node_modules/@hcaptcha" + ] }, "include": ["src"] } \ No newline at end of file From 7660b9134c76a90b2175b591aef109e59b86e5ad Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 6 Mar 2023 21:07:35 -0500 Subject: [PATCH 31/65] Removed unused exports --- src/cache.ts | 42 +++++++++++++------------- src/config-manager.ts | 7 +---- src/database.ts | 30 +++++++++--------- src/mailer.ts | 2 +- src/middleware/api.ts | 2 +- src/middleware/cemu.ts | 2 +- src/middleware/client-header.ts | 2 +- src/middleware/device-certificate.ts | 2 +- src/middleware/nasc.ts | 2 +- src/middleware/pnid.ts | 2 +- src/middleware/xml-parser.ts | 2 +- src/models/device.ts | 13 ++------ src/models/nex-account.ts | 9 ++---- src/models/pnid.ts | 9 ++---- src/models/server.ts | 9 ++---- src/nintendo-certificate.ts | 4 +-- src/types/mongoose/device-attribute.ts | 2 +- src/types/mongoose/device.ts | 2 +- src/types/mongoose/nex-account.ts | 2 +- src/types/mongoose/pnid.ts | 2 +- src/types/mongoose/server.ts | 2 +- 21 files changed, 60 insertions(+), 89 deletions(-) diff --git a/src/cache.ts b/src/cache.ts index 7da86d2..f14f2d1 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -10,7 +10,7 @@ const SERVICE_CERTS_BASE: string = `${__dirname}/../certs/service`; const NEX_CERTS_BASE: string = `${__dirname}/../certs/nex`; const LOCAL_CDN_BASE: string = `${__dirname}/../cdn`; -export async function connect(): Promise { +async function connect(): Promise { if (!disabledFeatures.redis) { client = redis.createClient(config.redis.client); client.on('error', (err) => console.log('Redis Client Error', err)); @@ -19,7 +19,7 @@ export async function connect(): Promise { } } -export async function setCachedFile(fileName: string, value: Buffer): Promise { +async function setCachedFile(fileName: string, value: Buffer): Promise { if (disabledFeatures.redis) { memoryCache[fileName] = value; } else { @@ -27,7 +27,7 @@ export async function setCachedFile(fileName: string, value: Buffer): Promise { +async function getCachedFile(fileName: string, encoding?: BufferEncoding): Promise { let cachedFile: Buffer; if (disabledFeatures.redis) { @@ -44,7 +44,7 @@ export async function getCachedFile(fileName: string, encoding?: BufferEncoding) // * NEX server cache functions -export async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise { +async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise { let publicKey: Buffer = await getCachedFile(`nex:${name}:public_key`, encoding); if (publicKey === null) { @@ -55,7 +55,7 @@ export async function getNEXPublicKey(name: string, encoding?: BufferEncoding): return publicKey; } -export async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promise { +async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promise { let privateKey: Buffer = await getCachedFile(`nex:${name}:private_key`, encoding); if (privateKey === null) { @@ -66,7 +66,7 @@ export async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): return privateKey; } -export async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise { +async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise { let secretKey: Buffer = await getCachedFile(`nex:${name}:secret_key`, encoding); if (secretKey === null) { @@ -78,7 +78,7 @@ export async function getNEXSecretKey(name: string, encoding?: BufferEncoding): return secretKey; } -export async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { +async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { let aesKey: Buffer = await getCachedFile(`nex:${name}:aes_key`, encoding); if (aesKey === null) { @@ -90,25 +90,25 @@ export async function getNEXAESKey(name: string, encoding?: BufferEncoding): Pro return aesKey; } -export async function setNEXPublicKey(name: string, value: Buffer): Promise { +async function setNEXPublicKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:public_key`, value); } -export async function setNEXPrivateKey(name: string, value: Buffer): Promise { +async function setNEXPrivateKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:private_key`, value); } -export async function setNEXSecretKey(name: string, value: Buffer): Promise { +async function setNEXSecretKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:secret_key`, value); } -export async function setNEXAESKey(name: string, value: Buffer): Promise { +async function setNEXAESKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:aes_key`, value); } // * 3rd party service cache functions -export async function getServicePublicKey(name: string, encoding?: BufferEncoding): Promise { +async function getServicePublicKey(name: string, encoding?: BufferEncoding): Promise { let publicKey: Buffer = await getCachedFile(`service:${name}:public_key`, encoding); if (publicKey === null) { @@ -119,7 +119,7 @@ export async function getServicePublicKey(name: string, encoding?: BufferEncodin return publicKey; } -export async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Promise { +async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Promise { let privateKey: Buffer = await getCachedFile(`service:${name}:private_key`, encoding); if (privateKey === null) { @@ -130,7 +130,7 @@ export async function getServicePrivateKey(name: string, encoding?: BufferEncodi return privateKey; } -export async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Promise { +async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Promise { let secretKey: Buffer = await getCachedFile(`service:${name}:secret_key`, encoding); if (secretKey === null) { @@ -142,7 +142,7 @@ export async function getServiceSecretKey(name: string, encoding?: BufferEncodin return secretKey; } -export async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promise { +async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promise { let aesKey: Buffer = await getCachedFile(`service:${name}:aes_key`, encoding); if (aesKey === null) { @@ -154,25 +154,25 @@ export async function getServiceAESKey(name: string, encoding?: BufferEncoding): return aesKey; } -export async function setServicePublicKey(name: string, value: Buffer): Promise { +async function setServicePublicKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:public_key`, value); } -export async function setServicePrivateKey(name: string, value: Buffer): Promise { +async function setServicePrivateKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:private_key`, value); } -export async function setServiceSecretKey(name: string, value: Buffer): Promise { +async function setServiceSecretKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:secret_key`, value); } -export async function setServiceAESKey(name: string, value: Buffer): Promise { +async function setServiceAESKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:aes_key`, value); } // * Local CDN cache functions -export async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise { +async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise { let file: Buffer = await getCachedFile(`local_cdn:${name}`, encoding); if (file === null) { @@ -186,7 +186,7 @@ export async function getLocalCDNFile(name: string, encoding?: BufferEncoding): return file; } -export async function setLocalCDNFile(name: string, value: Buffer): Promise { +async function setLocalCDNFile(name: string, value: Buffer): Promise { await setCachedFile(`local_cdn:${name}`, value); } diff --git a/src/config-manager.ts b/src/config-manager.ts index db16603..ed5631a 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -155,9 +155,4 @@ if (disabledFeatures.s3) { if (disabledFeatures.redis) { logger.warn('Both s3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable s3 if you\'re running a production server.'); } -} - -export default { - config, - disabledFeatures -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/database.ts b/src/database.ts index 0bd36bb..fa3e10d 100644 --- a/src/database.ts +++ b/src/database.ts @@ -25,14 +25,14 @@ const discordConnectionSchema: joi.ObjectSchema = joi.object({ let _connection: mongoose.Connection; -export async function connect(): Promise { +async function connect(): Promise { await mongoose.connect(connection_string, options); _connection = mongoose.connection; _connection.on('error', console.error.bind(console, 'connection error:')); } -export function connection(): mongoose.Connection { +function connection(): mongoose.Connection { return _connection; } @@ -42,7 +42,7 @@ function verifyConnected(): void { } } -export async function getUserByUsername(username: string): Promise { +async function getUserByUsername(username: string): Promise { verifyConnected(); if (typeof username !== 'string') { @@ -54,7 +54,7 @@ export async function getUserByUsername(username: string): Promise { +async function getUserByPID(pid: number): Promise { verifyConnected(); return await PNID.findOne({ @@ -62,7 +62,7 @@ export async function getUserByPID(pid: number): Promise { }) as HydratedPNIDDocument; } -export async function getUserByEmailAddress(email: string): Promise { +async function getUserByEmailAddress(email: string): Promise { verifyConnected(); return await PNID.findOne({ @@ -70,13 +70,13 @@ export async function getUserByEmailAddress(email: string): Promise { +async function doesUserExist(username: string): Promise { verifyConnected(); return !!await getUserByUsername(username); } -export async function getUserBasic(token: string): Promise { +async function getUserBasic(token: string): Promise { verifyConnected(); // * Wii U sends Basic auth as `username password`, where the password may not have spaces @@ -102,7 +102,7 @@ export async function getUserBasic(token: string): Promise return user; } -export async function getUserBearer(token: string): Promise { +async function getUserBearer(token: string): Promise { verifyConnected(); try { @@ -127,7 +127,7 @@ export async function getUserBearer(token: string): Promise { +async function getUserProfileJSONByPID(pid: number): Promise { verifyConnected(); const user: HydratedPNIDDocument = await getUserByPID(pid); @@ -199,27 +199,27 @@ export async function getUserProfileJSONByPID(pid: number): Promise }; } -export async function getServer(gameServerId: string, accessMode: string): Promise { +async function getServer(gameServerId: string, accessMode: string): Promise { return await Server.findOne({ game_server_id: gameServerId, access_mode: accessMode }); } -export async function getServerByTitleId(titleId: string, accessMode: string): Promise { +async function getServerByTitleId(titleId: string, accessMode: string): Promise { return await Server.findOne({ title_ids: titleId, access_mode: accessMode }); } -export async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { +async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { if (type === 'discord') { return await addUserConnectionDiscord(pnid, data); } } -export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { +async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { const valid: joi.ValidationResult = discordConnectionSchema.validate(data); if (valid.error) { @@ -242,14 +242,14 @@ export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: }; } -export async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { +async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { // * Add more connections later? if (type === 'discord') { return await removeUserConnectionDiscord(pnid); } } -export async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { +async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { await PNID.updateOne({ pid: pnid.get('pid') }, { $set: { 'connections.discord.id': '' diff --git a/src/mailer.ts b/src/mailer.ts index fd39b85..d87ec72 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -13,7 +13,7 @@ if (!disabledFeatures.email) { transporter = nodemailer.createTransport(config.email); } -export async function sendMail(options: MailerOptions): Promise { +async function sendMail(options: MailerOptions): Promise { if (!disabledFeatures.email) { const { to, subject, username, paragraph, preview, text, link, confirmation } = options; diff --git a/src/middleware/api.ts b/src/middleware/api.ts index 67edf9d..dc7c951 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -2,7 +2,7 @@ import express from 'express'; import database from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -export async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { +async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { const authHeader: string = request.headers.authorization; if (!authHeader || !(authHeader.startsWith('Bearer'))) { diff --git a/src/middleware/cemu.ts b/src/middleware/cemu.ts index 029e861..dc44985 100644 --- a/src/middleware/cemu.ts +++ b/src/middleware/cemu.ts @@ -1,6 +1,6 @@ import express from 'express'; -export function CemuMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { +function CemuMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { const subdomain: string = request.subdomains.reverse().join('.'); request.isCemu = subdomain === 'c.account'; diff --git a/src/middleware/client-header.ts b/src/middleware/client-header.ts index 1353c89..18b21fd 100644 --- a/src/middleware/client-header.ts +++ b/src/middleware/client-header.ts @@ -9,7 +9,7 @@ const VALID_CLIENT_ID_SECRET_PAIRS: { [key: string]: string } = { }; -export function nintendoClientHeaderCheck(request: express.Request, response: express.Response, next: express.NextFunction): void { +function nintendoClientHeaderCheck(request: express.Request, response: express.Response, next: express.NextFunction): void { response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); diff --git a/src/middleware/device-certificate.ts b/src/middleware/device-certificate.ts index 7cc95a7..e74c11c 100644 --- a/src/middleware/device-certificate.ts +++ b/src/middleware/device-certificate.ts @@ -1,7 +1,7 @@ import express from 'express'; import NintendoCertificate from '@/nintendo-certificate'; -export function deviceCertificateMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { +function deviceCertificateMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { const certificate: string = request.headers['x-nintendo-device-cert'] as string; if (!certificate) { diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index c3e5da6..ebf4dc5 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -11,7 +11,7 @@ import { NASCRequestParams } from '@/types/services/nasc/request-params'; import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; import { HydratedDeviceDocument } from '@/types/mongoose/device'; -export async function NASCMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { +async function NASCMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { const requestParams: NASCRequestParams = request.body; if (!requestParams.action || diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index 0f8b323..fd242cc 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -3,7 +3,7 @@ import xmlbuilder from 'xmlbuilder'; import database from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -export async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { +async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { const authHeader: string = request.headers.authorization; if (!authHeader || !(authHeader.startsWith('Bearer') || authHeader.startsWith('Basic'))) { diff --git a/src/middleware/xml-parser.ts b/src/middleware/xml-parser.ts index f89b7f5..37d09b2 100644 --- a/src/middleware/xml-parser.ts +++ b/src/middleware/xml-parser.ts @@ -2,7 +2,7 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { document as xmlParser } from 'xmlbuilder2'; -export function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void { +function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void { if (request.method == 'POST' || request.method == 'PUT') { const contentType: string = request.headers['content-type']; const contentLength: string = request.headers['content-length']; diff --git a/src/models/device.ts b/src/models/device.ts index d23c120..283dd98 100644 --- a/src/models/device.ts +++ b/src/models/device.ts @@ -2,13 +2,13 @@ import { Schema, model } from 'mongoose'; import { IDeviceAttribute, IDeviceAttributeMethods, DeviceAttributeModel } from '@/types/mongoose/device-attribute'; import { IDevice, IDeviceMethods, DeviceModel } from '@/types/mongoose/device'; -export const DeviceAttributeSchema = new Schema({ +const DeviceAttributeSchema = new Schema({ created_date: String, name: String, value: String }); -export const DeviceAttribute: DeviceAttributeModel = model('DeviceAttribute', DeviceAttributeSchema); +const DeviceAttribute: DeviceAttributeModel = model('DeviceAttribute', DeviceAttributeSchema); export const DeviceSchema = new Schema({ is_emulator: { @@ -50,11 +50,4 @@ export const DeviceSchema = new Schema({ } }); -export const Device: DeviceModel = model('Device', DeviceSchema); - -export default { - DeviceSchema, - Device, - DeviceAttributeSchema, - DeviceAttribute -}; \ No newline at end of file +export const Device: DeviceModel = model('Device', DeviceSchema); \ No newline at end of file diff --git a/src/models/nex-account.ts b/src/models/nex-account.ts index 2683a4f..fe8742e 100644 --- a/src/models/nex-account.ts +++ b/src/models/nex-account.ts @@ -2,7 +2,7 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; import { INEXAccount, INEXAccountMethods, NEXAccountModel } from '@/types/mongoose/nex-account'; -export const NEXAccountSchema = new Schema({ +const NEXAccountSchema = new Schema({ device_type: { type: String, enum: [ @@ -69,9 +69,4 @@ NEXAccountSchema.method('generatePassword', function generatePassword(): void { this.set('password', output.join('')); }); -export const NEXAccount: NEXAccountModel = model('NEXAccount', NEXAccountSchema); - -export default { - NEXAccountSchema, - NEXAccount -}; \ No newline at end of file +export const NEXAccount: NEXAccountModel = model('NEXAccount', NEXAccountSchema); \ No newline at end of file diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 3ccdd2d..b2a6888 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -9,7 +9,7 @@ import { DeviceSchema } from '@/models/device'; import util from '@/util'; import { IPNID, IPNIDMethods, PNIDModel } from '@/types/mongoose/pnid'; -export const PNIDSchema = new Schema({ +const PNIDSchema = new Schema({ access_level: { type: Number, default: 0 // 0: standard, 1: tester, 2: mod?, 3: dev @@ -211,9 +211,4 @@ PNIDSchema.method('getServerMode', function getServerMode(): string { return serverMode; }); -export const PNID: PNIDModel = model('PNID', PNIDSchema); - -export default { - PNIDSchema, - PNID -}; \ No newline at end of file +export const PNID: PNIDModel = model('PNID', PNIDSchema); \ No newline at end of file diff --git a/src/models/server.ts b/src/models/server.ts index 229142c..ab23f6a 100644 --- a/src/models/server.ts +++ b/src/models/server.ts @@ -2,7 +2,7 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; import { IServer, IServerMethods, ServerModel } from '@/types/mongoose/server'; -export const ServerSchema = new Schema({ +const ServerSchema = new Schema({ ip: String, // Example: 1.1.1.1 port: Number, // Example: 60000 service_name: String, // Example: friends @@ -16,9 +16,4 @@ export const ServerSchema = new Schema({ ServerSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); -export const Server: ServerModel = model('Server', ServerSchema); - -export default { - ServerSchema, - Server, -}; \ No newline at end of file +export const Server: ServerModel = model('Server', ServerSchema); \ No newline at end of file diff --git a/src/nintendo-certificate.ts b/src/nintendo-certificate.ts index 07b93f8..79cfcee 100644 --- a/src/nintendo-certificate.ts +++ b/src/nintendo-certificate.ts @@ -41,8 +41,6 @@ const CTR_LFCS_B_PUB = Buffer.from([ 0xAF, 0x07, 0xEB, 0x9C, 0xBF, 0xA9, 0xC9 ]); - - // Signature options const SIGNATURE_SIZES: { [key: string]: SignatureSize } = { RSA_4096_SHA1: { @@ -71,7 +69,7 @@ const SIGNATURE_SIZES: { [key: string]: SignatureSize } = { } }; -export class NintendoCertificate { +class NintendoCertificate { _certificate: Buffer; _certificateBody: Buffer; signatureType: number; diff --git a/src/types/mongoose/device-attribute.ts b/src/types/mongoose/device-attribute.ts index d77c3d8..e9eb87f 100644 --- a/src/types/mongoose/device-attribute.ts +++ b/src/types/mongoose/device-attribute.ts @@ -8,6 +8,6 @@ export interface IDeviceAttribute { export interface IDeviceAttributeMethods {} -export interface IDeviceAttributeQueryHelpers {} +interface IDeviceAttributeQueryHelpers {} export interface DeviceAttributeModel extends Model {} \ No newline at end of file diff --git a/src/types/mongoose/device.ts b/src/types/mongoose/device.ts index d9dcb1f..a2b2c78 100644 --- a/src/types/mongoose/device.ts +++ b/src/types/mongoose/device.ts @@ -27,7 +27,7 @@ export interface IDevice { export interface IDeviceMethods {} -export interface IDeviceQueryHelpers {} +interface IDeviceQueryHelpers {} export interface DeviceModel extends Model {} diff --git a/src/types/mongoose/nex-account.ts b/src/types/mongoose/nex-account.ts index fadc1bb..0e89b51 100644 --- a/src/types/mongoose/nex-account.ts +++ b/src/types/mongoose/nex-account.ts @@ -17,7 +17,7 @@ export interface INEXAccountMethods { generatePassword(): void; } -export interface INEXAccountQueryHelpers {} +interface INEXAccountQueryHelpers {} export interface NEXAccountModel extends Model {} diff --git a/src/types/mongoose/pnid.ts b/src/types/mongoose/pnid.ts index 8f87458..ee1fda6 100644 --- a/src/types/mongoose/pnid.ts +++ b/src/types/mongoose/pnid.ts @@ -73,7 +73,7 @@ export interface IPNIDMethods { getServerMode(): string; } -export interface IPNIDQueryHelpers {} +interface IPNIDQueryHelpers {} export interface PNIDModel extends Model {} diff --git a/src/types/mongoose/server.ts b/src/types/mongoose/server.ts index 65865d2..a385196 100644 --- a/src/types/mongoose/server.ts +++ b/src/types/mongoose/server.ts @@ -14,7 +14,7 @@ export interface IServer { export interface IServerMethods {} -export interface IServerQueryHelpers {} +interface IServerQueryHelpers {} export interface ServerModel extends Model {} From 19a695af3f71569bb774cf39e256677e58ff941e Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 6 Mar 2023 21:08:32 -0500 Subject: [PATCH 32/65] DeviceAttribute was defined but not used --- src/models/device.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/models/device.ts b/src/models/device.ts index 283dd98..1866e7f 100644 --- a/src/models/device.ts +++ b/src/models/device.ts @@ -8,8 +8,6 @@ const DeviceAttributeSchema = new Schema('DeviceAttribute', DeviceAttributeSchema); - export const DeviceSchema = new Schema({ is_emulator: { type: Boolean, From b01ef39fb234276a8baf6d60cb4cee4eb5e26bb2 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 6 Mar 2023 21:16:44 -0500 Subject: [PATCH 33/65] Added missing types --- src/mailer.ts | 8 +++---- src/models/nex-account.ts | 18 +++++++------- src/models/pnid.ts | 48 +++++++++++++++++++------------------ src/nintendo-certificate.ts | 12 +++++----- 4 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/mailer.ts b/src/mailer.ts index d87ec72..b7f52e9 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -21,14 +21,14 @@ async function sendMail(options: MailerOptions): Promise { html = html.replace(/{{username}}/g, username); html = html.replace(/{{paragraph}}/g, paragraph); - html = html.replace(/{{preview}}/g, (preview || "")); - html = html.replace(/{{confirmation-href}}/g, (confirmation?.href || "")); - html = html.replace(/{{confirmation-code}}/g, (confirmation?.code || "")); + html = html.replace(/{{preview}}/g, (preview || '')); + html = html.replace(/{{confirmation-href}}/g, (confirmation?.href || '')); + html = html.replace(/{{confirmation-code}}/g, (confirmation?.code || '')); if (link) { const { href, text } = link; - const button: string = ` ${text}` + const button: string = ` ${text}`; html = html.replace(//g, button); } diff --git a/src/models/nex-account.ts b/src/models/nex-account.ts index fe8742e..abfa407 100644 --- a/src/models/nex-account.ts +++ b/src/models/nex-account.ts @@ -1,6 +1,6 @@ import { Schema, model } from 'mongoose'; import uniqueValidator from 'mongoose-unique-validator'; -import { INEXAccount, INEXAccountMethods, NEXAccountModel } from '@/types/mongoose/nex-account'; +import { HydratedNEXAccountDocument, INEXAccount, INEXAccountMethods, NEXAccountModel } from '@/types/mongoose/nex-account'; const NEXAccountSchema = new Schema({ device_type: { @@ -38,12 +38,12 @@ NEXAccountSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); and the next few accounts counting down seem to be admin, service and internal test accounts */ NEXAccountSchema.method('generatePID', async function generatePID(): Promise { - const min = 1000000000; // The console (WiiU) seems to not accept PIDs smaller than this - const max = 1799999999; + const min: number = 1000000000; // The console (WiiU) seems to not accept PIDs smaller than this + const max: number = 1799999999; - let pid = Math.floor(Math.random() * (max - min + 1) + min); + const pid: number = Math.floor(Math.random() * (max - min + 1) + min); - const inuse = await NEXAccount.findOne({ pid }); + const inuse: HydratedNEXAccountDocument = await NEXAccount.findOne({ pid }); if (inuse) { await this.generatePID(); @@ -53,17 +53,17 @@ NEXAccountSchema.method('generatePID', async function generatePID(): Promise({ access_level: { @@ -116,12 +116,12 @@ PNIDSchema.plugin(uniqueValidator, {message: '{PATH} already in use.'}); and the next few accounts counting down seem to be admin, service and internal test accounts */ PNIDSchema.method('generatePID', async function generatePID(): Promise { - const min = 1000000000; // The console (WiiU) seems to not accept PIDs smaller than this - const max = 1799999999; + const min: number = 1000000000; // The console (WiiU) seems to not accept PIDs smaller than this + const max: number = 1799999999; - let pid = Math.floor(Math.random() * (max - min + 1) + min); + const pid: number = Math.floor(Math.random() * (max - min + 1) + min); - const inuse = await PNID.findOne({ + const inuse: HydratedPNIDDocument = await PNID.findOne({ pid }); @@ -135,15 +135,15 @@ PNIDSchema.method('generatePID', async function generatePID(): Promise { PNIDSchema.method('generateEmailValidationCode', async function generateEmailValidationCode(): Promise { // WiiU passes the PID along with the email code // Does not actually need to be unique to all users - const code = Math.random().toFixed(6).split('.')[1]; // Dirty one-liner to generate numbers of 6 length and padded 0 + const code: string = Math.random().toFixed(6).split('.')[1]; // Dirty one-liner to generate numbers of 6 length and padded 0 this.set('identification.email_code', code); }); PNIDSchema.method('generateEmailValidationToken', async function generateEmailValidationToken(): Promise { - let token = crypto.randomBytes(32).toString('hex'); + const token: string = crypto.randomBytes(32).toString('hex'); - const inuse = await PNID.findOne({ + const inuse: HydratedPNIDDocument = await PNID.findOne({ 'identification.email_token': token }); @@ -168,47 +168,49 @@ PNIDSchema.method('updateMii', async function updateMii({name, primary, data}): }); PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promise { - const miiData = this.get('mii.data'); - const mii = new Mii(Buffer.from(miiData, 'base64')); - const miiStudioUrl = mii.studioUrl({ + const miiData: string = this.get('mii.data'); + const mii: Mii = new Mii(Buffer.from(miiData, 'base64')); + const miiStudioUrl: string = mii.studioUrl({ type: 'face', width: '128', instanceCount: '1', }); - const miiStudioNormalFaceImageData = await got(miiStudioUrl).buffer(); - const pngData = await imagePixels(miiStudioNormalFaceImageData); - const tga = TGA.createTgaBuffer(pngData.width, pngData.height, pngData.data); + const miiStudioNormalFaceImageData: Buffer = await got(miiStudioUrl).buffer(); + const pngData: { + width: number; + height: number; + data: Buffer; + } = await imagePixels(miiStudioNormalFaceImageData); + const tga: Buffer = TGA.createTgaBuffer(pngData.width, pngData.height, pngData.data); - const userMiiKey = `mii/${this.get('pid')}`; + const userMiiKey: string = `mii/${this.get('pid')}`; await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/standard.tga`, tga, 'public-read'); await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/normal_face.png`, miiStudioNormalFaceImageData, 'public-read'); - const expressions = ['frustrated', 'smile_open_mouth', 'wink_left', 'sorrow', 'surprise_open_mouth']; + const expressions: string[] = ['frustrated', 'smile_open_mouth', 'wink_left', 'sorrow', 'surprise_open_mouth']; for (const expression of expressions) { - const miiStudioExpressionUrl = mii.studioUrl({ + const miiStudioExpressionUrl: string = mii.studioUrl({ type: 'face', expression: expression, width: '128', instanceCount: '1', }); - const miiStudioExpressionImageData = await got(miiStudioExpressionUrl).buffer(); + const miiStudioExpressionImageData: Buffer = await got(miiStudioExpressionUrl).buffer(); await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/${expression}.png`, miiStudioExpressionImageData, 'public-read'); } - const miiStudioBodyUrl = mii.studioUrl({ + const miiStudioBodyUrl: string = mii.studioUrl({ type: 'all_body', width: '270', instanceCount: '1', }); - const miiStudioBodyImageData = await got(miiStudioBodyUrl).buffer(); + const miiStudioBodyImageData: Buffer = await got(miiStudioBodyUrl).buffer(); await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/body.png`, miiStudioBodyImageData, 'public-read'); }); PNIDSchema.method('getServerMode', function getServerMode(): string { - const serverMode = this.get('server_mode') || 'prod'; - - return serverMode; + return this.get('server_mode') || 'prod'; }); export const PNID: PNIDModel = model('PNID', PNIDSchema); \ No newline at end of file diff --git a/src/nintendo-certificate.ts b/src/nintendo-certificate.ts index 79cfcee..0ee9ef1 100644 --- a/src/nintendo-certificate.ts +++ b/src/nintendo-certificate.ts @@ -106,7 +106,7 @@ class NintendoCertificate { } } - _parseCertificateData() { + _parseCertificateData(): void { if (this._certificate.length === 0x110) { // Assume fcdcert (3DS LFCS) this.signature = this._certificate.subarray(0x0, 0x100); @@ -149,7 +149,7 @@ class NintendoCertificate { } } - _verifySignature() { + _verifySignature(): void { switch (this.keyType) { case 0x0: this._verifySignatureRSA4096(); @@ -168,7 +168,7 @@ class NintendoCertificate { } } - _verifySignatureRSA4096() { + _verifySignatureRSA4096(): void { const publicKey: NodeRSA = new NodeRSA(); publicKey.importKey({ @@ -179,7 +179,7 @@ class NintendoCertificate { this.valid = publicKey.verify(this._certificateBody, this.signature); } - _verifySignatureRSA2048() { + _verifySignatureRSA2048(): void { const publicKey: NodeRSA = new NodeRSA(); publicKey.importKey({ @@ -194,7 +194,7 @@ class NintendoCertificate { // with Nodes native crypto module and getting the keys // from bytes to PEM! // https://github.com/Myriachan - _verifySignatureECDSA() { + _verifySignatureECDSA(): void { const pem: string = this.issuer == 'Root-CA00000003-MS00000012' ? WIIU_DEVICE_PUB_PEM : CTR_DEVICE_PUB_PEM; const key: crypto.VerifyPublicKeyInput = { key: pem, @@ -204,7 +204,7 @@ class NintendoCertificate { this.valid = crypto.verify('sha256', this._certificateBody, key, this.signature); } - _verifySignatureLFCS() { + _verifySignatureLFCS(): void { const publicKey: NodeRSA = new NodeRSA(); publicKey.importKey({ From 4f134fed7d68783e3af42a3a04715ec535267397 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 7 Mar 2023 17:54:24 -0500 Subject: [PATCH 34/65] Removed useless type check in getUserByUsername --- src/database.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/database.ts b/src/database.ts index fa3e10d..aed3385 100644 --- a/src/database.ts +++ b/src/database.ts @@ -45,10 +45,6 @@ function verifyConnected(): void { async function getUserByUsername(username: string): Promise { verifyConnected(); - if (typeof username !== 'string') { - return null; - } - return await PNID.findOne({ usernameLower: username.toLowerCase() }) as HydratedPNIDDocument; From bebae96f9230f86630f25df6f6d28c36a00b6205 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Tue, 7 Mar 2023 17:55:51 -0500 Subject: [PATCH 35/65] Removed HydratedPNIDDocument casting --- src/database.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/database.ts b/src/database.ts index aed3385..e79515c 100644 --- a/src/database.ts +++ b/src/database.ts @@ -45,25 +45,25 @@ function verifyConnected(): void { async function getUserByUsername(username: string): Promise { verifyConnected(); - return await PNID.findOne({ + return await PNID.findOne({ usernameLower: username.toLowerCase() - }) as HydratedPNIDDocument; + }); } async function getUserByPID(pid: number): Promise { verifyConnected(); - return await PNID.findOne({ + return await PNID.findOne({ pid - }) as HydratedPNIDDocument; + }); } async function getUserByEmailAddress(email: string): Promise { verifyConnected(); - return await PNID.findOne({ + return await PNID.findOne({ 'email.address': new RegExp(email, 'i') // * Ignore case - }) as HydratedPNIDDocument; + }); } async function doesUserExist(username: string): Promise { From 928e6f6701e1f966a5ed699fdb5d30902b40f5b7 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 8 Mar 2023 17:11:17 -0500 Subject: [PATCH 36/65] revert me --- src/database.ts | 66 ++++++++++----------- src/middleware/nasc.ts | 8 +-- src/middleware/pnid.ts | 2 +- src/models/pnid.ts | 6 +- src/services/api/routes/v1/login.ts | 10 ++-- src/services/api/routes/v1/register.ts | 10 ++-- src/services/api/routes/v1/resetPassword.ts | 4 +- src/services/nasc/routes/ac.ts | 4 +- src/services/nnid/routes/oauth.ts | 6 +- src/services/nnid/routes/people.ts | 8 +-- src/types/mongoose/pnid.ts | 4 +- src/types/services/nnid/pnid-profile.ts | 8 +-- src/util.ts | 26 ++++---- 13 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/database.ts b/src/database.ts index e79515c..a79ecc1 100644 --- a/src/database.ts +++ b/src/database.ts @@ -127,17 +127,17 @@ async function getUserProfileJSONByPID(pid: number): Promise { verifyConnected(); const user: HydratedPNIDDocument = await getUserByPID(pid); - const device: HydratedDeviceDocument = user.get('devices')[0]; // * Just grab the first device - let device_attributes: [{ + const device: HydratedDeviceDocument = user.devices[0]; // * Just grab the first device + let device_attributes: { device_attribute: { name: string; value: string; created_date: string; }; - }]; + }[]; if (device) { - device_attributes = device.get('device_attributes').map(({name, value, created_date}) => ({ + device_attributes = device.device_attributes.map(({name, value, created_date}) => ({ device_attribute: { name, value, @@ -148,50 +148,50 @@ async function getUserProfileJSONByPID(pid: number): Promise { return { //accounts: {}, // * We need to figure this out, no idea what these values mean or what they do - active_flag: user.get('flags.active') ? 'Y' : 'N', - birth_date: user.get('birthdate'), - country: user.get('country'), - create_date: user.get('creation_date'), + active_flag: user.flags.active ? 'Y' : 'N', + birth_date: user.birthdate, + country: user.country, + create_date: user.creation_date, device_attributes: device_attributes, - gender: user.get('gender'), - language: user.get('language'), - updated: user.get('updated'), - marketing_flag: user.get('flags.marketing') ? 'Y' : 'N', - off_device_flag: user.get('flags.off_device') ? 'Y' : 'N', - pid: user.get('pid'), + gender: user.gender, + language: user.language, + updated: user.updated, + marketing_flag: user.flags.marketing ? 'Y' : 'N', + off_device_flag: user.flags.off_device ? 'Y' : 'N', + pid: user.pid, email: { - address: user.get('email.address'), - id: user.get('email.id'), - parent: user.get('email.parent') ? 'Y' : 'N', - primary: user.get('email.primary') ? 'Y' : 'N', - reachable: user.get('email.reachable') ? 'Y' : 'N', + address: user.email.address, + id: user.email.id, + parent: user.email.parent ? 'Y' : 'N', + primary: user.email.primary ? 'Y' : 'N', + reachable: user.email.reachable ? 'Y' : 'N', type: 'DEFAULT', updated_by: 'USER', // * Can also be INTERNAL WS, don't know the difference - validated: user.get('email.validated') ? 'Y' : 'N', - validated_date: user.get('email.validated') ? user.get('email.validated_date') : '' + validated: user.email.validated ? 'Y' : 'N', + validated_date: user.email.validated ? user.email.validated_date : '' }, mii: { status: 'COMPLETED', - data: user.get('mii.data').replace(/(\r\n|\n|\r)/gm, ''), - id: user.get('mii.id'), - mii_hash: user.get('mii.hash'), + data: user.mii.data.replace(/(\r\n|\n|\r)/gm, ''), + id: user.mii.id, + mii_hash: user.mii.hash, mii_images: { mii_image: { // * Images MUST be loaded over HTTPS or console ignores them // * Bunny CDN is the only CDN which seems to support TLS 1.0/1.1 (required) cached_url: `${config.cdn.base_url}/mii/${user.pid}/standard.tga`, - id: user.get('mii.image_id'), + id: user.mii.image_id, url: `${config.cdn.base_url}/mii/${user.pid}/standard.tga`, type: 'standard' } }, - name: user.get('mii.name'), - primary: user.get('mii.primary') ? 'Y' : 'N', + name: user.mii.name, + primary: user.mii.primary ? 'Y' : 'N', }, - region: user.get('region'), - tz_name: user.get('timezone.name'), - user_id: user.get('username'), - utc_offset: user.get('timezone.offset') + region: user.region, + tz_name: user.timezone.name, + user_id: user.username, + utc_offset: user.timezone.offset }; } @@ -226,7 +226,7 @@ async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: Discor }; } - await PNID.updateOne({ pid: pnid.get('pid') }, { + await PNID.updateOne({ pid: pnid.pid }, { $set: { 'connections.discord.id': data.id } @@ -246,7 +246,7 @@ async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): P } async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { - await PNID.updateOne({ pid: pnid.get('pid') }, { + await PNID.updateOne({ pid: pnid.pid }, { $set: { 'connections.discord.id': '' } diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index ebf4dc5..941e57a 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -104,13 +104,13 @@ async function NASCMiddleware(request: express.Request, response: express.Respon }); if (device) { - if (device.get('access_level') < 0) { + if (device.access_level < 0) { response.status(200).send(util.nascError('102')); return; } if (pid) { - const linkedPIDs = device.get('linked_pids'); + const linkedPIDs = device.linked_pids; if (!linkedPIDs.includes(pid)) { response.status(200).send(util.nascError('102')); @@ -137,7 +137,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon await nexAccount.save({ session }); - pid = Number(nexAccount.get('pid')); + pid = nexAccount.pid; // Set password @@ -176,7 +176,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ pid }); - if (!nexUser || nexUser.get('access_level') < 0) { + if (!nexUser || nexUser.access_level < 0) { response.status(200).send(util.nascError('102')); return; } diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index fd242cc..ca10d31 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -54,7 +54,7 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon return; } - if (user.get('access_level') < 0) { + if (user.access_level < 0) { response.status(400).send(xmlbuilder.create({ errors: { error: { diff --git a/src/models/pnid.ts b/src/models/pnid.ts index c6a3b3f..24109c2 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -168,7 +168,7 @@ PNIDSchema.method('updateMii', async function updateMii({name, primary, data}): }); PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promise { - const miiData: string = this.get('mii.data'); + const miiData: string = this.mii.data; const mii: Mii = new Mii(Buffer.from(miiData, 'base64')); const miiStudioUrl: string = mii.studioUrl({ type: 'face', @@ -183,7 +183,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi } = await imagePixels(miiStudioNormalFaceImageData); const tga: Buffer = TGA.createTgaBuffer(pngData.width, pngData.height, pngData.data); - const userMiiKey: string = `mii/${this.get('pid')}`; + const userMiiKey: string = `mii/${this.pid}`; await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/standard.tga`, tga, 'public-read'); await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/normal_face.png`, miiStudioNormalFaceImageData, 'public-read'); @@ -210,7 +210,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi }); PNIDSchema.method('getServerMode', function getServerMode(): string { - return this.get('server_mode') || 'prod'; + return this.server_mode || 'prod'; }); export const PNID: PNIDModel = model('PNID', PNIDSchema); \ No newline at end of file diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index 4aa098a..79aca57 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -67,7 +67,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const hashedPassword: string = util.nintendoPasswordHash(password, pnid.get('pid')); + const hashedPassword: string = util.nintendoPasswordHash(password, pnid.pid); if (!pnid || !bcrypt.compareSync(hashedPassword, pnid.password)) { return response.status(400).json({ @@ -110,8 +110,8 @@ router.post('/', async (request: express.Request, response: express.Response) => const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, - pid: pnid.get('pid'), - access_level: pnid.get('access_level'), + pid: pnid.pid, + access_level: pnid.access_level, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; @@ -119,8 +119,8 @@ router.post('/', async (request: express.Request, response: express.Response) => const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, - pid: pnid.get('pid'), - access_level: pnid.get('access_level'), + pid: pnid.pid, + access_level: pnid.access_level, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 7712d29..8fc5ede 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -250,15 +250,15 @@ router.post('/', async (request: express.Request, response: express.Response) => // NN with a NNID will always use the NNID PID // even if the provided NEX PID is different // To fix this we make them the same PID - nexAccount.owning_pid = nexAccount.get('pid'); + nexAccount.owning_pid = nexAccount.pid; await nexAccount.save({ session }); - const primaryPasswordHash: string = util.nintendoPasswordHash(password, nexAccount.get('pid')); + const primaryPasswordHash: string = util.nintendoPasswordHash(password, nexAccount.pid); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid = new PNID({ - pid: nexAccount.get('pid'), + pid: nexAccount.pid, creation_date: creationDate, updated: creationDate, username: username, @@ -348,7 +348,7 @@ router.post('/', async (request: express.Request, response: express.Response) => const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, - pid: pnid.get('pid'), + pid: pnid.pid, access_level: 0, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) @@ -357,7 +357,7 @@ router.post('/', async (request: express.Request, response: express.Response) => const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, - pid: pnid.get('pid'), + pid: pnid.pid, access_level: 0, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 8f570b5..04d93a0 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -82,7 +82,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - if (password.toLowerCase() === pnid.get('usernameLower')) { + if (password.toLowerCase() === pnid.usernameLower) { return response.status(400).json({ app: 'api', status: 400, @@ -114,7 +114,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const primaryPasswordHash: string = util.nintendoPasswordHash(password, pnid.get('pid')); + const primaryPasswordHash: string = util.nintendoPasswordHash(password, pnid.pid); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 6e4589a..87dcf17 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -42,7 +42,7 @@ async function processLoginRequest(request: express.Request): Promise; + devices: Types.DocumentArray; identification: { // user identification tokens email_code: string; email_token: string; diff --git a/src/types/services/nnid/pnid-profile.ts b/src/types/services/nnid/pnid-profile.ts index ac95915..cb02669 100644 --- a/src/types/services/nnid/pnid-profile.ts +++ b/src/types/services/nnid/pnid-profile.ts @@ -6,13 +6,13 @@ export interface PNIDProfile { birth_date: string; country: string; create_date: string; - device_attributes: [{ + device_attributes: { device_attribute: { name: string; value: string; created_date: string; }; - }]; + }[]; gender: string; language: string; updated: string; @@ -21,7 +21,7 @@ export interface PNIDProfile { pid: number; email: { address: string; - id: string; + id: number; parent: YesNoBoolString; primary: YesNoBoolString; reachable: YesNoBoolString; @@ -38,7 +38,7 @@ export interface PNIDProfile { mii_images: { mii_image: { cached_url: string; - id: string; + id: number; url: string; type: 'standard'; } diff --git a/src/util.ts b/src/util.ts index eaec4c4..1f9d1fb 100644 --- a/src/util.ts +++ b/src/util.ts @@ -257,14 +257,14 @@ function nascError(errorCode: string): URLSearchParams { async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { - to: pnid.get('email.address'), + to: pnid.email.address, subject: '[Pretendo Network] Please confirm your email address', - username: pnid.get('username'), + username: pnid.username, confirmation: { - href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')}`, - code: pnid.get('identification.email_code') + href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token}`, + code: pnid.identification.email_code }, - text: `Hello ${pnid.get('username')}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.get('identification.email_code')}` + text: `Hello ${pnid.username}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.identification.email_code}` }; await mailer.sendMail(options); @@ -272,11 +272,11 @@ async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { - to: pnid.get('email.address'), + to: pnid.email.address, subject: '[Pretendo Network] Email address confirmed', - username: pnid.get('username'), + username: pnid.username, paragraph: 'your email address has been confirmed. We hope you have fun on Pretendo Network!', - text: `Dear ${pnid.get('username')}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` + text: `Dear ${pnid.username}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` }; await mailer.sendMail(options); @@ -294,8 +294,8 @@ async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument Date: Wed, 8 Mar 2023 17:11:26 -0500 Subject: [PATCH 37/65] Revert "revert me" This reverts commit 928e6f6701e1f966a5ed699fdb5d30902b40f5b7. --- src/database.ts | 66 ++++++++++----------- src/middleware/nasc.ts | 8 +-- src/middleware/pnid.ts | 2 +- src/models/pnid.ts | 6 +- src/services/api/routes/v1/login.ts | 10 ++-- src/services/api/routes/v1/register.ts | 10 ++-- src/services/api/routes/v1/resetPassword.ts | 4 +- src/services/nasc/routes/ac.ts | 4 +- src/services/nnid/routes/oauth.ts | 6 +- src/services/nnid/routes/people.ts | 8 +-- src/types/mongoose/pnid.ts | 4 +- src/types/services/nnid/pnid-profile.ts | 8 +-- src/util.ts | 26 ++++---- 13 files changed, 81 insertions(+), 81 deletions(-) diff --git a/src/database.ts b/src/database.ts index a79ecc1..e79515c 100644 --- a/src/database.ts +++ b/src/database.ts @@ -127,17 +127,17 @@ async function getUserProfileJSONByPID(pid: number): Promise { verifyConnected(); const user: HydratedPNIDDocument = await getUserByPID(pid); - const device: HydratedDeviceDocument = user.devices[0]; // * Just grab the first device - let device_attributes: { + const device: HydratedDeviceDocument = user.get('devices')[0]; // * Just grab the first device + let device_attributes: [{ device_attribute: { name: string; value: string; created_date: string; }; - }[]; + }]; if (device) { - device_attributes = device.device_attributes.map(({name, value, created_date}) => ({ + device_attributes = device.get('device_attributes').map(({name, value, created_date}) => ({ device_attribute: { name, value, @@ -148,50 +148,50 @@ async function getUserProfileJSONByPID(pid: number): Promise { return { //accounts: {}, // * We need to figure this out, no idea what these values mean or what they do - active_flag: user.flags.active ? 'Y' : 'N', - birth_date: user.birthdate, - country: user.country, - create_date: user.creation_date, + active_flag: user.get('flags.active') ? 'Y' : 'N', + birth_date: user.get('birthdate'), + country: user.get('country'), + create_date: user.get('creation_date'), device_attributes: device_attributes, - gender: user.gender, - language: user.language, - updated: user.updated, - marketing_flag: user.flags.marketing ? 'Y' : 'N', - off_device_flag: user.flags.off_device ? 'Y' : 'N', - pid: user.pid, + gender: user.get('gender'), + language: user.get('language'), + updated: user.get('updated'), + marketing_flag: user.get('flags.marketing') ? 'Y' : 'N', + off_device_flag: user.get('flags.off_device') ? 'Y' : 'N', + pid: user.get('pid'), email: { - address: user.email.address, - id: user.email.id, - parent: user.email.parent ? 'Y' : 'N', - primary: user.email.primary ? 'Y' : 'N', - reachable: user.email.reachable ? 'Y' : 'N', + address: user.get('email.address'), + id: user.get('email.id'), + parent: user.get('email.parent') ? 'Y' : 'N', + primary: user.get('email.primary') ? 'Y' : 'N', + reachable: user.get('email.reachable') ? 'Y' : 'N', type: 'DEFAULT', updated_by: 'USER', // * Can also be INTERNAL WS, don't know the difference - validated: user.email.validated ? 'Y' : 'N', - validated_date: user.email.validated ? user.email.validated_date : '' + validated: user.get('email.validated') ? 'Y' : 'N', + validated_date: user.get('email.validated') ? user.get('email.validated_date') : '' }, mii: { status: 'COMPLETED', - data: user.mii.data.replace(/(\r\n|\n|\r)/gm, ''), - id: user.mii.id, - mii_hash: user.mii.hash, + data: user.get('mii.data').replace(/(\r\n|\n|\r)/gm, ''), + id: user.get('mii.id'), + mii_hash: user.get('mii.hash'), mii_images: { mii_image: { // * Images MUST be loaded over HTTPS or console ignores them // * Bunny CDN is the only CDN which seems to support TLS 1.0/1.1 (required) cached_url: `${config.cdn.base_url}/mii/${user.pid}/standard.tga`, - id: user.mii.image_id, + id: user.get('mii.image_id'), url: `${config.cdn.base_url}/mii/${user.pid}/standard.tga`, type: 'standard' } }, - name: user.mii.name, - primary: user.mii.primary ? 'Y' : 'N', + name: user.get('mii.name'), + primary: user.get('mii.primary') ? 'Y' : 'N', }, - region: user.region, - tz_name: user.timezone.name, - user_id: user.username, - utc_offset: user.timezone.offset + region: user.get('region'), + tz_name: user.get('timezone.name'), + user_id: user.get('username'), + utc_offset: user.get('timezone.offset') }; } @@ -226,7 +226,7 @@ async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: Discor }; } - await PNID.updateOne({ pid: pnid.pid }, { + await PNID.updateOne({ pid: pnid.get('pid') }, { $set: { 'connections.discord.id': data.id } @@ -246,7 +246,7 @@ async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): P } async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { - await PNID.updateOne({ pid: pnid.pid }, { + await PNID.updateOne({ pid: pnid.get('pid') }, { $set: { 'connections.discord.id': '' } diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 941e57a..ebf4dc5 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -104,13 +104,13 @@ async function NASCMiddleware(request: express.Request, response: express.Respon }); if (device) { - if (device.access_level < 0) { + if (device.get('access_level') < 0) { response.status(200).send(util.nascError('102')); return; } if (pid) { - const linkedPIDs = device.linked_pids; + const linkedPIDs = device.get('linked_pids'); if (!linkedPIDs.includes(pid)) { response.status(200).send(util.nascError('102')); @@ -137,7 +137,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon await nexAccount.save({ session }); - pid = nexAccount.pid; + pid = Number(nexAccount.get('pid')); // Set password @@ -176,7 +176,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ pid }); - if (!nexUser || nexUser.access_level < 0) { + if (!nexUser || nexUser.get('access_level') < 0) { response.status(200).send(util.nascError('102')); return; } diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index ca10d31..fd242cc 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -54,7 +54,7 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon return; } - if (user.access_level < 0) { + if (user.get('access_level') < 0) { response.status(400).send(xmlbuilder.create({ errors: { error: { diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 24109c2..c6a3b3f 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -168,7 +168,7 @@ PNIDSchema.method('updateMii', async function updateMii({name, primary, data}): }); PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promise { - const miiData: string = this.mii.data; + const miiData: string = this.get('mii.data'); const mii: Mii = new Mii(Buffer.from(miiData, 'base64')); const miiStudioUrl: string = mii.studioUrl({ type: 'face', @@ -183,7 +183,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi } = await imagePixels(miiStudioNormalFaceImageData); const tga: Buffer = TGA.createTgaBuffer(pngData.width, pngData.height, pngData.data); - const userMiiKey: string = `mii/${this.pid}`; + const userMiiKey: string = `mii/${this.get('pid')}`; await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/standard.tga`, tga, 'public-read'); await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/normal_face.png`, miiStudioNormalFaceImageData, 'public-read'); @@ -210,7 +210,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi }); PNIDSchema.method('getServerMode', function getServerMode(): string { - return this.server_mode || 'prod'; + return this.get('server_mode') || 'prod'; }); export const PNID: PNIDModel = model('PNID', PNIDSchema); \ No newline at end of file diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index 79aca57..4aa098a 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -67,7 +67,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const hashedPassword: string = util.nintendoPasswordHash(password, pnid.pid); + const hashedPassword: string = util.nintendoPasswordHash(password, pnid.get('pid')); if (!pnid || !bcrypt.compareSync(hashedPassword, pnid.password)) { return response.status(400).json({ @@ -110,8 +110,8 @@ router.post('/', async (request: express.Request, response: express.Response) => const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, - pid: pnid.pid, - access_level: pnid.access_level, + pid: pnid.get('pid'), + access_level: pnid.get('access_level'), title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; @@ -119,8 +119,8 @@ router.post('/', async (request: express.Request, response: express.Response) => const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, - pid: pnid.pid, - access_level: pnid.access_level, + pid: pnid.get('pid'), + access_level: pnid.get('access_level'), title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 8fc5ede..7712d29 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -250,15 +250,15 @@ router.post('/', async (request: express.Request, response: express.Response) => // NN with a NNID will always use the NNID PID // even if the provided NEX PID is different // To fix this we make them the same PID - nexAccount.owning_pid = nexAccount.pid; + nexAccount.owning_pid = nexAccount.get('pid'); await nexAccount.save({ session }); - const primaryPasswordHash: string = util.nintendoPasswordHash(password, nexAccount.pid); + const primaryPasswordHash: string = util.nintendoPasswordHash(password, nexAccount.get('pid')); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid = new PNID({ - pid: nexAccount.pid, + pid: nexAccount.get('pid'), creation_date: creationDate, updated: creationDate, username: username, @@ -348,7 +348,7 @@ router.post('/', async (request: express.Request, response: express.Response) => const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, - pid: pnid.pid, + pid: pnid.get('pid'), access_level: 0, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) @@ -357,7 +357,7 @@ router.post('/', async (request: express.Request, response: express.Response) => const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, - pid: pnid.pid, + pid: pnid.get('pid'), access_level: 0, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 04d93a0..8f570b5 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -82,7 +82,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - if (password.toLowerCase() === pnid.usernameLower) { + if (password.toLowerCase() === pnid.get('usernameLower')) { return response.status(400).json({ app: 'api', status: 400, @@ -114,7 +114,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const primaryPasswordHash: string = util.nintendoPasswordHash(password, pnid.pid); + const primaryPasswordHash: string = util.nintendoPasswordHash(password, pnid.get('pid')); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 87dcf17..6e4589a 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -42,7 +42,7 @@ async function processLoginRequest(request: express.Request): Promise; + devices: Types.DocumentArray; identification: { // user identification tokens email_code: string; email_token: string; diff --git a/src/types/services/nnid/pnid-profile.ts b/src/types/services/nnid/pnid-profile.ts index cb02669..ac95915 100644 --- a/src/types/services/nnid/pnid-profile.ts +++ b/src/types/services/nnid/pnid-profile.ts @@ -6,13 +6,13 @@ export interface PNIDProfile { birth_date: string; country: string; create_date: string; - device_attributes: { + device_attributes: [{ device_attribute: { name: string; value: string; created_date: string; }; - }[]; + }]; gender: string; language: string; updated: string; @@ -21,7 +21,7 @@ export interface PNIDProfile { pid: number; email: { address: string; - id: number; + id: string; parent: YesNoBoolString; primary: YesNoBoolString; reachable: YesNoBoolString; @@ -38,7 +38,7 @@ export interface PNIDProfile { mii_images: { mii_image: { cached_url: string; - id: number; + id: string; url: string; type: 'standard'; } diff --git a/src/util.ts b/src/util.ts index 1f9d1fb..eaec4c4 100644 --- a/src/util.ts +++ b/src/util.ts @@ -257,14 +257,14 @@ function nascError(errorCode: string): URLSearchParams { async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { - to: pnid.email.address, + to: pnid.get('email.address'), subject: '[Pretendo Network] Please confirm your email address', - username: pnid.username, + username: pnid.get('username'), confirmation: { - href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token}`, - code: pnid.identification.email_code + href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')}`, + code: pnid.get('identification.email_code') }, - text: `Hello ${pnid.username}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.identification.email_code}` + text: `Hello ${pnid.get('username')}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.get('identification.email_code')}` }; await mailer.sendMail(options); @@ -272,11 +272,11 @@ async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { - to: pnid.email.address, + to: pnid.get('email.address'), subject: '[Pretendo Network] Email address confirmed', - username: pnid.username, + username: pnid.get('username'), paragraph: 'your email address has been confirmed. We hope you have fun on Pretendo Network!', - text: `Dear ${pnid.username}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` + text: `Dear ${pnid.get('username')}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` }; await mailer.sendMail(options); @@ -294,8 +294,8 @@ async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument Date: Fri, 17 Mar 2023 15:02:20 -0400 Subject: [PATCH 38/65] Removed RegExp from getUserByEmailAddress --- src/database.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/database.ts b/src/database.ts index e79515c..4589c58 100644 --- a/src/database.ts +++ b/src/database.ts @@ -61,8 +61,9 @@ async function getUserByPID(pid: number): Promise { async function getUserByEmailAddress(email: string): Promise { verifyConnected(); + // TODO - Update documents to store email normalized return await PNID.findOne({ - 'email.address': new RegExp(email, 'i') // * Ignore case + 'email.address': email }); } From 9f3d5c4a350c99c80ba26ca18443e9739239e4c6 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 17 Mar 2023 16:16:10 -0400 Subject: [PATCH 39/65] Removed default exports in favor of named exports --- src/cache.ts | 66 +++++++------------- src/config-manager.ts | 44 ++++++------- src/database.ts | 62 +++++++----------- src/logger.ts | 17 ++--- src/mailer.ts | 6 +- src/middleware/api.ts | 4 +- src/middleware/nasc.ts | 46 +++++++------- src/middleware/pnid.ts | 6 +- src/models/pnid.ts | 10 +-- src/server.ts | 30 ++++----- src/services/api/index.ts | 25 ++++---- src/services/api/routes/index.ts | 18 +++--- src/services/api/routes/v1/connections.ts | 6 +- src/services/api/routes/v1/email.ts | 4 +- src/services/api/routes/v1/forgotPassword.ts | 10 +-- src/services/api/routes/v1/login.ts | 20 +++--- src/services/api/routes/v1/register.ts | 26 ++++---- src/services/api/routes/v1/resetPassword.ts | 8 +-- src/services/api/routes/v1/user.ts | 2 +- src/services/assets/index.ts | 6 +- src/services/conntest/index.ts | 8 +-- src/services/datastore/index.ts | 11 ++-- src/services/datastore/routes/index.ts | 5 -- src/services/datastore/routes/upload.ts | 4 +- src/services/local-cdn/index.ts | 13 ++-- src/services/local-cdn/routes/get.ts | 4 +- src/services/local-cdn/routes/index.ts | 5 -- src/services/nasc/index.ts | 13 ++-- src/services/nasc/routes/ac.ts | 42 ++++++------- src/services/nasc/routes/index.ts | 5 -- src/services/nnid/index.ts | 36 ++++++----- src/services/nnid/routes/index.ts | 19 ------ src/services/nnid/routes/oauth.ts | 10 +-- src/services/nnid/routes/people.ts | 30 ++++----- src/services/nnid/routes/provider.ts | 22 +++---- src/services/nnid/routes/support.ts | 16 ++--- src/util.ts | 65 ++++++++----------- 37 files changed, 319 insertions(+), 405 deletions(-) delete mode 100644 src/services/datastore/routes/index.ts delete mode 100644 src/services/local-cdn/routes/index.ts delete mode 100644 src/services/nasc/routes/index.ts delete mode 100644 src/services/nnid/routes/index.ts diff --git a/src/cache.ts b/src/cache.ts index f14f2d1..cc5a6bb 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -10,7 +10,7 @@ const SERVICE_CERTS_BASE: string = `${__dirname}/../certs/service`; const NEX_CERTS_BASE: string = `${__dirname}/../certs/nex`; const LOCAL_CDN_BASE: string = `${__dirname}/../cdn`; -async function connect(): Promise { +export async function connect(): Promise { if (!disabledFeatures.redis) { client = redis.createClient(config.redis.client); client.on('error', (err) => console.log('Redis Client Error', err)); @@ -19,7 +19,7 @@ async function connect(): Promise { } } -async function setCachedFile(fileName: string, value: Buffer): Promise { +export async function setCachedFile(fileName: string, value: Buffer): Promise { if (disabledFeatures.redis) { memoryCache[fileName] = value; } else { @@ -27,7 +27,7 @@ async function setCachedFile(fileName: string, value: Buffer): Promise { } } -async function getCachedFile(fileName: string, encoding?: BufferEncoding): Promise { +export async function getCachedFile(fileName: string, encoding?: BufferEncoding): Promise { let cachedFile: Buffer; if (disabledFeatures.redis) { @@ -44,7 +44,7 @@ async function getCachedFile(fileName: string, encoding?: BufferEncoding): Promi // * NEX server cache functions -async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise { +export async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise { let publicKey: Buffer = await getCachedFile(`nex:${name}:public_key`, encoding); if (publicKey === null) { @@ -55,7 +55,7 @@ async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise return publicKey; } -async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promise { +export async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promise { let privateKey: Buffer = await getCachedFile(`nex:${name}:private_key`, encoding); if (privateKey === null) { @@ -66,7 +66,7 @@ async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promis return privateKey; } -async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise { +export async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise { let secretKey: Buffer = await getCachedFile(`nex:${name}:secret_key`, encoding); if (secretKey === null) { @@ -78,7 +78,7 @@ async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise return secretKey; } -async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { +export async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { let aesKey: Buffer = await getCachedFile(`nex:${name}:aes_key`, encoding); if (aesKey === null) { @@ -90,25 +90,25 @@ async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { +export async function setNEXPublicKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:public_key`, value); } -async function setNEXPrivateKey(name: string, value: Buffer): Promise { +export async function setNEXPrivateKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:private_key`, value); } -async function setNEXSecretKey(name: string, value: Buffer): Promise { +export async function setNEXSecretKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:secret_key`, value); } -async function setNEXAESKey(name: string, value: Buffer): Promise { +export async function setNEXAESKey(name: string, value: Buffer): Promise { await setCachedFile(`nex:${name}:aes_key`, value); } // * 3rd party service cache functions -async function getServicePublicKey(name: string, encoding?: BufferEncoding): Promise { +export async function getServicePublicKey(name: string, encoding?: BufferEncoding): Promise { let publicKey: Buffer = await getCachedFile(`service:${name}:public_key`, encoding); if (publicKey === null) { @@ -119,7 +119,7 @@ async function getServicePublicKey(name: string, encoding?: BufferEncoding): Pro return publicKey; } -async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Promise { +export async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Promise { let privateKey: Buffer = await getCachedFile(`service:${name}:private_key`, encoding); if (privateKey === null) { @@ -130,7 +130,7 @@ async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Pr return privateKey; } -async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Promise { +export async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Promise { let secretKey: Buffer = await getCachedFile(`service:${name}:secret_key`, encoding); if (secretKey === null) { @@ -142,7 +142,7 @@ async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Pro return secretKey; } -async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promise { +export async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promise { let aesKey: Buffer = await getCachedFile(`service:${name}:aes_key`, encoding); if (aesKey === null) { @@ -154,25 +154,25 @@ async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promis return aesKey; } -async function setServicePublicKey(name: string, value: Buffer): Promise { +export async function setServicePublicKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:public_key`, value); } -async function setServicePrivateKey(name: string, value: Buffer): Promise { +export async function setServicePrivateKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:private_key`, value); } -async function setServiceSecretKey(name: string, value: Buffer): Promise { +export async function setServiceSecretKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:secret_key`, value); } -async function setServiceAESKey(name: string, value: Buffer): Promise { +export async function setServiceAESKey(name: string, value: Buffer): Promise { await setCachedFile(`service:${name}:aes_key`, value); } // * Local CDN cache functions -async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise { +export async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise { let file: Buffer = await getCachedFile(`local_cdn:${name}`, encoding); if (file === null) { @@ -186,28 +186,6 @@ async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise return file; } -async function setLocalCDNFile(name: string, value: Buffer): Promise { +export async function setLocalCDNFile(name: string, value: Buffer): Promise { await setCachedFile(`local_cdn:${name}`, value); -} - -export default { - connect, - getNEXPublicKey, - getNEXPrivateKey, - getNEXSecretKey, - getNEXAESKey, - setNEXPublicKey, - setNEXPrivateKey, - setNEXSecretKey, - setNEXAESKey, - getServicePublicKey, - getServicePrivateKey, - getServiceSecretKey, - getServiceAESKey, - setServicePublicKey, - setServicePrivateKey, - setServiceSecretKey, - setServiceAESKey, - getLocalCDNFile, - setLocalCDNFile -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/config-manager.ts b/src/config-manager.ts index ed5631a..8b42c75 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -1,7 +1,7 @@ import fs from 'fs-extra'; import mongoose from 'mongoose'; import dotenv from 'dotenv'; -import logger from '@/logger'; +import { LOG_INFO, LOG_WARN, LOG_ERROR } from '@/logger'; import { Config, DisabledFeatures } from '@/types/common/config'; dotenv.config(); @@ -13,7 +13,7 @@ export const disabledFeatures: DisabledFeatures = { s3: false }; -logger.info('Loading config'); +LOG_INFO('Loading config'); let mongooseConnectOptions: mongoose.ConnectOptions; @@ -60,99 +60,99 @@ export const config: Config = { website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE }; -logger.info('Config loaded, checking integrity'); +LOG_INFO('Config loaded, checking integrity'); if (!config.http.port) { - logger.error('Failed to find HTTP port. Set the PN_ACT_CONFIG_HTTP_PORT environment variable'); + LOG_ERROR('Failed to find HTTP port. Set the PN_ACT_CONFIG_HTTP_PORT environment variable'); process.exit(0); } if (!config.mongoose.connection_string) { - logger.error('Failed to find MongoDB connection string. Set the PN_ACT_CONFIG_MONGO_CONNECTION_STRING environment variable'); + LOG_ERROR('Failed to find MongoDB connection string. Set the PN_ACT_CONFIG_MONGO_CONNECTION_STRING environment variable'); process.exit(0); } if (!config.cdn.base_url) { - logger.error('Failed to find asset CDN base URL. Set the PN_ACT_CONFIG_CDN_BASE_URL environment variable'); + LOG_ERROR('Failed to find asset CDN base URL. Set the PN_ACT_CONFIG_CDN_BASE_URL environment variable'); process.exit(0); } if (!config.redis.client.url) { - logger.warn('Failed to find Redis connection url. Disabling feature and using in-memory cache. To enable feature set the PN_ACT_CONFIG_REDIS_URL environment variable'); + LOG_WARN('Failed to find Redis connection url. Disabling feature and using in-memory cache. To enable feature set the PN_ACT_CONFIG_REDIS_URL environment variable'); disabledFeatures.redis = true; } if (!config.email.host) { - logger.warn('Failed to find email SMTP host. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_HOST environment variable'); + LOG_WARN('Failed to find email SMTP host. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_HOST environment variable'); disabledFeatures.email = true; } if (!config.email.port) { - logger.warn('Failed to find email SMTP port. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PORT environment variable'); + LOG_WARN('Failed to find email SMTP port. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PORT environment variable'); disabledFeatures.email = true; } if (config.email.secure === undefined) { - logger.warn('Failed to find email SMTP secure flag. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_SECURE environment variable'); + LOG_WARN('Failed to find email SMTP secure flag. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_SECURE environment variable'); disabledFeatures.email = true; } if (!config.email.auth.user) { - logger.warn('Failed to find email account username. Disabling feature. To enable feature set the auth.user environment variable'); + LOG_WARN('Failed to find email account username. Disabling feature. To enable feature set the auth.user environment variable'); disabledFeatures.email = true; } if (!config.email.auth.pass) { - logger.warn('Failed to find email account password. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PASSWORD environment variable'); + LOG_WARN('Failed to find email account password. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_PASSWORD environment variable'); disabledFeatures.email = true; } if (!config.email.from) { - logger.warn('Failed to find email from config. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_FROM environment variable'); + LOG_WARN('Failed to find email from config. Disabling feature. To enable feature set the PN_ACT_CONFIG_EMAIL_FROM environment variable'); disabledFeatures.email = true; } if (!disabledFeatures.email) { if (!config.website_base) { - logger.error('Email sending is enabled and no website base was configured. Set the PN_ACT_CONFIG_WEBSITE_BASE environment variable'); + LOG_ERROR('Email sending is enabled and no website base was configured. Set the PN_ACT_CONFIG_WEBSITE_BASE environment variable'); process.exit(0); } } if (!config.hcaptcha.secret) { - logger.warn('Failed to find captcha secret config. Disabling feature. To enable feature set the PN_ACT_CONFIG_HCAPTCHA_SECRET environment variable'); + LOG_WARN('Failed to find captcha secret config. Disabling feature. To enable feature set the PN_ACT_CONFIG_HCAPTCHA_SECRET environment variable'); disabledFeatures.captcha = true; } if (!config.s3.endpoint) { - logger.warn('Failed to find s3 endpoint config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ENDPOINT environment variable'); + LOG_WARN('Failed to find s3 endpoint config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ENDPOINT environment variable'); disabledFeatures.s3 = true; } if (!config.s3.key) { - logger.warn('Failed to find s3 access key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_KEY environment variable'); + LOG_WARN('Failed to find s3 access key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_KEY environment variable'); disabledFeatures.s3 = true; } if (!config.s3.secret) { - logger.warn('Failed to find s3 secret key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_SECRET environment variable'); + LOG_WARN('Failed to find s3 secret key config. Disabling feature. To enable feature set the PN_ACT_CONFIG_S3_ACCESS_SECRET environment variable'); disabledFeatures.s3 = true; } if (disabledFeatures.s3) { if (!config.cdn.subdomain) { - logger.error('s3 file storage is disabled and no CDN subdomain was set. Set the PN_ACT_CONFIG_CDN_SUBDOMAIN environment variable'); + LOG_ERROR('s3 file storage is disabled and no CDN subdomain was set. Set the PN_ACT_CONFIG_CDN_SUBDOMAIN environment variable'); process.exit(0); } if (!config.cdn.disk_path) { - logger.error('s3 file storage is disabled and no CDN disk path was set. Set the PN_ACT_CONFIG_CDN_DISK_PATH environment variable'); + LOG_ERROR('s3 file storage is disabled and no CDN disk path was set. Set the PN_ACT_CONFIG_CDN_DISK_PATH environment variable'); process.exit(0); } - logger.warn(`s3 file storage disabled. Using disk-based file storage. Please ensure cdn.base_url config or PN_ACT_CONFIG_CDN_BASE env variable is set to point to this server with the subdomain being ${config.cdn.subdomain}`); + LOG_WARN(`s3 file storage disabled. Using disk-based file storage. Please ensure cdn.base_url config or PN_ACT_CONFIG_CDN_BASE env variable is set to point to this server with the subdomain being ${config.cdn.subdomain}`); if (disabledFeatures.redis) { - logger.warn('Both s3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable s3 if you\'re running a production server.'); + LOG_WARN('Both s3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable s3 if you\'re running a production server.'); } } \ No newline at end of file diff --git a/src/database.ts b/src/database.ts index 4589c58..931d181 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1,10 +1,10 @@ import mongoose from 'mongoose'; import bcrypt from 'bcrypt'; import joi from 'joi'; -import util from '@/util'; +import { nintendoPasswordHash, decryptToken, unpackToken } from '@/util'; import { PNID } from '@/models/pnid'; import { Server } from '@/models/server'; -import logger from '@/logger'; +import { LOG_ERROR } from '@/logger'; import { config } from '@/config-manager'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; import { HydratedDeviceDocument } from '@/types/mongoose/device'; @@ -25,24 +25,24 @@ const discordConnectionSchema: joi.ObjectSchema = joi.object({ let _connection: mongoose.Connection; -async function connect(): Promise { +export async function connect(): Promise { await mongoose.connect(connection_string, options); _connection = mongoose.connection; _connection.on('error', console.error.bind(console, 'connection error:')); } -function connection(): mongoose.Connection { +export function connection(): mongoose.Connection { return _connection; } -function verifyConnected(): void { +export function verifyConnected(): void { if (!connection()) { throw new Error('Cannot make database requets without being connected'); } } -async function getUserByUsername(username: string): Promise { +export async function getUserByUsername(username: string): Promise { verifyConnected(); return await PNID.findOne({ @@ -50,7 +50,7 @@ async function getUserByUsername(username: string): Promise { +export async function getUserByPID(pid: number): Promise { verifyConnected(); return await PNID.findOne({ @@ -58,7 +58,7 @@ async function getUserByPID(pid: number): Promise { }); } -async function getUserByEmailAddress(email: string): Promise { +export async function getUserByEmailAddress(email: string): Promise { verifyConnected(); // TODO - Update documents to store email normalized @@ -67,13 +67,13 @@ async function getUserByEmailAddress(email: string): Promise { +export async function doesUserExist(username: string): Promise { verifyConnected(); return !!await getUserByUsername(username); } -async function getUserBasic(token: string): Promise { +export async function getUserBasic(token: string): Promise { verifyConnected(); // * Wii U sends Basic auth as `username password`, where the password may not have spaces @@ -90,7 +90,7 @@ async function getUserBasic(token: string): Promise { return null; } - const hashedPassword: string = util.nintendoPasswordHash(password, user.pid); + const hashedPassword: string = nintendoPasswordHash(password, user.pid); if (!bcrypt.compareSync(hashedPassword, user.password)) { return null; @@ -99,12 +99,12 @@ async function getUserBasic(token: string): Promise { return user; } -async function getUserBearer(token: string): Promise { +export async function getUserBearer(token: string): Promise { verifyConnected(); try { - const decryptedToken: Buffer = await util.decryptToken(Buffer.from(token, 'base64')); - const unpackedToken: Token = util.unpackToken(decryptedToken); + const decryptedToken: Buffer = await decryptToken(Buffer.from(token, 'base64')); + const unpackedToken: Token = unpackToken(decryptedToken); const user: HydratedPNIDDocument = await getUserByPID(unpackedToken.pid); @@ -119,12 +119,12 @@ async function getUserBearer(token: string): Promise { return user; } catch (error: any) { // TODO: Handle error - logger.error(error); + LOG_ERROR(error); return null; } } -async function getUserProfileJSONByPID(pid: number): Promise { +export async function getUserProfileJSONByPID(pid: number): Promise { verifyConnected(); const user: HydratedPNIDDocument = await getUserByPID(pid); @@ -196,27 +196,27 @@ async function getUserProfileJSONByPID(pid: number): Promise { }; } -async function getServer(gameServerId: string, accessMode: string): Promise { +export async function getServer(gameServerId: string, accessMode: string): Promise { return await Server.findOne({ game_server_id: gameServerId, access_mode: accessMode }); } -async function getServerByTitleId(titleId: string, accessMode: string): Promise { +export async function getServerByTitleId(titleId: string, accessMode: string): Promise { return await Server.findOne({ title_ids: titleId, access_mode: accessMode }); } -async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { +export async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { if (type === 'discord') { return await addUserConnectionDiscord(pnid, data); } } -async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { +export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { const valid: joi.ValidationResult = discordConnectionSchema.validate(data); if (valid.error) { @@ -239,14 +239,14 @@ async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: Discor }; } -async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { +export async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { // * Add more connections later? if (type === 'discord') { return await removeUserConnectionDiscord(pnid); } } -async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { +export async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { await PNID.updateOne({ pid: pnid.get('pid') }, { $set: { 'connections.discord.id': '' @@ -257,20 +257,4 @@ async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise< app: 'api', status: 200 }; -} - -export default { - connect, - connection, - getUserByUsername, - getUserByPID, - getUserByEmailAddress, - doesUserExist, - getUserBasic, - getUserBearer, - getUserProfileJSONByPID, - getServer, - getServerByTitleId, - addUserConnection, - removeUserConnection -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/logger.ts b/src/logger.ts index 64435a2..798ef62 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -14,7 +14,7 @@ const streams: { [key: string]: fs.WriteStream } = { info: fs.createWriteStream(`${root}/logs/info.log`) }; -function success(input: string): void { +export function LOG_SUCCESS(input: string): void { const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [SUCCESS]: ${input}`; streams.success.write(`${input}\n`); @@ -22,7 +22,7 @@ function success(input: string): void { console.log(`${input}`.green.bold); } -function error(input: string): void { +export function LOG_ERROR(input: string): void { const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [ERROR]: ${input}`; streams.error.write(`${input}\n`); @@ -30,7 +30,7 @@ function error(input: string): void { console.log(`${input}`.red.bold); } -function warn(input: string): void { +export function LOG_WARN(input: string): void { const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [WARN]: ${input}`; streams.warn.write(`${input}\n`); @@ -38,17 +38,10 @@ function warn(input: string): void { console.log(`${input}`.yellow.bold); } -function info(input: string): void { +export function LOG_INFO(input: string): void { const time: Date = new Date(); input = `[${time.getHours()}:${time.getMinutes()}:${time.getSeconds()}] [INFO]: ${input}`; streams.info.write(`${input}\n`); console.log(`${input}`.cyan.bold); -} - -export default { - success, - error, - warn, - info -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/mailer.ts b/src/mailer.ts index b7f52e9..a9ec1cc 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -13,7 +13,7 @@ if (!disabledFeatures.email) { transporter = nodemailer.createTransport(config.email); } -async function sendMail(options: MailerOptions): Promise { +export async function sendMail(options: MailerOptions): Promise { if (!disabledFeatures.email) { const { to, subject, username, paragraph, preview, text, link, confirmation } = options; @@ -41,7 +41,3 @@ async function sendMail(options: MailerOptions): Promise { }); } } - -export default { - sendMail -}; diff --git a/src/middleware/api.ts b/src/middleware/api.ts index dc7c951..0f7e876 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -1,5 +1,5 @@ import express from 'express'; -import database from '@/database'; +import { getUserBearer } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { @@ -10,7 +10,7 @@ async function APIMiddleware(request: express.Request, _response: express.Respon } const token: string = authHeader.split(' ')[1]; - const user: HydratedPNIDDocument = await database.getUserBearer(token); + const user: HydratedPNIDDocument = await getUserBearer(token); request.pnid = user; diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index ebf4dc5..5f1e5aa 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -3,10 +3,10 @@ import express from 'express'; import mongoose from 'mongoose'; import { Device } from '@/models/device'; import { NEXAccount } from '@/models/nex-account'; -import util from '@/util'; -import database from '@/database'; +import { nascError, nintendoBase64Decode } from '@/util'; +import { connection as databaseConnection } from '@/database'; import NintendoCertificate from '@/nintendo-certificate'; -import logger from '@/logger'; +import { LOG_ERROR } from '@/logger'; import { NASCRequestParams } from '@/types/services/nasc/request-params'; import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; import { HydratedDeviceDocument } from '@/types/mongoose/device'; @@ -21,16 +21,16 @@ async function NASCMiddleware(request: express.Request, response: express.Respon !requestParams.titleid || !requestParams.servertype ) { - response.status(200).send(util.nascError('null')); // This is what Nintendo sends + response.status(200).send(nascError('null')); // This is what Nintendo sends return; } - const action: string = util.nintendoBase64Decode(requestParams.action).toString(); - const fcdcert: Buffer = util.nintendoBase64Decode(requestParams.fcdcert); - const serialNumber: string = util.nintendoBase64Decode(requestParams.csnum).toString(); - const macAddress: string = util.nintendoBase64Decode(requestParams.macadr).toString(); - const titleID: string = util.nintendoBase64Decode(requestParams.titleid).toString(); - const environment: string = util.nintendoBase64Decode(requestParams.servertype).toString(); + const action: string = nintendoBase64Decode(requestParams.action).toString(); + const fcdcert: Buffer = nintendoBase64Decode(requestParams.fcdcert); + const serialNumber: string = nintendoBase64Decode(requestParams.csnum).toString(); + const macAddress: string = nintendoBase64Decode(requestParams.macadr).toString(); + const titleID: string = nintendoBase64Decode(requestParams.titleid).toString(); + const environment: string = nintendoBase64Decode(requestParams.servertype).toString(); const macAddressHash: string = crypto.createHash('sha256').update(macAddress).digest('base64'); const fcdcertHash: string = crypto.createHash('sha256').update(fcdcert).digest('base64'); @@ -40,31 +40,31 @@ async function NASCMiddleware(request: express.Request, response: express.Respon let password: string; if (requestParams.userid) { - pid = Number(util.nintendoBase64Decode(requestParams.userid).toString()); + pid = Number(nintendoBase64Decode(requestParams.userid).toString()); } if (requestParams.uidhmac) { - pidHmac = util.nintendoBase64Decode(requestParams.uidhmac).toString(); + pidHmac = nintendoBase64Decode(requestParams.uidhmac).toString(); } if (requestParams.passwd) { - password = util.nintendoBase64Decode(requestParams.passwd).toString(); + password = nintendoBase64Decode(requestParams.passwd).toString(); } if (action !== 'LOGIN' && action !== 'SVCLOC') { - response.status(200).send(util.nascError('null')); // This is what Nintendo sends + response.status(200).send(nascError('null')); // This is what Nintendo sends return; } const cert: NintendoCertificate = new NintendoCertificate(fcdcert); if (!cert.valid) { - response.status(200).send(util.nascError('121')); + response.status(200).send(nascError('121')); return; } if (!validNintendoMACAddress(macAddress)) { - response.status(200).send(util.nascError('null')); + response.status(200).send(nascError('null')); return; } @@ -91,7 +91,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon } if (!model) { - response.status(200).send(util.nascError('null')); + response.status(200).send(nascError('null')); return; } @@ -105,7 +105,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon if (device) { if (device.get('access_level') < 0) { - response.status(200).send(util.nascError('102')); + response.status(200).send(nascError('102')); return; } @@ -113,7 +113,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const linkedPIDs = device.get('linked_pids'); if (!linkedPIDs.includes(pid)) { - response.status(200).send(util.nascError('102')); + response.status(200).send(nascError('102')); return; } } @@ -123,7 +123,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon if (password && !pid && !pidHmac) { // Register new user - const session: mongoose.ClientSession = await database.connection().startSession(); + const session: mongoose.ClientSession = await databaseConnection().startSession(); await session.startTransaction(); try { @@ -159,12 +159,12 @@ async function NASCMiddleware(request: express.Request, response: express.Respon await session.commitTransaction(); } catch (error) { - logger.error('[NASC] REGISTER ACCOUNT: ' + error); + LOG_ERROR('[NASC] REGISTER ACCOUNT: ' + error); await session.abortTransaction(); // 3DS expects 200 even on error - response.status(200).send(util.nascError('102')); + response.status(200).send(nascError('102')); return; } finally { // * This runs regardless of failure @@ -177,7 +177,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ pid }); if (!nexUser || nexUser.get('access_level') < 0) { - response.status(200).send(util.nascError('102')); + response.status(200).send(nascError('102')); return; } diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index fd242cc..2d52342 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -1,6 +1,6 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; -import database from '@/database'; +import { getUserBasic, getUserBearer } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { @@ -20,9 +20,9 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon } if (type === 'Basic') { - user = await database.getUserBasic(token); + user = await getUserBasic(token); } else { - user = await database.getUserBearer(token); + user = await getUserBearer(token); } if (!user) { diff --git a/src/models/pnid.ts b/src/models/pnid.ts index c6a3b3f..601b1fe 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -6,7 +6,7 @@ import TGA from 'tga'; import got from 'got'; import Mii from 'mii-js'; import { DeviceSchema } from '@/models/device'; -import util from '@/util'; +import { uploadCDNAsset } from '@/util'; import { HydratedPNIDDocument, IPNID, IPNIDMethods, PNIDModel } from '@/types/mongoose/pnid'; const PNIDSchema = new Schema({ @@ -185,8 +185,8 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi const userMiiKey: string = `mii/${this.get('pid')}`; - await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/standard.tga`, tga, 'public-read'); - await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/normal_face.png`, miiStudioNormalFaceImageData, 'public-read'); + await uploadCDNAsset('pn-cdn', `${userMiiKey}/standard.tga`, tga, 'public-read'); + await uploadCDNAsset('pn-cdn', `${userMiiKey}/normal_face.png`, miiStudioNormalFaceImageData, 'public-read'); const expressions: string[] = ['frustrated', 'smile_open_mouth', 'wink_left', 'sorrow', 'surprise_open_mouth']; for (const expression of expressions) { @@ -197,7 +197,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi instanceCount: '1', }); const miiStudioExpressionImageData: Buffer = await got(miiStudioExpressionUrl).buffer(); - await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/${expression}.png`, miiStudioExpressionImageData, 'public-read'); + await uploadCDNAsset('pn-cdn', `${userMiiKey}/${expression}.png`, miiStudioExpressionImageData, 'public-read'); } const miiStudioBodyUrl: string = mii.studioUrl({ @@ -206,7 +206,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi instanceCount: '1', }); const miiStudioBodyImageData: Buffer = await got(miiStudioBodyUrl).buffer(); - await util.uploadCDNAsset('pn-cdn', `${userMiiKey}/body.png`, miiStudioBodyImageData, 'public-read'); + await uploadCDNAsset('pn-cdn', `${userMiiKey}/body.png`, miiStudioBodyImageData, 'public-read'); }); PNIDSchema.method('getServerMode', function getServerMode(): string { diff --git a/src/server.ts b/src/server.ts index 1d3710f..52fe75a 100644 --- a/src/server.ts +++ b/src/server.ts @@ -7,10 +7,10 @@ process.on('uncaughtException', (err, origin) => { import express from 'express'; import morgan from 'morgan'; import xmlparser from '@/middleware/xml-parser'; -import cache from '@/cache'; -import database from '@/database'; -import util from '@/util'; -import logger from '@/logger'; +import { connect as connectCache } from '@/cache'; +import { connect as connectDatabase } from '@/database'; +import { fullUrl } from '@/util'; +import { LOG_INFO, LOG_SUCCESS, LOG_WARN } from '@/logger'; import conntest from '@/services/conntest'; import nnid from '@/services/nnid'; @@ -28,7 +28,7 @@ const app = express(); // START APPLICATION // Create router -logger.info('Setting up Middleware'); +LOG_INFO('Setting up Middleware'); app.use(morgan('dev')); app.use(express.json()); app.use(express.urlencoded({ @@ -46,12 +46,12 @@ app.use(localcdn); app.use(assets); // 404 handler -logger.info('Creating 404 status handler'); +LOG_INFO('Creating 404 status handler'); app.use((request: express.Request, response: express.Response) => { - const fullUrl: string = util.fullUrl(request); + const url: string = fullUrl(request); const deviceId: string = request.headers['X-Nintendo-Device-ID'] as string || 'Unknown'; - logger.warn(`HTTP 404 at ${fullUrl} from ${deviceId}`); + LOG_WARN(`HTTP 404 at ${url} from ${deviceId}`); response.set('Content-Type', 'text/xml'); response.set('Server', 'Nintendo 3DS (http)'); @@ -62,13 +62,13 @@ app.use((request: express.Request, response: express.Response) => { }); // non-404 error handler -logger.info('Creating non-404 status handler'); +LOG_INFO('Creating non-404 status handler'); app.use((error: any, request: express.Request, response: express.Response, _next: express.NextFunction) => { const status: number = error.status || 500; - const fullUrl: string = util.fullUrl(request); + const url: string = fullUrl(request); const deviceId: string = request.headers['X-Nintendo-Device-ID'] as string || 'Unknown'; - logger.warn(`HTTP ${status} at ${fullUrl} from ${deviceId}: ${error.message}`); + LOG_WARN(`HTTP ${status} at ${url} from ${deviceId}: ${error.message}`); response.status(status); response.json({ @@ -80,13 +80,13 @@ app.use((error: any, request: express.Request, response: express.Response, _next async function main(): Promise { // Starts the server - logger.info('Starting server'); + LOG_INFO('Starting server'); - await database.connect(); - await cache.connect(); + await connectDatabase(); + await connectCache(); app.listen(port, () => { - logger.success(`Server started on port ${port}`); + LOG_SUCCESS(`Server started on port ${port}`); }); } diff --git a/src/services/api/index.ts b/src/services/api/index.ts index df383af..18b7cde 100644 --- a/src/services/api/index.ts +++ b/src/services/api/index.ts @@ -4,33 +4,34 @@ import express from 'express'; import subdomain from 'express-subdomain'; import cors from 'cors'; import APIMiddleware from '@/middleware/api'; -import routes from '@/services/api/routes'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; + +import { V1 } from '@/services/api/routes'; // Router to handle the subdomain restriction const api: express.Router = express.Router(); -logger.info('[USER API] Importing middleware'); +LOG_INFO('[USER API] Importing middleware'); api.use(APIMiddleware); api.use(cors()); api.options('*', cors()); // Setup routes -logger.info('[USER API] Applying imported routes'); -api.use('/v1/connections', routes.V1.CONNECTIONS); -api.use('/v1/email', routes.V1.EMAIL); -api.use('/v1/forgot-password', routes.V1.FORGOT_PASSWORD); -api.use('/v1/login', routes.V1.LOGIN); -api.use('/v1/register', routes.V1.REGISTER); -api.use('/v1/reset-password', routes.V1.RESET_PASSWORD); -api.use('/v1/user', routes.V1.USER); +LOG_INFO('[USER API] Applying imported routes'); +api.use('/v1/connections', V1.CONNECTIONS); +api.use('/v1/email', V1.EMAIL); +api.use('/v1/forgot-password', V1.FORGOT_PASSWORD); +api.use('/v1/login', V1.LOGIN); +api.use('/v1/register', V1.REGISTER); +api.use('/v1/reset-password', V1.RESET_PASSWORD); +api.use('/v1/user', V1.USER); // Main router for endpoints const router: express.Router = express.Router(); // Create subdomains -logger.info('[USER API] Creating \'api\' subdomain'); +LOG_INFO('[USER API] Creating \'api\' subdomain'); router.use(subdomain('api', api)); export default router; \ No newline at end of file diff --git a/src/services/api/routes/index.ts b/src/services/api/routes/index.ts index 61691f2..6f25c45 100644 --- a/src/services/api/routes/index.ts +++ b/src/services/api/routes/index.ts @@ -6,14 +6,12 @@ import register_v1 from '@/services/api/routes/v1/register'; import resetPassword_v1 from '@/services/api/routes/v1/resetPassword'; import user_v1 from '@/services/api/routes/v1/user'; -export default { - V1: { - CONNECTIONS: connections_v1, - EMAIL: email_v1, - FORGOT_PASSWORD: forgotPassword_v1, - LOGIN: login_v1, - REGISTER: register_v1, - RESET_PASSWORD: resetPassword_v1, - USER: user_v1 - } +export const V1 = { + CONNECTIONS: connections_v1, + EMAIL: email_v1, + FORGOT_PASSWORD: forgotPassword_v1, + LOGIN: login_v1, + REGISTER: register_v1, + RESET_PASSWORD: resetPassword_v1, + USER: user_v1 }; \ No newline at end of file diff --git a/src/services/api/routes/v1/connections.ts b/src/services/api/routes/v1/connections.ts index 1a307e6..6ddfd31 100644 --- a/src/services/api/routes/v1/connections.ts +++ b/src/services/api/routes/v1/connections.ts @@ -1,5 +1,5 @@ import express from 'express'; -import database from '@/database'; +import { addUserConnection, removeUserConnection } from '@/database'; import { ConnectionData } from '@/types/services/api/connection-data'; import { ConnectionResponse } from '@/types/services/api/connection-response'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -44,7 +44,7 @@ router.post('/add/:type', async (request: express.Request, response: express.Res }); } - const result: ConnectionResponse = await database.addUserConnection(pnid, data, type); + const result: ConnectionResponse = await addUserConnection(pnid, data, type); response.status(result.status).json(result); }); @@ -74,7 +74,7 @@ router.delete('/remove/:type', async (request: express.Request, response: expres }); } - const result: ConnectionResponse = await database.removeUserConnection(pnid, type); + const result: ConnectionResponse = await removeUserConnection(pnid, type); response.status(result.status).json(result); }); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index 308bc84..2b12d60 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -1,7 +1,7 @@ import express from 'express'; import moment from 'moment'; import { PNID } from '@/models/pnid'; -import util from '@/util'; +import { sendEmailConfirmedEmail } from '@/util'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; const router: express.Router = express.Router(); @@ -37,7 +37,7 @@ router.get('/verify', async (request: express.Request, response: express.Respons await pnid.save(); - await util.sendEmailConfirmedEmail(pnid); + await sendEmailConfirmedEmail(pnid); response.status(200).send('Email validated. You may close this window'); }); diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index 24148ba..74e7cdc 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -1,7 +1,7 @@ import express from 'express'; import validator from 'validator'; -import database from '@/database'; -import util from '@/util'; +import { getUserByEmailAddress, getUserByUsername } from '@/database'; +import { sendForgotPasswordEmail } from '@/util'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; const router: express.Router = express.Router(); @@ -20,13 +20,13 @@ router.post('/', async (request: express.Request, response: express.Response) => let pnid: HydratedPNIDDocument; if (validator.isEmail(input)) { - pnid = await database.getUserByEmailAddress(input); + pnid = await getUserByEmailAddress(input); } else { - pnid = await database.getUserByUsername(input); + pnid = await getUserByUsername(input); } if (pnid) { - await util.sendForgotPasswordEmail(pnid); + await sendForgotPasswordEmail(pnid); } response.json({ diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index 4aa098a..c6bfaa6 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -1,9 +1,9 @@ import express from 'express'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import database from '@/database'; -import cache from '@/cache'; -import util from '@/util'; +import { getUserByUsername, getUserBearer } from '@/database'; +import { getServicePublicKey, getServiceSecretKey } from '@/cache'; +import { nintendoPasswordHash, generateToken} from '@/util'; import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -57,7 +57,7 @@ router.post('/', async (request: express.Request, response: express.Response) => let pnid: HydratedPNIDDocument; if (grantType === 'password') { - pnid = await database.getUserByUsername(username); + pnid = await getUserByUsername(username); if (!pnid) { return response.status(400).json({ @@ -67,7 +67,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const hashedPassword: string = util.nintendoPasswordHash(password, pnid.get('pid')); + const hashedPassword: string = nintendoPasswordHash(password, pnid.get('pid')); if (!pnid || !bcrypt.compareSync(hashedPassword, pnid.password)) { return response.status(400).json({ @@ -77,7 +77,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } } else { - pnid = await database.getUserBearer(refreshToken); + pnid = await getUserBearer(refreshToken); if (!pnid) { return response.status(400).json({ @@ -99,8 +99,8 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const publicKey: Buffer = await cache.getServicePublicKey('account'); - const secretKey: Buffer = await cache.getServiceSecretKey('account'); + const publicKey: Buffer = await getServicePublicKey('account'); + const secretKey: Buffer = await getServiceSecretKey('account'); const cryptoOptions: CryptoOptions = { public_key: publicKey, @@ -125,8 +125,8 @@ router.post('/', async (request: express.Request, response: express.Response) => expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken: string = await util.generateToken(cryptoOptions, accessTokenOptions); - const newRefreshToken: string = await util.generateToken(cryptoOptions, refreshTokenOptions); + const accessToken: string = await generateToken(cryptoOptions, accessTokenOptions); + const newRefreshToken: string = await generateToken(cryptoOptions, refreshTokenOptions); response.json({ access_token: accessToken, diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 7712d29..3b6d315 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -8,10 +8,10 @@ import moment from 'moment'; import hcaptcha from 'hcaptcha'; import Mii from 'mii-js'; import mongoose from 'mongoose'; -import database from '@/database'; -import cache from '@/cache'; -import util from '@/util'; -import logger from '@/logger'; +import { doesUserExist, connection as databaseConnection } from '@/database'; +import { getServicePublicKey, getServiceSecretKey } from '@/cache'; +import { nintendoPasswordHash, sendConfirmationEmail, generateToken } from '@/util'; +import { LOG_ERROR } from '@/logger'; import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; import { config, disabledFeatures } from '@/config-manager'; @@ -141,7 +141,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const userExists: boolean = await database.doesUserExist(username); + const userExists: boolean = await doesUserExist(username); if (userExists) { return response.status(400).json({ @@ -232,7 +232,7 @@ router.post('/', async (request: express.Request, response: express.Response) => let pnid: HydratedPNIDDocument; let nexAccount: HydratedNEXAccountDocument; - const session: mongoose.ClientSession = await database.connection().startSession(); + const session: mongoose.ClientSession = await databaseConnection().startSession(); await session.startTransaction(); try { @@ -254,7 +254,7 @@ router.post('/', async (request: express.Request, response: express.Response) => await nexAccount.save({ session }); - const primaryPasswordHash: string = util.nintendoPasswordHash(password, nexAccount.get('pid')); + const primaryPasswordHash: string = nintendoPasswordHash(password, nexAccount.get('pid')); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid = new PNID({ @@ -309,7 +309,7 @@ router.post('/', async (request: express.Request, response: express.Response) => await session.commitTransaction(); } catch (error) { - logger.error('[POST] /v1/register: ' + error); + LOG_ERROR('[POST] /v1/register: ' + error); await session.abortTransaction(); @@ -324,7 +324,7 @@ router.post('/', async (request: express.Request, response: express.Response) => await session.endSession(); } - await util.sendConfirmationEmail(pnid); + await sendConfirmationEmail(pnid); const cryptoPath: string = `${__dirname}/../../../../../certs/service/account`; @@ -337,8 +337,8 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const publicKey: Buffer = await cache.getServicePublicKey('account'); - const secretKey: Buffer = await cache.getServiceSecretKey('account'); + const publicKey: Buffer = await getServicePublicKey('account'); + const secretKey: Buffer = await getServiceSecretKey('account'); const cryptoOptions: CryptoOptions = { public_key: publicKey, @@ -363,8 +363,8 @@ router.post('/', async (request: express.Request, response: express.Response) => expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken: string = await util.generateToken(cryptoOptions, accessTokenOptions); - const refreshToken: string = await util.generateToken(cryptoOptions, refreshTokenOptions); + const accessToken: string = await generateToken(cryptoOptions, accessTokenOptions); + const refreshToken: string = await generateToken(cryptoOptions, refreshTokenOptions); response.json({ access_token: accessToken, diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 8f570b5..fe7f3c8 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -1,7 +1,7 @@ import express from 'express'; import bcrypt from 'bcrypt'; import { PNID } from '@/models/pnid'; -import util from '@/util'; +import { decryptToken, unpackToken, nintendoPasswordHash } from '@/util'; import { Token } from '@/types/common/token'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -28,8 +28,8 @@ router.post('/', async (request: express.Request, response: express.Response) => let unpackedToken: Token; try { - const decryptedToken: Buffer = await util.decryptToken(Buffer.from(token, 'base64')); - unpackedToken = util.unpackToken(decryptedToken); + const decryptedToken: Buffer = await decryptToken(Buffer.from(token, 'base64')); + unpackedToken = unpackToken(decryptedToken); } catch (error) { console.log(error); return response.status(400).json({ @@ -114,7 +114,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const primaryPasswordHash: string = util.nintendoPasswordHash(password, pnid.get('pid')); + const primaryPasswordHash: string = nintendoPasswordHash(password, pnid.get('pid')); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; diff --git a/src/services/api/routes/v1/user.ts b/src/services/api/routes/v1/user.ts index ef03c25..15fb167 100644 --- a/src/services/api/routes/v1/user.ts +++ b/src/services/api/routes/v1/user.ts @@ -1,6 +1,6 @@ import express from 'express'; import joi from 'joi'; -import { PNID } from '@/models/pnid'; +//import { PNID } from '@/models/pnid'; import { config } from '@/config-manager'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; import { UpdateUserRequest } from '@/types/services/api/update-user-request'; diff --git a/src/services/assets/index.ts b/src/services/assets/index.ts index f40cd56..03faa93 100644 --- a/src/services/assets/index.ts +++ b/src/services/assets/index.ts @@ -3,20 +3,20 @@ import path from 'node:path'; import express from 'express'; import subdomain from 'express-subdomain'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; // Router to handle the subdomain restriction const assets: express.Router = express.Router(); // Setup public folder -logger.info('[assets] Setting up public folder'); +LOG_INFO('[assets] Setting up public folder'); assets.use(express.static(path.join(__dirname, '../../assets'))); // Main router for endpoints const router: express.Router = express.Router(); // Create subdomains -logger.info('[conntest] Creating \'assets\' subdomain'); +LOG_INFO('[conntest] Creating \'assets\' subdomain'); router.use(subdomain('assets', assets)); export default router; \ No newline at end of file diff --git a/src/services/conntest/index.ts b/src/services/conntest/index.ts index 610cdda..c016eca 100644 --- a/src/services/conntest/index.ts +++ b/src/services/conntest/index.ts @@ -2,13 +2,13 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; // Router to handle the subdomain restriction const conntest: express.Router = express.Router(); // Setup route -logger.info('[conntest] Applying imported routes'); +LOG_INFO('[conntest] Applying imported routes'); conntest.get('/', async (request: express.Request, response: express.Response) => { response.set('Content-Type', 'text/html'); response.set('X-Organization', 'Nintendo'); @@ -23,14 +23,14 @@ conntest.get('/', async (request: express.Request, response: express.Response) = This is test.html page -`) +`); }); // Main router for endpoints const router: express.Router = express.Router(); // Create subdomains -logger.info('[conntest] Creating \'conntest\' subdomain'); +LOG_INFO('[conntest] Creating \'conntest\' subdomain'); router.use(subdomain('conntest', conntest)); export default router; \ No newline at end of file diff --git a/src/services/datastore/index.ts b/src/services/datastore/index.ts index a06640d..3d2e4f7 100644 --- a/src/services/datastore/index.ts +++ b/src/services/datastore/index.ts @@ -1,20 +1,21 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import routes from '@/services/datastore/routes'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; + +import upload from '@/services/datastore/routes/upload'; // Router to handle the subdomain const datastore: express.Router = express.Router(); // Setup routes -logger.info('[DATASTORE] Applying imported routes'); -datastore.use(routes.UPLOAD); +LOG_INFO('[DATASTORE] Applying imported routes'); +datastore.use(upload); // Main router for endpoints const router: express.Router = express.Router(); // Create subdomains -logger.info('[DATASTORE] Creating \'datastore\' subdomain'); +LOG_INFO('[DATASTORE] Creating \'datastore\' subdomain'); router.use(subdomain('datastore', datastore)); export default router; \ No newline at end of file diff --git a/src/services/datastore/routes/index.ts b/src/services/datastore/routes/index.ts deleted file mode 100644 index 5e00989..0000000 --- a/src/services/datastore/routes/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import upload from '@/services/datastore/routes/upload'; - -export default { - UPLOAD: upload -}; \ No newline at end of file diff --git a/src/services/datastore/routes/upload.ts b/src/services/datastore/routes/upload.ts index 5b47857..c8c9ddf 100644 --- a/src/services/datastore/routes/upload.ts +++ b/src/services/datastore/routes/upload.ts @@ -2,7 +2,7 @@ import fs from 'node:fs'; import crypto from 'node:crypto'; import express from 'express'; import Dicer from 'dicer'; -import util from '@/util'; +import { uploadCDNAsset } from '@/util'; const router: express.Router = express.Router(); @@ -72,7 +72,7 @@ router.post('/upload', multipartParser, async (request: express.Request, respons return response.sendStatus(400); } - await util.uploadCDNAsset(bucket, key, file, acl); + await uploadCDNAsset(bucket, key, file, acl); response.sendStatus(200); }); diff --git a/src/services/local-cdn/index.ts b/src/services/local-cdn/index.ts index 9f9fe3f..c1b2963 100644 --- a/src/services/local-cdn/index.ts +++ b/src/services/local-cdn/index.ts @@ -1,8 +1,9 @@ import express from 'express'; import subdomain from 'express-subdomain'; -import routes from '@/services/local-cdn/routes'; import { config, disabledFeatures } from '@/config-manager'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; + +import get from '@/services/local-cdn/routes/get'; const router: express.Router = express.Router(); @@ -13,14 +14,14 @@ if (disabledFeatures.s3) { const localcdn: express.Router = express.Router(); // * Setup routes - logger.info('[LOCAL-CDN] Applying imported routes'); - localcdn.use(routes.GET); + LOG_INFO('[LOCAL-CDN] Applying imported routes'); + localcdn.use(get); // * Create subdomains - logger.info(`[LOCAL-CDN] Creating '${config.cdn.subdomain}' subdomain`); + LOG_INFO(`[LOCAL-CDN] Creating '${config.cdn.subdomain}' subdomain`); router.use(subdomain(config.cdn.subdomain, localcdn)); } else { - logger.info('[LOCAL-CDN] s3 enabled, skipping local CDN'); + LOG_INFO('[LOCAL-CDN] s3 enabled, skipping local CDN'); } export default router; \ No newline at end of file diff --git a/src/services/local-cdn/routes/get.ts b/src/services/local-cdn/routes/get.ts index 1492c13..ff18990 100644 --- a/src/services/local-cdn/routes/get.ts +++ b/src/services/local-cdn/routes/get.ts @@ -1,12 +1,12 @@ import express from 'express'; -import cache from '@/cache'; +import { getLocalCDNFile } from '@/cache'; const router: express.Router = express.Router(); router.get('/*', async (request: express.Request, response: express.Response) => { const filePath: string = request.params[0] as string; - const file: Buffer = await cache.getLocalCDNFile(filePath); + const file: Buffer = await getLocalCDNFile(filePath); if (file) { response.send(file); diff --git a/src/services/local-cdn/routes/index.ts b/src/services/local-cdn/routes/index.ts deleted file mode 100644 index 5038ab4..0000000 --- a/src/services/local-cdn/routes/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import get from '@/services/local-cdn/routes/get'; - -export default { - GET: get, -}; \ No newline at end of file diff --git a/src/services/nasc/index.ts b/src/services/nasc/index.ts index 38f1d60..29d1148 100644 --- a/src/services/nasc/index.ts +++ b/src/services/nasc/index.ts @@ -3,24 +3,25 @@ import express from 'express'; import subdomain from 'express-subdomain'; import NASCMiddleware from '@/middleware/nasc'; -import routes from '@/services/nasc/routes'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; + +import ac from '@/services/nasc/routes/ac'; // Router to handle the subdomain restriction const nasc: express.Router = express.Router(); -logger.info('[NASC] Importing middleware'); +LOG_INFO('[NASC] Importing middleware'); nasc.use(NASCMiddleware); // Setup routes -logger.info('[NASC] Applying imported routes'); -nasc.use('/ac', routes.AC); +LOG_INFO('[NASC] Applying imported routes'); +nasc.use('/ac', ac); // Main router for endpoints const router: express.Router = express.Router(); // Create subdomains -logger.info('[NASC] Creating \'nasc\' subdomain'); +LOG_INFO('[NASC] Creating \'nasc\' subdomain'); router.use(subdomain('nasc', nasc)); export default router; \ No newline at end of file diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 6e4589a..001de88 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -1,7 +1,7 @@ import express from 'express'; -import util from '@/util'; -import database from '@/database'; -import cache from '@/cache'; +import { nintendoBase64Encode, nintendoBase64Decode, nascError, generateToken } from '@/util'; +import { getServerByTitleId } from '@/database'; +import { getNEXPublicKey, getNEXSecretKey } from '@/cache'; import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; import { NASCRequestParams } from '@/types/services/nasc/request-params'; @@ -17,7 +17,7 @@ const router: express.Router = express.Router(); */ router.post('/', async (request: express.Request, response: express.Response) => { const requestParams: NASCRequestParams = request.body; - const action: string = util.nintendoBase64Decode(requestParams.action).toString(); + const action: string = nintendoBase64Decode(requestParams.action).toString(); let responseData: URLSearchParams; switch (action) { @@ -34,7 +34,7 @@ router.post('/', async (request: express.Request, response: express.Response) => async function processLoginRequest(request: express.Request): Promise { const requestParams: NASCRequestParams = request.body; - const titleID: string = util.nintendoBase64Decode(requestParams.titleid).toString(); + const titleID: string = nintendoBase64Decode(requestParams.titleid).toString(); const nexUser: HydratedNEXAccountDocument = request.nexUser; // TODO: REMOVE AFTER PUBLIC LAUNCH @@ -45,18 +45,18 @@ async function processLoginRequest(request: express.Request): Promise { return new URLSearchParams({ - retry: util.nintendoBase64Encode('0'), - returncd: util.nintendoBase64Encode('007'), - servicetoken: util.nintendoBase64Encode(Buffer.alloc(64).toString()), // hard coded for now - statusdata: util.nintendoBase64Encode('Y'), - svchost: util.nintendoBase64Encode('n/a'), - datetime: util.nintendoBase64Encode(Date.now().toString()), + retry: nintendoBase64Encode('0'), + returncd: nintendoBase64Encode('007'), + servicetoken: nintendoBase64Encode(Buffer.alloc(64).toString()), // hard coded for now + statusdata: nintendoBase64Encode('Y'), + svchost: nintendoBase64Encode('n/a'), + datetime: nintendoBase64Encode(Date.now().toString()), }); } diff --git a/src/services/nasc/routes/index.ts b/src/services/nasc/routes/index.ts deleted file mode 100644 index e8dfff6..0000000 --- a/src/services/nasc/routes/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import ac from '@/services/nasc/routes/ac'; - -export default { - AC: ac -}; \ No newline at end of file diff --git a/src/services/nnid/index.ts b/src/services/nnid/index.ts index 9c9cdd3..8fbcf6b 100644 --- a/src/services/nnid/index.ts +++ b/src/services/nnid/index.ts @@ -5,36 +5,44 @@ import subdomain from 'express-subdomain'; import clientHeaderCheck from '@/middleware/client-header'; import cemuMiddleware from '@/middleware/cemu'; import pnidMiddleware from '@/middleware/pnid'; -import routes from '@/services/nnid/routes'; -import logger from '@/logger'; +import { LOG_INFO } from '@/logger'; + +import admin from '@/services/nnid/routes/admin'; +import content from '@/services/nnid/routes/content'; +import devices from '@/services/nnid/routes/devices'; +import miis from '@/services/nnid/routes/miis'; +import oauth from '@/services/nnid/routes/oauth'; +import people from '@/services/nnid/routes/people'; +import provider from '@/services/nnid/routes/provider'; +import support from '@/services/nnid/routes/support'; // Router to handle the subdomain restriction const nnid = express.Router(); -logger.info('[NNID] Importing middleware'); +LOG_INFO('[NNID] Importing middleware'); nnid.use(clientHeaderCheck); nnid.use(cemuMiddleware); nnid.use(pnidMiddleware); // Setup routes -logger.info('[NNID] Applying imported routes'); -nnid.use('/v1/api/admin', routes.ADMIN); -nnid.use('/v1/api/content', routes.CONTENT); -nnid.use('/v1/api/devices', routes.DEVICES); -nnid.use('/v1/api/miis', routes.MIIS); -nnid.use('/v1/api/oauth20', routes.OAUTH); -nnid.use('/v1/api/people', routes.PEOPLE); -nnid.use('/v1/api/provider', routes.PROVIDER); -nnid.use('/v1/api/support', routes.SUPPORT); +LOG_INFO('[NNID] Applying imported routes'); +nnid.use('/v1/api/admin', admin); +nnid.use('/v1/api/content', content); +nnid.use('/v1/api/devices', devices); +nnid.use('/v1/api/miis', miis); +nnid.use('/v1/api/oauth20', oauth); +nnid.use('/v1/api/people', people); +nnid.use('/v1/api/provider', provider); +nnid.use('/v1/api/support', support); // Main router for endpoints const router = express.Router(); // Create subdomains -logger.info('[NNID] Creating \'account\' subdomain'); +LOG_INFO('[NNID] Creating \'account\' subdomain'); router.use(subdomain('account', nnid)); -logger.info('[NNID] Creating \'c.account\' subdomain'); +LOG_INFO('[NNID] Creating \'c.account\' subdomain'); router.use(subdomain('c.account', nnid)); export default router; \ No newline at end of file diff --git a/src/services/nnid/routes/index.ts b/src/services/nnid/routes/index.ts deleted file mode 100644 index 7510b1f..0000000 --- a/src/services/nnid/routes/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -import admin from '@/services/nnid/routes/admin'; -import content from '@/services/nnid/routes/content'; -import devices from '@/services/nnid/routes/devices'; -import miis from '@/services/nnid/routes/miis'; -import oauth from '@/services/nnid/routes/oauth'; -import people from '@/services/nnid/routes/people'; -import provider from '@/services/nnid/routes/provider'; -import support from '@/services/nnid/routes/support'; - -export default { - ADMIN: admin, - CONTENT: content, - DEVICES: devices, - MIIS: miis, - OAUTH: oauth, - PEOPLE: people, - PROVIDER: provider, - SUPPORT: support, -}; \ No newline at end of file diff --git a/src/services/nnid/routes/oauth.ts b/src/services/nnid/routes/oauth.ts index 800cad5..7d19804 100644 --- a/src/services/nnid/routes/oauth.ts +++ b/src/services/nnid/routes/oauth.ts @@ -2,8 +2,8 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import database from '@/database'; -import util from '@/util'; +import { getUserByUsername } from '@/database'; +import { generateToken } from '@/util'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -52,7 +52,7 @@ router.post('/access_token/generate', async (request: express.Request, response: }).end()); } - const pnid: HydratedPNIDDocument = await database.getUserByUsername(username); + const pnid: HydratedPNIDDocument = await getUserByUsername(username); if (!pnid || !await bcrypt.compare(password, pnid.password)) { response.status(400); @@ -103,8 +103,8 @@ router.post('/access_token/generate', async (request: express.Request, response: expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let accessToken: string = await util.generateToken(null, accessTokenOptions); - let refreshToken: string = await util.generateToken(null, refreshTokenOptions); + let accessToken: string = await generateToken(null, accessTokenOptions); + let refreshToken: string = await generateToken(null, refreshTokenOptions); if (request.isCemu) { accessToken = Buffer.from(accessToken, 'base64').toString('hex'); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 9c508f2..b838ffc 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -6,12 +6,14 @@ import moment from 'moment'; import mongoose from 'mongoose'; import deviceCertificateMiddleware from '@/middleware/device-certificate'; import ratelimit from '@/middleware/ratelimit'; -import database from '@/database'; -import util from '@/util'; +import { connection as databaseConnection, doesUserExist, getUserProfileJSONByPID } from '@/database'; +import { nintendoPasswordHash, sendConfirmationEmail } from '@/util'; import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; -import logger from '@/logger'; +import { LOG_ERROR } from '@/logger'; + import timezones from '@/services/nnid/timezones.json'; + import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; import { RegionLanguages } from '@/types/services/nnid/region-languages'; @@ -29,7 +31,7 @@ const router: express.Router = express.Router(); router.get('/:username', async (request: express.Request, response: express.Response) => { const username: string = request.params.username; - const userExists: boolean = await database.doesUserExist(username); + const userExists: boolean = await doesUserExist(username); if (userExists) { response.status(400); @@ -70,7 +72,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express // * request.body is a Map, as is request.body.person const person: Person = request.body.get('person'); - const userExists: boolean = await database.doesUserExist(person.get('user_id')); + const userExists: boolean = await doesUserExist(person.get('user_id')); if (userExists) { response.status(400); @@ -89,7 +91,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express let pnid: HydratedPNIDDocument; let nexAccount: HydratedNEXAccountDocument; - const session: mongoose.ClientSession = await database.connection().startSession(); + const session: mongoose.ClientSession = await databaseConnection().startSession(); await session.startTransaction(); try { @@ -109,7 +111,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express await nexAccount.save({ session }); - const primaryPasswordHash: string = util.nintendoPasswordHash(person.get('password'), nexAccount.get('pid')); + const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), nexAccount.get('pid')); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); const countryCode: string = person.get('country'); @@ -172,7 +174,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express await session.commitTransaction(); } catch (error) { - logger.error('[POST] /v1/api/people: ' + error); + LOG_ERROR('[POST] /v1/api/people: ' + error); await session.abortTransaction(); @@ -191,7 +193,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express await session.endSession(); } - await util.sendConfirmationEmail(pnid); + await sendConfirmationEmail(pnid); response.send(xmlbuilder.create({ person: { @@ -212,7 +214,7 @@ router.get('/@me/profile', async (request: express.Request, response: express.Re const pnid: HydratedPNIDDocument = request.pnid; - const person: PNIDProfile = await database.getUserProfileJSONByPID(pnid.get('pid')); + const person: PNIDProfile = await getUserProfileJSONByPID(pnid.get('pid')); response.send(xmlbuilder.create({ person @@ -237,7 +239,7 @@ router.post('/@me/devices', async (request: express.Request, response: express.R const pnid: HydratedPNIDDocument = request.pnid; - const person: PNIDProfile = await database.getUserProfileJSONByPID(pnid.pid); + const person: PNIDProfile = await getUserProfileJSONByPID(pnid.pid); response.send(xmlbuilder.create({ person @@ -295,7 +297,7 @@ router.get('/@me/devices/owner', async (request: express.Request, response: expr const pnid: HydratedPNIDDocument = request.pnid; - const person: PNIDProfile = await database.getUserProfileJSONByPID(pnid.get('pid')); + const person: PNIDProfile = await getUserProfileJSONByPID(pnid.get('pid')); response.send(xmlbuilder.create({ person @@ -428,7 +430,7 @@ router.put('/@me', async (request: express.Request, response: express.Response) const timezone: RegionTimezone = regionTimezones.find(tz => tz.area === timezoneName); if (person.get('password')) { - const primaryPasswordHash: string = util.nintendoPasswordHash(person.get('password'), pnid.get('pid')); + const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), pnid.get('pid')); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; @@ -523,7 +525,7 @@ router.put('/@me/emails/@primary', async (request: express.Request, response: ex await pnid.save(); - await util.sendConfirmationEmail(pnid); + await sendConfirmationEmail(pnid); response.send(''); }); diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index ca1de25..2f8dd70 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -1,9 +1,9 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import fs from 'fs-extra'; -import database from '@/database'; -import util from '@/util'; -import cache from '@/cache'; +import { getServerByTitleId, getServer } from '@/database'; +import { generateToken } from '@/util'; +import { getServicePublicKey, getServiceSecretKey, getNEXPublicKey, getNEXSecretKey } from '@/cache'; import { NEXAccount } from '@/models/nex-account'; import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; @@ -23,7 +23,7 @@ router.get('/service_token/@me', async (request: express.Request, response: expr const titleId: string = request.headers['x-nintendo-title-id'] as string; const serverAccessLevel: string = pnid.get('server_access_level'); - const server: HydratedServerDocument = await database.getServerByTitleId(titleId, serverAccessLevel); + const server: HydratedServerDocument = await getServerByTitleId(titleId, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ @@ -53,8 +53,8 @@ router.get('/service_token/@me', async (request: express.Request, response: expr }).end()); } - const publicKey: Buffer = await cache.getServicePublicKey(serverName); - const secretKey: Buffer = await cache.getServiceSecretKey(serverName); + const publicKey: Buffer = await getServicePublicKey(serverName); + const secretKey: Buffer = await getServiceSecretKey(serverName); const cryptoOptions: CryptoOptions = { public_key: publicKey, @@ -70,7 +70,7 @@ router.get('/service_token/@me', async (request: express.Request, response: expr expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let serviceToken: string = await util.generateToken(cryptoOptions, tokenOptions); + let serviceToken: string = await generateToken(cryptoOptions, tokenOptions); if (request.isCemu) { serviceToken = Buffer.from(serviceToken, 'base64').toString('hex'); @@ -104,7 +104,7 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. } const serverAccessLevel: string = pnid.get('server_access_level'); - const server: HydratedServerDocument = await database.getServer(gameServerID, serverAccessLevel); + const server: HydratedServerDocument = await getServer(gameServerID, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ @@ -137,8 +137,8 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. }).end()); } - const publicKey: Buffer = await cache.getNEXPublicKey(serverName); - const secretKey: Buffer = await cache.getNEXSecretKey(serverName); + const publicKey: Buffer = await getNEXPublicKey(serverName); + const secretKey: Buffer = await getNEXSecretKey(serverName); const cryptoOptions: CryptoOptions = { public_key: publicKey, @@ -163,7 +163,7 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. return response.send('0008Not Found'); } - let nexToken: string = await util.generateToken(cryptoOptions, tokenOptions); + let nexToken: string = await generateToken(cryptoOptions, tokenOptions); if (request.isCemu) { nexToken = Buffer.from(nexToken, 'base64').toString('hex'); diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index edfe201..6ecb0c9 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -2,8 +2,8 @@ import dns from 'node:dns'; import express from 'express'; import xmlbuilder from 'xmlbuilder'; import moment from 'moment'; -import database from '@/database'; -import util from '@/util'; +import { getUserByPID } from '@/database'; +import { sendEmailConfirmedEmail, sendConfirmationEmail, sendForgotPasswordEmail } from '@/util'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; const router: express.Router = express.Router(); @@ -56,7 +56,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re const code: string = request.params.code; const pid: number = Number(request.params.pid); - const pnid: HydratedPNIDDocument = await database.getUserByPID(pid); + const pnid: HydratedPNIDDocument = await getUserByPID(pid); if (!pnid) { return response.status(400).send(xmlbuilder.create({ @@ -88,7 +88,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re await pnid.save(); - await util.sendEmailConfirmedEmail(pnid); + await sendEmailConfirmedEmail(pnid); response.status(200).send(''); }); @@ -101,7 +101,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re router.get('/resend_confirmation', async (request: express.Request, response: express.Response) => { const pid: number = Number(request.headers['x-nintendo-pid']); - const pnid: HydratedPNIDDocument = await database.getUserByPID(pid); + const pnid: HydratedPNIDDocument = await getUserByPID(pid); if (!pnid) { // TODO - Unsure if this is the right error @@ -115,7 +115,7 @@ router.get('/resend_confirmation', async (request: express.Request, response: ex }).end()); } - await util.sendConfirmationEmail(pnid); + await sendConfirmationEmail(pnid); response.status(200).send(''); }); @@ -129,7 +129,7 @@ router.get('/resend_confirmation', async (request: express.Request, response: ex router.get('/forgotten_password/:pid', async (request: express.Request, response: express.Response) => { const pid: number = Number(request.params.pid); - const pnid: HydratedPNIDDocument = await database.getUserByPID(pid); + const pnid: HydratedPNIDDocument = await getUserByPID(pid); if (!pnid) { // TODO - Better errors @@ -144,7 +144,7 @@ router.get('/forgotten_password/:pid', async (request: express.Request, response }).end()); } - await util.sendForgotPasswordEmail(pnid); + await sendForgotPasswordEmail(pnid); response.status(200).send(''); }); diff --git a/src/util.ts b/src/util.ts index eaec4c4..f2ca7d6 100644 --- a/src/util.ts +++ b/src/util.ts @@ -5,8 +5,8 @@ import aws from 'aws-sdk'; import fs from 'fs-extra'; import express from 'express'; import mongoose from 'mongoose'; -import mailer from '@/mailer'; -import cache from '@/cache'; +import { sendMail } from '@/mailer'; +import { getServiceAESKey, getServicePrivateKey, getServiceSecretKey, getServicePublicKey } from '@/cache'; import { config, disabledFeatures } from '@/config-manager'; import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; @@ -24,7 +24,7 @@ if (!disabledFeatures.s3) { }); } -function nintendoPasswordHash(password: string, pid: number): string { +export function nintendoPasswordHash(password: string, pid: number): string { const pidBuffer: Buffer = Buffer.alloc(4); pidBuffer.writeUInt32LE(pid); @@ -37,21 +37,21 @@ function nintendoPasswordHash(password: string, pid: number): string { return crypto.createHash('sha256').update(unpacked).digest().toString('hex'); } -function nintendoBase64Decode(encoded: string): Buffer { +export function nintendoBase64Decode(encoded: string): Buffer { encoded = encoded.replaceAll('.', '+').replaceAll('-', '/').replaceAll('*', '='); return Buffer.from(encoded, 'base64'); } -function nintendoBase64Encode(decoded: string | Buffer): string { +export function nintendoBase64Encode(decoded: string | Buffer): string { const encoded: string = Buffer.from(decoded).toString('base64'); return encoded.replaceAll('+', '.').replaceAll('/', '-').replaceAll('=', '*'); } -async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: TokenOptions): Promise { +export async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: TokenOptions): Promise { // Access and refresh tokens use a different format since they must be much smaller // They take no extra crypto options if (!cryptoOptions) { - const aesKey: Buffer = await cache.getServiceAESKey('account', 'hex'); + const aesKey: Buffer = await getServiceAESKey('account', 'hex'); const dataBuffer: Buffer = Buffer.alloc(1 + 1 + 4 + 8); @@ -136,11 +136,11 @@ async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: return token.toString('base64'); // Encode to base64 for transport } -async function decryptToken(token: Buffer): Promise { +export async function decryptToken(token: Buffer): Promise { // Access and refresh tokens use a different format since they must be much smaller // Assume a small length means access or refresh token if (token.length <= 32) { - const aesKey: Buffer = await cache.getServiceAESKey('account', 'hex'); + const aesKey: Buffer = await getServiceAESKey('account', 'hex'); const iv: Buffer = Buffer.alloc(16); @@ -154,8 +154,8 @@ async function decryptToken(token: Buffer): Promise { return decryptedBody; } - const privateKeyBytes: Buffer = await cache.getServicePrivateKey('account'); - const secretKey: Buffer = await cache.getServiceSecretKey('account'); + const privateKeyBytes: Buffer = await getServicePrivateKey('account'); + const secretKey: Buffer = await getServiceSecretKey('account'); const privateKey: NodeRSA = new NodeRSA(privateKeyBytes, 'pkcs1-private-pem', { environment: 'browser', @@ -198,7 +198,7 @@ async function decryptToken(token: Buffer): Promise { return decryptedBody; } -function unpackToken(token: Buffer): Token { +export function unpackToken(token: Buffer): Token { if (token.length <= 14) { return { system_type: token.readUInt8(0x0), @@ -218,7 +218,7 @@ function unpackToken(token: Buffer): Token { }; } -function fullUrl(request: express.Request): string { +export function fullUrl(request: express.Request): string { const protocol: string = request.protocol; const host: string = request.host; const opath: string = request.originalUrl; @@ -226,7 +226,7 @@ function fullUrl(request: express.Request): string { return `${protocol}://${host}${opath}`; } -async function uploadCDNAsset(bucket: string, key: string, data: Buffer, acl: string): Promise { +export async function uploadCDNAsset(bucket: string, key: string, data: Buffer, acl: string): Promise { if (disabledFeatures.s3) { await writeLocalCDNFile(key, data); } else { @@ -239,7 +239,7 @@ async function uploadCDNAsset(bucket: string, key: string, data: Buffer, acl: st } } -async function writeLocalCDNFile(key: string, data: Buffer): Promise { +export async function writeLocalCDNFile(key: string, data: Buffer): Promise { const filePath: string = config.cdn.disk_path; const folder: string = path.dirname(filePath); @@ -247,7 +247,7 @@ async function writeLocalCDNFile(key: string, data: Buffer): Promise { await fs.writeFile(filePath, data); } -function nascError(errorCode: string): URLSearchParams { +export function nascError(errorCode: string): URLSearchParams { return new URLSearchParams({ retry: nintendoBase64Encode('1'), returncd: errorCode == 'null' ? errorCode : nintendoBase64Encode(errorCode), @@ -255,7 +255,7 @@ function nascError(errorCode: string): URLSearchParams { }); } -async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { +export async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { to: pnid.get('email.address'), subject: '[Pretendo Network] Please confirm your email address', @@ -267,10 +267,10 @@ async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { +export async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { to: pnid.get('email.address'), subject: '[Pretendo Network] Email address confirmed', @@ -279,12 +279,12 @@ async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument): Promise { - const publicKey: Buffer = await cache.getServicePublicKey('account'); - const secretKey: Buffer = await cache.getServiceSecretKey('account'); +export async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument): Promise { + const publicKey: Buffer = await getServicePublicKey('account'); + const secretKey: Buffer = await getServiceSecretKey('account'); const cryptoOptions: CryptoOptions = { public_key: publicKey, @@ -314,20 +314,5 @@ async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument Date: Fri, 17 Mar 2023 16:18:18 -0400 Subject: [PATCH 40/65] Removed unneccesary casts --- src/database.ts | 8 ++++---- src/util.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/database.ts b/src/database.ts index 931d181..d5b8c8c 100644 --- a/src/database.ts +++ b/src/database.ts @@ -147,7 +147,7 @@ export async function getUserProfileJSONByPID(pid: number): Promise })); } - return { + return { //accounts: {}, // * We need to figure this out, no idea what these values mean or what they do active_flag: user.get('flags.active') ? 'Y' : 'N', birth_date: user.get('birthdate'), @@ -220,7 +220,7 @@ export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: const valid: joi.ValidationResult = discordConnectionSchema.validate(data); if (valid.error) { - return { + return { app: 'api', status: 400, error: 'Invalid or missing connection data' @@ -233,7 +233,7 @@ export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: } }); - return { + return { app: 'api', status: 200 }; @@ -253,7 +253,7 @@ export async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): P } }); - return { + return { app: 'api', status: 200 }; diff --git a/src/util.ts b/src/util.ts index f2ca7d6..5269666 100644 --- a/src/util.ts +++ b/src/util.ts @@ -200,7 +200,7 @@ export async function decryptToken(token: Buffer): Promise { export function unpackToken(token: Buffer): Token { if (token.length <= 14) { - return { + return { system_type: token.readUInt8(0x0), token_type: token.readUInt8(0x1), pid: token.readUInt32LE(0x2), @@ -208,7 +208,7 @@ export function unpackToken(token: Buffer): Token { }; } - return { + return { system_type: token.readUInt8(0x0), token_type: token.readUInt8(0x1), pid: token.readUInt32LE(0x2), From dd952954fde5262c4f2d0e03ad425e79310e42aa Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 17 Mar 2023 17:39:46 -0400 Subject: [PATCH 41/65] Enable strict mode in TS and fix most issues with it --- .eslintignore | 3 +- package-lock.json | 3083 +++++++++++++++++- package.json | 6 +- src/cache.ts | 6 +- src/config-manager.ts | 36 +- src/database.ts | 55 +- src/mailer.ts | 8 +- src/middleware/api.ts | 4 +- src/middleware/nasc.ts | 12 +- src/middleware/pnid.ts | 4 +- src/middleware/xml-parser.ts | 4 +- src/models/pnid.ts | 4 +- src/services/api/routes/v1/connections.ts | 26 +- src/services/api/routes/v1/email.ts | 4 +- src/services/api/routes/v1/forgotPassword.ts | 2 +- src/services/api/routes/v1/login.ts | 8 +- src/services/api/routes/v1/register.ts | 6 +- src/services/api/routes/v1/resetPassword.ts | 2 +- src/services/api/routes/v1/user.ts | 4 +- src/services/datastore/routes/upload.ts | 20 +- src/services/nasc/routes/ac.ts | 17 +- src/services/nnid/routes/admin.ts | 3 +- src/services/nnid/routes/oauth.ts | 12 +- src/services/nnid/routes/people.ts | 87 +- src/services/nnid/routes/provider.ts | 51 +- src/services/nnid/routes/support.ts | 8 +- src/types/express.d.ts | 4 +- src/types/services/nnid/pnid-profile.ts | 4 +- src/util.ts | 15 +- tsconfig.json | 1 + 30 files changed, 3358 insertions(+), 141 deletions(-) diff --git a/.eslintignore b/.eslintignore index 53c37a1..7c5c224 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ -dist \ No newline at end of file +dist +*.js \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 612c092..78ae38f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "dotenv": "^16.0.3", "email-validator": "^2.0.4", "express": "^4.17.1", - "express-rate-limit": "^5.3.0", + "express-rate-limit": "^6.7.0", "express-subdomain": "^1.0.5", "fs-extra": "^8.1.0", "got": "^11.8.2", @@ -39,13 +39,17 @@ }, "devDependencies": { "@hcaptcha/types": "^1.0.3", + "@types/bcrypt": "^5.0.0", + "@types/cors": "^2.8.13", "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", + "@types/mongoose-unique-validator": "^1.0.7", "@types/morgan": "^1.9.4", "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", "@types/nodemailer": "^6.4.7", + "@types/validator": "^13.7.14", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", "eslint": "^8.35.0", @@ -54,6 +58,1404 @@ "yesno": "^0.4.0" } }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "optional": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "optional": true, + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "optional": true, + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "optional": true, + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-sdk/abort-controller": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.292.0.tgz", + "integrity": "sha512-lf+OPptL01kvryIJy7+dvFux5KbJ6OTwLPPEekVKZ2AfEvwcVtOZWFUhyw3PJCBTVncjKB1Kjl3V/eTS3YuPXQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/abort-controller/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/client-cognito-identity": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.294.0.tgz", + "integrity": "sha512-QMk/QratNvAvmnJ77pu9KDjpfUf/5LOJplHcLKcY962ewJGBtFFY4XZVnmUgQMSG0phRODtex7pyH//FueGKLQ==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.294.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/credential-provider-node": "3.294.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-signing": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.294.0.tgz", + "integrity": "sha512-+FuxQTi5WvnaXM5JbNLkBIzQ3An4gA0ox61N1u+3xled+nywKb1yQ7WmRpyMG5bLbkmnj3aqoo5/uskFc4c4EA==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.294.0.tgz", + "integrity": "sha512-/ZfDud76MdSPJ/TxjV2xLE30XbBQDZwKQ32axwoK1eziPvrAIUBYVgpBwj+m0quhoiQhBKkg3aFl6j39AF2thw==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso-oidc/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/client-sso/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.294.0.tgz", + "integrity": "sha512-AefqwhFjTDzelZuSYhriJbiI+GQwf2yKiKAnCt0gRj6rswewStM63Gtlhfb01sFPp+ZiqPcyQ47LqUaHp1mz/g==", + "optional": true, + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/credential-provider-node": "3.294.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-sdk-sts": "3.292.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-signing": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "fast-xml-parser": "4.1.2", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/config-resolver": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.292.0.tgz", + "integrity": "sha512-cB3twnNR7vYvlt2jvw8VlA1+iv/tVzl+/S39MKqw2tepU+AbJAM0EHwb/dkf1OKSmlrnANXhshx80MHF9zL4mA==", + "optional": true, + "dependencies": { + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-config-provider": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/config-resolver/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.294.0.tgz", + "integrity": "sha512-YSPqHEbLC0dnbFF5LdlMH0B50sMSN/CyG/sHkPYUwL/hkbUk9URnVW7ZJlt6lRftT7X4C7muzLqUP8sJAaiJEA==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.294.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.292.0.tgz", + "integrity": "sha512-YbafSG0ZEKE2969CJWVtUhh3hfOeLPecFVoXOtegCyAJgY5Ghtu4TsVhL4DgiGAgOC30ojAmUVQEXzd7xJF5xA==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-imds": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.292.0.tgz", + "integrity": "sha512-W/peOgDSRYulgzFpUhvgi1pCm6piBz6xrVN17N4QOy+3NHBXRVMVzYk6ct2qpLPgJUSEZkcpP+Gds+bBm8ed1A==", + "optional": true, + "dependencies": { + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-imds/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.294.0.tgz", + "integrity": "sha512-pdTPbaAb5bWA+DnuKoL2TpXeNDp6Ejpv/OYt+bw2gdzl9w5r/ZCtUTTbW+Vvejr4WL5s3c1bY96kwdqCn7iLqA==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/credential-provider-process": "3.292.0", + "@aws-sdk/credential-provider-sso": "3.294.0", + "@aws-sdk/credential-provider-web-identity": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.294.0.tgz", + "integrity": "sha512-zUL1Qhb4BsQIZCs/TPpG4oIYH/9YsGiS+Se1tasSGjTOLfBy7jhOZ0QIdpEeyAx/EP8blOBredM9xWfEXgiHVA==", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/credential-provider-ini": "3.294.0", + "@aws-sdk/credential-provider-process": "3.292.0", + "@aws-sdk/credential-provider-sso": "3.294.0", + "@aws-sdk/credential-provider-web-identity": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.292.0.tgz", + "integrity": "sha512-CFVXuMuUvg/a4tknzRikEDwZBnKlHs1LZCpTXIGjBdUTdosoi4WNzDLzGp93ZRTtcgFz+4wirz2f7P3lC0NrQw==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.294.0.tgz", + "integrity": "sha512-UxrcAA/0l7j9+3tolYcG5M61D/IE1Bjd/9H87H1i2A2BrwUUBhW1Dp/vvROEDrrywlMDG3CDF3T/7ADtTak+sg==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso": "3.294.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/token-providers": "3.294.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.292.0.tgz", + "integrity": "sha512-4DbtIEM9gGVfqYlMdYXg3XY+vBhemjB1zXIequottW8loLYM8Vuz4/uGxxKNze6evVVzowsA0wKrYclE1aj/Rg==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.294.0.tgz", + "integrity": "sha512-CRGwCs6F31mQzjYi5YF2Z6c1T+UrFKtJSa6Ff/Q1rrPnROexyhBVnpP8WzpkODx/pZxKtTX50IX7ehIxbFDIyQ==", + "optional": true, + "dependencies": { + "@aws-sdk/client-cognito-identity": "3.294.0", + "@aws-sdk/client-sso": "3.294.0", + "@aws-sdk/client-sts": "3.294.0", + "@aws-sdk/credential-provider-cognito-identity": "3.294.0", + "@aws-sdk/credential-provider-env": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/credential-provider-ini": "3.294.0", + "@aws-sdk/credential-provider-node": "3.294.0", + "@aws-sdk/credential-provider-process": "3.292.0", + "@aws-sdk/credential-provider-sso": "3.294.0", + "@aws-sdk/credential-provider-web-identity": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/fetch-http-handler": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.292.0.tgz", + "integrity": "sha512-zh3bhUJbL8RSa39ZKDcy+AghtUkIP8LwcNlwRIoxMQh3Row4D1s4fCq0KZCx98NJBEXoiTLyTQlZxxI//BOb1Q==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/querystring-builder": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/fetch-http-handler/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/hash-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.292.0.tgz", + "integrity": "sha512-1yLxmIsvE+eK36JXEgEIouTITdykQLVhsA5Oai//Lar6Ddgu1sFpLDbdkMtKbrh4I0jLN9RacNCkeVQjZPTCCQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-buffer-from": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/hash-node/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/invalid-dependency": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.292.0.tgz", + "integrity": "sha512-39OUV78CD3TmEbjhpt+V+Fk4wAGWhixqHxDSN8+4WL0uB4Fl7k5m3Z9hNY78AttHQSl2twR7WtLztnXPAFsriw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/invalid-dependency/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/is-array-buffer": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.292.0.tgz", + "integrity": "sha512-kW/G5T/fzI0sJH5foZG6XJiNCevXqKLxV50qIT4B1pMuw7regd4ALIy0HwSqj1nnn9mSbRWBfmby0jWCJsMcwg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/is-array-buffer/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-content-length": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.292.0.tgz", + "integrity": "sha512-2gMWzQus5mj14menolpPDbYBeaOYcj7KNFZOjTjjI3iQ0KqyetG6XasirNrcJ/8QX1BRmpTol8Xjp2Ue3Gbzwg==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-content-length/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-endpoint": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.292.0.tgz", + "integrity": "sha512-cPMkiSxpZGG6tYlW4OS+ucS6r43f9ddX9kcUoemJCY10MOuogdPjulCAjE0HTs2PLKSOrrG4CTP4Q4wWDrH4Bw==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-config-provider": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.292.0.tgz", + "integrity": "sha512-mHuCWe3Yg2S5YZ7mB7sKU6C97XspfqrimWjMW9pfV2usAvLA3R0HrB03jpR5vpZ3P4q7HB6wK3S6CjYMGGRNag==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.292.0.tgz", + "integrity": "sha512-yZNY1XYmG3NG+uonET7jzKXNiwu61xm/ZZ6i/l51SusuaYN+qQtTAhOFsieQqTehF9kP4FzbsWgPDwD8ZZX9lw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.292.0.tgz", + "integrity": "sha512-kA3VZpPko0Zqd7CYPTKAxhjEv0HJqFu2054L04dde1JLr43ro+2MTdX7vsHzeAFUVRphqatFFofCumvXmU6Mig==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-retry": { + "version": "3.293.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.293.0.tgz", + "integrity": "sha512-7tiaz2GzRecNHaZ6YnF+Nrtk3au8qF6oiipf11R7MJiqJ0fkMLnz/iRrlakDziS9qF/a9v+3yxb4W4NHK3f4Tw==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/service-error-classification": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "@aws-sdk/util-retry": "3.292.0", + "tslib": "^2.3.1", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-retry/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-retry/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.292.0.tgz", + "integrity": "sha512-GN5ZHEqXZqDi+HkVbaXRX9HaW/vA5rikYpWKYsmxTUZ7fB7ijvEO3co3lleJv2C+iGYRtUIHC4wYNB5xgoTCxg==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-signing": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-serde": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.292.0.tgz", + "integrity": "sha512-6hN9mTQwSvV8EcGvtXbS/MpK7WMCokUku5Wu7X24UwCNMVkoRHLIkYcxHcvBTwttuOU0d8hph1/lIX4dkLwkQw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-serde/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.292.0.tgz", + "integrity": "sha512-GVfoSjDjEQ4TaO6x9MffyP3uRV+2KcS5FtexLCYOM9pJcnE9tqq9FJOrZ1xl1g+YjUVKxo4x8lu3tpEtIb17qg==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-stack": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.292.0.tgz", + "integrity": "sha512-WdQpRkuMysrEwrkByCM1qCn2PPpFGGQ2iXqaFha5RzCdZDlxJni9cVNb6HzWUcgjLEYVTXCmOR9Wxm3CNW44Qg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-stack/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.293.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.293.0.tgz", + "integrity": "sha512-gZ7/e6XwpKk9mvgA78q4Ffc796jTn02TUKx2qMDnkLVbeJXBNN2jnvYEKq8v70+o7fd/ALRudg8gBDmkkhM/Hw==", + "optional": true, + "dependencies": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/node-config-provider": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.292.0.tgz", + "integrity": "sha512-S3NnC9dQ5GIbJYSDIldZb4zdpCOEua1tM7bjYL3VS5uqCEM93kIi/o/UkIUveMp/eqTS2LJa5HjNIz5Te6je0A==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/node-config-provider/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/node-http-handler": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.292.0.tgz", + "integrity": "sha512-L/E3UDSwXLXjt1XWWh0RBD55F+aZI1AEdPwdES9i1PjnZLyuxuDhEDptVibNN56+I9/4Q3SbmuVRVlOD0uzBag==", + "optional": true, + "dependencies": { + "@aws-sdk/abort-controller": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/querystring-builder": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/node-http-handler/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/property-provider": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.292.0.tgz", + "integrity": "sha512-dHArSvsiqhno/g55N815gXmAMrmN8DP7OeFNqJ4wJG42xsF2PFN3DAsjIuHuXMwu+7A3R1LHqIpvv0hA9KeoJQ==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/property-provider/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/protocol-http": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.292.0.tgz", + "integrity": "sha512-NLi4fq3k41aXIh1I97yX0JTy+3p6aW1NdwFwdMa674z86QNfb4SfRQRZBQe9wEnAZ/eWHVnlKIuII+U1URk/Kg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/protocol-http/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/querystring-builder": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.292.0.tgz", + "integrity": "sha512-XElIFJaReIm24eEvBtV2dOtZvcm3gXsGu/ftG8MLJKbKXFKpAP1q+K6En0Bs7/T88voKghKdKpKT+eZUWgTqlg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-uri-escape": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/querystring-builder/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/querystring-parser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.292.0.tgz", + "integrity": "sha512-iTYpYo7a8X9RxiPbjjewIpm6XQPx2EOcF1dWCPRII9EFlmZ4bwnX+PDI36fIo9oVs8TIKXmwNGODU9nsg7CSAw==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/querystring-parser/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/service-error-classification": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.292.0.tgz", + "integrity": "sha512-X1k3sixCeC45XSNHBe+kRBQBwPDyTFtFITb8O5Qw4dS9XWGhrUJT4CX0qE5aj8qP3F9U5nRizs9c2mBVVP0Caw==", + "optional": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/shared-ini-file-loader": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.292.0.tgz", + "integrity": "sha512-Av2TTYg1Jig2kbkD56ybiqZJB6vVrYjv1W5UQwY/q3nA/T2mcrgQ20ByCOt5Bv9VvY7FSgC+znj+L4a7RLGmBg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/shared-ini-file-loader/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/signature-v4": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.292.0.tgz", + "integrity": "sha512-+rw47VY5mvBecn13tDQTl1ipGWg5tE63faWgmZe68HoBL87ZiDzsd7bUKOvjfW21iMgWlwAppkaNNQayYRb2zg==", + "optional": true, + "dependencies": { + "@aws-sdk/is-array-buffer": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-hex-encoding": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "@aws-sdk/util-uri-escape": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/smithy-client": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.292.0.tgz", + "integrity": "sha512-S8PKzjPkZ6SXYZuZiU787dMsvQ0d/LFEhw2OI4Oe2An9Fc2IwJ2FYukyHoQJOV2tV0DiuMebPo7eMyQyjKElvA==", + "optional": true, + "dependencies": { + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/smithy-client/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.294.0.tgz", + "integrity": "sha512-6nwO04LtC5f4AsUvGZXyjaswuEK4Rr2VsuANpMKrPCgunRfI58a8YXLniudOSXN6e7CFJ6M3uo/h5YXqtnzGug==", + "optional": true, + "dependencies": { + "@aws-sdk/client-sso-oidc": "3.294.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/types": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.292.0.tgz", + "integrity": "sha512-1teYAY2M73UXZxMAxqZxVS2qwXjQh0OWtt7qyLfha0TtIk/fZ1hRwFgxbDCHUFcdNBSOSbKH/ESor90KROXLCQ==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/url-parser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.292.0.tgz", + "integrity": "sha512-NZeAuZCk1x6TIiWuRfbOU6wHPBhf0ly2qOHzWut4BCH+b4RrDmFF8EmXcH1auEfGhE7yRyR6XqIN0t3S+hYACA==", + "optional": true, + "dependencies": { + "@aws-sdk/querystring-parser": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/url-parser/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-base64": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.292.0.tgz", + "integrity": "sha512-zjNCwNdy617yFvEjZorepNWXB2sQCVfsShCwFy/kIQ5iW5tT2jQKaqc0K77diU9atkooxw9p1W9m9sOgrkOFNw==", + "optional": true, + "dependencies": { + "@aws-sdk/util-buffer-from": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-base64/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-body-length-browser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.292.0.tgz", + "integrity": "sha512-Wd/BM+JsMiKvKs/bN3z6TredVEHh2pKudGfg3CSjTRpqFpOG903KDfyHBD42yg5PuCHoHoewJvTPKwgn7/vhaw==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-body-length-browser/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-body-length-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.292.0.tgz", + "integrity": "sha512-BBgipZ2P6RhogWE/qj0oqpdlyd3iSBYmb+aD/TBXwB2lA/X8A99GxweBd/kp06AmcJRoMS9WIXgbWkiiBlRlSA==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-body-length-node/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-buffer-from": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.292.0.tgz", + "integrity": "sha512-RxNZjLoXNxHconH9TYsk5RaEBjSgTtozHeyIdacaHPj5vlQKi4hgL2hIfKeeNiAfQEVjaUFF29lv81xpNMzVMQ==", + "optional": true, + "dependencies": { + "@aws-sdk/is-array-buffer": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-buffer-from/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-config-provider": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.292.0.tgz", + "integrity": "sha512-t3noYll6bPRSxeeNNEkC5czVjAiTPcsq00OwfJ2xyUqmquhLEfLwoJKmrT1uP7DjIEXdUtfoIQ2jWiIVm/oO5A==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-config-provider/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-defaults-mode-browser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.292.0.tgz", + "integrity": "sha512-7+zVUlMGfa8/KT++9humHo6IDxTnxMCmWUj5jVNlkpk6h7Ecmppf7aXotviyVIA43lhtz0p2AErs0N0ekEUK+w==", + "optional": true, + "dependencies": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/util-defaults-mode-browser/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-defaults-mode-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.292.0.tgz", + "integrity": "sha512-SSIw85eF4BVs0fOJRyshT+R3b/UmBPhiVKCUZm2rq6+lIGkDPiSwQU3d/80AhXtiL5SFT/IzAKKgQd8qMa7q3A==", + "optional": true, + "dependencies": { + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@aws-sdk/util-defaults-mode-node/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.293.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.293.0.tgz", + "integrity": "sha512-R/99aNV49Refpv5guiUjEUrZYlvnfaNBniB+/ZtMO3ixxUopapssCrUivuJrmhccmrYaTCZw7dRzIWjU1jJhKg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-hex-encoding": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.292.0.tgz", + "integrity": "sha512-qBd5KFIUywQ3qSSbj814S2srk0vfv8A6QMI+Obs1y2LHZFdQN5zViptI4UhXhKOHe+NnrHWxSuLC/LMH6q3SmA==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-hex-encoding/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.292.0.tgz", + "integrity": "sha512-6xnFJXZI9pKw5lQCDvuWA5PnOaUtNRKWwdxvGkkLx5orboFaoVMS6zowjSQxwVNRjW82u6dYNkhmj9mZ8VSjWg==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-middleware": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.292.0.tgz", + "integrity": "sha512-KjhS7flfoBKDxbiBZjLjMvEizXgjfQb7GQEItgzGoI9rfGCmZtvqCcqQQoIlxb8bIzGRggAUHtBGWnlLbpb+GQ==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-middleware/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-retry": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.292.0.tgz", + "integrity": "sha512-JEHyF7MpVeRF5uR4LDYgpOKcFpOPiAj8TqN46SVOQQcL1K+V7cSr7O7N7J6MwJaN9XOzAcBadeIupMm7/BFbgw==", + "optional": true, + "dependencies": { + "@aws-sdk/service-error-classification": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/util-retry/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-uri-escape": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.292.0.tgz", + "integrity": "sha512-hOQtUMQ4VcQ9iwKz50AoCp1XBD5gJ9nly/gJZccAM7zSA5mOO8RRKkbdonqquVHxrO0CnYgiFeCh3V35GFecUw==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-uri-escape/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.292.0.tgz", + "integrity": "sha512-dld+lpC3QdmTQHdBWJ0WFDkXDSrJgfz03q6mQ8+7H+BC12ZhT0I0g9iuvUjolqy7QR00OxOy47Y9FVhq8EC0Gg==", + "optional": true, + "dependencies": { + "@aws-sdk/types": "3.292.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.292.0.tgz", + "integrity": "sha512-f+NfIMal5E61MDc5WGhUEoicr7b1eNNhA+GgVdSB/Hg5fYhEZvFK9RZizH5rrtsLjjgcr9nPYSR7/nDKCJLumw==", + "optional": true, + "dependencies": { + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-user-agent-node/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-utf8": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.292.0.tgz", + "integrity": "sha512-FPkj+Z59/DQWvoVu2wFaRncc3KVwe/pgK3MfVb0Lx+Ibey5KUx+sNpJmYcVYHUAe/Nv/JeIpOtYuC96IXOnI6w==", + "optional": true, + "dependencies": { + "@aws-sdk/util-buffer-from": "3.292.0", + "tslib": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "optional": true, + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/util-utf8-browser/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "node_modules/@aws-sdk/util-utf8/node_modules/tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -456,6 +1858,15 @@ "node": ">=10" } }, + "node_modules/@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -486,6 +1897,15 @@ "@types/node": "*" } }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/dicer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@types/dicer/-/dicer-0.2.2.tgz", @@ -562,6 +1982,132 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, + "node_modules/@types/mongoose-unique-validator": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/mongoose-unique-validator/-/mongoose-unique-validator-1.0.7.tgz", + "integrity": "sha512-wgPWN7x9mHdy8x1jcluDF7EDWFb/s8LD7skLr012C8i2Q3tUhdTlp3JxRhFbEM3TD7J1INaoTrWaSaguhuqilQ==", + "dev": true, + "dependencies": { + "mongoose": "^6.3.0" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dev": true, + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@types/mongoose-unique-validator/node_modules/mongodb": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", + "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", + "dev": true, + "dependencies": { + "bson": "^4.7.0", + "mongodb-connection-string-url": "^2.5.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "saslprep": "^1.0.3" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/mongoose": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.3.tgz", + "integrity": "sha512-fZ3pIlQn7lM632r1l4qiU58lKrJ+FufKVG8TNeRXSChAeu9alCl5KoQ9bLw4jnQNYevSq9o+sqZmFDHP+EVW3g==", + "dev": true, + "dependencies": { + "bson": "^4.7.0", + "kareem": "2.5.1", + "mongodb": "4.14.0", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dev": true, + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@types/mongoose-unique-validator/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==", + "dev": true + }, "node_modules/@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -630,6 +2176,12 @@ "@types/node": "*" } }, + "node_modules/@types/validator": { + "version": "13.7.14", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.14.tgz", + "integrity": "sha512-J6OAed6rhN6zyqL9Of6ZMamhlsOEU/poBVvbHr/dKOYKTeuYYMlDkMv+b6UUV0o2i0tw73cgyv/97WTWaUl0/g==", + "dev": true + }, "node_modules/@types/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -1308,6 +2860,12 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "optional": true + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2379,9 +3937,15 @@ } }, "node_modules/express-rate-limit": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", - "integrity": "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz", + "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==", + "engines": { + "node": ">= 12.9.0" + }, + "peerDependencies": { + "express": "^4 || ^5" + } }, "node_modules/express-subdomain": { "version": "1.0.5", @@ -2466,6 +4030,22 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "node_modules/fast-xml-parser": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", + "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", + "optional": true, + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -4943,6 +6523,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "optional": true + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5093,7 +6679,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "devOptional": true }, "node_modules/tsutils": { "version": "3.21.0", @@ -5470,6 +7056,1349 @@ } }, "dependencies": { + "@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "optional": true, + "requires": { + "tslib": "^1.11.1" + } + }, + "@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "optional": true, + "requires": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "optional": true, + "requires": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "optional": true, + "requires": { + "tslib": "^1.11.1" + } + }, + "@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "optional": true, + "requires": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "@aws-sdk/abort-controller": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.292.0.tgz", + "integrity": "sha512-lf+OPptL01kvryIJy7+dvFux5KbJ6OTwLPPEekVKZ2AfEvwcVtOZWFUhyw3PJCBTVncjKB1Kjl3V/eTS3YuPXQ==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/client-cognito-identity": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.294.0.tgz", + "integrity": "sha512-QMk/QratNvAvmnJ77pu9KDjpfUf/5LOJplHcLKcY962ewJGBtFFY4XZVnmUgQMSG0phRODtex7pyH//FueGKLQ==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.294.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/credential-provider-node": "3.294.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-signing": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/client-sso": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.294.0.tgz", + "integrity": "sha512-+FuxQTi5WvnaXM5JbNLkBIzQ3An4gA0ox61N1u+3xled+nywKb1yQ7WmRpyMG5bLbkmnj3aqoo5/uskFc4c4EA==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/client-sso-oidc": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.294.0.tgz", + "integrity": "sha512-/ZfDud76MdSPJ/TxjV2xLE30XbBQDZwKQ32axwoK1eziPvrAIUBYVgpBwj+m0quhoiQhBKkg3aFl6j39AF2thw==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/client-sts": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.294.0.tgz", + "integrity": "sha512-AefqwhFjTDzelZuSYhriJbiI+GQwf2yKiKAnCt0gRj6rswewStM63Gtlhfb01sFPp+ZiqPcyQ47LqUaHp1mz/g==", + "optional": true, + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/credential-provider-node": "3.294.0", + "@aws-sdk/fetch-http-handler": "3.292.0", + "@aws-sdk/hash-node": "3.292.0", + "@aws-sdk/invalid-dependency": "3.292.0", + "@aws-sdk/middleware-content-length": "3.292.0", + "@aws-sdk/middleware-endpoint": "3.292.0", + "@aws-sdk/middleware-host-header": "3.292.0", + "@aws-sdk/middleware-logger": "3.292.0", + "@aws-sdk/middleware-recursion-detection": "3.292.0", + "@aws-sdk/middleware-retry": "3.293.0", + "@aws-sdk/middleware-sdk-sts": "3.292.0", + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/middleware-signing": "3.292.0", + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/middleware-user-agent": "3.293.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/node-http-handler": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/smithy-client": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "@aws-sdk/util-body-length-browser": "3.292.0", + "@aws-sdk/util-body-length-node": "3.292.0", + "@aws-sdk/util-defaults-mode-browser": "3.292.0", + "@aws-sdk/util-defaults-mode-node": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "@aws-sdk/util-retry": "3.292.0", + "@aws-sdk/util-user-agent-browser": "3.292.0", + "@aws-sdk/util-user-agent-node": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "fast-xml-parser": "4.1.2", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/config-resolver": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.292.0.tgz", + "integrity": "sha512-cB3twnNR7vYvlt2jvw8VlA1+iv/tVzl+/S39MKqw2tepU+AbJAM0EHwb/dkf1OKSmlrnANXhshx80MHF9zL4mA==", + "optional": true, + "requires": { + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-config-provider": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-cognito-identity": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.294.0.tgz", + "integrity": "sha512-YSPqHEbLC0dnbFF5LdlMH0B50sMSN/CyG/sHkPYUwL/hkbUk9URnVW7ZJlt6lRftT7X4C7muzLqUP8sJAaiJEA==", + "optional": true, + "requires": { + "@aws-sdk/client-cognito-identity": "3.294.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-env": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.292.0.tgz", + "integrity": "sha512-YbafSG0ZEKE2969CJWVtUhh3hfOeLPecFVoXOtegCyAJgY5Ghtu4TsVhL4DgiGAgOC30ojAmUVQEXzd7xJF5xA==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-imds": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.292.0.tgz", + "integrity": "sha512-W/peOgDSRYulgzFpUhvgi1pCm6piBz6xrVN17N4QOy+3NHBXRVMVzYk6ct2qpLPgJUSEZkcpP+Gds+bBm8ed1A==", + "optional": true, + "requires": { + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.294.0.tgz", + "integrity": "sha512-pdTPbaAb5bWA+DnuKoL2TpXeNDp6Ejpv/OYt+bw2gdzl9w5r/ZCtUTTbW+Vvejr4WL5s3c1bY96kwdqCn7iLqA==", + "optional": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/credential-provider-process": "3.292.0", + "@aws-sdk/credential-provider-sso": "3.294.0", + "@aws-sdk/credential-provider-web-identity": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-node": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.294.0.tgz", + "integrity": "sha512-zUL1Qhb4BsQIZCs/TPpG4oIYH/9YsGiS+Se1tasSGjTOLfBy7jhOZ0QIdpEeyAx/EP8blOBredM9xWfEXgiHVA==", + "optional": true, + "requires": { + "@aws-sdk/credential-provider-env": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/credential-provider-ini": "3.294.0", + "@aws-sdk/credential-provider-process": "3.292.0", + "@aws-sdk/credential-provider-sso": "3.294.0", + "@aws-sdk/credential-provider-web-identity": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-process": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.292.0.tgz", + "integrity": "sha512-CFVXuMuUvg/a4tknzRikEDwZBnKlHs1LZCpTXIGjBdUTdosoi4WNzDLzGp93ZRTtcgFz+4wirz2f7P3lC0NrQw==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-sso": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.294.0.tgz", + "integrity": "sha512-UxrcAA/0l7j9+3tolYcG5M61D/IE1Bjd/9H87H1i2A2BrwUUBhW1Dp/vvROEDrrywlMDG3CDF3T/7ADtTak+sg==", + "optional": true, + "requires": { + "@aws-sdk/client-sso": "3.294.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/token-providers": "3.294.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-provider-web-identity": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.292.0.tgz", + "integrity": "sha512-4DbtIEM9gGVfqYlMdYXg3XY+vBhemjB1zXIequottW8loLYM8Vuz4/uGxxKNze6evVVzowsA0wKrYclE1aj/Rg==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/credential-providers": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.294.0.tgz", + "integrity": "sha512-CRGwCs6F31mQzjYi5YF2Z6c1T+UrFKtJSa6Ff/Q1rrPnROexyhBVnpP8WzpkODx/pZxKtTX50IX7ehIxbFDIyQ==", + "optional": true, + "requires": { + "@aws-sdk/client-cognito-identity": "3.294.0", + "@aws-sdk/client-sso": "3.294.0", + "@aws-sdk/client-sts": "3.294.0", + "@aws-sdk/credential-provider-cognito-identity": "3.294.0", + "@aws-sdk/credential-provider-env": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/credential-provider-ini": "3.294.0", + "@aws-sdk/credential-provider-node": "3.294.0", + "@aws-sdk/credential-provider-process": "3.292.0", + "@aws-sdk/credential-provider-sso": "3.294.0", + "@aws-sdk/credential-provider-web-identity": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/fetch-http-handler": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.292.0.tgz", + "integrity": "sha512-zh3bhUJbL8RSa39ZKDcy+AghtUkIP8LwcNlwRIoxMQh3Row4D1s4fCq0KZCx98NJBEXoiTLyTQlZxxI//BOb1Q==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/querystring-builder": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-base64": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/hash-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.292.0.tgz", + "integrity": "sha512-1yLxmIsvE+eK36JXEgEIouTITdykQLVhsA5Oai//Lar6Ddgu1sFpLDbdkMtKbrh4I0jLN9RacNCkeVQjZPTCCQ==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-buffer-from": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/invalid-dependency": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.292.0.tgz", + "integrity": "sha512-39OUV78CD3TmEbjhpt+V+Fk4wAGWhixqHxDSN8+4WL0uB4Fl7k5m3Z9hNY78AttHQSl2twR7WtLztnXPAFsriw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/is-array-buffer": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.292.0.tgz", + "integrity": "sha512-kW/G5T/fzI0sJH5foZG6XJiNCevXqKLxV50qIT4B1pMuw7regd4ALIy0HwSqj1nnn9mSbRWBfmby0jWCJsMcwg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-content-length": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.292.0.tgz", + "integrity": "sha512-2gMWzQus5mj14menolpPDbYBeaOYcj7KNFZOjTjjI3iQ0KqyetG6XasirNrcJ/8QX1BRmpTol8Xjp2Ue3Gbzwg==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-endpoint": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.292.0.tgz", + "integrity": "sha512-cPMkiSxpZGG6tYlW4OS+ucS6r43f9ddX9kcUoemJCY10MOuogdPjulCAjE0HTs2PLKSOrrG4CTP4Q4wWDrH4Bw==", + "optional": true, + "requires": { + "@aws-sdk/middleware-serde": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/url-parser": "3.292.0", + "@aws-sdk/util-config-provider": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.292.0.tgz", + "integrity": "sha512-mHuCWe3Yg2S5YZ7mB7sKU6C97XspfqrimWjMW9pfV2usAvLA3R0HrB03jpR5vpZ3P4q7HB6wK3S6CjYMGGRNag==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-logger": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.292.0.tgz", + "integrity": "sha512-yZNY1XYmG3NG+uonET7jzKXNiwu61xm/ZZ6i/l51SusuaYN+qQtTAhOFsieQqTehF9kP4FzbsWgPDwD8ZZX9lw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-recursion-detection": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.292.0.tgz", + "integrity": "sha512-kA3VZpPko0Zqd7CYPTKAxhjEv0HJqFu2054L04dde1JLr43ro+2MTdX7vsHzeAFUVRphqatFFofCumvXmU6Mig==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-retry": { + "version": "3.293.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.293.0.tgz", + "integrity": "sha512-7tiaz2GzRecNHaZ6YnF+Nrtk3au8qF6oiipf11R7MJiqJ0fkMLnz/iRrlakDziS9qF/a9v+3yxb4W4NHK3f4Tw==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/service-error-classification": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "@aws-sdk/util-retry": "3.292.0", + "tslib": "^2.3.1", + "uuid": "^8.3.2" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-sdk-sts": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.292.0.tgz", + "integrity": "sha512-GN5ZHEqXZqDi+HkVbaXRX9HaW/vA5rikYpWKYsmxTUZ7fB7ijvEO3co3lleJv2C+iGYRtUIHC4wYNB5xgoTCxg==", + "optional": true, + "requires": { + "@aws-sdk/middleware-signing": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-serde": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.292.0.tgz", + "integrity": "sha512-6hN9mTQwSvV8EcGvtXbS/MpK7WMCokUku5Wu7X24UwCNMVkoRHLIkYcxHcvBTwttuOU0d8hph1/lIX4dkLwkQw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-signing": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.292.0.tgz", + "integrity": "sha512-GVfoSjDjEQ4TaO6x9MffyP3uRV+2KcS5FtexLCYOM9pJcnE9tqq9FJOrZ1xl1g+YjUVKxo4x8lu3tpEtIb17qg==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/signature-v4": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-stack": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.292.0.tgz", + "integrity": "sha512-WdQpRkuMysrEwrkByCM1qCn2PPpFGGQ2iXqaFha5RzCdZDlxJni9cVNb6HzWUcgjLEYVTXCmOR9Wxm3CNW44Qg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "3.293.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.293.0.tgz", + "integrity": "sha512-gZ7/e6XwpKk9mvgA78q4Ffc796jTn02TUKx2qMDnkLVbeJXBNN2jnvYEKq8v70+o7fd/ALRudg8gBDmkkhM/Hw==", + "optional": true, + "requires": { + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-endpoints": "3.293.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/node-config-provider": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.292.0.tgz", + "integrity": "sha512-S3NnC9dQ5GIbJYSDIldZb4zdpCOEua1tM7bjYL3VS5uqCEM93kIi/o/UkIUveMp/eqTS2LJa5HjNIz5Te6je0A==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/node-http-handler": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.292.0.tgz", + "integrity": "sha512-L/E3UDSwXLXjt1XWWh0RBD55F+aZI1AEdPwdES9i1PjnZLyuxuDhEDptVibNN56+I9/4Q3SbmuVRVlOD0uzBag==", + "optional": true, + "requires": { + "@aws-sdk/abort-controller": "3.292.0", + "@aws-sdk/protocol-http": "3.292.0", + "@aws-sdk/querystring-builder": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/property-provider": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.292.0.tgz", + "integrity": "sha512-dHArSvsiqhno/g55N815gXmAMrmN8DP7OeFNqJ4wJG42xsF2PFN3DAsjIuHuXMwu+7A3R1LHqIpvv0hA9KeoJQ==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/protocol-http": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.292.0.tgz", + "integrity": "sha512-NLi4fq3k41aXIh1I97yX0JTy+3p6aW1NdwFwdMa674z86QNfb4SfRQRZBQe9wEnAZ/eWHVnlKIuII+U1URk/Kg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/querystring-builder": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.292.0.tgz", + "integrity": "sha512-XElIFJaReIm24eEvBtV2dOtZvcm3gXsGu/ftG8MLJKbKXFKpAP1q+K6En0Bs7/T88voKghKdKpKT+eZUWgTqlg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-uri-escape": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/querystring-parser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.292.0.tgz", + "integrity": "sha512-iTYpYo7a8X9RxiPbjjewIpm6XQPx2EOcF1dWCPRII9EFlmZ4bwnX+PDI36fIo9oVs8TIKXmwNGODU9nsg7CSAw==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/service-error-classification": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.292.0.tgz", + "integrity": "sha512-X1k3sixCeC45XSNHBe+kRBQBwPDyTFtFITb8O5Qw4dS9XWGhrUJT4CX0qE5aj8qP3F9U5nRizs9c2mBVVP0Caw==", + "optional": true + }, + "@aws-sdk/shared-ini-file-loader": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.292.0.tgz", + "integrity": "sha512-Av2TTYg1Jig2kbkD56ybiqZJB6vVrYjv1W5UQwY/q3nA/T2mcrgQ20ByCOt5Bv9VvY7FSgC+znj+L4a7RLGmBg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/signature-v4": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.292.0.tgz", + "integrity": "sha512-+rw47VY5mvBecn13tDQTl1ipGWg5tE63faWgmZe68HoBL87ZiDzsd7bUKOvjfW21iMgWlwAppkaNNQayYRb2zg==", + "optional": true, + "requires": { + "@aws-sdk/is-array-buffer": "3.292.0", + "@aws-sdk/types": "3.292.0", + "@aws-sdk/util-hex-encoding": "3.292.0", + "@aws-sdk/util-middleware": "3.292.0", + "@aws-sdk/util-uri-escape": "3.292.0", + "@aws-sdk/util-utf8": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/smithy-client": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.292.0.tgz", + "integrity": "sha512-S8PKzjPkZ6SXYZuZiU787dMsvQ0d/LFEhw2OI4Oe2An9Fc2IwJ2FYukyHoQJOV2tV0DiuMebPo7eMyQyjKElvA==", + "optional": true, + "requires": { + "@aws-sdk/middleware-stack": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/token-providers": { + "version": "3.294.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.294.0.tgz", + "integrity": "sha512-6nwO04LtC5f4AsUvGZXyjaswuEK4Rr2VsuANpMKrPCgunRfI58a8YXLniudOSXN6e7CFJ6M3uo/h5YXqtnzGug==", + "optional": true, + "requires": { + "@aws-sdk/client-sso-oidc": "3.294.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/shared-ini-file-loader": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/types": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.292.0.tgz", + "integrity": "sha512-1teYAY2M73UXZxMAxqZxVS2qwXjQh0OWtt7qyLfha0TtIk/fZ1hRwFgxbDCHUFcdNBSOSbKH/ESor90KROXLCQ==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/url-parser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.292.0.tgz", + "integrity": "sha512-NZeAuZCk1x6TIiWuRfbOU6wHPBhf0ly2qOHzWut4BCH+b4RrDmFF8EmXcH1auEfGhE7yRyR6XqIN0t3S+hYACA==", + "optional": true, + "requires": { + "@aws-sdk/querystring-parser": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-base64": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.292.0.tgz", + "integrity": "sha512-zjNCwNdy617yFvEjZorepNWXB2sQCVfsShCwFy/kIQ5iW5tT2jQKaqc0K77diU9atkooxw9p1W9m9sOgrkOFNw==", + "optional": true, + "requires": { + "@aws-sdk/util-buffer-from": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-body-length-browser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.292.0.tgz", + "integrity": "sha512-Wd/BM+JsMiKvKs/bN3z6TredVEHh2pKudGfg3CSjTRpqFpOG903KDfyHBD42yg5PuCHoHoewJvTPKwgn7/vhaw==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-body-length-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.292.0.tgz", + "integrity": "sha512-BBgipZ2P6RhogWE/qj0oqpdlyd3iSBYmb+aD/TBXwB2lA/X8A99GxweBd/kp06AmcJRoMS9WIXgbWkiiBlRlSA==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-buffer-from": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.292.0.tgz", + "integrity": "sha512-RxNZjLoXNxHconH9TYsk5RaEBjSgTtozHeyIdacaHPj5vlQKi4hgL2hIfKeeNiAfQEVjaUFF29lv81xpNMzVMQ==", + "optional": true, + "requires": { + "@aws-sdk/is-array-buffer": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-config-provider": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.292.0.tgz", + "integrity": "sha512-t3noYll6bPRSxeeNNEkC5czVjAiTPcsq00OwfJ2xyUqmquhLEfLwoJKmrT1uP7DjIEXdUtfoIQ2jWiIVm/oO5A==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-defaults-mode-browser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.292.0.tgz", + "integrity": "sha512-7+zVUlMGfa8/KT++9humHo6IDxTnxMCmWUj5jVNlkpk6h7Ecmppf7aXotviyVIA43lhtz0p2AErs0N0ekEUK+w==", + "optional": true, + "requires": { + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-defaults-mode-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.292.0.tgz", + "integrity": "sha512-SSIw85eF4BVs0fOJRyshT+R3b/UmBPhiVKCUZm2rq6+lIGkDPiSwQU3d/80AhXtiL5SFT/IzAKKgQd8qMa7q3A==", + "optional": true, + "requires": { + "@aws-sdk/config-resolver": "3.292.0", + "@aws-sdk/credential-provider-imds": "3.292.0", + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/property-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-endpoints": { + "version": "3.293.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.293.0.tgz", + "integrity": "sha512-R/99aNV49Refpv5guiUjEUrZYlvnfaNBniB+/ZtMO3ixxUopapssCrUivuJrmhccmrYaTCZw7dRzIWjU1jJhKg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-hex-encoding": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.292.0.tgz", + "integrity": "sha512-qBd5KFIUywQ3qSSbj814S2srk0vfv8A6QMI+Obs1y2LHZFdQN5zViptI4UhXhKOHe+NnrHWxSuLC/LMH6q3SmA==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-locate-window": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.292.0.tgz", + "integrity": "sha512-6xnFJXZI9pKw5lQCDvuWA5PnOaUtNRKWwdxvGkkLx5orboFaoVMS6zowjSQxwVNRjW82u6dYNkhmj9mZ8VSjWg==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-middleware": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.292.0.tgz", + "integrity": "sha512-KjhS7flfoBKDxbiBZjLjMvEizXgjfQb7GQEItgzGoI9rfGCmZtvqCcqQQoIlxb8bIzGRggAUHtBGWnlLbpb+GQ==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-retry": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.292.0.tgz", + "integrity": "sha512-JEHyF7MpVeRF5uR4LDYgpOKcFpOPiAj8TqN46SVOQQcL1K+V7cSr7O7N7J6MwJaN9XOzAcBadeIupMm7/BFbgw==", + "optional": true, + "requires": { + "@aws-sdk/service-error-classification": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-uri-escape": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.292.0.tgz", + "integrity": "sha512-hOQtUMQ4VcQ9iwKz50AoCp1XBD5gJ9nly/gJZccAM7zSA5mOO8RRKkbdonqquVHxrO0CnYgiFeCh3V35GFecUw==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.292.0.tgz", + "integrity": "sha512-dld+lpC3QdmTQHdBWJ0WFDkXDSrJgfz03q6mQ8+7H+BC12ZhT0I0g9iuvUjolqy7QR00OxOy47Y9FVhq8EC0Gg==", + "optional": true, + "requires": { + "@aws-sdk/types": "3.292.0", + "bowser": "^2.11.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.292.0.tgz", + "integrity": "sha512-f+NfIMal5E61MDc5WGhUEoicr7b1eNNhA+GgVdSB/Hg5fYhEZvFK9RZizH5rrtsLjjgcr9nPYSR7/nDKCJLumw==", + "optional": true, + "requires": { + "@aws-sdk/node-config-provider": "3.292.0", + "@aws-sdk/types": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-utf8": { + "version": "3.292.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.292.0.tgz", + "integrity": "sha512-FPkj+Z59/DQWvoVu2wFaRncc3KVwe/pgK3MfVb0Lx+Ibey5KUx+sNpJmYcVYHUAe/Nv/JeIpOtYuC96IXOnI6w==", + "optional": true, + "requires": { + "@aws-sdk/util-buffer-from": "3.292.0", + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, + "@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "optional": true, + "requires": { + "tslib": "^2.3.1" + }, + "dependencies": { + "tslib": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", + "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", + "optional": true + } + } + }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -5778,6 +8707,15 @@ "defer-to-connect": "^2.0.0" } }, + "@types/bcrypt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/bcrypt/-/bcrypt-5.0.0.tgz", + "integrity": "sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/body-parser": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", @@ -5808,6 +8746,15 @@ "@types/node": "*" } }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/dicer": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@types/dicer/-/dicer-0.2.2.tgz", @@ -5884,6 +8831,96 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, + "@types/mongoose-unique-validator": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/mongoose-unique-validator/-/mongoose-unique-validator-1.0.7.tgz", + "integrity": "sha512-wgPWN7x9mHdy8x1jcluDF7EDWFb/s8LD7skLr012C8i2Q3tUhdTlp3JxRhFbEM3TD7J1INaoTrWaSaguhuqilQ==", + "dev": true, + "requires": { + "mongoose": "^6.3.0" + }, + "dependencies": { + "bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dev": true, + "requires": { + "buffer": "^5.6.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "mongodb": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", + "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", + "dev": true, + "requires": { + "@aws-sdk/credential-providers": "^3.186.0", + "bson": "^4.7.0", + "mongodb-connection-string-url": "^2.5.4", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "mongoose": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.3.tgz", + "integrity": "sha512-fZ3pIlQn7lM632r1l4qiU58lKrJ+FufKVG8TNeRXSChAeu9alCl5KoQ9bLw4jnQNYevSq9o+sqZmFDHP+EVW3g==", + "dev": true, + "requires": { + "bson": "^4.7.0", + "kareem": "2.5.1", + "mongodb": "4.14.0", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + } + }, + "mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dev": true, + "requires": { + "debug": "4.x" + } + }, + "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 + } + } + }, "@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -5952,6 +8989,12 @@ "@types/node": "*" } }, + "@types/validator": { + "version": "13.7.14", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.14.tgz", + "integrity": "sha512-J6OAed6rhN6zyqL9Of6ZMamhlsOEU/poBVvbHr/dKOYKTeuYYMlDkMv+b6UUV0o2i0tw73cgyv/97WTWaUl0/g==", + "dev": true + }, "@types/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -6432,6 +9475,12 @@ "unpipe": "1.0.0" } }, + "bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "optional": true + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -7278,9 +10327,10 @@ } }, "express-rate-limit": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.5.1.tgz", - "integrity": "sha512-MTjE2eIbHv5DyfuFz4zLYWxpqVhEhkTiwFGuB74Q9CSou2WHO52nlE5y3Zlg6SIsiYUIPj6ifFxnkPz6O3sIUg==" + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz", + "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==", + "requires": {} }, "express-subdomain": { "version": "1.0.5", @@ -7357,6 +10407,15 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, + "fast-xml-parser": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", + "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", + "optional": true, + "requires": { + "strnum": "^1.0.5" + } + }, "fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", @@ -9212,6 +12271,12 @@ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "optional": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -9337,7 +12402,7 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "devOptional": true }, "tsutils": { "version": "3.21.0", diff --git a/package.json b/package.json index f97be5c..88063fd 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "dotenv": "^16.0.3", "email-validator": "^2.0.4", "express": "^4.17.1", - "express-rate-limit": "^5.3.0", + "express-rate-limit": "^6.7.0", "express-subdomain": "^1.0.5", "fs-extra": "^8.1.0", "got": "^11.8.2", @@ -55,13 +55,17 @@ }, "devDependencies": { "@hcaptcha/types": "^1.0.3", + "@types/bcrypt": "^5.0.0", + "@types/cors": "^2.8.13", "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", + "@types/mongoose-unique-validator": "^1.0.7", "@types/morgan": "^1.9.4", "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", "@types/nodemailer": "^6.4.7", + "@types/validator": "^13.7.14", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", "eslint": "^8.35.0", diff --git a/src/cache.ts b/src/cache.ts index cc5a6bb..912f78c 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -28,12 +28,12 @@ export async function setCachedFile(fileName: string, value: Buffer): Promise { - let cachedFile: Buffer; + let cachedFile: Buffer = Buffer.alloc(0); if (disabledFeatures.redis) { cachedFile = memoryCache[fileName] || null; } else { - const redisValue: string = await client.get(fileName); + const redisValue: string | null = await client.get(fileName); if (redisValue) { cachedFile = Buffer.from(redisValue, encoding); } @@ -177,7 +177,7 @@ export async function getLocalCDNFile(name: string, encoding?: BufferEncoding): if (file === null) { if (await fs.pathExists(`${LOCAL_CDN_BASE}/${name}`)) { - const fileBuffer: string = await fs.readFile(`${LOCAL_CDN_BASE}/${name}`, { encoding }); + const fileBuffer: string | Buffer = await fs.readFile(`${LOCAL_CDN_BASE}/${name}`, { encoding }); file = Buffer.from(fileBuffer); await setLocalCDNFile(name, file); } diff --git a/src/config-manager.ts b/src/config-manager.ts index 8b42c75..9f98cc8 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -15,7 +15,7 @@ export const disabledFeatures: DisabledFeatures = { LOG_INFO('Loading config'); -let mongooseConnectOptions: mongoose.ConnectOptions; +let mongooseConnectOptions: mongoose.ConnectOptions = {}; if (process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH) { mongooseConnectOptions = fs.readJSONSync(process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH); @@ -23,41 +23,41 @@ if (process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH) { export const config: Config = { http: { - port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT) + port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT || '') }, mongoose: { - connection_string: process.env.PN_ACT_CONFIG_MONGO_CONNECTION_STRING, + connection_string: process.env.PN_ACT_CONFIG_MONGO_CONNECTION_STRING || '', options: mongooseConnectOptions }, redis: { client: { - url: process.env.PN_ACT_CONFIG_REDIS_URL + url: process.env.PN_ACT_CONFIG_REDIS_URL || '' } }, email: { - host: process.env.PN_ACT_CONFIG_EMAIL_HOST, - port: Number(process.env.PN_ACT_CONFIG_EMAIL_PORT), - secure: Boolean(process.env.PN_ACT_CONFIG_EMAIL_SECURE), + host: process.env.PN_ACT_CONFIG_EMAIL_HOST || '', + port: Number(process.env.PN_ACT_CONFIG_EMAIL_PORT || ''), + secure: Boolean(process.env.PN_ACT_CONFIG_EMAIL_SECURE || ''), auth: { - user: process.env.PN_ACT_CONFIG_EMAIL_USERNAME, - pass: process.env.PN_ACT_CONFIG_EMAIL_PASSWORD + user: process.env.PN_ACT_CONFIG_EMAIL_USERNAME || '', + pass: process.env.PN_ACT_CONFIG_EMAIL_PASSWORD || '' }, - from: process.env.PN_ACT_CONFIG_EMAIL_FROM + from: process.env.PN_ACT_CONFIG_EMAIL_FROM || '' }, s3: { - endpoint: process.env.PN_ACT_CONFIG_S3_ENDPOINT, - key: process.env.PN_ACT_CONFIG_S3_ACCESS_KEY, - secret: process.env.PN_ACT_CONFIG_S3_ACCESS_SECRET + endpoint: process.env.PN_ACT_CONFIG_S3_ENDPOINT || '', + key: process.env.PN_ACT_CONFIG_S3_ACCESS_KEY || '', + secret: process.env.PN_ACT_CONFIG_S3_ACCESS_SECRET || '' }, hcaptcha: { - secret: process.env.PN_ACT_CONFIG_HCAPTCHA_SECRET + secret: process.env.PN_ACT_CONFIG_HCAPTCHA_SECRET || '' }, cdn: { - subdomain: process.env.PN_ACT_CONFIG_CDN_SUBDOMAIN, - disk_path: process.env.PN_ACT_CONFIG_CDN_DISK_PATH, - base_url: process.env.PN_ACT_CONFIG_CDN_BASE_URL + subdomain: process.env.PN_ACT_CONFIG_CDN_SUBDOMAIN || '', + disk_path: process.env.PN_ACT_CONFIG_CDN_DISK_PATH || '', + base_url: process.env.PN_ACT_CONFIG_CDN_BASE_URL || '' }, - website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE + website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE || '' }; LOG_INFO('Config loaded, checking integrity'); diff --git a/src/database.ts b/src/database.ts index d5b8c8c..3406aab 100644 --- a/src/database.ts +++ b/src/database.ts @@ -42,7 +42,7 @@ export function verifyConnected(): void { } } -export async function getUserByUsername(username: string): Promise { +export async function getUserByUsername(username: string): Promise { verifyConnected(); return await PNID.findOne({ @@ -50,7 +50,7 @@ export async function getUserByUsername(username: string): Promise { +export async function getUserByPID(pid: number): Promise { verifyConnected(); return await PNID.findOne({ @@ -58,7 +58,7 @@ export async function getUserByPID(pid: number): Promise { }); } -export async function getUserByEmailAddress(email: string): Promise { +export async function getUserByEmailAddress(email: string): Promise { verifyConnected(); // TODO - Update documents to store email normalized @@ -73,7 +73,7 @@ export async function doesUserExist(username: string): Promise { return !!await getUserByUsername(username); } -export async function getUserBasic(token: string): Promise { +export async function getUserBasic(token: string): Promise { verifyConnected(); // * Wii U sends Basic auth as `username password`, where the password may not have spaces @@ -84,7 +84,7 @@ export async function getUserBasic(token: string): Promise const username: string = parts[0]; const password: string = parts[1]; - const user: HydratedPNIDDocument = await getUserByUsername(username); + const user: HydratedPNIDDocument | null = await getUserByUsername(username); if (!user) { return null; @@ -99,14 +99,14 @@ export async function getUserBasic(token: string): Promise return user; } -export async function getUserBearer(token: string): Promise { +export async function getUserBearer(token: string): Promise { verifyConnected(); try { const decryptedToken: Buffer = await decryptToken(Buffer.from(token, 'base64')); const unpackedToken: Token = unpackToken(decryptedToken); - const user: HydratedPNIDDocument = await getUserByPID(unpackedToken.pid); + const user: HydratedPNIDDocument | null = await getUserByPID(unpackedToken.pid); if (user) { const expireTime: number = Math.floor((Number(unpackedToken.expire_time) / 1000)); @@ -124,27 +124,38 @@ export async function getUserBearer(token: string): Promise { +export async function getUserProfileJSONByPID(pid: number): Promise { verifyConnected(); - const user: HydratedPNIDDocument = await getUserByPID(pid); + const user: HydratedPNIDDocument | null = await getUserByPID(pid); + + if (!user) { + return null; + } + const device: HydratedDeviceDocument = user.get('devices')[0]; // * Just grab the first device - let device_attributes: [{ + let device_attributes: { device_attribute: { name: string; value: string; created_date: string; }; - }]; + }[] = []; if (device) { - device_attributes = device.get('device_attributes').map(({name, value, created_date}) => ({ - device_attribute: { - name, - value, - created_date: created_date ? created_date : '' - } - })); + device_attributes = device.get('device_attributes').map((attribute: { name: string; value: string; created_date: string; }) => { + const name: string = attribute.name; + const value: string = attribute.value; + const created_date: string = attribute.created_date; + + return { + device_attribute: { + name, + value, + created_date: created_date ? created_date : '' + } + }; + }); } return { @@ -196,21 +207,21 @@ export async function getUserProfileJSONByPID(pid: number): Promise }; } -export async function getServer(gameServerId: string, accessMode: string): Promise { +export async function getServer(gameServerId: string, accessMode: string): Promise { return await Server.findOne({ game_server_id: gameServerId, access_mode: accessMode }); } -export async function getServerByTitleId(titleId: string, accessMode: string): Promise { +export async function getServerByTitleId(titleId: string, accessMode: string): Promise { return await Server.findOne({ title_ids: titleId, access_mode: accessMode }); } -export async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { +export async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { if (type === 'discord') { return await addUserConnectionDiscord(pnid, data); } @@ -239,7 +250,7 @@ export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: }; } -export async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { +export async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { // * Add more connections later? if (type === 'discord') { return await removeUserConnectionDiscord(pnid); diff --git a/src/mailer.ts b/src/mailer.ts index a9ec1cc..230d412 100644 --- a/src/mailer.ts +++ b/src/mailer.ts @@ -20,10 +20,10 @@ export async function sendMail(options: MailerOptions): Promise { let html: string = confirmation ? confirmationEmailTemplate : genericEmailTemplate; html = html.replace(/{{username}}/g, username); - html = html.replace(/{{paragraph}}/g, paragraph); - html = html.replace(/{{preview}}/g, (preview || '')); - html = html.replace(/{{confirmation-href}}/g, (confirmation?.href || '')); - html = html.replace(/{{confirmation-code}}/g, (confirmation?.code || '')); + html = html.replace(/{{paragraph}}/g, paragraph || ''); + html = html.replace(/{{preview}}/g, preview || ''); + html = html.replace(/{{confirmation-href}}/g, confirmation?.href || ''); + html = html.replace(/{{confirmation-code}}/g, confirmation?.code || ''); if (link) { const { href, text } = link; diff --git a/src/middleware/api.ts b/src/middleware/api.ts index 0f7e876..e4fa82a 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -3,14 +3,14 @@ import { getUserBearer } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { - const authHeader: string = request.headers.authorization; + const authHeader: string | undefined = request.headers.authorization; if (!authHeader || !(authHeader.startsWith('Bearer'))) { return next(); } const token: string = authHeader.split(' ')[1]; - const user: HydratedPNIDDocument = await getUserBearer(token); + const user: HydratedPNIDDocument | null = await getUserBearer(token); request.pnid = user; diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 5f1e5aa..9308bb9 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -35,9 +35,9 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const macAddressHash: string = crypto.createHash('sha256').update(macAddress).digest('base64'); const fcdcertHash: string = crypto.createHash('sha256').update(fcdcert).digest('base64'); - let pid: number; - let pidHmac: string; - let password: string; + let pid: number = 0; // * Real PIDs are always positive and non-zero + let pidHmac: string = ''; + let password: string = ''; if (requestParams.userid) { pid = Number(nintendoBase64Decode(requestParams.userid).toString()); @@ -68,7 +68,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon return; } - let model: string; + let model: string = ''; switch (serialNumber[0]) { case 'C': model = 'ctr'; @@ -95,7 +95,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon return; } - let device: HydratedDeviceDocument = await Device.findOne({ + let device: HydratedDeviceDocument | null = await Device.findOne({ model, serial: serialNumber, environment, @@ -174,7 +174,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon } } - const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ pid }); + const nexUser: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ pid }); if (!nexUser || nexUser.get('access_level') < 0) { response.status(200).send(nascError('102')); diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index 2d52342..96f58cd 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -4,7 +4,7 @@ import { getUserBasic, getUserBearer } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { - const authHeader: string = request.headers.authorization; + const authHeader: string | undefined = request.headers.authorization; if (!authHeader || !(authHeader.startsWith('Bearer') || authHeader.startsWith('Basic'))) { return next(); @@ -13,7 +13,7 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon const parts: string[] = authHeader.split(' '); const type: string = parts[0]; let token: string = parts[1]; - let user: HydratedPNIDDocument; + let user: HydratedPNIDDocument | null; if (request.isCemu) { token = Buffer.from(token, 'hex').toString('base64'); diff --git a/src/middleware/xml-parser.ts b/src/middleware/xml-parser.ts index 37d09b2..cf1335e 100644 --- a/src/middleware/xml-parser.ts +++ b/src/middleware/xml-parser.ts @@ -4,8 +4,8 @@ import { document as xmlParser } from 'xmlbuilder2'; function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void { if (request.method == 'POST' || request.method == 'PUT') { - const contentType: string = request.headers['content-type']; - const contentLength: string = request.headers['content-length']; + const contentType: string | undefined = request.headers['content-type']; + const contentLength: string | undefined = request.headers['content-length']; let body: string = ''; if ( diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 601b1fe..8849822 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -121,7 +121,7 @@ PNIDSchema.method('generatePID', async function generatePID(): Promise { const pid: number = Math.floor(Math.random() * (max - min + 1) + min); - const inuse: HydratedPNIDDocument = await PNID.findOne({ + const inuse: HydratedPNIDDocument | null = await PNID.findOne({ pid }); @@ -143,7 +143,7 @@ PNIDSchema.method('generateEmailValidationCode', async function generateEmailVal PNIDSchema.method('generateEmailValidationToken', async function generateEmailValidationToken(): Promise { const token: string = crypto.randomBytes(32).toString('hex'); - const inuse: HydratedPNIDDocument = await PNID.findOne({ + const inuse: HydratedPNIDDocument | null = await PNID.findOne({ 'identification.email_token': token }); diff --git a/src/services/api/routes/v1/connections.ts b/src/services/api/routes/v1/connections.ts index 6ddfd31..a828c2d 100644 --- a/src/services/api/routes/v1/connections.ts +++ b/src/services/api/routes/v1/connections.ts @@ -17,7 +17,7 @@ const VALID_CONNECTION_TYPES: string[] = [ */ router.post('/add/:type', async (request: express.Request, response: express.Response) => { const data: ConnectionData = request.body?.data; - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; const type: string = request.params.type; if (!pnid) { @@ -44,9 +44,17 @@ router.post('/add/:type', async (request: express.Request, response: express.Res }); } - const result: ConnectionResponse = await addUserConnection(pnid, data, type); + let result: ConnectionResponse | undefined = await addUserConnection(pnid, data, type); - response.status(result.status).json(result); + if (!result) { + result = { + app: 'api', + status: 500, + error: 'Unknown server error' + }; + } + + response.status(result.status || 500).json(result); }); /** @@ -55,7 +63,7 @@ router.post('/add/:type', async (request: express.Request, response: express.Res * Description: Removes an account connection from the users PNID */ router.delete('/remove/:type', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; const type: string = request.params.type; if (!pnid) { @@ -74,7 +82,15 @@ router.delete('/remove/:type', async (request: express.Request, response: expres }); } - const result: ConnectionResponse = await removeUserConnection(pnid, type); + let result: ConnectionResponse | undefined = await removeUserConnection(pnid, type); + + if (!result) { + result = { + app: 'api', + status: 500, + error: 'Unknown server error' + }; + } response.status(result.status).json(result); }); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index 2b12d60..a7c6eb7 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -7,7 +7,7 @@ import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; const router: express.Router = express.Router(); router.get('/verify', async (request: express.Request, response: express.Response) => { - let token: string = request.query.token as string; + const token: string = request.query.token as string; if (!token || token.trim() == '') { return response.status(400).json({ @@ -17,7 +17,7 @@ router.get('/verify', async (request: express.Request, response: express.Respons }); } - const pnid: HydratedPNIDDocument = await PNID.findOne({ + const pnid: HydratedPNIDDocument | null = await PNID.findOne({ 'identification.email_token': token }); diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index 74e7cdc..bfc6d61 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -17,7 +17,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - let pnid: HydratedPNIDDocument; + let pnid: HydratedPNIDDocument | null; if (validator.isEmail(input)) { pnid = await getUserByEmailAddress(input); diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index c6bfaa6..692f13d 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -54,7 +54,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - let pnid: HydratedPNIDDocument; + let pnid: HydratedPNIDDocument | null; if (grantType === 'password') { pnid = await getUserByUsername(username); @@ -125,8 +125,10 @@ router.post('/', async (request: express.Request, response: express.Response) => expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken: string = await generateToken(cryptoOptions, accessTokenOptions); - const newRefreshToken: string = await generateToken(cryptoOptions, refreshTokenOptions); + const accessToken: string | null = await generateToken(cryptoOptions, accessTokenOptions); + const newRefreshToken: string | null = await generateToken(cryptoOptions, refreshTokenOptions); + + // TODO - Handle null tokens response.json({ access_token: accessToken, diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 3b6d315..b1e37b1 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -363,8 +363,10 @@ router.post('/', async (request: express.Request, response: express.Response) => expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken: string = await generateToken(cryptoOptions, accessTokenOptions); - const refreshToken: string = await generateToken(cryptoOptions, refreshTokenOptions); + const accessToken: string | null = await generateToken(cryptoOptions, accessTokenOptions); + const refreshToken: string | null = await generateToken(cryptoOptions, refreshTokenOptions); + + // TODO - Handle null tokens response.json({ access_token: accessToken, diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index fe7f3c8..95266f7 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -47,7 +47,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const pnid: HydratedPNIDDocument = await PNID.findOne({ pid: unpackedToken.pid }); + const pnid: HydratedPNIDDocument | null = await PNID.findOne({ pid: unpackedToken.pid }); if (!pnid) { return response.status(400).json({ diff --git a/src/services/api/routes/v1/user.ts b/src/services/api/routes/v1/user.ts index 15fb167..28eac4e 100644 --- a/src/services/api/routes/v1/user.ts +++ b/src/services/api/routes/v1/user.ts @@ -22,7 +22,7 @@ const userSchema: joi.ObjectSchema = joi.object({ * Description: Gets PNID details about the current user */ router.get('/', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; if (!pnid) { return response.status(400).json({ @@ -70,7 +70,7 @@ router.get('/', async (request: express.Request, response: express.Response) => * Description: Updates PNID certain details about the current user */ router.post('/', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; const updateUserRequest: UpdateUserRequest = request.body; if (!pnid) { diff --git a/src/services/datastore/routes/upload.ts b/src/services/datastore/routes/upload.ts index c8c9ddf..88130b1 100644 --- a/src/services/datastore/routes/upload.ts +++ b/src/services/datastore/routes/upload.ts @@ -8,11 +8,22 @@ const router: express.Router = express.Router(); const signatureSecret: Buffer = fs.readFileSync(`${__dirname}/../../../../certs/nex/datastore/secret.key`); -function multipartParser(request: express.Request, response: express.Response, next: express.NextFunction) { +function multipartParser(request: express.Request, response: express.Response, next: express.NextFunction): void { const RE_BOUNDARY: RegExp = /^multipart\/.+?(?:; boundary=(?:(?:"(.+)")|(?:([^\s]+))))$/i; const RE_FILE_NAME: RegExp = /name="(.*)"/; - const boundary: RegExpExecArray = RE_BOUNDARY.exec(request.header('content-type')); + const contentType: string | undefined = request.header('content-type'); + + if (!contentType) { + return next(); + } + + const boundary: RegExpExecArray | null = RE_BOUNDARY.exec(contentType); + + if (!boundary) { + return next(); + } + const dicer: Dicer = new Dicer({ boundary: boundary[1] || boundary[2] }); const files: { [key: string]: Buffer } = {}; @@ -21,6 +32,7 @@ function multipartParser(request: express.Request, response: express.Response, n let fileName: string = ''; part.on('header', header => { + // TODO - strict mode yells here fileName = RE_FILE_NAME.exec(header['content-disposition'][0])[1]; }); @@ -46,6 +58,10 @@ function multipartParser(request: express.Request, response: express.Response, n } router.post('/upload', multipartParser, async (request: express.Request, response: express.Response) => { + if (!request.files) { + return response.sendStatus(500); + } + const bucket: string = request.files.bucket.toString(); const key: string = request.files.key.toString(); const file: Buffer = request.files.file; diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 001de88..a46fc04 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -18,7 +18,7 @@ const router: express.Router = express.Router(); router.post('/', async (request: express.Request, response: express.Response) => { const requestParams: NASCRequestParams = request.body; const action: string = nintendoBase64Decode(requestParams.action).toString(); - let responseData: URLSearchParams; + let responseData: URLSearchParams = nascError('null'); switch (action) { case 'LOGIN': @@ -35,7 +35,12 @@ router.post('/', async (request: express.Request, response: express.Response) => async function processLoginRequest(request: express.Request): Promise { const requestParams: NASCRequestParams = request.body; const titleID: string = nintendoBase64Decode(requestParams.titleid).toString(); - const nexUser: HydratedNEXAccountDocument = request.nexUser; + const nexUser: HydratedNEXAccountDocument | null = request.nexUser; + + if (!nexUser) { + // TODO - Research this error more + return nascError('null'); + } // TODO: REMOVE AFTER PUBLIC LAUNCH // LET EVERYONE IN THE `test` FRIENDS SERVER @@ -45,7 +50,7 @@ async function processLoginRequest(request: express.Request): Promise0008Not Found'); + } + + const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.get('pid')); + + if (!person) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } response.send(xmlbuilder.create({ person @@ -237,9 +249,21 @@ router.post('/@me/devices', async (request: express.Request, response: express.R // TODO - CHANGE THIS. WE NEED TO SAVE CONSOLE DETAILS !!! - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; - const person: PNIDProfile = await getUserProfileJSONByPID(pnid.pid); + if (!pnid) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } + + const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.get('pid')); + + if (!person) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } response.send(xmlbuilder.create({ person @@ -256,7 +280,7 @@ router.get('/@me/devices', async (request: express.Request, response: express.Re response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; const deviceId: string = request.headers['x-nintendo-device-id'] as string; const acceptLanguage: string = request.headers['accept-language'] as string; const platformId: string = request.headers['x-nintendo-platform-id'] as string; @@ -264,6 +288,12 @@ router.get('/@me/devices', async (request: express.Request, response: express.Re const serialNumber: string = request.headers['x-nintendo-serial-number'] as string; const systemVersion: string = request.headers['x-nintendo-system-version'] as string; + if (!pnid) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } + response.send(xmlbuilder.create({ devices: [ { @@ -295,9 +325,21 @@ router.get('/@me/devices/owner', async (request: express.Request, response: expr response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', moment().add(5, 'h').toString()); - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; - const person: PNIDProfile = await getUserProfileJSONByPID(pnid.get('pid')); + if (!pnid) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } + + const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.get('pid')); + + if (!person) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } response.send(xmlbuilder.create({ person @@ -326,14 +368,22 @@ router.get('/@me/devices/status', async (_request: express.Request, response: ex * Description: Updates a users Mii */ router.put('/@me/miis/@primary', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; + + if (!pnid) { + // TODO - Research this error more + response.status(404); + return response.send('0008Not Found'); + } // TODO - Make this more strictly typed? const mii: Map = request.body.get('mii'); - const name: string = mii.get('name'); - const primary: string = mii.get('primary'); - const data: string = mii.get('data'); + // TODO - Better checks + + const name: string | undefined = mii.get('name') || ''; + const primary: string | undefined = mii.get('primary') || ''; + const data: string | undefined = mii.get('data') || ''; await pnid.updateMii({ name, primary, data }); @@ -349,7 +399,7 @@ router.put('/@me/devices/@current/inactivate', async (request: express.Request, response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; if (!pnid) { response.status(400); @@ -375,7 +425,7 @@ router.put('/@me/devices/@current/inactivate', async (request: express.Request, * Description: Deletes a NNID */ router.put('/@me/deletion', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; if (!pnid) { response.status(400); @@ -400,7 +450,7 @@ router.put('/@me/deletion', async (request: express.Request, response: express.R * Description: Updates a PNIDs account details */ router.put('/@me', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; const person: Person = request.body.get('person'); if (!pnid) { @@ -454,7 +504,7 @@ router.put('/@me', async (request: express.Request, response: express.Response) * Description: Gets a list (why?) of PNID emails */ router.get('/@me/emails', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; if (!pnid) { response.status(400); @@ -495,12 +545,12 @@ router.get('/@me/emails', async (request: express.Request, response: express.Res * Description: Updates a users email address */ router.put('/@me/emails/@primary', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; // TODO - Make this more strictly typed? const email: Map = request.body.get('email'); - if (!pnid) { + if (!pnid || !email) { response.status(400); return response.end(xmlbuilder.create({ @@ -514,7 +564,8 @@ router.put('/@me/emails/@primary', async (request: express.Request, response: ex }).end()); } - pnid.set('email.address', email.get('address').toLowerCase()); + // TODO - Better email check + pnid.set('email.address', (email.get('address') || '').toLowerCase()); pnid.set('email.reachable', false); pnid.set('email.validated', false); pnid.set('email.validated_date', ''); diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 2f8dd70..e2cfa4d 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -19,11 +19,25 @@ const router: express.Router = express.Router(); * Description: Gets a service token */ router.get('/service_token/@me', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; + + if (!pnid) { + response.status(400); + + return response.end(xmlbuilder.create({ + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }).end()); + } const titleId: string = request.headers['x-nintendo-title-id'] as string; const serverAccessLevel: string = pnid.get('server_access_level'); - const server: HydratedServerDocument = await getServerByTitleId(titleId, serverAccessLevel); + const server: HydratedServerDocument | null = await getServerByTitleId(titleId, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ @@ -70,10 +84,12 @@ router.get('/service_token/@me', async (request: express.Request, response: expr expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let serviceToken: string = await generateToken(cryptoOptions, tokenOptions); + let serviceToken: string | null = await generateToken(cryptoOptions, tokenOptions); + + // TODO - Handle null tokens if (request.isCemu) { - serviceToken = Buffer.from(serviceToken, 'base64').toString('hex'); + serviceToken = Buffer.from(serviceToken || '', 'base64').toString('hex'); } response.send(xmlbuilder.create({ @@ -89,7 +105,22 @@ router.get('/service_token/@me', async (request: express.Request, response: expr * Description: Gets a NEX server address and token */ router.get('/nex_token/@me', async (request: express.Request, response: express.Response) => { - const pnid: HydratedPNIDDocument = request.pnid; + const pnid: HydratedPNIDDocument | null = request.pnid; + + if (!pnid) { + response.status(400); + + return response.end(xmlbuilder.create({ + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }).end()); + } + const gameServerID: string = request.query.game_server_id as string; if (!gameServerID) { @@ -104,7 +135,7 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. } const serverAccessLevel: string = pnid.get('server_access_level'); - const server: HydratedServerDocument = await getServer(gameServerID, serverAccessLevel); + const server: HydratedServerDocument | null = await getServer(gameServerID, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ @@ -154,7 +185,7 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const nexUser: HydratedNEXAccountDocument = await NEXAccount.findOne({ + const nexUser: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ owning_pid: pnid.get('pid') }); @@ -163,10 +194,12 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. return response.send('0008Not Found'); } - let nexToken: string = await generateToken(cryptoOptions, tokenOptions); + let nexToken: string | null = await generateToken(cryptoOptions, tokenOptions); + + // TODO = Handle null tokens if (request.isCemu) { - nexToken = Buffer.from(nexToken, 'base64').toString('hex'); + nexToken = Buffer.from(nexToken || '', 'base64').toString('hex'); } response.send(xmlbuilder.create({ diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index 6ecb0c9..5e4aab0 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -30,7 +30,7 @@ router.post('/validate/email', async (request: express.Request, response: expres const domain: string = email.split('@')[1]; - dns.resolveMx(domain, (error: NodeJS.ErrnoException) => { + dns.resolveMx(domain, (error: NodeJS.ErrnoException | null) => { if (error) { return response.send(xmlbuilder.create({ errors: { @@ -56,7 +56,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re const code: string = request.params.code; const pid: number = Number(request.params.pid); - const pnid: HydratedPNIDDocument = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); if (!pnid) { return response.status(400).send(xmlbuilder.create({ @@ -101,7 +101,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re router.get('/resend_confirmation', async (request: express.Request, response: express.Response) => { const pid: number = Number(request.headers['x-nintendo-pid']); - const pnid: HydratedPNIDDocument = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); if (!pnid) { // TODO - Unsure if this is the right error @@ -129,7 +129,7 @@ router.get('/resend_confirmation', async (request: express.Request, response: ex router.get('/forgotten_password/:pid', async (request: express.Request, response: express.Response) => { const pid: number = Number(request.params.pid); - const pnid: HydratedPNIDDocument = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); if (!pnid) { // TODO - Better errors diff --git a/src/types/express.d.ts b/src/types/express.d.ts index 26882cb..0e614bc 100644 --- a/src/types/express.d.ts +++ b/src/types/express.d.ts @@ -5,8 +5,8 @@ import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; declare global { namespace Express { interface Request { - pnid?: HydratedPNIDDocument; - nexUser?: HydratedNEXAccountDocument; + pnid: HydratedPNIDDocument | null; + nexUser: HydratedNEXAccountDocument | null; isCemu?: boolean; files?: Record; certificate?: NintendoCertificate; diff --git a/src/types/services/nnid/pnid-profile.ts b/src/types/services/nnid/pnid-profile.ts index ac95915..c0fb21a 100644 --- a/src/types/services/nnid/pnid-profile.ts +++ b/src/types/services/nnid/pnid-profile.ts @@ -6,13 +6,13 @@ export interface PNIDProfile { birth_date: string; country: string; create_date: string; - device_attributes: [{ + device_attributes: { device_attribute: { name: string; value: string; created_date: string; }; - }]; + }[]; gender: string; language: string; updated: string; diff --git a/src/util.ts b/src/util.ts index 5269666..5a79d1f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -47,7 +47,7 @@ export function nintendoBase64Encode(decoded: string | Buffer): string { return encoded.replaceAll('+', '.').replaceAll('/', '-').replaceAll('=', '*'); } -export async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: TokenOptions): Promise { +export async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: TokenOptions): Promise { // Access and refresh tokens use a different format since they must be much smaller // They take no extra crypto options if (!cryptoOptions) { @@ -67,6 +67,8 @@ export async function generateToken(cryptoOptions: CryptoOptions | null, tokenOp encryptedBody = Buffer.concat([encryptedBody, cipher.final()]); return encryptedBody.toString('base64'); + } else if (!tokenOptions.access_level || !tokenOptions.title_id) { + return null; } const publicKey: NodeRSA = new NodeRSA(cryptoOptions.public_key, 'pkcs8-public-pem', { @@ -191,8 +193,9 @@ export async function decryptToken(token: Buffer): Promise { const calculatedSignature: Buffer = hmac.digest(); if (!signature.equals(calculatedSignature)) { + // TODO - FIX THIS. ONLY DONE SO STRICT MODE DOESN'T YELL console.log('Token signature did not match'); - return null; + return Buffer.alloc(0); } return decryptedBody; @@ -300,7 +303,9 @@ export async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument Date: Sat, 18 Mar 2023 10:12:37 -0400 Subject: [PATCH 42/65] Stubbed missing types from 3rd party modules --- package-lock.json | 721 ++++++++++++----------- package.json | 1 - src/models/pnid.ts | 12 +- src/types/express-subdomain.d.ts | 3 + src/types/image-pixels.d.ts | 3 + src/types/mii-js.d.ts | 98 +++ src/types/mongoose-unique-validator.d.ts | 1 + src/types/tga.d.ts | 3 + 8 files changed, 494 insertions(+), 348 deletions(-) create mode 100644 src/types/express-subdomain.d.ts create mode 100644 src/types/image-pixels.d.ts create mode 100644 src/types/mii-js.d.ts create mode 100644 src/types/mongoose-unique-validator.d.ts create mode 100644 src/types/tga.d.ts diff --git a/package-lock.json b/package-lock.json index 78ae38f..dc8a274 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,6 @@ "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", - "@types/mongoose-unique-validator": "^1.0.7", "@types/morgan": "^1.9.4", "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", @@ -63,6 +62,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, + "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -72,6 +72,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -88,6 +89,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -99,6 +101,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -108,6 +111,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -119,6 +123,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.292.0.tgz", "integrity": "sha512-lf+OPptL01kvryIJy7+dvFux5KbJ6OTwLPPEekVKZ2AfEvwcVtOZWFUhyw3PJCBTVncjKB1Kjl3V/eTS3YuPXQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -131,13 +136,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/client-cognito-identity": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.294.0.tgz", "integrity": "sha512-QMk/QratNvAvmnJ77pu9KDjpfUf/5LOJplHcLKcY962ewJGBtFFY4XZVnmUgQMSG0phRODtex7pyH//FueGKLQ==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -183,13 +190,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/client-sso": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.294.0.tgz", "integrity": "sha512-+FuxQTi5WvnaXM5JbNLkBIzQ3An4gA0ox61N1u+3xled+nywKb1yQ7WmRpyMG5bLbkmnj3aqoo5/uskFc4c4EA==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -233,6 +242,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.294.0.tgz", "integrity": "sha512-/ZfDud76MdSPJ/TxjV2xLE30XbBQDZwKQ32axwoK1eziPvrAIUBYVgpBwj+m0quhoiQhBKkg3aFl6j39AF2thw==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -275,19 +285,22 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/client-sso/node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/client-sts": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.294.0.tgz", "integrity": "sha512-AefqwhFjTDzelZuSYhriJbiI+GQwf2yKiKAnCt0gRj6rswewStM63Gtlhfb01sFPp+ZiqPcyQ47LqUaHp1mz/g==", "optional": true, + "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -334,13 +347,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/config-resolver": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.292.0.tgz", "integrity": "sha512-cB3twnNR7vYvlt2jvw8VlA1+iv/tVzl+/S39MKqw2tepU+AbJAM0EHwb/dkf1OKSmlrnANXhshx80MHF9zL4mA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/signature-v4": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -356,13 +371,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.294.0.tgz", "integrity": "sha512-YSPqHEbLC0dnbFF5LdlMH0B50sMSN/CyG/sHkPYUwL/hkbUk9URnVW7ZJlt6lRftT7X4C7muzLqUP8sJAaiJEA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -377,13 +394,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-env": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.292.0.tgz", "integrity": "sha512-YbafSG0ZEKE2969CJWVtUhh3hfOeLPecFVoXOtegCyAJgY5Ghtu4TsVhL4DgiGAgOC30ojAmUVQEXzd7xJF5xA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -397,13 +416,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-imds": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.292.0.tgz", "integrity": "sha512-W/peOgDSRYulgzFpUhvgi1pCm6piBz6xrVN17N4QOy+3NHBXRVMVzYk6ct2qpLPgJUSEZkcpP+Gds+bBm8ed1A==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -419,13 +440,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.294.0.tgz", "integrity": "sha512-pdTPbaAb5bWA+DnuKoL2TpXeNDp6Ejpv/OYt+bw2gdzl9w5r/ZCtUTTbW+Vvejr4WL5s3c1bY96kwdqCn7iLqA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -445,13 +468,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-node": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.294.0.tgz", "integrity": "sha512-zUL1Qhb4BsQIZCs/TPpG4oIYH/9YsGiS+Se1tasSGjTOLfBy7jhOZ0QIdpEeyAx/EP8blOBredM9xWfEXgiHVA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -472,13 +497,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-process": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.292.0.tgz", "integrity": "sha512-CFVXuMuUvg/a4tknzRikEDwZBnKlHs1LZCpTXIGjBdUTdosoi4WNzDLzGp93ZRTtcgFz+4wirz2f7P3lC0NrQw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -493,13 +520,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-sso": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.294.0.tgz", "integrity": "sha512-UxrcAA/0l7j9+3tolYcG5M61D/IE1Bjd/9H87H1i2A2BrwUUBhW1Dp/vvROEDrrywlMDG3CDF3T/7ADtTak+sg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-sso": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -516,13 +545,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.292.0.tgz", "integrity": "sha512-4DbtIEM9gGVfqYlMdYXg3XY+vBhemjB1zXIequottW8loLYM8Vuz4/uGxxKNze6evVVzowsA0wKrYclE1aj/Rg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -536,13 +567,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/credential-providers": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.294.0.tgz", "integrity": "sha512-CRGwCs6F31mQzjYi5YF2Z6c1T+UrFKtJSa6Ff/Q1rrPnROexyhBVnpP8WzpkODx/pZxKtTX50IX7ehIxbFDIyQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/client-sso": "3.294.0", @@ -568,13 +601,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/fetch-http-handler": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.292.0.tgz", "integrity": "sha512-zh3bhUJbL8RSa39ZKDcy+AghtUkIP8LwcNlwRIoxMQh3Row4D1s4fCq0KZCx98NJBEXoiTLyTQlZxxI//BOb1Q==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/querystring-builder": "3.292.0", @@ -587,13 +622,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/hash-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.292.0.tgz", "integrity": "sha512-1yLxmIsvE+eK36JXEgEIouTITdykQLVhsA5Oai//Lar6Ddgu1sFpLDbdkMtKbrh4I0jLN9RacNCkeVQjZPTCCQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-buffer-from": "3.292.0", @@ -608,13 +645,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/invalid-dependency": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.292.0.tgz", "integrity": "sha512-39OUV78CD3TmEbjhpt+V+Fk4wAGWhixqHxDSN8+4WL0uB4Fl7k5m3Z9hNY78AttHQSl2twR7WtLztnXPAFsriw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -624,13 +663,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/is-array-buffer": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.292.0.tgz", "integrity": "sha512-kW/G5T/fzI0sJH5foZG6XJiNCevXqKLxV50qIT4B1pMuw7regd4ALIy0HwSqj1nnn9mSbRWBfmby0jWCJsMcwg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -642,13 +683,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-content-length": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.292.0.tgz", "integrity": "sha512-2gMWzQus5mj14menolpPDbYBeaOYcj7KNFZOjTjjI3iQ0KqyetG6XasirNrcJ/8QX1BRmpTol8Xjp2Ue3Gbzwg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -662,13 +705,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-endpoint": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.292.0.tgz", "integrity": "sha512-cPMkiSxpZGG6tYlW4OS+ucS6r43f9ddX9kcUoemJCY10MOuogdPjulCAjE0HTs2PLKSOrrG4CTP4Q4wWDrH4Bw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/middleware-serde": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -687,13 +732,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-host-header": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.292.0.tgz", "integrity": "sha512-mHuCWe3Yg2S5YZ7mB7sKU6C97XspfqrimWjMW9pfV2usAvLA3R0HrB03jpR5vpZ3P4q7HB6wK3S6CjYMGGRNag==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -707,13 +754,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-logger": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.292.0.tgz", "integrity": "sha512-yZNY1XYmG3NG+uonET7jzKXNiwu61xm/ZZ6i/l51SusuaYN+qQtTAhOFsieQqTehF9kP4FzbsWgPDwD8ZZX9lw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -726,13 +775,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.292.0.tgz", "integrity": "sha512-kA3VZpPko0Zqd7CYPTKAxhjEv0HJqFu2054L04dde1JLr43ro+2MTdX7vsHzeAFUVRphqatFFofCumvXmU6Mig==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -746,13 +797,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-retry": { "version": "3.293.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.293.0.tgz", "integrity": "sha512-7tiaz2GzRecNHaZ6YnF+Nrtk3au8qF6oiipf11R7MJiqJ0fkMLnz/iRrlakDziS9qF/a9v+3yxb4W4NHK3f4Tw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/service-error-classification": "3.292.0", @@ -770,13 +823,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-retry/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "optional": true, + "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -786,6 +841,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.292.0.tgz", "integrity": "sha512-GN5ZHEqXZqDi+HkVbaXRX9HaW/vA5rikYpWKYsmxTUZ7fB7ijvEO3co3lleJv2C+iGYRtUIHC4wYNB5xgoTCxg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/middleware-signing": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -802,13 +858,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-serde": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.292.0.tgz", "integrity": "sha512-6hN9mTQwSvV8EcGvtXbS/MpK7WMCokUku5Wu7X24UwCNMVkoRHLIkYcxHcvBTwttuOU0d8hph1/lIX4dkLwkQw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -821,13 +879,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-signing": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.292.0.tgz", "integrity": "sha512-GVfoSjDjEQ4TaO6x9MffyP3uRV+2KcS5FtexLCYOM9pJcnE9tqq9FJOrZ1xl1g+YjUVKxo4x8lu3tpEtIb17qg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -844,13 +904,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-stack": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.292.0.tgz", "integrity": "sha512-WdQpRkuMysrEwrkByCM1qCn2PPpFGGQ2iXqaFha5RzCdZDlxJni9cVNb6HzWUcgjLEYVTXCmOR9Wxm3CNW44Qg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -862,13 +924,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.293.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.293.0.tgz", "integrity": "sha512-gZ7/e6XwpKk9mvgA78q4Ffc796jTn02TUKx2qMDnkLVbeJXBNN2jnvYEKq8v70+o7fd/ALRudg8gBDmkkhM/Hw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -883,13 +947,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/node-config-provider": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.292.0.tgz", "integrity": "sha512-S3NnC9dQ5GIbJYSDIldZb4zdpCOEua1tM7bjYL3VS5uqCEM93kIi/o/UkIUveMp/eqTS2LJa5HjNIz5Te6je0A==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -904,13 +970,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/node-http-handler": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.292.0.tgz", "integrity": "sha512-L/E3UDSwXLXjt1XWWh0RBD55F+aZI1AEdPwdES9i1PjnZLyuxuDhEDptVibNN56+I9/4Q3SbmuVRVlOD0uzBag==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/abort-controller": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -926,13 +994,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/property-provider": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.292.0.tgz", "integrity": "sha512-dHArSvsiqhno/g55N815gXmAMrmN8DP7OeFNqJ4wJG42xsF2PFN3DAsjIuHuXMwu+7A3R1LHqIpvv0hA9KeoJQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -945,13 +1015,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/protocol-http": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.292.0.tgz", "integrity": "sha512-NLi4fq3k41aXIh1I97yX0JTy+3p6aW1NdwFwdMa674z86QNfb4SfRQRZBQe9wEnAZ/eWHVnlKIuII+U1URk/Kg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -964,13 +1036,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/querystring-builder": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.292.0.tgz", "integrity": "sha512-XElIFJaReIm24eEvBtV2dOtZvcm3gXsGu/ftG8MLJKbKXFKpAP1q+K6En0Bs7/T88voKghKdKpKT+eZUWgTqlg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-uri-escape": "3.292.0", @@ -984,13 +1058,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/querystring-parser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.292.0.tgz", "integrity": "sha512-iTYpYo7a8X9RxiPbjjewIpm6XQPx2EOcF1dWCPRII9EFlmZ4bwnX+PDI36fIo9oVs8TIKXmwNGODU9nsg7CSAw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1003,13 +1079,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/service-error-classification": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.292.0.tgz", "integrity": "sha512-X1k3sixCeC45XSNHBe+kRBQBwPDyTFtFITb8O5Qw4dS9XWGhrUJT4CX0qE5aj8qP3F9U5nRizs9c2mBVVP0Caw==", "optional": true, + "peer": true, "engines": { "node": ">=14.0.0" } @@ -1019,6 +1097,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.292.0.tgz", "integrity": "sha512-Av2TTYg1Jig2kbkD56ybiqZJB6vVrYjv1W5UQwY/q3nA/T2mcrgQ20ByCOt5Bv9VvY7FSgC+znj+L4a7RLGmBg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1031,13 +1110,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/signature-v4": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.292.0.tgz", "integrity": "sha512-+rw47VY5mvBecn13tDQTl1ipGWg5tE63faWgmZe68HoBL87ZiDzsd7bUKOvjfW21iMgWlwAppkaNNQayYRb2zg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/is-array-buffer": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1055,13 +1136,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/smithy-client": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.292.0.tgz", "integrity": "sha512-S8PKzjPkZ6SXYZuZiU787dMsvQ0d/LFEhw2OI4Oe2An9Fc2IwJ2FYukyHoQJOV2tV0DiuMebPo7eMyQyjKElvA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/middleware-stack": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1075,13 +1158,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/token-providers": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.294.0.tgz", "integrity": "sha512-6nwO04LtC5f4AsUvGZXyjaswuEK4Rr2VsuANpMKrPCgunRfI58a8YXLniudOSXN6e7CFJ6M3uo/h5YXqtnzGug==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/client-sso-oidc": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -1097,13 +1182,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/types": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.292.0.tgz", "integrity": "sha512-1teYAY2M73UXZxMAxqZxVS2qwXjQh0OWtt7qyLfha0TtIk/fZ1hRwFgxbDCHUFcdNBSOSbKH/ESor90KROXLCQ==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1115,13 +1202,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/url-parser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.292.0.tgz", "integrity": "sha512-NZeAuZCk1x6TIiWuRfbOU6wHPBhf0ly2qOHzWut4BCH+b4RrDmFF8EmXcH1auEfGhE7yRyR6XqIN0t3S+hYACA==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/querystring-parser": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1132,13 +1221,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-base64": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.292.0.tgz", "integrity": "sha512-zjNCwNdy617yFvEjZorepNWXB2sQCVfsShCwFy/kIQ5iW5tT2jQKaqc0K77diU9atkooxw9p1W9m9sOgrkOFNw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -1151,13 +1242,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-body-length-browser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.292.0.tgz", "integrity": "sha512-Wd/BM+JsMiKvKs/bN3z6TredVEHh2pKudGfg3CSjTRpqFpOG903KDfyHBD42yg5PuCHoHoewJvTPKwgn7/vhaw==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" } @@ -1166,13 +1259,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-body-length-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.292.0.tgz", "integrity": "sha512-BBgipZ2P6RhogWE/qj0oqpdlyd3iSBYmb+aD/TBXwB2lA/X8A99GxweBd/kp06AmcJRoMS9WIXgbWkiiBlRlSA==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1184,13 +1279,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-buffer-from": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.292.0.tgz", "integrity": "sha512-RxNZjLoXNxHconH9TYsk5RaEBjSgTtozHeyIdacaHPj5vlQKi4hgL2hIfKeeNiAfQEVjaUFF29lv81xpNMzVMQ==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/is-array-buffer": "3.292.0", "tslib": "^2.3.1" @@ -1203,13 +1300,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-config-provider": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.292.0.tgz", "integrity": "sha512-t3noYll6bPRSxeeNNEkC5czVjAiTPcsq00OwfJ2xyUqmquhLEfLwoJKmrT1uP7DjIEXdUtfoIQ2jWiIVm/oO5A==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1221,13 +1320,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-defaults-mode-browser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.292.0.tgz", "integrity": "sha512-7+zVUlMGfa8/KT++9humHo6IDxTnxMCmWUj5jVNlkpk6h7Ecmppf7aXotviyVIA43lhtz0p2AErs0N0ekEUK+w==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1242,13 +1343,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-defaults-mode-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.292.0.tgz", "integrity": "sha512-SSIw85eF4BVs0fOJRyshT+R3b/UmBPhiVKCUZm2rq6+lIGkDPiSwQU3d/80AhXtiL5SFT/IzAKKgQd8qMa7q3A==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/config-resolver": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -1265,13 +1368,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-endpoints": { "version": "3.293.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.293.0.tgz", "integrity": "sha512-R/99aNV49Refpv5guiUjEUrZYlvnfaNBniB+/ZtMO3ixxUopapssCrUivuJrmhccmrYaTCZw7dRzIWjU1jJhKg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1284,13 +1389,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-hex-encoding": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.292.0.tgz", "integrity": "sha512-qBd5KFIUywQ3qSSbj814S2srk0vfv8A6QMI+Obs1y2LHZFdQN5zViptI4UhXhKOHe+NnrHWxSuLC/LMH6q3SmA==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1302,13 +1409,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-locate-window": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.292.0.tgz", "integrity": "sha512-6xnFJXZI9pKw5lQCDvuWA5PnOaUtNRKWwdxvGkkLx5orboFaoVMS6zowjSQxwVNRjW82u6dYNkhmj9mZ8VSjWg==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1320,13 +1429,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-middleware": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.292.0.tgz", "integrity": "sha512-KjhS7flfoBKDxbiBZjLjMvEizXgjfQb7GQEItgzGoI9rfGCmZtvqCcqQQoIlxb8bIzGRggAUHtBGWnlLbpb+GQ==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1338,13 +1449,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-retry": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.292.0.tgz", "integrity": "sha512-JEHyF7MpVeRF5uR4LDYgpOKcFpOPiAj8TqN46SVOQQcL1K+V7cSr7O7N7J6MwJaN9XOzAcBadeIupMm7/BFbgw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/service-error-classification": "3.292.0", "tslib": "^2.3.1" @@ -1357,13 +1470,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-uri-escape": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.292.0.tgz", "integrity": "sha512-hOQtUMQ4VcQ9iwKz50AoCp1XBD5gJ9nly/gJZccAM7zSA5mOO8RRKkbdonqquVHxrO0CnYgiFeCh3V35GFecUw==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1375,13 +1490,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.292.0.tgz", "integrity": "sha512-dld+lpC3QdmTQHdBWJ0WFDkXDSrJgfz03q6mQ8+7H+BC12ZhT0I0g9iuvUjolqy7QR00OxOy47Y9FVhq8EC0Gg==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "bowser": "^2.11.0", @@ -1392,13 +1509,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-user-agent-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.292.0.tgz", "integrity": "sha512-f+NfIMal5E61MDc5WGhUEoicr7b1eNNhA+GgVdSB/Hg5fYhEZvFK9RZizH5rrtsLjjgcr9nPYSR7/nDKCJLumw==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1420,13 +1539,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-utf8": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.292.0.tgz", "integrity": "sha512-FPkj+Z59/DQWvoVu2wFaRncc3KVwe/pgK3MfVb0Lx+Ibey5KUx+sNpJmYcVYHUAe/Nv/JeIpOtYuC96IXOnI6w==", "optional": true, + "peer": true, "dependencies": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -1440,6 +1561,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.3.1" } @@ -1448,13 +1570,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@aws-sdk/util-utf8/node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "node_modules/@colors/colors": { "version": "1.5.0", @@ -1982,132 +2106,6 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, - "node_modules/@types/mongoose-unique-validator": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/mongoose-unique-validator/-/mongoose-unique-validator-1.0.7.tgz", - "integrity": "sha512-wgPWN7x9mHdy8x1jcluDF7EDWFb/s8LD7skLr012C8i2Q3tUhdTlp3JxRhFbEM3TD7J1INaoTrWaSaguhuqilQ==", - "dev": true, - "dependencies": { - "mongoose": "^6.3.0" - } - }, - "node_modules/@types/mongoose-unique-validator/node_modules/bson": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", - "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", - "dev": true, - "dependencies": { - "buffer": "^5.6.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@types/mongoose-unique-validator/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "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" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/@types/mongoose-unique-validator/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@types/mongoose-unique-validator/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@types/mongoose-unique-validator/node_modules/mongodb": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", - "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", - "dev": true, - "dependencies": { - "bson": "^4.7.0", - "mongodb-connection-string-url": "^2.5.4", - "socks": "^2.7.1" - }, - "engines": { - "node": ">=12.9.0" - }, - "optionalDependencies": { - "@aws-sdk/credential-providers": "^3.186.0", - "saslprep": "^1.0.3" - } - }, - "node_modules/@types/mongoose-unique-validator/node_modules/mongoose": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.3.tgz", - "integrity": "sha512-fZ3pIlQn7lM632r1l4qiU58lKrJ+FufKVG8TNeRXSChAeu9alCl5KoQ9bLw4jnQNYevSq9o+sqZmFDHP+EVW3g==", - "dev": true, - "dependencies": { - "bson": "^4.7.0", - "kareem": "2.5.1", - "mongodb": "4.14.0", - "mpath": "0.9.0", - "mquery": "4.0.3", - "ms": "2.1.3", - "sift": "16.0.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mongoose" - } - }, - "node_modules/@types/mongoose-unique-validator/node_modules/mquery": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", - "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", - "dev": true, - "dependencies": { - "debug": "4.x" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/@types/mongoose-unique-validator/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==", - "dev": true - }, "node_modules/@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -2864,7 +2862,8 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true + "optional": true, + "peer": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -4035,6 +4034,7 @@ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", "optional": true, + "peer": true, "dependencies": { "strnum": "^1.0.5" }, @@ -6527,7 +6527,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "optional": true, + "peer": true }, "node_modules/supports-color": { "version": "7.2.0", @@ -7061,6 +7062,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, + "peer": true, "requires": { "tslib": "^1.11.1" } @@ -7070,6 +7072,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, + "peer": true, "requires": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -7086,6 +7089,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, + "peer": true, "requires": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -7097,6 +7101,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, + "peer": true, "requires": { "tslib": "^1.11.1" } @@ -7106,6 +7111,7 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -7117,6 +7123,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.292.0.tgz", "integrity": "sha512-lf+OPptL01kvryIJy7+dvFux5KbJ6OTwLPPEekVKZ2AfEvwcVtOZWFUhyw3PJCBTVncjKB1Kjl3V/eTS3YuPXQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7126,7 +7133,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7135,6 +7143,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.294.0.tgz", "integrity": "sha512-QMk/QratNvAvmnJ77pu9KDjpfUf/5LOJplHcLKcY962ewJGBtFFY4XZVnmUgQMSG0phRODtex7pyH//FueGKLQ==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7177,7 +7186,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7186,6 +7196,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.294.0.tgz", "integrity": "sha512-+FuxQTi5WvnaXM5JbNLkBIzQ3An4gA0ox61N1u+3xled+nywKb1yQ7WmRpyMG5bLbkmnj3aqoo5/uskFc4c4EA==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7225,7 +7236,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7234,6 +7246,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.294.0.tgz", "integrity": "sha512-/ZfDud76MdSPJ/TxjV2xLE30XbBQDZwKQ32axwoK1eziPvrAIUBYVgpBwj+m0quhoiQhBKkg3aFl6j39AF2thw==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7273,7 +7286,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7282,6 +7296,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.294.0.tgz", "integrity": "sha512-AefqwhFjTDzelZuSYhriJbiI+GQwf2yKiKAnCt0gRj6rswewStM63Gtlhfb01sFPp+ZiqPcyQ47LqUaHp1mz/g==", "optional": true, + "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7325,7 +7340,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7334,6 +7350,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.292.0.tgz", "integrity": "sha512-cB3twnNR7vYvlt2jvw8VlA1+iv/tVzl+/S39MKqw2tepU+AbJAM0EHwb/dkf1OKSmlrnANXhshx80MHF9zL4mA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/signature-v4": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7346,7 +7363,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7355,6 +7373,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.294.0.tgz", "integrity": "sha512-YSPqHEbLC0dnbFF5LdlMH0B50sMSN/CyG/sHkPYUwL/hkbUk9URnVW7ZJlt6lRftT7X4C7muzLqUP8sJAaiJEA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -7366,7 +7385,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7375,6 +7395,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.292.0.tgz", "integrity": "sha512-YbafSG0ZEKE2969CJWVtUhh3hfOeLPecFVoXOtegCyAJgY5Ghtu4TsVhL4DgiGAgOC30ojAmUVQEXzd7xJF5xA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7385,7 +7406,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7394,6 +7416,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.292.0.tgz", "integrity": "sha512-W/peOgDSRYulgzFpUhvgi1pCm6piBz6xrVN17N4QOy+3NHBXRVMVzYk6ct2qpLPgJUSEZkcpP+Gds+bBm8ed1A==", "optional": true, + "peer": true, "requires": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -7406,7 +7429,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7415,6 +7439,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.294.0.tgz", "integrity": "sha512-pdTPbaAb5bWA+DnuKoL2TpXeNDp6Ejpv/OYt+bw2gdzl9w5r/ZCtUTTbW+Vvejr4WL5s3c1bY96kwdqCn7iLqA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -7431,7 +7456,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7440,6 +7466,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.294.0.tgz", "integrity": "sha512-zUL1Qhb4BsQIZCs/TPpG4oIYH/9YsGiS+Se1tasSGjTOLfBy7jhOZ0QIdpEeyAx/EP8blOBredM9xWfEXgiHVA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -7457,7 +7484,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7466,6 +7494,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.292.0.tgz", "integrity": "sha512-CFVXuMuUvg/a4tknzRikEDwZBnKlHs1LZCpTXIGjBdUTdosoi4WNzDLzGp93ZRTtcgFz+4wirz2f7P3lC0NrQw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -7477,7 +7506,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7486,6 +7516,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.294.0.tgz", "integrity": "sha512-UxrcAA/0l7j9+3tolYcG5M61D/IE1Bjd/9H87H1i2A2BrwUUBhW1Dp/vvROEDrrywlMDG3CDF3T/7ADtTak+sg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-sso": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -7499,7 +7530,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7508,6 +7540,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.292.0.tgz", "integrity": "sha512-4DbtIEM9gGVfqYlMdYXg3XY+vBhemjB1zXIequottW8loLYM8Vuz4/uGxxKNze6evVVzowsA0wKrYclE1aj/Rg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7518,7 +7551,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7527,6 +7561,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.294.0.tgz", "integrity": "sha512-CRGwCs6F31mQzjYi5YF2Z6c1T+UrFKtJSa6Ff/Q1rrPnROexyhBVnpP8WzpkODx/pZxKtTX50IX7ehIxbFDIyQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/client-sso": "3.294.0", @@ -7549,7 +7584,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7558,6 +7594,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.292.0.tgz", "integrity": "sha512-zh3bhUJbL8RSa39ZKDcy+AghtUkIP8LwcNlwRIoxMQh3Row4D1s4fCq0KZCx98NJBEXoiTLyTQlZxxI//BOb1Q==", "optional": true, + "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/querystring-builder": "3.292.0", @@ -7570,7 +7607,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7579,6 +7617,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.292.0.tgz", "integrity": "sha512-1yLxmIsvE+eK36JXEgEIouTITdykQLVhsA5Oai//Lar6Ddgu1sFpLDbdkMtKbrh4I0jLN9RacNCkeVQjZPTCCQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-buffer-from": "3.292.0", @@ -7590,7 +7629,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7599,6 +7639,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.292.0.tgz", "integrity": "sha512-39OUV78CD3TmEbjhpt+V+Fk4wAGWhixqHxDSN8+4WL0uB4Fl7k5m3Z9hNY78AttHQSl2twR7WtLztnXPAFsriw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7608,7 +7649,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7617,6 +7659,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.292.0.tgz", "integrity": "sha512-kW/G5T/fzI0sJH5foZG6XJiNCevXqKLxV50qIT4B1pMuw7regd4ALIy0HwSqj1nnn9mSbRWBfmby0jWCJsMcwg==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -7625,7 +7668,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7634,6 +7678,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.292.0.tgz", "integrity": "sha512-2gMWzQus5mj14menolpPDbYBeaOYcj7KNFZOjTjjI3iQ0KqyetG6XasirNrcJ/8QX1BRmpTol8Xjp2Ue3Gbzwg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7644,7 +7689,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7653,6 +7699,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.292.0.tgz", "integrity": "sha512-cPMkiSxpZGG6tYlW4OS+ucS6r43f9ddX9kcUoemJCY10MOuogdPjulCAjE0HTs2PLKSOrrG4CTP4Q4wWDrH4Bw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/middleware-serde": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -7668,7 +7715,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7677,6 +7725,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.292.0.tgz", "integrity": "sha512-mHuCWe3Yg2S5YZ7mB7sKU6C97XspfqrimWjMW9pfV2usAvLA3R0HrB03jpR5vpZ3P4q7HB6wK3S6CjYMGGRNag==", "optional": true, + "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7687,7 +7736,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7696,6 +7746,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.292.0.tgz", "integrity": "sha512-yZNY1XYmG3NG+uonET7jzKXNiwu61xm/ZZ6i/l51SusuaYN+qQtTAhOFsieQqTehF9kP4FzbsWgPDwD8ZZX9lw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7705,7 +7756,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7714,6 +7766,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.292.0.tgz", "integrity": "sha512-kA3VZpPko0Zqd7CYPTKAxhjEv0HJqFu2054L04dde1JLr43ro+2MTdX7vsHzeAFUVRphqatFFofCumvXmU6Mig==", "optional": true, + "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7724,7 +7777,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7733,6 +7787,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.293.0.tgz", "integrity": "sha512-7tiaz2GzRecNHaZ6YnF+Nrtk3au8qF6oiipf11R7MJiqJ0fkMLnz/iRrlakDziS9qF/a9v+3yxb4W4NHK3f4Tw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/service-error-classification": "3.292.0", @@ -7747,13 +7802,15 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7762,6 +7819,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.292.0.tgz", "integrity": "sha512-GN5ZHEqXZqDi+HkVbaXRX9HaW/vA5rikYpWKYsmxTUZ7fB7ijvEO3co3lleJv2C+iGYRtUIHC4wYNB5xgoTCxg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/middleware-signing": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -7775,7 +7833,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7784,6 +7843,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.292.0.tgz", "integrity": "sha512-6hN9mTQwSvV8EcGvtXbS/MpK7WMCokUku5Wu7X24UwCNMVkoRHLIkYcxHcvBTwttuOU0d8hph1/lIX4dkLwkQw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7793,7 +7853,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7802,6 +7863,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.292.0.tgz", "integrity": "sha512-GVfoSjDjEQ4TaO6x9MffyP3uRV+2KcS5FtexLCYOM9pJcnE9tqq9FJOrZ1xl1g+YjUVKxo4x8lu3tpEtIb17qg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -7815,7 +7877,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7824,6 +7887,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.292.0.tgz", "integrity": "sha512-WdQpRkuMysrEwrkByCM1qCn2PPpFGGQ2iXqaFha5RzCdZDlxJni9cVNb6HzWUcgjLEYVTXCmOR9Wxm3CNW44Qg==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -7832,7 +7896,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7841,6 +7906,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.293.0.tgz", "integrity": "sha512-gZ7/e6XwpKk9mvgA78q4Ffc796jTn02TUKx2qMDnkLVbeJXBNN2jnvYEKq8v70+o7fd/ALRudg8gBDmkkhM/Hw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7852,7 +7918,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7861,6 +7928,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.292.0.tgz", "integrity": "sha512-S3NnC9dQ5GIbJYSDIldZb4zdpCOEua1tM7bjYL3VS5uqCEM93kIi/o/UkIUveMp/eqTS2LJa5HjNIz5Te6je0A==", "optional": true, + "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -7872,7 +7940,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7881,6 +7950,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.292.0.tgz", "integrity": "sha512-L/E3UDSwXLXjt1XWWh0RBD55F+aZI1AEdPwdES9i1PjnZLyuxuDhEDptVibNN56+I9/4Q3SbmuVRVlOD0uzBag==", "optional": true, + "peer": true, "requires": { "@aws-sdk/abort-controller": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -7893,7 +7963,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7902,6 +7973,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.292.0.tgz", "integrity": "sha512-dHArSvsiqhno/g55N815gXmAMrmN8DP7OeFNqJ4wJG42xsF2PFN3DAsjIuHuXMwu+7A3R1LHqIpvv0hA9KeoJQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7911,7 +7983,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7920,6 +7993,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.292.0.tgz", "integrity": "sha512-NLi4fq3k41aXIh1I97yX0JTy+3p6aW1NdwFwdMa674z86QNfb4SfRQRZBQe9wEnAZ/eWHVnlKIuII+U1URk/Kg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7929,7 +8003,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7938,6 +8013,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.292.0.tgz", "integrity": "sha512-XElIFJaReIm24eEvBtV2dOtZvcm3gXsGu/ftG8MLJKbKXFKpAP1q+K6En0Bs7/T88voKghKdKpKT+eZUWgTqlg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-uri-escape": "3.292.0", @@ -7948,7 +8024,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7957,6 +8034,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.292.0.tgz", "integrity": "sha512-iTYpYo7a8X9RxiPbjjewIpm6XQPx2EOcF1dWCPRII9EFlmZ4bwnX+PDI36fIo9oVs8TIKXmwNGODU9nsg7CSAw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7966,7 +8044,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7974,13 +8053,15 @@ "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.292.0.tgz", "integrity": "sha512-X1k3sixCeC45XSNHBe+kRBQBwPDyTFtFITb8O5Qw4dS9XWGhrUJT4CX0qE5aj8qP3F9U5nRizs9c2mBVVP0Caw==", - "optional": true + "optional": true, + "peer": true }, "@aws-sdk/shared-ini-file-loader": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.292.0.tgz", "integrity": "sha512-Av2TTYg1Jig2kbkD56ybiqZJB6vVrYjv1W5UQwY/q3nA/T2mcrgQ20ByCOt5Bv9VvY7FSgC+znj+L4a7RLGmBg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7990,7 +8071,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -7999,6 +8081,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.292.0.tgz", "integrity": "sha512-+rw47VY5mvBecn13tDQTl1ipGWg5tE63faWgmZe68HoBL87ZiDzsd7bUKOvjfW21iMgWlwAppkaNNQayYRb2zg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/is-array-buffer": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8013,7 +8096,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8022,6 +8106,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.292.0.tgz", "integrity": "sha512-S8PKzjPkZ6SXYZuZiU787dMsvQ0d/LFEhw2OI4Oe2An9Fc2IwJ2FYukyHoQJOV2tV0DiuMebPo7eMyQyjKElvA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/middleware-stack": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8032,7 +8117,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8041,6 +8127,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.294.0.tgz", "integrity": "sha512-6nwO04LtC5f4AsUvGZXyjaswuEK4Rr2VsuANpMKrPCgunRfI58a8YXLniudOSXN6e7CFJ6M3uo/h5YXqtnzGug==", "optional": true, + "peer": true, "requires": { "@aws-sdk/client-sso-oidc": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -8053,7 +8140,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8062,6 +8150,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.292.0.tgz", "integrity": "sha512-1teYAY2M73UXZxMAxqZxVS2qwXjQh0OWtt7qyLfha0TtIk/fZ1hRwFgxbDCHUFcdNBSOSbKH/ESor90KROXLCQ==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8070,7 +8159,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8079,6 +8169,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.292.0.tgz", "integrity": "sha512-NZeAuZCk1x6TIiWuRfbOU6wHPBhf0ly2qOHzWut4BCH+b4RrDmFF8EmXcH1auEfGhE7yRyR6XqIN0t3S+hYACA==", "optional": true, + "peer": true, "requires": { "@aws-sdk/querystring-parser": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8089,7 +8180,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8098,6 +8190,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.292.0.tgz", "integrity": "sha512-zjNCwNdy617yFvEjZorepNWXB2sQCVfsShCwFy/kIQ5iW5tT2jQKaqc0K77diU9atkooxw9p1W9m9sOgrkOFNw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -8107,7 +8200,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8116,6 +8210,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.292.0.tgz", "integrity": "sha512-Wd/BM+JsMiKvKs/bN3z6TredVEHh2pKudGfg3CSjTRpqFpOG903KDfyHBD42yg5PuCHoHoewJvTPKwgn7/vhaw==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8124,7 +8219,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8133,6 +8229,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.292.0.tgz", "integrity": "sha512-BBgipZ2P6RhogWE/qj0oqpdlyd3iSBYmb+aD/TBXwB2lA/X8A99GxweBd/kp06AmcJRoMS9WIXgbWkiiBlRlSA==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8141,7 +8238,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8150,6 +8248,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.292.0.tgz", "integrity": "sha512-RxNZjLoXNxHconH9TYsk5RaEBjSgTtozHeyIdacaHPj5vlQKi4hgL2hIfKeeNiAfQEVjaUFF29lv81xpNMzVMQ==", "optional": true, + "peer": true, "requires": { "@aws-sdk/is-array-buffer": "3.292.0", "tslib": "^2.3.1" @@ -8159,7 +8258,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8168,6 +8268,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.292.0.tgz", "integrity": "sha512-t3noYll6bPRSxeeNNEkC5czVjAiTPcsq00OwfJ2xyUqmquhLEfLwoJKmrT1uP7DjIEXdUtfoIQ2jWiIVm/oO5A==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8176,7 +8277,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8185,6 +8287,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.292.0.tgz", "integrity": "sha512-7+zVUlMGfa8/KT++9humHo6IDxTnxMCmWUj5jVNlkpk6h7Ecmppf7aXotviyVIA43lhtz0p2AErs0N0ekEUK+w==", "optional": true, + "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8196,7 +8299,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8205,6 +8309,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.292.0.tgz", "integrity": "sha512-SSIw85eF4BVs0fOJRyshT+R3b/UmBPhiVKCUZm2rq6+lIGkDPiSwQU3d/80AhXtiL5SFT/IzAKKgQd8qMa7q3A==", "optional": true, + "peer": true, "requires": { "@aws-sdk/config-resolver": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -8218,7 +8323,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8227,6 +8333,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.293.0.tgz", "integrity": "sha512-R/99aNV49Refpv5guiUjEUrZYlvnfaNBniB+/ZtMO3ixxUopapssCrUivuJrmhccmrYaTCZw7dRzIWjU1jJhKg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -8236,7 +8343,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8245,6 +8353,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.292.0.tgz", "integrity": "sha512-qBd5KFIUywQ3qSSbj814S2srk0vfv8A6QMI+Obs1y2LHZFdQN5zViptI4UhXhKOHe+NnrHWxSuLC/LMH6q3SmA==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8253,7 +8362,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8262,6 +8372,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.292.0.tgz", "integrity": "sha512-6xnFJXZI9pKw5lQCDvuWA5PnOaUtNRKWwdxvGkkLx5orboFaoVMS6zowjSQxwVNRjW82u6dYNkhmj9mZ8VSjWg==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8270,7 +8381,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8279,6 +8391,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.292.0.tgz", "integrity": "sha512-KjhS7flfoBKDxbiBZjLjMvEizXgjfQb7GQEItgzGoI9rfGCmZtvqCcqQQoIlxb8bIzGRggAUHtBGWnlLbpb+GQ==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8287,7 +8400,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8296,6 +8410,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.292.0.tgz", "integrity": "sha512-JEHyF7MpVeRF5uR4LDYgpOKcFpOPiAj8TqN46SVOQQcL1K+V7cSr7O7N7J6MwJaN9XOzAcBadeIupMm7/BFbgw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/service-error-classification": "3.292.0", "tslib": "^2.3.1" @@ -8305,7 +8420,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8314,6 +8430,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.292.0.tgz", "integrity": "sha512-hOQtUMQ4VcQ9iwKz50AoCp1XBD5gJ9nly/gJZccAM7zSA5mOO8RRKkbdonqquVHxrO0CnYgiFeCh3V35GFecUw==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8322,7 +8439,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8331,6 +8449,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.292.0.tgz", "integrity": "sha512-dld+lpC3QdmTQHdBWJ0WFDkXDSrJgfz03q6mQ8+7H+BC12ZhT0I0g9iuvUjolqy7QR00OxOy47Y9FVhq8EC0Gg==", "optional": true, + "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "bowser": "^2.11.0", @@ -8341,7 +8460,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8350,6 +8470,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.292.0.tgz", "integrity": "sha512-f+NfIMal5E61MDc5WGhUEoicr7b1eNNhA+GgVdSB/Hg5fYhEZvFK9RZizH5rrtsLjjgcr9nPYSR7/nDKCJLumw==", "optional": true, + "peer": true, "requires": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8360,7 +8481,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8369,6 +8491,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.292.0.tgz", "integrity": "sha512-FPkj+Z59/DQWvoVu2wFaRncc3KVwe/pgK3MfVb0Lx+Ibey5KUx+sNpJmYcVYHUAe/Nv/JeIpOtYuC96IXOnI6w==", "optional": true, + "peer": true, "requires": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -8378,7 +8501,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8387,6 +8511,7 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, + "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8395,7 +8520,8 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true + "optional": true, + "peer": true } } }, @@ -8831,96 +8957,6 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, - "@types/mongoose-unique-validator": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/mongoose-unique-validator/-/mongoose-unique-validator-1.0.7.tgz", - "integrity": "sha512-wgPWN7x9mHdy8x1jcluDF7EDWFb/s8LD7skLr012C8i2Q3tUhdTlp3JxRhFbEM3TD7J1INaoTrWaSaguhuqilQ==", - "dev": true, - "requires": { - "mongoose": "^6.3.0" - }, - "dependencies": { - "bson": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", - "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", - "dev": true, - "requires": { - "buffer": "^5.6.0" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "mongodb": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", - "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", - "dev": true, - "requires": { - "@aws-sdk/credential-providers": "^3.186.0", - "bson": "^4.7.0", - "mongodb-connection-string-url": "^2.5.4", - "saslprep": "^1.0.3", - "socks": "^2.7.1" - } - }, - "mongoose": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.3.tgz", - "integrity": "sha512-fZ3pIlQn7lM632r1l4qiU58lKrJ+FufKVG8TNeRXSChAeu9alCl5KoQ9bLw4jnQNYevSq9o+sqZmFDHP+EVW3g==", - "dev": true, - "requires": { - "bson": "^4.7.0", - "kareem": "2.5.1", - "mongodb": "4.14.0", - "mpath": "0.9.0", - "mquery": "4.0.3", - "ms": "2.1.3", - "sift": "16.0.1" - } - }, - "mquery": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", - "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", - "dev": true, - "requires": { - "debug": "4.x" - } - }, - "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 - } - } - }, "@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -9479,7 +9515,8 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true + "optional": true, + "peer": true }, "brace-expansion": { "version": "1.1.11", @@ -10412,6 +10449,7 @@ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", "optional": true, + "peer": true, "requires": { "strnum": "^1.0.5" } @@ -12275,7 +12313,8 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true + "optional": true, + "peer": true }, "supports-color": { "version": "7.2.0", diff --git a/package.json b/package.json index 88063fd..5ca8b49 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", - "@types/mongoose-unique-validator": "^1.0.7", "@types/morgan": "^1.9.4", "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 8849822..dd09b8f 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -172,8 +172,8 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi const mii: Mii = new Mii(Buffer.from(miiData, 'base64')); const miiStudioUrl: string = mii.studioUrl({ type: 'face', - width: '128', - instanceCount: '1', + width: 128, + instanceCount: 1, }); const miiStudioNormalFaceImageData: Buffer = await got(miiStudioUrl).buffer(); const pngData: { @@ -193,8 +193,8 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi const miiStudioExpressionUrl: string = mii.studioUrl({ type: 'face', expression: expression, - width: '128', - instanceCount: '1', + width: 128, + instanceCount: 1, }); const miiStudioExpressionImageData: Buffer = await got(miiStudioExpressionUrl).buffer(); await uploadCDNAsset('pn-cdn', `${userMiiKey}/${expression}.png`, miiStudioExpressionImageData, 'public-read'); @@ -202,8 +202,8 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi const miiStudioBodyUrl: string = mii.studioUrl({ type: 'all_body', - width: '270', - instanceCount: '1', + width: 270, + instanceCount: 1, }); const miiStudioBodyImageData: Buffer = await got(miiStudioBodyUrl).buffer(); await uploadCDNAsset('pn-cdn', `${userMiiKey}/body.png`, miiStudioBodyImageData, 'public-read'); diff --git a/src/types/express-subdomain.d.ts b/src/types/express-subdomain.d.ts new file mode 100644 index 0000000..cb1cbdc --- /dev/null +++ b/src/types/express-subdomain.d.ts @@ -0,0 +1,3 @@ +declare module 'express-subdomain'; + +// TODO - Add proper types \ No newline at end of file diff --git a/src/types/image-pixels.d.ts b/src/types/image-pixels.d.ts new file mode 100644 index 0000000..bd142c3 --- /dev/null +++ b/src/types/image-pixels.d.ts @@ -0,0 +1,3 @@ +declare module 'image-pixels'; + +// TODO - Add proper types \ No newline at end of file diff --git a/src/types/mii-js.d.ts b/src/types/mii-js.d.ts new file mode 100644 index 0000000..9421b0f --- /dev/null +++ b/src/types/mii-js.d.ts @@ -0,0 +1,98 @@ +declare module 'mii-js'; + +// TODO - These have limits, and should be validated + +type MiiStudioURLOptions = { + type?: string; + expression?: string; + width?: number; + bgColor?: string; + clothesColor?: string; + cameraXRotate?: number; + cameraYRotate?: number; + cameraZRotate?: number; + characterXRotate?: number; + characterYRotate?: number; + characterZRotate?: number; + lightXDirection?: number; + lightYDirection?: number; + lightZDirection?: number; + lightDirectionMode?: string; + instanceCount?: number; + instanceRotationMode?: string; +}; + +type Mii = { + version: number; + allowCopying: boolean; + profanityFlag: boolean; + regionLock: number; + characterSet: number; + pageIndex: number; + slotIndex: number; + unknown1: number; + deviceOrigin: number; + systemId: Buffer; + normalMii: boolean; + dsMii: boolean; + nonUserMii: boolean; + isValid: boolean; + creationTime: number; + consoleMAC: Buffer; + gender: number; + birthMonth: number; + birthDay: number; + favoriteColor: number; + favorite: boolean; + miiName: string; + height: number; + build: number; + disableSharing: boolean; + faceType: number; + skinColor: number; + wrinklesType: number; + makeupType: number; + hairType: number; + hairColor: number; + flipHair: boolean; + eyeType: number; + eyeColor: number; + eyeScale: number; + eyeVerticalStretch: number; + eyeRotation: number; + eyeSpacing: number; + eyeYPosition: number; + eyebrowType: number; + eyebrowColor: number; + eyebrowScale: number; + eyebrowVerticalStretch: number; + eyebrowRotation: number; + eyebrowSpacing: number; + eyebrowYPosition: number; + noseType: number; + noseScale: number; + noseYPosition: number; + mouthType: number; + mouthColor: number; + mouthScale: number; + mouthHorizontalStretch: number; + mouthYPosition: number; + mustacheType: number; + unknown2: number; + beardType: number; + facialHairColor: number; + mustacheScale: number; + mustacheYPosition: number; + glassesType: number; + glassesColor: number; + glassesScale: number; + glassesYPosition: number; + moleEnabled: boolean; + moleScale: number; + moleXPosition: number; + moleYPosition: number; + creatorName: string; + checksum: number; + + studioUrl: (options: MiiStudioURLOptions) => string +}; \ No newline at end of file diff --git a/src/types/mongoose-unique-validator.d.ts b/src/types/mongoose-unique-validator.d.ts new file mode 100644 index 0000000..0909028 --- /dev/null +++ b/src/types/mongoose-unique-validator.d.ts @@ -0,0 +1 @@ +declare module 'mongoose-unique-validator'; \ No newline at end of file diff --git a/src/types/tga.d.ts b/src/types/tga.d.ts new file mode 100644 index 0000000..e1c6188 --- /dev/null +++ b/src/types/tga.d.ts @@ -0,0 +1,3 @@ +declare module 'tga'; + +// TODO - Add proper types \ No newline at end of file From b309eecff9503ae4e1977900f70eccf81ecb185d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 18 Mar 2023 16:58:20 -0400 Subject: [PATCH 43/65] Finish strict mode errors --- src/models/nex-account.ts | 2 +- src/nintendo-certificate.ts | 21 ++++++++-------- src/services/datastore/routes/upload.ts | 8 +++++-- src/services/nnid/routes/admin.ts | 23 +++++++++++++----- src/services/nnid/routes/content.ts | 2 +- src/services/nnid/routes/people.ts | 32 +++++++++++++++++++++---- src/types/mii-js.d.ts | 3 ++- 7 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/models/nex-account.ts b/src/models/nex-account.ts index abfa407..cddd72b 100644 --- a/src/models/nex-account.ts +++ b/src/models/nex-account.ts @@ -43,7 +43,7 @@ NEXAccountSchema.method('generatePID', async function generatePID(): Promise { - // TODO - strict mode yells here - fileName = RE_FILE_NAME.exec(header['content-disposition'][0])[1]; + const contentDisposition = header['content-disposition' as keyof object]; + const regexResult = RE_FILE_NAME.exec(contentDisposition); + + if (regexResult) { + fileName = regexResult[0]; + } }); part.on('data', (data: Buffer | string) => { diff --git a/src/services/nnid/routes/admin.ts b/src/services/nnid/routes/admin.ts index c5f44d6..6a4437c 100644 --- a/src/services/nnid/routes/admin.ts +++ b/src/services/nnid/routes/admin.ts @@ -39,10 +39,10 @@ router.get('/mapped_ids', async (request: express.Request, response: express.Res queryOutput = 'pid'; } - // This is slower than PNID.where() - // but it ensures that each input - // ALWAYS has an output and filters - // out unwanted input/output types + // * This is slower than PNID.where() + // * but it ensures that each input + // * ALWAYS has an output and filters + // * out unwanted input/output types const results: { in_id: string; out_id: string; @@ -64,8 +64,19 @@ router.get('/mapped_ids', async (request: express.Request, response: express.Res pid?: number; } = {}; - // TODO - TS strict mode...what? - query[queryInput] = input; + if (queryInput === 'usernameLower') { + query.usernameLower = input; + } + + if (queryInput === 'pid') { + query.pid = Number(input); + + if (isNaN(query.pid)) { + // * Bail early + results.push(result); + continue; + } + } const searchResult: HydratedPNIDDocument | null = await PNID.findOne(query); diff --git a/src/services/nnid/routes/content.ts b/src/services/nnid/routes/content.ts index 5d45aa6..56dc2f5 100644 --- a/src/services/nnid/routes/content.ts +++ b/src/services/nnid/routes/content.ts @@ -154,7 +154,7 @@ router.get('/time_zones/:countryCode/:language', (request: express.Request, resp const countryCode: string = request.params.countryCode; const language: string = request.params.language; - const regionLanguages: RegionLanguages = timezones[countryCode]; + const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones]; const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; response.send(xmlbuilder.create({ diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 239c9a0..3258375 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -56,7 +56,7 @@ router.get('/:username', async (request: express.Request, response: express.Resp * Description: Registers a new NNID */ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express.Request, response: express.Response) => { - if (!request.certificate.valid) { + if (!request.certificate || !request.certificate.valid) { // TODO: Change this to a different error response.status(400); @@ -118,9 +118,20 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express const language: string = person.get('language'); const timezoneName: string = person.get('tz_name'); - const regionLanguages: RegionLanguages = timezones[countryCode]; + const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones]; const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; - const timezone: RegionTimezone = regionTimezones.find(tz => tz.area === timezoneName); + let timezone: RegionTimezone | undefined = regionTimezones.find(tz => tz.area === timezoneName); + + if (!timezone) { + // TODO - Change this, handle the error + timezone = { + area: 'America/New_York', + language: 'en', + name: 'Eastern Time (US & Canada)', + order: '11', + utc_offset: '-14400' + }; + } pnid = new PNID({ pid: nexAccount.get('pid'), @@ -475,9 +486,20 @@ router.put('/@me', async (request: express.Request, response: express.Response) const marketingFlag: boolean = person.get('marketing_flag') ? person.get('marketing_flag') === 'Y' : pnid.get('flags.marketing'); const offDeviceFlag: boolean = person.get('off_device_flag') ? person.get('off_device_flag') === 'Y' : pnid.get('flags.off_device'); - const regionLanguages: RegionLanguages = timezones[countryCode]; + const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones]; const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; - const timezone: RegionTimezone = regionTimezones.find(tz => tz.area === timezoneName); + let timezone: RegionTimezone | undefined = regionTimezones.find(tz => tz.area === timezoneName); + + if (!timezone) { + // TODO - Change this, handle the error + timezone = { + area: 'America/New_York', + language: 'en', + name: 'Eastern Time (US & Canada)', + order: '11', + utc_offset: '-14400' + }; + } if (person.get('password')) { const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), pnid.get('pid')); diff --git a/src/types/mii-js.d.ts b/src/types/mii-js.d.ts index 9421b0f..a63a5b8 100644 --- a/src/types/mii-js.d.ts +++ b/src/types/mii-js.d.ts @@ -94,5 +94,6 @@ type Mii = { creatorName: string; checksum: number; - studioUrl: (options: MiiStudioURLOptions) => string + studioUrl: (options: MiiStudioURLOptions) => string; + encode: () => Buffer; }; \ No newline at end of file From a2415faab88f469face22041168187072c83917f Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 18 Mar 2023 17:00:12 -0400 Subject: [PATCH 44/65] Removed unnecessary regex escapes --- src/services/api/routes/v1/register.ts | 12 ++++++------ src/services/api/routes/v1/resetPassword.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index b1e37b1..ef6cda8 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -22,15 +22,15 @@ import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; const router: express.Router = express.Router(); -const PNID_VALID_CHARACTERS_REGEX: RegExp = /^[\w\-\.]*$/gm; -const PNID_PUNCTUATION_START_REGEX: RegExp = /^[\_\-\.]/gm; -const PNID_PUNCTUATION_END_REGEX: RegExp = /[\_\-\.]$/gm; -const PNID_PUNCTUATION_DUPLICATE_REGEX: RegExp = /[\_\-\.]{2,}/gm; +const PNID_VALID_CHARACTERS_REGEX: RegExp = /^[\w\-.]*$/gm; +const PNID_PUNCTUATION_START_REGEX: RegExp = /^[_\-.]/gm; +const PNID_PUNCTUATION_END_REGEX: RegExp = /[_\-.]$/gm; +const PNID_PUNCTUATION_DUPLICATE_REGEX: RegExp = /[_\-.]{2,}/gm; // This sucks const PASSWORD_WORD_OR_NUMBER_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*\d).*/; -const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[\_\-\.]).*/; -const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[\_\-\.]).*/; +const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[_\-.]).*/; +const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[_\-.]).*/; const PASSWORD_REPEATED_CHARACTER_REGEX: RegExp = /(.)\1\1/; const DEFAULT_MII_DATA: Buffer = Buffer.from('AwAAQOlVognnx0GC2/uogAOzuI0n2QAAAEBEAGUAZgBhAHUAbAB0AAAAAAAAAEBAAAAhAQJoRBgmNEYUgRIXaA0AACkAUkhQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGm9', 'base64'); diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 95266f7..0a52acf 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -9,8 +9,8 @@ const router: express.Router = express.Router(); // This sucks const PASSWORD_WORD_OR_NUMBER_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*\d).*/; -const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[\_\-\.]).*/; -const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[\_\-\.]).*/; +const PASSWORD_WORD_OR_PUNCTUATION_REGEX: RegExp = /(?=.*[a-zA-Z])(?=.*[_\-.]).*/; +const PASSWORD_NUMBER_OR_PUNCTUATION_REGEX: RegExp = /(?=.*\d)(?=.*[_\-.]).*/; const PASSWORD_REPEATED_CHARACTER_REGEX: RegExp = /(.)\1\1/; router.post('/', async (request: express.Request, response: express.Response) => { From 5c7738d1d0a6a3ec2e87ec5d8d6b0318cf10393a Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 18 Mar 2023 17:04:32 -0400 Subject: [PATCH 45/65] Changed ACCESS_LEVEL to enum --- src/types/mongoose/nex-account.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/types/mongoose/nex-account.ts b/src/types/mongoose/nex-account.ts index 0e89b51..99342e4 100644 --- a/src/types/mongoose/nex-account.ts +++ b/src/types/mongoose/nex-account.ts @@ -1,7 +1,12 @@ import { Model, HydratedDocument } from 'mongoose'; type DEVICE = 'wiiu' | '3ds'; -type ACCESS_LEVEL = 0 | 1 | 2 | 3; +enum ACCESS_LEVEL { + User = 0, + Admin = 1, + Owner = 2, + Dev = 3 +} export interface INEXAccount { device_type: DEVICE; From a9de4d94dcc63b55613bd5c8a1fdaeb363919714 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 18 Mar 2023 17:07:46 -0400 Subject: [PATCH 46/65] Removed useless await in nasc middleware --- src/middleware/nasc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 9308bb9..301e6f4 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -128,7 +128,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon try { // Create new NEX account - const nexAccount: HydratedNEXAccountDocument = await new NEXAccount({ + const nexAccount: HydratedNEXAccountDocument = new NEXAccount({ device_type: '3ds', password }); From b28aababbe3a2818de500c1d253336a27899d190 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 18 Mar 2023 17:18:39 -0400 Subject: [PATCH 47/65] Made logger object as const --- src/logger.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/logger.ts b/src/logger.ts index 798ef62..917b677 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -6,13 +6,13 @@ colors.enable(); const root: string = process.env.PN_ACT_LOGGER_PATH ? process.env.PN_ACT_LOGGER_PATH : `${__dirname}/..`; fs.ensureDirSync(`${root}/logs`); -const streams: { [key: string]: fs.WriteStream } = { +const streams = { latest: fs.createWriteStream(`${root}/logs/latest.log`), success: fs.createWriteStream(`${root}/logs/success.log`), error: fs.createWriteStream(`${root}/logs/error.log`), warn: fs.createWriteStream(`${root}/logs/warn.log`), info: fs.createWriteStream(`${root}/logs/info.log`) -}; +} as const; export function LOG_SUCCESS(input: string): void { const time: Date = new Date(); From a95d4e10a615b1bfaa138b547295d148acfbab82 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 11:52:43 -0400 Subject: [PATCH 48/65] Handle arrays and proper types on headers and query strings --- package-lock.json | 64 ++++++++++++++++++++++++---- package.json | 2 + src/middleware/api.ts | 3 +- src/middleware/client-header.ts | 5 ++- src/middleware/device-certificate.ts | 3 +- src/middleware/pnid.ts | 3 +- src/middleware/ratelimit.ts | 8 +++- src/middleware/xml-parser.ts | 5 ++- src/nintendo-certificate.ts | 4 +- src/server.ts | 14 ++++-- src/services/api/routes/v1/email.ts | 4 +- src/services/local-cdn/routes/get.ts | 2 +- src/services/nnid/routes/admin.ts | 28 +++++++----- src/services/nnid/routes/miis.ts | 20 ++++++--- src/services/nnid/routes/people.ts | 27 +++++++++--- src/services/nnid/routes/provider.ts | 33 ++++++++++++-- src/types/common/safe-qs.ts | 3 ++ src/util.ts | 54 +++++++++++++++++++++++ 18 files changed, 230 insertions(+), 52 deletions(-) create mode 100644 src/types/common/safe-qs.ts diff --git a/package-lock.json b/package-lock.json index dc8a274..3c28cac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", + "typescript-is": "^0.19.0", "validator": "^13.7.0", "xmlbuilder": "^13.0.2", "xmlbuilder2": "0.0.4" @@ -48,6 +49,7 @@ "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", "@types/nodemailer": "^6.4.7", + "@types/qs": "^6.9.7", "@types/validator": "^13.7.14", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", @@ -5465,6 +5467,11 @@ "node": ">= 0.6" } }, + "node_modules/nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" + }, "node_modules/next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -5976,6 +5983,12 @@ "@redis/time-series": "1.0.4" } }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "optional": true + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -6679,14 +6692,12 @@ "node_modules/tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "devOptional": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, "dependencies": { "tslib": "^1.8.1" }, @@ -6762,7 +6773,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -6771,6 +6781,24 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-is": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/typescript-is/-/typescript-is-0.19.0.tgz", + "integrity": "sha512-SAJEx2cxbQZhfOjDEjPnQJt1qRS1M3wrKbUwvsywVHWGbMgM1dcIf9gPWNDS1/dgTa/7Iexk2mmAHHsP9MeCsA==", + "dependencies": { + "nested-error-stacks": "^2", + "tsutils": "^3.17.1" + }, + "engines": { + "node": ">=6.14.4" + }, + "optionalDependencies": { + "reflect-metadata": ">=0.1.12" + }, + "peerDependencies": { + "typescript": "^4.1.5" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -11517,6 +11545,11 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, + "nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" + }, "next-tick": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", @@ -11892,6 +11925,12 @@ "@redis/time-series": "1.0.4" } }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "optional": true + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -12440,14 +12479,12 @@ "tslib": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "devOptional": true + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, "tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, "requires": { "tslib": "^1.8.1" } @@ -12501,8 +12538,17 @@ "typescript": { "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" + }, + "typescript-is": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/typescript-is/-/typescript-is-0.19.0.tgz", + "integrity": "sha512-SAJEx2cxbQZhfOjDEjPnQJt1qRS1M3wrKbUwvsywVHWGbMgM1dcIf9gPWNDS1/dgTa/7Iexk2mmAHHsP9MeCsA==", + "requires": { + "nested-error-stacks": "^2", + "reflect-metadata": ">=0.1.12", + "tsutils": "^3.17.1" + } }, "universalify": { "version": "0.1.2", diff --git a/package.json b/package.json index 5ca8b49..8e2b0dc 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "nodemailer": "^6.4.2", "redis": "^4.3.1", "tga": "^1.0.4", + "typescript-is": "^0.19.0", "validator": "^13.7.0", "xmlbuilder": "^13.0.2", "xmlbuilder2": "0.0.4" @@ -64,6 +65,7 @@ "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", "@types/nodemailer": "^6.4.7", + "@types/qs": "^6.9.7", "@types/validator": "^13.7.14", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", diff --git a/src/middleware/api.ts b/src/middleware/api.ts index e4fa82a..c196d0b 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -1,9 +1,10 @@ import express from 'express'; +import { getValueFromHeaders } from '@/util'; import { getUserBearer } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { - const authHeader: string | undefined = request.headers.authorization; + const authHeader: string | undefined = getValueFromHeaders(request.headers, 'authorization'); if (!authHeader || !(authHeader.startsWith('Bearer'))) { return next(); diff --git a/src/middleware/client-header.ts b/src/middleware/client-header.ts index 18b21fd..fc9c1e5 100644 --- a/src/middleware/client-header.ts +++ b/src/middleware/client-header.ts @@ -1,5 +1,6 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; +import { getValueFromHeaders } from '@/util'; const VALID_CLIENT_ID_SECRET_PAIRS: { [key: string]: string } = { // * 'Key' is the client ID, 'Value' is the client secret @@ -14,8 +15,8 @@ function nintendoClientHeaderCheck(request: express.Request, response: express.R response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - const clientId: string = request.headers['x-nintendo-client-id'] as string; - const clientSecret: string = request.headers['x-nintendo-client-secret'] as string; + const clientId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-client-id'); + const clientSecret: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-client-secret'); if ( !clientId || diff --git a/src/middleware/device-certificate.ts b/src/middleware/device-certificate.ts index e74c11c..9e7d224 100644 --- a/src/middleware/device-certificate.ts +++ b/src/middleware/device-certificate.ts @@ -1,8 +1,9 @@ import express from 'express'; import NintendoCertificate from '@/nintendo-certificate'; +import { getValueFromHeaders } from '@/util'; function deviceCertificateMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void { - const certificate: string = request.headers['x-nintendo-device-cert'] as string; + const certificate: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-device-cert'); if (!certificate) { return next(); diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index 96f58cd..c1e0933 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -1,10 +1,11 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; +import { getValueFromHeaders } from '@/util'; import { getUserBasic, getUserBearer } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { - const authHeader: string | undefined = request.headers.authorization; + const authHeader: string | undefined = getValueFromHeaders(request.headers, 'authorization'); if (!authHeader || !(authHeader.startsWith('Bearer') || authHeader.startsWith('Basic'))) { return next(); diff --git a/src/middleware/ratelimit.ts b/src/middleware/ratelimit.ts index e6909f2..0cc8b38 100644 --- a/src/middleware/ratelimit.ts +++ b/src/middleware/ratelimit.ts @@ -1,12 +1,18 @@ import crypto from 'node:crypto'; import express from 'express'; import ratelimit from 'express-rate-limit'; +import { getValueFromHeaders } from '@/util'; export default ratelimit({ windowMs: 60 * 1000, max: 1, keyGenerator: (request: express.Request) => { - const data: string = request.headers['x-nintendo-device-cert'] as string; + let data: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-device-cert'); + + if (!data) { + data = request.ip; + } + return crypto.createHash('md5').update(data).digest('hex'); } }); \ No newline at end of file diff --git a/src/middleware/xml-parser.ts b/src/middleware/xml-parser.ts index cf1335e..31bb8b4 100644 --- a/src/middleware/xml-parser.ts +++ b/src/middleware/xml-parser.ts @@ -1,11 +1,12 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { document as xmlParser } from 'xmlbuilder2'; +import { getValueFromHeaders } from '@/util'; function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void { if (request.method == 'POST' || request.method == 'PUT') { - const contentType: string | undefined = request.headers['content-type']; - const contentLength: string | undefined = request.headers['content-length']; + const contentType: string | undefined = getValueFromHeaders(request.headers, 'content-type'); + const contentLength: string | undefined = getValueFromHeaders(request.headers, 'content-length'); let body: string = ''; if ( diff --git a/src/nintendo-certificate.ts b/src/nintendo-certificate.ts index 92dc9f0..4cc3105 100644 --- a/src/nintendo-certificate.ts +++ b/src/nintendo-certificate.ts @@ -42,7 +42,7 @@ const CTR_LFCS_B_PUB = Buffer.from([ ]); // Signature options -const SIGNATURE_SIZES: { [key: string]: SignatureSize } = { +const SIGNATURE_SIZES = { RSA_4096_SHA1: { SIZE: 0x200, PADDING_SIZE: 0x3C @@ -67,7 +67,7 @@ const SIGNATURE_SIZES: { [key: string]: SignatureSize } = { SIZE: 0x3C, PADDING_SIZE: 0x40 } -}; +} as const; class NintendoCertificate { _certificate: Buffer; diff --git a/src/server.ts b/src/server.ts index 52fe75a..c18941f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -9,7 +9,7 @@ import morgan from 'morgan'; import xmlparser from '@/middleware/xml-parser'; import { connect as connectCache } from '@/cache'; import { connect as connectDatabase } from '@/database'; -import { fullUrl } from '@/util'; +import { fullUrl, getValueFromHeaders } from '@/util'; import { LOG_INFO, LOG_SUCCESS, LOG_WARN } from '@/logger'; import conntest from '@/services/conntest'; @@ -49,7 +49,11 @@ app.use(assets); LOG_INFO('Creating 404 status handler'); app.use((request: express.Request, response: express.Response) => { const url: string = fullUrl(request); - const deviceId: string = request.headers['X-Nintendo-Device-ID'] as string || 'Unknown'; + let deviceId: string | undefined = getValueFromHeaders(request.headers, 'X-Nintendo-Device-ID'); + + if (!deviceId) { + deviceId = 'Unknown'; + } LOG_WARN(`HTTP 404 at ${url} from ${deviceId}`); @@ -66,7 +70,11 @@ LOG_INFO('Creating non-404 status handler'); app.use((error: any, request: express.Request, response: express.Response, _next: express.NextFunction) => { const status: number = error.status || 500; const url: string = fullUrl(request); - const deviceId: string = request.headers['X-Nintendo-Device-ID'] as string || 'Unknown'; + let deviceId: string | undefined = getValueFromHeaders(request.headers, 'X-Nintendo-Device-ID'); + + if (!deviceId) { + deviceId = 'Unknown'; + } LOG_WARN(`HTTP ${status} at ${url} from ${deviceId}: ${error.message}`); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index a7c6eb7..2db0fd6 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -1,13 +1,13 @@ import express from 'express'; import moment from 'moment'; import { PNID } from '@/models/pnid'; -import { sendEmailConfirmedEmail } from '@/util'; +import { getValueFromQueryString, sendEmailConfirmedEmail } from '@/util'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; const router: express.Router = express.Router(); router.get('/verify', async (request: express.Request, response: express.Response) => { - const token: string = request.query.token as string; + const token: string | undefined = getValueFromQueryString(request.query, 'token'); if (!token || token.trim() == '') { return response.status(400).json({ diff --git a/src/services/local-cdn/routes/get.ts b/src/services/local-cdn/routes/get.ts index ff18990..6c98b71 100644 --- a/src/services/local-cdn/routes/get.ts +++ b/src/services/local-cdn/routes/get.ts @@ -4,7 +4,7 @@ import { getLocalCDNFile } from '@/cache'; const router: express.Router = express.Router(); router.get('/*', async (request: express.Request, response: express.Response) => { - const filePath: string = request.params[0] as string; + const filePath: string = request.params[0]; const file: Buffer = await getLocalCDNFile(filePath); diff --git a/src/services/nnid/routes/admin.ts b/src/services/nnid/routes/admin.ts index 6a4437c..f1b63b4 100644 --- a/src/services/nnid/routes/admin.ts +++ b/src/services/nnid/routes/admin.ts @@ -1,5 +1,6 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; +import { getValueFromQueryString } from '@/util'; import { PNID } from '@/models/pnid'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -11,19 +12,26 @@ const router: express.Router = express.Router(); * Description: Maps between NNID usernames and PIDs */ router.get('/mapped_ids', async (request: express.Request, response: express.Response) => { - const inputType: string = request.query.input_type as string; - const outputType: string = request.query.output_type as string; - let inputList: string[]; + const inputType: string | undefined = getValueFromQueryString(request.query, 'input_type'); + const outputType: string | undefined = getValueFromQueryString(request.query, 'output_type'); + const input: string | undefined = getValueFromQueryString(request.query, 'input'); + + if (!inputType || !outputType || !input) { + return response.status(400).send(xmlbuilder.create({ + errors: { + error: { + cause: 'Bad Request', + code: '1600', + message: 'Unable to process request' + } + } + }).end()); + } + + let inputList: string[] = input.split(','); let queryInput: string; let queryOutput: string; - if (Array.isArray(request.query.input)) { - inputList = request.query.input as string[]; - } else { - const input = request.query.input as string; - inputList = input.split(','); - } - inputList = inputList.filter(input => input); // * Remove null inputs if (inputType === 'user_id') { diff --git a/src/services/nnid/routes/miis.ts b/src/services/nnid/routes/miis.ts index 368cb9e..4333e29 100644 --- a/src/services/nnid/routes/miis.ts +++ b/src/services/nnid/routes/miis.ts @@ -1,5 +1,6 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; +import { getValueFromQueryString } from '@/util'; import { PNID } from '@/models/pnid'; import { config } from '@/config-manager'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -13,15 +14,22 @@ const router: express.Router = express.Router(); * Description: Returns a list of NNID miis */ router.get('/', async (request: express.Request, response: express.Response) => { - let pids: number[]; + const input: string | undefined = getValueFromQueryString(request.query, 'pids'); - if (Array.isArray(request.query.pids)) { - pids = request.query.pids.map(pid => Number(pid)); - } else { - const input = request.query.pids as string; - pids = input.split(',').map(pid => Number(pid)); + if (!input) { + return response.status(400).send(xmlbuilder.create({ + errors: { + error: { + cause: 'Bad Request', + code: '1600', + message: 'Unable to process request' + } + } + }).end()); } + const pids: number[] = input.split(',').map(pid => Number(pid)); + const results: HydratedPNIDDocument[] = await PNID.where('pid', pids); const miis: { data: string; diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 3258375..c145759 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -7,7 +7,7 @@ import mongoose from 'mongoose'; import deviceCertificateMiddleware from '@/middleware/device-certificate'; import ratelimit from '@/middleware/ratelimit'; import { connection as databaseConnection, doesUserExist, getUserProfileJSONByPID } from '@/database'; -import { nintendoPasswordHash, sendConfirmationEmail } from '@/util'; +import { getValueFromHeaders, nintendoPasswordHash, sendConfirmationEmail } from '@/util'; import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; import { LOG_ERROR } from '@/logger'; @@ -292,12 +292,25 @@ router.get('/@me/devices', async (request: express.Request, response: express.Re response.set('X-Nintendo-Date', new Date().getTime().toString()); const pnid: HydratedPNIDDocument | null = request.pnid; - const deviceId: string = request.headers['x-nintendo-device-id'] as string; - const acceptLanguage: string = request.headers['accept-language'] as string; - const platformId: string = request.headers['x-nintendo-platform-id'] as string; - const region: string = request.headers['x-nintendo-region'] as string; - const serialNumber: string = request.headers['x-nintendo-serial-number'] as string; - const systemVersion: string = request.headers['x-nintendo-system-version'] as string; + const deviceId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-device-id'); + const acceptLanguage: string | undefined = getValueFromHeaders(request.headers, 'accept-language'); + const platformId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-platform-id'); + const region: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-region'); + const serialNumber: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-serial-number'); + const systemVersion: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-system-version'); + + if (!deviceId || !acceptLanguage || !platformId || !region || !serialNumber || !systemVersion) { + // TODO - Research these error more + return response.status(400).send(xmlbuilder.create({ + errors: { + error: { + cause: 'Bad Request', + code: '1600', + message: 'Unable to process request' + } + } + }).end()); + } if (!pnid) { // TODO - Research this error more diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index e2cfa4d..793739c 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -2,7 +2,7 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import fs from 'fs-extra'; import { getServerByTitleId, getServer } from '@/database'; -import { generateToken } from '@/util'; +import { generateToken, getValueFromHeaders, getValueFromQueryString } from '@/util'; import { getServicePublicKey, getServiceSecretKey, getNEXPublicKey, getNEXSecretKey } from '@/cache'; import { NEXAccount } from '@/models/nex-account'; import { CryptoOptions } from '@/types/common/crypto-options'; @@ -35,7 +35,20 @@ router.get('/service_token/@me', async (request: express.Request, response: expr }).end()); } - const titleId: string = request.headers['x-nintendo-title-id'] as string; + const titleId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-title-id'); + + if (!titleId) { + // TODO - Research this error more + return response.send(xmlbuilder.create({ + errors: { + error: { + code: '1021', + message: 'The requested game server was not found' + } + } + }).end()); + } + const serverAccessLevel: string = pnid.get('server_access_level'); const server: HydratedServerDocument | null = await getServerByTitleId(titleId, serverAccessLevel); @@ -121,7 +134,7 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. }).end()); } - const gameServerID: string = request.query.game_server_id as string; + const gameServerID: string | undefined = getValueFromQueryString(request.query, 'game_server_id'); if (!gameServerID) { return response.send(xmlbuilder.create({ @@ -152,7 +165,19 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. const ip: string = server.ip; const port: number = server.port; const device: number = server.device; - const titleId: string = request.headers['x-nintendo-title-id'] as string; + const titleId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-title-id'); + + if (!titleId) { + // TODO - Research this error more + return response.send(xmlbuilder.create({ + errors: { + error: { + code: '1021', + message: 'The requested game server was not found' + } + } + }).end()); + } const cryptoPath: string = `${__dirname}/../../../../certs/nex/${serverName}`; diff --git a/src/types/common/safe-qs.ts b/src/types/common/safe-qs.ts new file mode 100644 index 0000000..a17df29 --- /dev/null +++ b/src/types/common/safe-qs.ts @@ -0,0 +1,3 @@ +export interface SafeQs { + [key: string]: string | undefined +} \ No newline at end of file diff --git a/src/util.ts b/src/util.ts index 5a79d1f..d791840 100644 --- a/src/util.ts +++ b/src/util.ts @@ -5,6 +5,7 @@ import aws from 'aws-sdk'; import fs from 'fs-extra'; import express from 'express'; import mongoose from 'mongoose'; +import { ParsedQs } from 'qs'; import { sendMail } from '@/mailer'; import { getServiceAESKey, getServicePrivateKey, getServiceSecretKey, getServicePublicKey } from '@/cache'; import { config, disabledFeatures } from '@/config-manager'; @@ -13,6 +14,8 @@ import { TokenOptions } from '@/types/common/token-options'; import { Token } from '@/types/common/token'; import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; import { MailerOptions } from '@/types/common/mailer-options'; +import { SafeQs } from '@/types/common/safe-qs'; +import { IncomingHttpHeaders } from 'node:http'; let s3: aws.S3; @@ -320,4 +323,55 @@ export async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocumentproperty); + value = (property)[key]; + } else { + value = property; + } + } + + return value; +} + +export function getValueFromHeaders(headers: IncomingHttpHeaders, key: string): string | undefined { + let header: string | string[] | undefined = headers[key]; + let value: string | undefined; + + if (header) { + if (Array.isArray(header)) { + header = header[0]; + } + + value = header; + } + + return value; } \ No newline at end of file From 821ad69b4748f366ed343f97a1123ba3a64e468d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 11:59:44 -0400 Subject: [PATCH 49/65] Removed hard coded XML string responses --- src/server.ts | 12 +++- src/services/nnid/routes/people.ts | 88 +++++++++++++++++++++++----- src/services/nnid/routes/provider.ts | 11 +++- 3 files changed, 91 insertions(+), 20 deletions(-) diff --git a/src/server.ts b/src/server.ts index c18941f..1d9eac4 100644 --- a/src/server.ts +++ b/src/server.ts @@ -6,6 +6,7 @@ process.on('uncaughtException', (err, origin) => { import express from 'express'; import morgan from 'morgan'; +import xmlbuilder from 'xmlbuilder'; import xmlparser from '@/middleware/xml-parser'; import { connect as connectCache } from '@/cache'; import { connect as connectDatabase } from '@/database'; @@ -61,8 +62,15 @@ app.use((request: express.Request, response: express.Response) => { response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime().toString()); - response.status(404); - response.send('0008Not Found'); + response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); }); // non-404 error handler diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index c145759..770cec5 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -227,16 +227,30 @@ router.get('/@me/profile', async (request: express.Request, response: express.Re if (!pnid) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.get('pid')); if (!person) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } response.send(xmlbuilder.create({ @@ -264,16 +278,30 @@ router.post('/@me/devices', async (request: express.Request, response: express.R if (!pnid) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.get('pid')); if (!person) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } response.send(xmlbuilder.create({ @@ -314,8 +342,15 @@ router.get('/@me/devices', async (request: express.Request, response: express.Re if (!pnid) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } response.send(xmlbuilder.create({ @@ -353,16 +388,30 @@ router.get('/@me/devices/owner', async (request: express.Request, response: expr if (!pnid) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.get('pid')); if (!person) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } response.send(xmlbuilder.create({ @@ -396,8 +445,15 @@ router.put('/@me/miis/@primary', async (request: express.Request, response: expr if (!pnid) { // TODO - Research this error more - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } // TODO - Make this more strictly typed? diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 793739c..546463b 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -215,8 +215,15 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. }); if (!nexUser) { - response.status(404); - return response.send('0008Not Found'); + return response.status(404).send(xmlbuilder.create({ + errors: { + error: { + cause: '', + code: '0008', + message: 'Not Found' + } + } + }).end()); } let nexToken: string | null = await generateToken(cryptoOptions, tokenOptions); From 5b00bae36f50f1a6f42f68f3afaa486e77713858 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 13:27:28 -0400 Subject: [PATCH 50/65] Removed .get calls on documents --- src/database.ts | 67 +++++++++++---------- src/middleware/nasc.ts | 4 +- src/middleware/pnid.ts | 2 +- src/services/api/routes/v1/login.ts | 10 +-- src/services/api/routes/v1/register.ts | 10 +-- src/services/api/routes/v1/resetPassword.ts | 4 +- src/services/nasc/routes/ac.ts | 4 +- src/services/nnid/routes/oauth.ts | 6 +- src/services/nnid/routes/people.ts | 46 +++++++------- src/services/nnid/routes/provider.ts | 18 +++--- src/services/nnid/routes/support.ts | 2 +- src/types/services/nnid/pnid-profile.ts | 4 +- src/util.ts | 26 ++++---- 13 files changed, 102 insertions(+), 101 deletions(-) diff --git a/src/database.ts b/src/database.ts index 3406aab..09ca816 100644 --- a/src/database.ts +++ b/src/database.ts @@ -7,7 +7,8 @@ import { Server } from '@/models/server'; import { LOG_ERROR } from '@/logger'; import { config } from '@/config-manager'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; -import { HydratedDeviceDocument } from '@/types/mongoose/device'; +import { IDevice } from '@/types/mongoose/device'; +import { IDeviceAttribute } from '@/types/mongoose/device-attribute'; import { HydratedServerDocument } from '@/types/mongoose/server'; import { Token } from '@/types/common/token'; import { PNIDProfile } from '@/types/services/nnid/pnid-profile'; @@ -133,7 +134,7 @@ export async function getUserProfileJSONByPID(pid: number): Promise { + device_attributes = device.device_attributes.map((attribute: IDeviceAttribute) => { const name: string = attribute.name; const value: string = attribute.value; - const created_date: string = attribute.created_date; + const created_date: string | undefined = attribute.created_date; return { device_attribute: { @@ -160,50 +161,50 @@ export async function getUserProfileJSONByPID(pid: number): Promise { - await PNID.updateOne({ pid: pnid.get('pid') }, { + await PNID.updateOne({ pid: pnid.pid }, { $set: { 'connections.discord.id': '' } diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 301e6f4..ead3387 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -137,7 +137,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon await nexAccount.save({ session }); - pid = Number(nexAccount.get('pid')); + pid = nexAccount.pid; // Set password @@ -176,7 +176,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const nexUser: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ pid }); - if (!nexUser || nexUser.get('access_level') < 0) { + if (!nexUser || nexUser.access_level < 0) { response.status(200).send(nascError('102')); return; } diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index c1e0933..75471a1 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -55,7 +55,7 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon return; } - if (user.get('access_level') < 0) { + if (user.access_level < 0) { response.status(400).send(xmlbuilder.create({ errors: { error: { diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index 692f13d..ff36efa 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -67,7 +67,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const hashedPassword: string = nintendoPasswordHash(password, pnid.get('pid')); + const hashedPassword: string = nintendoPasswordHash(password, pnid.pid); if (!pnid || !bcrypt.compareSync(hashedPassword, pnid.password)) { return response.status(400).json({ @@ -110,8 +110,8 @@ router.post('/', async (request: express.Request, response: express.Response) => const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, - pid: pnid.get('pid'), - access_level: pnid.get('access_level'), + pid: pnid.pid, + access_level: pnid.access_level, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; @@ -119,8 +119,8 @@ router.post('/', async (request: express.Request, response: express.Response) => const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, - pid: pnid.get('pid'), - access_level: pnid.get('access_level'), + pid: pnid.pid, + access_level: pnid.access_level, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index ef6cda8..ca61d96 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -250,15 +250,15 @@ router.post('/', async (request: express.Request, response: express.Response) => // NN with a NNID will always use the NNID PID // even if the provided NEX PID is different // To fix this we make them the same PID - nexAccount.owning_pid = nexAccount.get('pid'); + nexAccount.owning_pid = nexAccount.pid; await nexAccount.save({ session }); - const primaryPasswordHash: string = nintendoPasswordHash(password, nexAccount.get('pid')); + const primaryPasswordHash: string = nintendoPasswordHash(password, nexAccount.pid); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid = new PNID({ - pid: nexAccount.get('pid'), + pid: nexAccount.pid, creation_date: creationDate, updated: creationDate, username: username, @@ -348,7 +348,7 @@ router.post('/', async (request: express.Request, response: express.Response) => const accessTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x1, // OAuth Access, - pid: pnid.get('pid'), + pid: pnid.pid, access_level: 0, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) @@ -357,7 +357,7 @@ router.post('/', async (request: express.Request, response: express.Response) => const refreshTokenOptions: TokenOptions = { system_type: 0xF, // API token_type: 0x2, // OAuth Refresh, - pid: pnid.get('pid'), + pid: pnid.pid, access_level: 0, title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 0a52acf..9b90138 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -82,7 +82,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - if (password.toLowerCase() === pnid.get('usernameLower')) { + if (password.toLowerCase() === pnid.usernameLower) { return response.status(400).json({ app: 'api', status: 400, @@ -114,7 +114,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const primaryPasswordHash: string = nintendoPasswordHash(password, pnid.get('pid')); + const primaryPasswordHash: string = nintendoPasswordHash(password, pnid.pid); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index a46fc04..ca1f9aa 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -47,7 +47,7 @@ async function processLoginRequest(request: express.Request): Promise): Promise { const options: MailerOptions = { - to: pnid.get('email.address'), + to: pnid.email.address, subject: '[Pretendo Network] Please confirm your email address', - username: pnid.get('username'), + username: pnid.username, confirmation: { - href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')}`, - code: pnid.get('identification.email_code') + href: `https://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token}`, + code: pnid.identification.email_code }, - text: `Hello ${pnid.get('username')}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.get('identification.email_token')} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.get('identification.email_code')}` + text: `Hello ${pnid.username}! \r\n\r\nYour Pretendo Network ID activation is almost complete. Please click the link to confirm your e-mail address and complete the activation process: \r\nhttps://api.pretendo.cc/v1/email/verify?token=${pnid.identification.email_token} \r\n\r\nYou may also enter the following 6-digit code on your console: ${pnid.identification.email_code}` }; await sendMail(options); @@ -278,11 +278,11 @@ export async function sendConfirmationEmail(pnid: mongoose.HydratedDocument): Promise { const options: MailerOptions = { - to: pnid.get('email.address'), + to: pnid.email.address, subject: '[Pretendo Network] Email address confirmed', - username: pnid.get('username'), + username: pnid.username, paragraph: 'your email address has been confirmed. We hope you have fun on Pretendo Network!', - text: `Dear ${pnid.get('username')}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` + text: `Dear ${pnid.username}, \r\n\r\nYour email address has been confirmed. We hope you have fun on Pretendo Network!` }; await sendMail(options); @@ -300,8 +300,8 @@ export async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument Date: Sun, 19 Mar 2023 13:36:01 -0400 Subject: [PATCH 51/65] Removed all .set calls from documents --- src/models/nex-account.ts | 4 ++-- src/models/pnid.ts | 18 +++++++++--------- src/services/api/routes/v1/email.ts | 6 +++--- src/services/nnid/routes/people.ts | 10 +++++----- src/services/nnid/routes/support.ts | 6 +++--- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/models/nex-account.ts b/src/models/nex-account.ts index cddd72b..c302c4b 100644 --- a/src/models/nex-account.ts +++ b/src/models/nex-account.ts @@ -48,7 +48,7 @@ NEXAccountSchema.method('generatePID', async function generatePID(): Promise('NEXAccount', NEXAccountSchema); \ No newline at end of file diff --git a/src/models/pnid.ts b/src/models/pnid.ts index dd09b8f..9fa984a 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -128,7 +128,7 @@ PNIDSchema.method('generatePID', async function generatePID(): Promise { if (inuse) { await this.generatePID(); } else { - this.set('pid', pid); + this.pid = pid; } }); @@ -137,7 +137,7 @@ PNIDSchema.method('generateEmailValidationCode', async function generateEmailVal // Does not actually need to be unique to all users const code: string = Math.random().toFixed(6).split('.')[1]; // Dirty one-liner to generate numbers of 6 length and padded 0 - this.set('identification.email_code', code); + this.identification.email_code = code; }); PNIDSchema.method('generateEmailValidationToken', async function generateEmailValidationToken(): Promise { @@ -150,17 +150,17 @@ PNIDSchema.method('generateEmailValidationToken', async function generateEmailVa if (inuse) { await this.generateEmailValidationToken(); } else { - this.set('identification.email_token', token); + this.identification.email_token = token; } }); PNIDSchema.method('updateMii', async function updateMii({name, primary, data}): Promise { - this.set('mii.name', name); - this.set('mii.primary', primary === 'Y'); - this.set('mii.data', data); - this.set('mii.hash', crypto.randomBytes(7).toString('hex')); - this.set('mii.id', crypto.randomBytes(4).readUInt32LE()); - this.set('mii.image_id', crypto.randomBytes(4).readUInt32LE()); + this.mii.name = name; + this.mii.primary = primary === 'Y'; + this.mii.data = data; + this.mii.hash = crypto.randomBytes(7).toString('hex'); + this.mii.id = crypto.randomBytes(4).readUInt32LE(); + this.mii.image_id = crypto.randomBytes(4).readUInt32LE(); await this.generateMiiImages(); diff --git a/src/services/api/routes/v1/email.ts b/src/services/api/routes/v1/email.ts index 2db0fd6..7a2efed 100644 --- a/src/services/api/routes/v1/email.ts +++ b/src/services/api/routes/v1/email.ts @@ -31,9 +31,9 @@ router.get('/verify', async (request: express.Request, response: express.Respons const validatedDate: string = moment().format('YYYY-MM-DDTHH:MM:SS'); - pnid.set('email.reachable', true); - pnid.set('email.validated', true); - pnid.set('email.validated_date', validatedDate); + pnid.email.reachable = true; + pnid.email.validated = true; + pnid.email.validated_date = validatedDate; await pnid.save(); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index bca1dde..6d5cc5d 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -656,11 +656,11 @@ router.put('/@me/emails/@primary', async (request: express.Request, response: ex } // TODO - Better email check - pnid.set('email.address', (email.get('address') || '').toLowerCase()); - pnid.set('email.reachable', false); - pnid.set('email.validated', false); - pnid.set('email.validated_date', ''); - pnid.set('email.id', crypto.randomBytes(4).readUInt32LE()); + pnid.email.address = (email.get('address') || '').toLowerCase(); + pnid.email.reachable = false; + pnid.email.validated = false; + pnid.email.validated_date = ''; + pnid.email.id = crypto.randomBytes(4).readUInt32LE(); await pnid.generateEmailValidationCode(); await pnid.generateEmailValidationToken(); diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index 583dee7..dfb8eec 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -82,9 +82,9 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re const validatedDate: string = moment().format('YYYY-MM-DDTHH:MM:SS'); - pnid.set('email.reachable', true); - pnid.set('email.validated', true); - pnid.set('email.validated_date', validatedDate); + pnid.email.reachable = true; + pnid.email.validated = true; + pnid.email.validated_date = validatedDate; await pnid.save(); From b89d3a15b091dbcd203bc6717fa2da2a33786575 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 13:42:08 -0400 Subject: [PATCH 52/65] Renamed user variables to better match their types --- src/database.ts | 80 ++++++++++++++-------------- src/middleware/api.ts | 4 +- src/middleware/nasc.ts | 6 +-- src/middleware/pnid.ts | 12 ++--- src/services/nasc/routes/ac.ts | 8 +-- src/services/nnid/routes/provider.ts | 8 +-- src/types/express.d.ts | 2 +- 7 files changed, 60 insertions(+), 60 deletions(-) diff --git a/src/database.ts b/src/database.ts index 09ca816..a73ced4 100644 --- a/src/database.ts +++ b/src/database.ts @@ -85,19 +85,19 @@ export async function getUserBasic(token: string): Promise { @@ -107,9 +107,9 @@ export async function getUserBearer(token: string): Promise expireTime) { @@ -117,7 +117,7 @@ export async function getUserBearer(token: string): Promise { verifyConnected(); - const user: HydratedPNIDDocument | null = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); - if (!user) { + if (!pnid) { return null; } - const device: IDevice = user.devices[0]; // * Just grab the first device + const device: IDevice = pnid.devices[0]; // * Just grab the first device let device_attributes: { device_attribute: { name: string; @@ -161,50 +161,50 @@ export async function getUserProfileJSONByPID(pid: number): Promise async function processLoginRequest(request: express.Request): Promise { const requestParams: NASCRequestParams = request.body; const titleID: string = nintendoBase64Decode(requestParams.titleid).toString(); - const nexUser: HydratedNEXAccountDocument | null = request.nexUser; + const nexAccount: HydratedNEXAccountDocument | null = request.nexAccount; - if (!nexUser) { + if (!nexAccount) { // TODO - Research this error more return nascError('null'); } @@ -47,7 +47,7 @@ async function processLoginRequest(request: express.Request): Promise; certificate?: NintendoCertificate; From f977d77c5ccfc4064425b22badcb1907fd8a73ac Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 13:46:29 -0400 Subject: [PATCH 53/65] Renamed user functions to PNID for clarity --- src/database.ts | 32 ++++++++++---------- src/middleware/api.ts | 4 +-- src/middleware/pnid.ts | 6 ++-- src/services/api/routes/v1/connections.ts | 6 ++-- src/services/api/routes/v1/forgotPassword.ts | 6 ++-- src/services/api/routes/v1/login.ts | 6 ++-- src/services/api/routes/v1/register.ts | 4 +-- src/services/nnid/routes/oauth.ts | 4 +-- src/services/nnid/routes/people.ts | 12 ++++---- src/services/nnid/routes/provider.ts | 4 +-- src/services/nnid/routes/support.ts | 8 ++--- 11 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/database.ts b/src/database.ts index a73ced4..33319c8 100644 --- a/src/database.ts +++ b/src/database.ts @@ -43,7 +43,7 @@ export function verifyConnected(): void { } } -export async function getUserByUsername(username: string): Promise { +export async function getPNIDByUsername(username: string): Promise { verifyConnected(); return await PNID.findOne({ @@ -51,7 +51,7 @@ export async function getUserByUsername(username: string): Promise { +export async function getPNIDByPID(pid: number): Promise { verifyConnected(); return await PNID.findOne({ @@ -59,7 +59,7 @@ export async function getUserByPID(pid: number): Promise { +export async function getPNIDByEmailAddress(email: string): Promise { verifyConnected(); // TODO - Update documents to store email normalized @@ -68,13 +68,13 @@ export async function getUserByEmailAddress(email: string): Promise { +export async function doesPNIDExist(username: string): Promise { verifyConnected(); - return !!await getUserByUsername(username); + return !!await getPNIDByUsername(username); } -export async function getUserBasic(token: string): Promise { +export async function getPNIDByBasicAuth(token: string): Promise { verifyConnected(); // * Wii U sends Basic auth as `username password`, where the password may not have spaces @@ -85,7 +85,7 @@ export async function getUserBasic(token: string): Promise { +export async function getPNIDByBearerAuth(token: string): Promise { verifyConnected(); try { const decryptedToken: Buffer = await decryptToken(Buffer.from(token, 'base64')); const unpackedToken: Token = unpackToken(decryptedToken); - const pnid: HydratedPNIDDocument | null = await getUserByPID(unpackedToken.pid); + const pnid: HydratedPNIDDocument | null = await getPNIDByPID(unpackedToken.pid); if (pnid) { const expireTime: number = Math.floor((Number(unpackedToken.expire_time) / 1000)); @@ -125,10 +125,10 @@ export async function getUserBearer(token: string): Promise { +export async function getPNIDProfileJSONByPID(pid: number): Promise { verifyConnected(); - const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getPNIDByPID(pid); if (!pnid) { return null; @@ -208,7 +208,7 @@ export async function getUserProfileJSONByPID(pid: number): Promise { +export async function getServerByGameServerId(gameServerId: string, accessMode: string): Promise { return await Server.findOne({ game_server_id: gameServerId, access_mode: accessMode @@ -222,13 +222,13 @@ export async function getServerByTitleId(titleId: string, accessMode: string): P }); } -export async function addUserConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { +export async function addPNIDConnection(pnid: HydratedPNIDDocument, data: ConnectionData, type: string): Promise { if (type === 'discord') { - return await addUserConnectionDiscord(pnid, data); + return await addPNIDConnectionDiscord(pnid, data); } } -export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { +export async function addPNIDConnectionDiscord(pnid: HydratedPNIDDocument, data: DiscordConnectionData): Promise { const valid: joi.ValidationResult = discordConnectionSchema.validate(data); if (valid.error) { @@ -251,7 +251,7 @@ export async function addUserConnectionDiscord(pnid: HydratedPNIDDocument, data: }; } -export async function removeUserConnection(pnid: HydratedPNIDDocument, type: string): Promise { +export async function removePNIDConnection(pnid: HydratedPNIDDocument, type: string): Promise { // * Add more connections later? if (type === 'discord') { return await removeUserConnectionDiscord(pnid); diff --git a/src/middleware/api.ts b/src/middleware/api.ts index c47af01..8645559 100644 --- a/src/middleware/api.ts +++ b/src/middleware/api.ts @@ -1,6 +1,6 @@ import express from 'express'; import { getValueFromHeaders } from '@/util'; -import { getUserBearer } from '@/database'; +import { getPNIDByBearerAuth } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise { @@ -11,7 +11,7 @@ async function APIMiddleware(request: express.Request, _response: express.Respon } const token: string = authHeader.split(' ')[1]; - const pnid: HydratedPNIDDocument | null = await getUserBearer(token); + const pnid: HydratedPNIDDocument | null = await getPNIDByBearerAuth(token); request.pnid = pnid; diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index d8b955d..3ab6d96 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -1,7 +1,7 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { getValueFromHeaders } from '@/util'; -import { getUserBasic, getUserBearer } from '@/database'; +import { getPNIDByBasicAuth, getPNIDByBearerAuth } from '@/database'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise { @@ -21,9 +21,9 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon } if (type === 'Basic') { - pnid = await getUserBasic(token); + pnid = await getPNIDByBasicAuth(token); } else { - pnid = await getUserBearer(token); + pnid = await getPNIDByBearerAuth(token); } if (!pnid) { diff --git a/src/services/api/routes/v1/connections.ts b/src/services/api/routes/v1/connections.ts index a828c2d..5bf79b4 100644 --- a/src/services/api/routes/v1/connections.ts +++ b/src/services/api/routes/v1/connections.ts @@ -1,5 +1,5 @@ import express from 'express'; -import { addUserConnection, removeUserConnection } from '@/database'; +import { addPNIDConnection, removePNIDConnection } from '@/database'; import { ConnectionData } from '@/types/services/api/connection-data'; import { ConnectionResponse } from '@/types/services/api/connection-response'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -44,7 +44,7 @@ router.post('/add/:type', async (request: express.Request, response: express.Res }); } - let result: ConnectionResponse | undefined = await addUserConnection(pnid, data, type); + let result: ConnectionResponse | undefined = await addPNIDConnection(pnid, data, type); if (!result) { result = { @@ -82,7 +82,7 @@ router.delete('/remove/:type', async (request: express.Request, response: expres }); } - let result: ConnectionResponse | undefined = await removeUserConnection(pnid, type); + let result: ConnectionResponse | undefined = await removePNIDConnection(pnid, type); if (!result) { result = { diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index bfc6d61..1cb3283 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -1,6 +1,6 @@ import express from 'express'; import validator from 'validator'; -import { getUserByEmailAddress, getUserByUsername } from '@/database'; +import { getPNIDByEmailAddress, getPNIDByUsername } from '@/database'; import { sendForgotPasswordEmail } from '@/util'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -20,9 +20,9 @@ router.post('/', async (request: express.Request, response: express.Response) => let pnid: HydratedPNIDDocument | null; if (validator.isEmail(input)) { - pnid = await getUserByEmailAddress(input); + pnid = await getPNIDByEmailAddress(input); } else { - pnid = await getUserByUsername(input); + pnid = await getPNIDByUsername(input); } if (pnid) { diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index ff36efa..61fcac9 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -1,7 +1,7 @@ import express from 'express'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import { getUserByUsername, getUserBearer } from '@/database'; +import { getPNIDByUsername, getPNIDByBearerAuth } from '@/database'; import { getServicePublicKey, getServiceSecretKey } from '@/cache'; import { nintendoPasswordHash, generateToken} from '@/util'; import { CryptoOptions } from '@/types/common/crypto-options'; @@ -57,7 +57,7 @@ router.post('/', async (request: express.Request, response: express.Response) => let pnid: HydratedPNIDDocument | null; if (grantType === 'password') { - pnid = await getUserByUsername(username); + pnid = await getPNIDByUsername(username); if (!pnid) { return response.status(400).json({ @@ -77,7 +77,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } } else { - pnid = await getUserBearer(refreshToken); + pnid = await getPNIDByBearerAuth(refreshToken); if (!pnid) { return response.status(400).json({ diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index ca61d96..2487ae2 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -8,7 +8,7 @@ import moment from 'moment'; import hcaptcha from 'hcaptcha'; import Mii from 'mii-js'; import mongoose from 'mongoose'; -import { doesUserExist, connection as databaseConnection } from '@/database'; +import { doesPNIDExist, connection as databaseConnection } from '@/database'; import { getServicePublicKey, getServiceSecretKey } from '@/cache'; import { nintendoPasswordHash, sendConfirmationEmail, generateToken } from '@/util'; import { LOG_ERROR } from '@/logger'; @@ -141,7 +141,7 @@ router.post('/', async (request: express.Request, response: express.Response) => }); } - const userExists: boolean = await doesUserExist(username); + const userExists: boolean = await doesPNIDExist(username); if (userExists) { return response.status(400).json({ diff --git a/src/services/nnid/routes/oauth.ts b/src/services/nnid/routes/oauth.ts index 559329b..867f93d 100644 --- a/src/services/nnid/routes/oauth.ts +++ b/src/services/nnid/routes/oauth.ts @@ -2,7 +2,7 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; import fs from 'fs-extra'; -import { getUserByUsername } from '@/database'; +import { getPNIDByUsername } from '@/database'; import { generateToken } from '@/util'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -52,7 +52,7 @@ router.post('/access_token/generate', async (request: express.Request, response: }).end()); } - const pnid: HydratedPNIDDocument | null = await getUserByUsername(username); + const pnid: HydratedPNIDDocument | null = await getPNIDByUsername(username); if (!pnid || !await bcrypt.compare(password, pnid.password)) { response.status(400); diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 6d5cc5d..8f48453 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -6,7 +6,7 @@ import moment from 'moment'; import mongoose from 'mongoose'; import deviceCertificateMiddleware from '@/middleware/device-certificate'; import ratelimit from '@/middleware/ratelimit'; -import { connection as databaseConnection, doesUserExist, getUserProfileJSONByPID } from '@/database'; +import { connection as databaseConnection, doesPNIDExist, getPNIDProfileJSONByPID } from '@/database'; import { getValueFromHeaders, nintendoPasswordHash, sendConfirmationEmail } from '@/util'; import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; @@ -31,7 +31,7 @@ const router: express.Router = express.Router(); router.get('/:username', async (request: express.Request, response: express.Response) => { const username: string = request.params.username; - const userExists: boolean = await doesUserExist(username); + const userExists: boolean = await doesPNIDExist(username); if (userExists) { response.status(400); @@ -72,7 +72,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express // * request.body is a Map, as is request.body.person const person: Person = request.body.get('person'); - const userExists: boolean = await doesUserExist(person.get('user_id')); + const userExists: boolean = await doesPNIDExist(person.get('user_id')); if (userExists) { response.status(400); @@ -238,7 +238,7 @@ router.get('/@me/profile', async (request: express.Request, response: express.Re }).end()); } - const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.pid); + const person: PNIDProfile | null = await getPNIDProfileJSONByPID(pnid.pid); if (!person) { // TODO - Research this error more @@ -289,7 +289,7 @@ router.post('/@me/devices', async (request: express.Request, response: express.R }).end()); } - const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.pid); + const person: PNIDProfile | null = await getPNIDProfileJSONByPID(pnid.pid); if (!person) { // TODO - Research this error more @@ -399,7 +399,7 @@ router.get('/@me/devices/owner', async (request: express.Request, response: expr }).end()); } - const person: PNIDProfile | null = await getUserProfileJSONByPID(pnid.pid); + const person: PNIDProfile | null = await getPNIDProfileJSONByPID(pnid.pid); if (!person) { // TODO - Research this error more diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 560380b..93633c7 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -1,7 +1,7 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import fs from 'fs-extra'; -import { getServerByTitleId, getServer } from '@/database'; +import { getServerByTitleId, getServerByGameServerId } from '@/database'; import { generateToken, getValueFromHeaders, getValueFromQueryString } from '@/util'; import { getServicePublicKey, getServiceSecretKey, getNEXPublicKey, getNEXSecretKey } from '@/cache'; import { NEXAccount } from '@/models/nex-account'; @@ -148,7 +148,7 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. } const serverAccessLevel: string = pnid.server_access_level; - const server: HydratedServerDocument | null = await getServer(gameServerID, serverAccessLevel); + const server: HydratedServerDocument | null = await getServerByGameServerId(gameServerID, serverAccessLevel); if (!server) { return response.send(xmlbuilder.create({ diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index dfb8eec..a8e4811 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -2,7 +2,7 @@ import dns from 'node:dns'; import express from 'express'; import xmlbuilder from 'xmlbuilder'; import moment from 'moment'; -import { getUserByPID } from '@/database'; +import { getPNIDByPID } from '@/database'; import { sendEmailConfirmedEmail, sendConfirmationEmail, sendForgotPasswordEmail } from '@/util'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -56,7 +56,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re const code: string = request.params.code; const pid: number = Number(request.params.pid); - const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getPNIDByPID(pid); if (!pnid) { return response.status(400).send(xmlbuilder.create({ @@ -101,7 +101,7 @@ router.put('/email_confirmation/:pid/:code', async (request: express.Request, re router.get('/resend_confirmation', async (request: express.Request, response: express.Response) => { const pid: number = Number(request.headers['x-nintendo-pid']); - const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getPNIDByPID(pid); if (!pnid) { // TODO - Unsure if this is the right error @@ -129,7 +129,7 @@ router.get('/resend_confirmation', async (request: express.Request, response: ex router.get('/forgotten_password/:pid', async (request: express.Request, response: express.Response) => { const pid: number = Number(request.params.pid); - const pnid: HydratedPNIDDocument | null = await getUserByPID(pid); + const pnid: HydratedPNIDDocument | null = await getPNIDByPID(pid); if (!pnid) { // TODO - Better errors From 39ccd942cb6a3dad737d7192bc2ad94c9806c499 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 16:21:30 -0400 Subject: [PATCH 54/65] Convert Maps to JSON objects on request body --- src/middleware/xml-parser.ts | 3 +- src/services/nnid/routes/miis.ts | 2 - src/services/nnid/routes/people.ts | 85 +++++++++++++++-------------- src/services/nnid/routes/support.ts | 2 +- src/types/services/nnid/person.ts | 4 +- src/util.ts | 4 ++ 6 files changed, 53 insertions(+), 47 deletions(-) diff --git a/src/middleware/xml-parser.ts b/src/middleware/xml-parser.ts index 31bb8b4..4f639d5 100644 --- a/src/middleware/xml-parser.ts +++ b/src/middleware/xml-parser.ts @@ -1,7 +1,7 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import { document as xmlParser } from 'xmlbuilder2'; -import { getValueFromHeaders } from '@/util'; +import { getValueFromHeaders, mapToObject } from '@/util'; function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void { if (request.method == 'POST' || request.method == 'PUT') { @@ -32,6 +32,7 @@ function XMLMiddleware(request: express.Request, response: express.Response, nex try { request.body = xmlParser(body); request.body = request.body.toObject(); + request.body = mapToObject(request.body); } catch (error) { response.status(401); diff --git a/src/services/nnid/routes/miis.ts b/src/services/nnid/routes/miis.ts index 4333e29..dd58978 100644 --- a/src/services/nnid/routes/miis.ts +++ b/src/services/nnid/routes/miis.ts @@ -121,8 +121,6 @@ router.get('/', async (request: express.Request, response: express.Response) => }); } - //console.log(results[0].mii.data.replace(/(\r\n|\n|\r)/gm, '')); - response.send(xmlbuilder.create({ miis: { mii: miis diff --git a/src/services/nnid/routes/people.ts b/src/services/nnid/routes/people.ts index 8f48453..a1c271e 100644 --- a/src/services/nnid/routes/people.ts +++ b/src/services/nnid/routes/people.ts @@ -69,10 +69,9 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express }).end()); } - // * request.body is a Map, as is request.body.person - const person: Person = request.body.get('person'); + const person: Person = request.body.person; - const userExists: boolean = await doesPNIDExist(person.get('user_id')); + const userExists: boolean = await doesPNIDExist(person.user_id); if (userExists) { response.status(400); @@ -111,12 +110,12 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express await nexAccount.save({ session }); - const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), nexAccount.pid); + const primaryPasswordHash: string = nintendoPasswordHash(person.password, nexAccount.pid); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); - const countryCode: string = person.get('country'); - const language: string = person.get('language'); - const timezoneName: string = person.get('tz_name'); + const countryCode: string = person.country; + const language: string = person.language; + const timezoneName: string = person.tz_name; const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones]; const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; @@ -137,30 +136,30 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express pid: nexAccount.pid, creation_date: creationDate, updated: creationDate, - username: person.get('user_id'), - usernameLower: person.get('user_id').toLowerCase(), + username: person.user_id, + usernameLower: person.user_id.toLowerCase(), password: passwordHash, - birthdate: person.get('birth_date'), - gender: person.get('gender'), + birthdate: person.birth_date, + gender: person.gender, country: countryCode, language: language, email: { - address: person.get('email').get('address').toLowerCase(), - primary: person.get('email').get('primary') === 'Y', - parent: person.get('email').get('parent') === 'Y', + address: person.email.address.toLowerCase(), + primary: person.email.primary === 'Y', + parent: person.email.parent === 'Y', reachable: false, - validated: person.get('email').get('validated') === 'Y', + validated: person.email.validated === 'Y', id: crypto.randomBytes(4).readUInt32LE() }, - region: person.get('region'), + region: person.region, timezone: { name: timezoneName, offset: Number(timezone.utc_offset) }, mii: { - name: person.get('mii').get('name'), - primary: person.get('mii').get('name') === 'Y', - data: person.get('mii').get('data'), + name: person.mii.name, + primary: person.mii.name === 'Y', + data: person.mii.data, id: crypto.randomBytes(4).readUInt32LE(), hash: crypto.randomBytes(7).toString('hex'), image_url: '', // deprecated, will be removed in the future @@ -168,8 +167,8 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express }, flags: { active: true, - marketing: person.get('marketing_flag') === 'Y', - off_device: person.get('off_device_flag') === 'Y' + marketing: person.marketing_flag === 'Y', + off_device: person.off_device_flag === 'Y' }, identification: { email_code: 1, // will be overwritten before saving @@ -456,14 +455,17 @@ router.put('/@me/miis/@primary', async (request: express.Request, response: expr }).end()); } - // TODO - Make this more strictly typed? - const mii: Map = request.body.get('mii'); + const mii: { + name: string; + primary: string; + data: string; + } = request.body.mii; // TODO - Better checks - const name: string | undefined = mii.get('name') || ''; - const primary: string | undefined = mii.get('primary') || ''; - const data: string | undefined = mii.get('data') || ''; + const name: string = mii.name; + const primary: string = mii.primary; + const data: string = mii.data; await pnid.updateMii({ name, primary, data }); @@ -531,7 +533,7 @@ router.put('/@me/deletion', async (request: express.Request, response: express.R */ router.put('/@me', async (request: express.Request, response: express.Response) => { const pnid: HydratedPNIDDocument | null = request.pnid; - const person: Person = request.body.get('person'); + const person: Person = request.body.person; if (!pnid) { response.status(400); @@ -547,13 +549,13 @@ router.put('/@me', async (request: express.Request, response: express.Response) }).end()); } - const gender: string = person.get('gender') ? person.get('gender') : pnid.gender; - const region: string = person.get('region') ? person.get('region') : pnid.region; - const countryCode: string = person.get('country') ? person.get('country') : pnid.country; - const language: string = person.get('language') ? person.get('language') : pnid.language; - const timezoneName: string = person.get('tz_name') ? person.get('tz_name') : pnid.timezone.name; - const marketingFlag: boolean = person.get('marketing_flag') ? person.get('marketing_flag') === 'Y' : pnid.flags.marketing; - const offDeviceFlag: boolean = person.get('off_device_flag') ? person.get('off_device_flag') === 'Y' : pnid.flags.off_device; + const gender: string = person.gender ? person.gender : pnid.gender; + const region: number = person.region ? person.region : pnid.region; + const countryCode: string = person.country ? person.country : pnid.country; + const language: string = person.language ? person.language : pnid.language; + const timezoneName: string = person.tz_name ? person.tz_name : pnid.timezone.name; + const marketingFlag: boolean = person.marketing_flag ? person.marketing_flag === 'Y' : pnid.flags.marketing; + const offDeviceFlag: boolean = person.off_device_flag ? person.off_device_flag === 'Y' : pnid.flags.off_device; const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones]; const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0]; @@ -570,15 +572,15 @@ router.put('/@me', async (request: express.Request, response: express.Response) }; } - if (person.get('password')) { - const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), pnid.pid); + if (person.password) { + const primaryPasswordHash: string = nintendoPasswordHash(person.password, pnid.pid); const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10); pnid.password = passwordHash; } pnid.gender = gender; - pnid.region = Number(region); + pnid.region = region; pnid.timezone.name = timezoneName; pnid.timezone.offset = Number(timezone.utc_offset); pnid.timezone.marketing = marketingFlag; @@ -638,10 +640,11 @@ router.get('/@me/emails', async (request: express.Request, response: express.Res router.put('/@me/emails/@primary', async (request: express.Request, response: express.Response) => { const pnid: HydratedPNIDDocument | null = request.pnid; - // TODO - Make this more strictly typed? - const email: Map = request.body.get('email'); + const email: { + address: string; + } = request.body.email; - if (!pnid || !email) { + if (!pnid || !email || !email.address) { response.status(400); return response.end(xmlbuilder.create({ @@ -656,7 +659,7 @@ router.put('/@me/emails/@primary', async (request: express.Request, response: ex } // TODO - Better email check - pnid.email.address = (email.get('address') || '').toLowerCase(); + pnid.email.address = email.address.toLowerCase(); pnid.email.reachable = false; pnid.email.validated = false; pnid.email.validated_date = ''; diff --git a/src/services/nnid/routes/support.ts b/src/services/nnid/routes/support.ts index a8e4811..be795d6 100644 --- a/src/services/nnid/routes/support.ts +++ b/src/services/nnid/routes/support.ts @@ -14,7 +14,7 @@ const router: express.Router = express.Router(); * Description: Verifies a provided email address is valid */ router.post('/validate/email', async (request: express.Request, response: express.Response) => { - const email: string = request.body; + const email: string = request.body.email; if (!email) { return response.send(xmlbuilder.create({ diff --git a/src/types/services/nnid/person.ts b/src/types/services/nnid/person.ts index 9da3757..00958e5 100644 --- a/src/types/services/nnid/person.ts +++ b/src/types/services/nnid/person.ts @@ -2,7 +2,7 @@ import { YesNoBoolString } from '@/types/common/yes-no-bool-string'; import { IDeviceAttribute } from '@/types/mongoose/device-attribute'; // TODO - Change this Map type to something more strongly typed -export interface Person extends Map { +export interface Person { birth_date: string; user_id: string; password: string; @@ -35,7 +35,7 @@ export interface Person extends Map { approval_id: string; }; gender: string; - region: string; + region: number; marketing_flag: YesNoBoolString; device_attributes: { device_attribute: IDeviceAttribute[] diff --git a/src/util.ts b/src/util.ts index 32db6da..d43d14a 100644 --- a/src/util.ts +++ b/src/util.ts @@ -374,4 +374,8 @@ export function getValueFromHeaders(headers: IncomingHttpHeaders, key: string): } return value; +} + +export function mapToObject(map: Map): object { + return Object.fromEntries(Array.from(map.entries(), ([ k, v ]) => v instanceof Map ? [ k, mapToObject(v) ] : [ k, v ])); } \ No newline at end of file From 77348791303a3ec47b98495375242479c3c8486d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sun, 19 Mar 2023 16:34:14 -0400 Subject: [PATCH 55/65] Fixed email secure boolean check/conversion --- src/config-manager.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/config-manager.ts b/src/config-manager.ts index 9f98cc8..9dc36e5 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -21,6 +21,13 @@ if (process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH) { mongooseConnectOptions = fs.readJSONSync(process.env.PN_ACT_CONFIG_MONGOOSE_CONNECT_OPTIONS_PATH); } +if (process.env.PN_ACT_CONFIG_EMAIL_SECURE) { + if (process.env.PN_ACT_CONFIG_EMAIL_SECURE !== 'true' && process.env.PN_ACT_CONFIG_EMAIL_SECURE !== 'false') { + LOG_ERROR(`PN_ACT_CONFIG_EMAIL_SECURE must be either true or false, got ${process.env.PN_ACT_CONFIG_EMAIL_SECURE}`); + process.exit(0); + } +} + export const config: Config = { http: { port: Number(process.env.PN_ACT_CONFIG_HTTP_PORT || '') @@ -37,7 +44,7 @@ export const config: Config = { email: { host: process.env.PN_ACT_CONFIG_EMAIL_HOST || '', port: Number(process.env.PN_ACT_CONFIG_EMAIL_PORT || ''), - secure: Boolean(process.env.PN_ACT_CONFIG_EMAIL_SECURE || ''), + secure: (process.env.PN_ACT_CONFIG_EMAIL_SECURE || '') === 'true', auth: { user: process.env.PN_ACT_CONFIG_EMAIL_USERNAME || '', pass: process.env.PN_ACT_CONFIG_EMAIL_PASSWORD || '' From 00b1aecd70398fae2b29408825e67bfbbb3b9ec7 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 30 Mar 2023 10:22:31 -0400 Subject: [PATCH 56/65] Fixed token generation for production users --- src/database.ts | 4 ++-- src/util.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/database.ts b/src/database.ts index 33319c8..09ef40d 100644 --- a/src/database.ts +++ b/src/database.ts @@ -254,11 +254,11 @@ export async function addPNIDConnectionDiscord(pnid: HydratedPNIDDocument, data: export async function removePNIDConnection(pnid: HydratedPNIDDocument, type: string): Promise { // * Add more connections later? if (type === 'discord') { - return await removeUserConnectionDiscord(pnid); + return await removePNIDConnectionDiscord(pnid); } } -export async function removeUserConnectionDiscord(pnid: HydratedPNIDDocument): Promise { +export async function removePNIDConnectionDiscord(pnid: HydratedPNIDDocument): Promise { await PNID.updateOne({ pid: pnid.pid }, { $set: { 'connections.discord.id': '' diff --git a/src/util.ts b/src/util.ts index d43d14a..16b1b08 100644 --- a/src/util.ts +++ b/src/util.ts @@ -70,7 +70,7 @@ export async function generateToken(cryptoOptions: CryptoOptions | null, tokenOp encryptedBody = Buffer.concat([encryptedBody, cipher.final()]); return encryptedBody.toString('base64'); - } else if (!tokenOptions.access_level || !tokenOptions.title_id) { + } else if (tokenOptions.access_level === undefined || tokenOptions.title_id === undefined) { return null; } From 2b53c5d5a064220d57d0ae09427f3a1c88e9e8fc Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 31 Mar 2023 12:09:12 -0400 Subject: [PATCH 57/65] Fixed 3DS cert not being verified correctly --- src/nintendo-certificate.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nintendo-certificate.ts b/src/nintendo-certificate.ts index 4cc3105..a371c8f 100644 --- a/src/nintendo-certificate.ts +++ b/src/nintendo-certificate.ts @@ -103,7 +103,6 @@ class NintendoCertificate { } this._parseCertificateData(); - this._verifySignature(); } } @@ -128,6 +127,8 @@ class NintendoCertificate { this.certificateName = this._certificate.subarray(0xC4, 0x104).toString().split('\0')[0]; this.ngKeyId = this._certificate.readUInt32BE(0x104); this.publicKeyData = this._certificate.subarray(0x108); + + this._verifySignature(); } } From b8f1486fbf253c46425104c09036b68b5793d8f9 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 31 Mar 2023 12:11:36 -0400 Subject: [PATCH 58/65] Fixed NASC errors not being sent correctly in middleware --- src/middleware/nasc.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index f30ca45..5b4da42 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -21,7 +21,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon !requestParams.titleid || !requestParams.servertype ) { - response.status(200).send(nascError('null')); // This is what Nintendo sends + response.status(200).send(nascError('null').toString()); // This is what Nintendo sends return; } @@ -52,19 +52,19 @@ async function NASCMiddleware(request: express.Request, response: express.Respon } if (action !== 'LOGIN' && action !== 'SVCLOC') { - response.status(200).send(nascError('null')); // This is what Nintendo sends + response.status(200).send(nascError('null').toString()); // This is what Nintendo sends return; } const cert: NintendoCertificate = new NintendoCertificate(fcdcert); if (!cert.valid) { - response.status(200).send(nascError('121')); + response.status(200).send(nascError('121').toString()); return; } if (!validNintendoMACAddress(macAddress)) { - response.status(200).send(nascError('null')); + response.status(200).send(nascError('null').toString()); return; } @@ -91,7 +91,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon } if (!model) { - response.status(200).send(nascError('null')); + response.status(200).send(nascError('null').toString()); return; } @@ -105,7 +105,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon if (device) { if (device.get('access_level') < 0) { - response.status(200).send(nascError('102')); + response.status(200).send(nascError('102').toString()); return; } @@ -113,7 +113,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const linkedPIDs = device.get('linked_pids'); if (!linkedPIDs.includes(pid)) { - response.status(200).send(nascError('102')); + response.status(200).send(nascError('102').toString()); return; } } @@ -164,7 +164,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon await session.abortTransaction(); // 3DS expects 200 even on error - response.status(200).send(nascError('102')); + response.status(200).send(nascError('102').toString()); return; } finally { // * This runs regardless of failure @@ -177,7 +177,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon const nexAccount: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ pid }); if (!nexAccount || nexAccount.access_level < 0) { - response.status(200).send(nascError('102')); + response.status(200).send(nascError('102').toString()); return; } From 2e0bb207a9f03587ec22cf6f350e69e32c2ee060 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 31 Mar 2023 16:15:36 -0400 Subject: [PATCH 59/65] Fixed bug where 0.0.0.0:0 NEX addresses were seen as invalid --- src/services/nasc/routes/ac.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index 25147c8..d00fae2 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -52,7 +52,13 @@ async function processLoginRequest(request: express.Request): Promise Date: Sat, 1 Apr 2023 11:15:59 -0400 Subject: [PATCH 60/65] Changed token format to be much smaller (thanks 3DS) --- src/cache.ts | 130 ------------- src/config-manager.ts | 8 +- src/database.ts | 2 +- src/models/server.ts | 19 +- src/services/api/routes/v1/login.ts | 42 +--- src/services/api/routes/v1/register.ts | 41 +--- src/services/api/routes/v1/resetPassword.ts | 3 +- src/services/nasc/routes/ac.ts | 85 ++++---- src/services/nnid/routes/oauth.ts | 36 +--- src/services/nnid/routes/provider.ts | 182 ++++++----------- src/types/common/config.ts | 1 + src/types/common/crypto-options.ts | 4 - src/types/mongoose/server.ts | 19 +- src/util.ts | 205 ++++---------------- 14 files changed, 203 insertions(+), 574 deletions(-) delete mode 100644 src/types/common/crypto-options.ts diff --git a/src/cache.ts b/src/cache.ts index 912f78c..593554b 100644 --- a/src/cache.ts +++ b/src/cache.ts @@ -6,8 +6,6 @@ let client: redis.RedisClientType; const memoryCache: { [key: string]: Buffer } = {}; -const SERVICE_CERTS_BASE: string = `${__dirname}/../certs/service`; -const NEX_CERTS_BASE: string = `${__dirname}/../certs/nex`; const LOCAL_CDN_BASE: string = `${__dirname}/../cdn`; export async function connect(): Promise { @@ -42,134 +40,6 @@ export async function getCachedFile(fileName: string, encoding?: BufferEncoding) return cachedFile; } -// * NEX server cache functions - -export async function getNEXPublicKey(name: string, encoding?: BufferEncoding): Promise { - let publicKey: Buffer = await getCachedFile(`nex:${name}:public_key`, encoding); - - if (publicKey === null) { - publicKey = await fs.readFile(`${NEX_CERTS_BASE}/${name}/public.pem`); - await setNEXPublicKey(name, publicKey); - } - - return publicKey; -} - -export async function getNEXPrivateKey(name: string, encoding?: BufferEncoding): Promise { - let privateKey: Buffer = await getCachedFile(`nex:${name}:private_key`, encoding); - - if (privateKey === null) { - privateKey = await fs.readFile(`${NEX_CERTS_BASE}/${name}/private.pem`); - await setNEXPrivateKey(name, privateKey); - } - - return privateKey; -} - -export async function getNEXSecretKey(name: string, encoding?: BufferEncoding): Promise { - let secretKey: Buffer = await getCachedFile(`nex:${name}:secret_key`, encoding); - - if (secretKey === null) { - const fileBuffer: string = await fs.readFile(`${NEX_CERTS_BASE}/${name}/secret.key`, { encoding: 'utf8' }); - secretKey = Buffer.from(fileBuffer, encoding); - await setNEXSecretKey(name, secretKey); - } - - return secretKey; -} - -export async function getNEXAESKey(name: string, encoding?: BufferEncoding): Promise { - let aesKey: Buffer = await getCachedFile(`nex:${name}:aes_key`, encoding); - - if (aesKey === null) { - const fileBuffer: string = await fs.readFile(`${NEX_CERTS_BASE}/${name}/aes.key`, { encoding: 'utf8' }); - aesKey = Buffer.from(fileBuffer, encoding); - await setNEXAESKey(name, aesKey); - } - - return aesKey; -} - -export async function setNEXPublicKey(name: string, value: Buffer): Promise { - await setCachedFile(`nex:${name}:public_key`, value); -} - -export async function setNEXPrivateKey(name: string, value: Buffer): Promise { - await setCachedFile(`nex:${name}:private_key`, value); -} - -export async function setNEXSecretKey(name: string, value: Buffer): Promise { - await setCachedFile(`nex:${name}:secret_key`, value); -} - -export async function setNEXAESKey(name: string, value: Buffer): Promise { - await setCachedFile(`nex:${name}:aes_key`, value); -} - -// * 3rd party service cache functions - -export async function getServicePublicKey(name: string, encoding?: BufferEncoding): Promise { - let publicKey: Buffer = await getCachedFile(`service:${name}:public_key`, encoding); - - if (publicKey === null) { - publicKey = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/public.pem`); - await setServicePublicKey(name, publicKey); - } - - return publicKey; -} - -export async function getServicePrivateKey(name: string, encoding?: BufferEncoding): Promise { - let privateKey: Buffer = await getCachedFile(`service:${name}:private_key`, encoding); - - if (privateKey === null) { - privateKey = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/private.pem`); - await setServicePrivateKey(name, privateKey); - } - - return privateKey; -} - -export async function getServiceSecretKey(name: string, encoding?: BufferEncoding): Promise { - let secretKey: Buffer = await getCachedFile(`service:${name}:secret_key`, encoding); - - if (secretKey === null) { - const fileBuffer: string = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/secret.key`, { encoding: 'utf8' }); - secretKey = Buffer.from(fileBuffer, encoding); - await setServiceSecretKey(name, secretKey); - } - - return secretKey; -} - -export async function getServiceAESKey(name: string, encoding?: BufferEncoding): Promise { - let aesKey: Buffer = await getCachedFile(`service:${name}:aes_key`, encoding); - - if (aesKey === null) { - const fileBuffer: string = await fs.readFile(`${SERVICE_CERTS_BASE}/${name}/aes.key`, { encoding: 'utf8' }); - aesKey = Buffer.from(fileBuffer, encoding); - await setServiceAESKey(name, aesKey); - } - - return aesKey; -} - -export async function setServicePublicKey(name: string, value: Buffer): Promise { - await setCachedFile(`service:${name}:public_key`, value); -} - -export async function setServicePrivateKey(name: string, value: Buffer): Promise { - await setCachedFile(`service:${name}:private_key`, value); -} - -export async function setServiceSecretKey(name: string, value: Buffer): Promise { - await setCachedFile(`service:${name}:secret_key`, value); -} - -export async function setServiceAESKey(name: string, value: Buffer): Promise { - await setCachedFile(`service:${name}:aes_key`, value); -} - // * Local CDN cache functions export async function getLocalCDNFile(name: string, encoding?: BufferEncoding): Promise { diff --git a/src/config-manager.ts b/src/config-manager.ts index 9dc36e5..23c9f84 100644 --- a/src/config-manager.ts +++ b/src/config-manager.ts @@ -64,7 +64,8 @@ export const config: Config = { disk_path: process.env.PN_ACT_CONFIG_CDN_DISK_PATH || '', base_url: process.env.PN_ACT_CONFIG_CDN_BASE_URL || '' }, - website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE || '' + website_base: process.env.PN_ACT_CONFIG_WEBSITE_BASE || '', + aes_key: process.env.PN_ACT_CONFIG_AES_KEY || '' }; LOG_INFO('Config loaded, checking integrity'); @@ -162,4 +163,9 @@ if (disabledFeatures.s3) { if (disabledFeatures.redis) { LOG_WARN('Both s3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable s3 if you\'re running a production server.'); } +} + +if (!config.aes_key) { + LOG_ERROR('Token AES key is not set. Set the PN_ACT_CONFIG_AES_KEY environment variable to your AES-256-CBC key'); + process.exit(0); } \ No newline at end of file diff --git a/src/database.ts b/src/database.ts index 09ef40d..e7f7748 100644 --- a/src/database.ts +++ b/src/database.ts @@ -104,7 +104,7 @@ export async function getPNIDByBearerAuth(token: string): Promise({ - ip: String, // Example: 1.1.1.1 - port: Number, // Example: 60000 - service_name: String, // Example: friends - service_type: String, // Example: nex - game_server_id: String, // Example: 00003200 - title_ids: [String], // Example: ["000500001018DB00", "000500001018DC00", "000500001018DD00"] - access_mode: String, // Example: prod - maintenance_mode: Boolean, // Example: false - device: Number, // Example: 1 (WiiU) + ip: String, + port: Number, + service_name: String, + service_type: String, + game_server_id: String, + title_ids: [String], + access_mode: String, + maintenance_mode: Boolean, + device: Number, + aes_key: String }); ServerSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' }); diff --git a/src/services/api/routes/v1/login.ts b/src/services/api/routes/v1/login.ts index 61fcac9..400b3fe 100644 --- a/src/services/api/routes/v1/login.ts +++ b/src/services/api/routes/v1/login.ts @@ -1,10 +1,8 @@ import express from 'express'; import bcrypt from 'bcrypt'; -import fs from 'fs-extra'; import { getPNIDByUsername, getPNIDByBearerAuth } from '@/database'; -import { getServicePublicKey, getServiceSecretKey } from '@/cache'; import { nintendoPasswordHash, generateToken} from '@/util'; -import { CryptoOptions } from '@/types/common/crypto-options'; +import { config } from '@/config-manager'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -88,45 +86,25 @@ router.post('/', async (request: express.Request, response: express.Response) => } } - const cryptoPath: string = `${__dirname}/../../../../../certs/service/account`; - - if (!await fs.pathExists(cryptoPath)) { - // Need to generate keys - return response.status(500).json({ - app: 'api', - status: 500, - error: 'Failed to locate crypto keys. Please contact an administrator' - }); - } - - const publicKey: Buffer = await getServicePublicKey('account'); - const secretKey: Buffer = await getServiceSecretKey('account'); - - const cryptoOptions: CryptoOptions = { - public_key: publicKey, - hmac_secret: secretKey - }; - const accessTokenOptions: TokenOptions = { - system_type: 0xF, // API - token_type: 0x1, // OAuth Access, + system_type: 0x1, // * WiiU + token_type: 0x1, // * OAuth Access pid: pnid.pid, - access_level: pnid.access_level, - title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; const refreshTokenOptions: TokenOptions = { - system_type: 0xF, // API - token_type: 0x2, // OAuth Refresh, + system_type: 0x1, // * WiiU + token_type: 0x2, // * OAuth Refresh pid: pnid.pid, - access_level: pnid.access_level, - title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken: string | null = await generateToken(cryptoOptions, accessTokenOptions); - const newRefreshToken: string | null = await generateToken(cryptoOptions, refreshTokenOptions); + const accessTokenBuffer: Buffer | null = await generateToken(config.aes_key, accessTokenOptions); + const refreshTokenBuffer: Buffer | null = await generateToken(config.aes_key, refreshTokenOptions); + + const accessToken: string = accessTokenBuffer ? accessTokenBuffer.toString('hex') : ''; + const newRefreshToken: string = refreshTokenBuffer ? refreshTokenBuffer.toString('hex') : ''; // TODO - Handle null tokens diff --git a/src/services/api/routes/v1/register.ts b/src/services/api/routes/v1/register.ts index 2487ae2..25d30ca 100644 --- a/src/services/api/routes/v1/register.ts +++ b/src/services/api/routes/v1/register.ts @@ -3,19 +3,16 @@ import crypto from 'node:crypto'; import express from 'express'; import emailvalidator from 'email-validator'; import bcrypt from 'bcrypt'; -import fs from 'fs-extra'; import moment from 'moment'; import hcaptcha from 'hcaptcha'; import Mii from 'mii-js'; import mongoose from 'mongoose'; import { doesPNIDExist, connection as databaseConnection } from '@/database'; -import { getServicePublicKey, getServiceSecretKey } from '@/cache'; import { nintendoPasswordHash, sendConfirmationEmail, generateToken } from '@/util'; import { LOG_ERROR } from '@/logger'; import { PNID } from '@/models/pnid'; import { NEXAccount } from '@/models/nex-account'; import { config, disabledFeatures } from '@/config-manager'; -import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -326,45 +323,25 @@ router.post('/', async (request: express.Request, response: express.Response) => await sendConfirmationEmail(pnid); - const cryptoPath: string = `${__dirname}/../../../../../certs/service/account`; - - if (!await fs.pathExists(cryptoPath)) { - // Need to generate keys - return response.status(500).json({ - app: 'api', - status: 500, - error: 'Failed to locate crypto keys. Please contact an administrator' - }); - } - - const publicKey: Buffer = await getServicePublicKey('account'); - const secretKey: Buffer = await getServiceSecretKey('account'); - - const cryptoOptions: CryptoOptions = { - public_key: publicKey, - hmac_secret: secretKey - }; - const accessTokenOptions: TokenOptions = { - system_type: 0xF, // API - token_type: 0x1, // OAuth Access, + system_type: 0x1, // * WiiU + token_type: 0x1, // * OAuth Access pid: pnid.pid, - access_level: 0, - title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; const refreshTokenOptions: TokenOptions = { - system_type: 0xF, // API - token_type: 0x2, // OAuth Refresh, + system_type: 0x1, // * WiiU + token_type: 0x2, // * OAuth Refresh pid: pnid.pid, - access_level: 0, - title_id: BigInt(0), expire_time: BigInt(Date.now() + (3600 * 1000)) }; - const accessToken: string | null = await generateToken(cryptoOptions, accessTokenOptions); - const refreshToken: string | null = await generateToken(cryptoOptions, refreshTokenOptions); + const accessTokenBuffer: Buffer | null = await generateToken(config.aes_key, accessTokenOptions); + const refreshTokenBuffer: Buffer | null = await generateToken(config.aes_key, refreshTokenOptions); + + const accessToken: string = accessTokenBuffer ? accessTokenBuffer.toString('hex') : ''; + const refreshToken: string = refreshTokenBuffer ? refreshTokenBuffer.toString('hex') : ''; // TODO - Handle null tokens diff --git a/src/services/api/routes/v1/resetPassword.ts b/src/services/api/routes/v1/resetPassword.ts index 9b90138..266e887 100644 --- a/src/services/api/routes/v1/resetPassword.ts +++ b/src/services/api/routes/v1/resetPassword.ts @@ -2,6 +2,7 @@ import express from 'express'; import bcrypt from 'bcrypt'; import { PNID } from '@/models/pnid'; import { decryptToken, unpackToken, nintendoPasswordHash } from '@/util'; +import { config } from '@/config-manager'; import { Token } from '@/types/common/token'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -28,7 +29,7 @@ router.post('/', async (request: express.Request, response: express.Response) => let unpackedToken: Token; try { - const decryptedToken: Buffer = await decryptToken(Buffer.from(token, 'base64')); + const decryptedToken: Buffer = await decryptToken(config.aes_key, Buffer.from(token, 'base64')); unpackedToken = unpackToken(decryptedToken); } catch (error) { console.log(error); diff --git a/src/services/nasc/routes/ac.ts b/src/services/nasc/routes/ac.ts index d00fae2..cd688d3 100644 --- a/src/services/nasc/routes/ac.ts +++ b/src/services/nasc/routes/ac.ts @@ -1,8 +1,6 @@ import express from 'express'; import { nintendoBase64Encode, nintendoBase64Decode, nascError, generateToken } from '@/util'; import { getServerByTitleId } from '@/database'; -import { getNEXPublicKey, getNEXSecretKey } from '@/cache'; -import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; import { NASCRequestParams } from '@/types/services/nasc/request-params'; import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account'; @@ -18,33 +16,17 @@ const router: express.Router = express.Router(); router.post('/', async (request: express.Request, response: express.Response) => { const requestParams: NASCRequestParams = request.body; const action: string = nintendoBase64Decode(requestParams.action).toString(); - let responseData: URLSearchParams = nascError('null'); - - switch (action) { - case 'LOGIN': - responseData = await processLoginRequest(request); - break; - case 'SVCLOC': - responseData = await processServiceTokenRequest(request); - break; - } - - response.status(200).send(responseData.toString()); -}); - -async function processLoginRequest(request: express.Request): Promise { - const requestParams: NASCRequestParams = request.body; const titleID: string = nintendoBase64Decode(requestParams.titleid).toString(); const nexAccount: HydratedNEXAccountDocument | null = request.nexAccount; + let responseData: URLSearchParams = nascError('null'); if (!nexAccount) { - // TODO - Research this error more - return nascError('null'); + return response.status(200).send(responseData.toString()); } // TODO: REMOVE AFTER PUBLIC LAUNCH - // LET EVERYONE IN THE `test` FRIENDS SERVER - // THAT WAY EVERYONE CAN GET AN ASSIGNED PID + // * LET EVERYONE IN THE `test` FRIENDS SERVER + // * THAT WAY EVERYONE CAN GET AN ASSIGNED PID let serverAccessLevel: string = 'test'; if (titleID !== '0004013000003202') { serverAccessLevel = nexAccount.server_access_level; @@ -52,32 +34,33 @@ async function processLoginRequest(request: express.Request): Promise { const tokenOptions: TokenOptions = { - system_type: 0x2, // 3DS - token_type: 0x3, // nex token, - pid: nexAccount.pid, + system_type: 0x2, // * 3DS + token_type: 0x3, // * NEX token + pid: pid, access_level: 0, title_id: BigInt(parseInt(titleID, 16)), expire_time: BigInt(Date.now() + (3600 * 1000)) @@ -85,11 +68,11 @@ async function processLoginRequest(request: express.Request): Promise { +async function processServiceTokenRequest(server: HydratedServerDocument, pid: number, titleID: string): Promise { + const tokenOptions: TokenOptions = { + system_type: 0x2, // * 3DS + token_type: 0x4, // * Service token + pid: pid, + access_level: 0, + title_id: BigInt(parseInt(titleID, 16)), + expire_time: BigInt(Date.now() + (3600 * 1000)) + }; + + // TODO - Handle null tokens + + const serviceTokenBuffer: Buffer | null = await generateToken(server.aes_key, tokenOptions); + const serviceToken: string = nintendoBase64Encode(serviceTokenBuffer || ''); + return new URLSearchParams({ retry: nintendoBase64Encode('0'), returncd: nintendoBase64Encode('007'), - servicetoken: nintendoBase64Encode(Buffer.alloc(64).toString()), // hard coded for now + servicetoken: serviceToken, statusdata: nintendoBase64Encode('Y'), svchost: nintendoBase64Encode('n/a'), datetime: nintendoBase64Encode(Date.now().toString()), diff --git a/src/services/nnid/routes/oauth.ts b/src/services/nnid/routes/oauth.ts index 867f93d..c276b9f 100644 --- a/src/services/nnid/routes/oauth.ts +++ b/src/services/nnid/routes/oauth.ts @@ -1,9 +1,9 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; import bcrypt from 'bcrypt'; -import fs from 'fs-extra'; import { getPNIDByUsername } from '@/database'; import { generateToken } from '@/util'; +import { config } from '@/config-manager'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; @@ -75,44 +75,28 @@ router.post('/access_token/generate', async (request: express.Request, response: }).end()); } - const cryptoPath: string = `${__dirname}/../../../../certs/service/account`; - - if (!await fs.pathExists(cryptoPath)) { - // Need to generate keys - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '0000', - message: 'Could not find account access key crypto path' - } - } - }).end()); - } - const accessTokenOptions: TokenOptions = { - system_type: 0x1, // WiiU - token_type: 0x1, // OAuth Access, + system_type: 0x1, // * WiiU + token_type: 0x1, // * OAuth Access pid: pnid.pid, expire_time: BigInt(Date.now() + (3600 * 1000)) }; const refreshTokenOptions: TokenOptions = { - system_type: 0x1, // WiiU - token_type: 0x2, // OAuth Refresh, + system_type: 0x1, // * WiiU + token_type: 0x2, // * OAuth Refresh pid: pnid.pid, expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let accessToken: string | null = await generateToken(null, accessTokenOptions); - let refreshToken: string | null = await generateToken(null, refreshTokenOptions); + const accessTokenBuffer: Buffer | null = await generateToken(config.aes_key, accessTokenOptions); + const refreshTokenBuffer: Buffer | null = await generateToken(config.aes_key, refreshTokenOptions); + + const accessToken: string = accessTokenBuffer ? accessTokenBuffer.toString('hex') : ''; + const refreshToken: string = refreshTokenBuffer ? refreshTokenBuffer.toString('hex') : ''; // TODO - Handle null tokens - if (request.isCemu) { - accessToken = Buffer.from(accessToken || '', 'base64').toString('hex'); - refreshToken = Buffer.from(refreshToken || '', 'base64').toString('hex'); - } - response.send(xmlbuilder.create({ OAuth20: { access_token: { diff --git a/src/services/nnid/routes/provider.ts b/src/services/nnid/routes/provider.ts index 93633c7..21160d3 100644 --- a/src/services/nnid/routes/provider.ts +++ b/src/services/nnid/routes/provider.ts @@ -1,11 +1,8 @@ import express from 'express'; import xmlbuilder from 'xmlbuilder'; -import fs from 'fs-extra'; import { getServerByTitleId, getServerByGameServerId } from '@/database'; import { generateToken, getValueFromHeaders, getValueFromQueryString } from '@/util'; -import { getServicePublicKey, getServiceSecretKey, getNEXPublicKey, getNEXSecretKey } from '@/cache'; import { NEXAccount } from '@/models/nex-account'; -import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; import { HydratedPNIDDocument } from '@/types/mongoose/pnid'; import { HydratedServerDocument } from '@/types/mongoose/server'; @@ -35,9 +32,9 @@ router.get('/service_token/@me', async (request: express.Request, response: expr }).end()); } - const titleId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-title-id'); + const titleID: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-title-id'); - if (!titleId) { + if (!titleID) { // TODO - Research this error more return response.send(xmlbuilder.create({ errors: { @@ -50,9 +47,9 @@ router.get('/service_token/@me', async (request: express.Request, response: expr } const serverAccessLevel: string = pnid.server_access_level; - const server: HydratedServerDocument | null = await getServerByTitleId(titleId, serverAccessLevel); + const server: HydratedServerDocument | null = await getServerByTitleId(titleID, serverAccessLevel); - if (!server) { + if (!server || !server.aes_key) { return response.send(xmlbuilder.create({ errors: { error: { @@ -63,46 +60,20 @@ router.get('/service_token/@me', async (request: express.Request, response: expr }).end()); } - const serverName: string = server.service_name; - const device: number = server.device; - - const cryptoPath: string = `${__dirname}/../../../../certs/service/${serverName}`; - - if (!await fs.pathExists(cryptoPath)) { - // Need to generate keys - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '1021', - message: 'The requested game server was not found' - } - } - }).end()); - } - - const publicKey: Buffer = await getServicePublicKey(serverName); - const secretKey: Buffer = await getServiceSecretKey(serverName); - - const cryptoOptions: CryptoOptions = { - public_key: publicKey, - hmac_secret: secretKey - }; - const tokenOptions: TokenOptions = { - system_type: device, - token_type: 0x4, // service token, + system_type: server.device, + token_type: 0x4, // * Service token pid: pnid.pid, access_level: pnid.access_level, - title_id: BigInt(parseInt(titleId, 16)), + title_id: BigInt(parseInt(titleID, 16)), expire_time: BigInt(Date.now() + (3600 * 1000)) }; - let serviceToken: string | null = await generateToken(cryptoOptions, tokenOptions); - - // TODO - Handle null tokens + const serviceTokenBuffer: Buffer | null = await generateToken(server.aes_key, tokenOptions); + let serviceToken: string = serviceTokenBuffer ? serviceTokenBuffer.toString('base64') : ''; if (request.isCemu) { - serviceToken = Buffer.from(serviceToken || '', 'base64').toString('hex'); + serviceToken = Buffer.from(serviceToken, 'base64').toString('hex'); } response.send(xmlbuilder.create({ @@ -134,82 +105,6 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. }).end()); } - const gameServerID: string | undefined = getValueFromQueryString(request.query, 'game_server_id'); - - if (!gameServerID) { - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '0118', - message: 'Unique ID and Game Server ID are not linked' - } - } - }).end()); - } - - const serverAccessLevel: string = pnid.server_access_level; - const server: HydratedServerDocument | null = await getServerByGameServerId(gameServerID, serverAccessLevel); - - if (!server) { - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '1021', - message: 'The requested game server was not found' - } - } - }).end()); - } - - const serverName: string = server.service_name; - const ip: string = server.ip; - const port: number = server.port; - const device: number = server.device; - const titleId: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-title-id'); - - if (!titleId) { - // TODO - Research this error more - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '1021', - message: 'The requested game server was not found' - } - } - }).end()); - } - - const cryptoPath: string = `${__dirname}/../../../../certs/nex/${serverName}`; - - if (!await fs.pathExists(cryptoPath)) { - // Need to generate keys - return response.send(xmlbuilder.create({ - errors: { - error: { - code: '1021', - message: 'The requested game server was not found' - } - } - }).end()); - } - - const publicKey: Buffer = await getNEXPublicKey(serverName); - const secretKey: Buffer = await getNEXSecretKey(serverName); - - const cryptoOptions: CryptoOptions = { - public_key: publicKey, - hmac_secret: secretKey - }; - - const tokenOptions: TokenOptions = { - system_type: device, - token_type: 0x3, // nex token, - pid: pnid.pid, - access_level: pnid.access_level, - title_id: BigInt(parseInt(titleId, 16)), - expire_time: BigInt(Date.now() + (3600 * 1000)) - }; - const nexAccount: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ owning_pid: pnid.pid }); @@ -226,9 +121,58 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. }).end()); } - let nexToken: string | null = await generateToken(cryptoOptions, tokenOptions); + const gameServerID: string | undefined = getValueFromQueryString(request.query, 'game_server_id'); - // TODO = Handle null tokens + if (!gameServerID) { + return response.send(xmlbuilder.create({ + errors: { + error: { + code: '0118', + message: 'Unique ID and Game Server ID are not linked' + } + } + }).end()); + } + + const serverAccessLevel: string = pnid.server_access_level; + const server: HydratedServerDocument | null = await getServerByGameServerId(gameServerID, serverAccessLevel); + + if (!server || !server.aes_key) { + return response.send(xmlbuilder.create({ + errors: { + error: { + code: '1021', + message: 'The requested game server was not found' + } + } + }).end()); + } + + const titleID: string | undefined = getValueFromHeaders(request.headers, 'x-nintendo-title-id'); + + if (!titleID) { + // TODO - Research this error more + return response.send(xmlbuilder.create({ + errors: { + error: { + code: '1021', + message: 'The requested game server was not found' + } + } + }).end()); + } + + const tokenOptions: TokenOptions = { + system_type: server.device, + token_type: 0x3, // nex token, + pid: pnid.pid, + access_level: pnid.access_level, + title_id: BigInt(parseInt(titleID, 16)), + expire_time: BigInt(Date.now() + (3600 * 1000)) + }; + + const nexTokenBuffer: Buffer | null = await generateToken(server.aes_key, tokenOptions); + let nexToken: string = nexTokenBuffer ? nexTokenBuffer.toString('base64') : ''; if (request.isCemu) { nexToken = Buffer.from(nexToken || '', 'base64').toString('hex'); @@ -236,10 +180,10 @@ router.get('/nex_token/@me', async (request: express.Request, response: express. response.send(xmlbuilder.create({ nex_token: { - host: ip, + host: server.ip, nex_password: nexAccount.password, pid: nexAccount.pid, - port: port, + port: server.port, token: nexToken } }).end()); diff --git a/src/types/common/config.ts b/src/types/common/config.ts index 4ce668d..4780d00 100644 --- a/src/types/common/config.ts +++ b/src/types/common/config.ts @@ -37,6 +37,7 @@ export interface Config { base_url: string; }; website_base: string; + aes_key: string; } export interface DisabledFeatures { diff --git a/src/types/common/crypto-options.ts b/src/types/common/crypto-options.ts deleted file mode 100644 index d4a5918..0000000 --- a/src/types/common/crypto-options.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface CryptoOptions { - public_key: Buffer; - hmac_secret: Buffer; -}; \ No newline at end of file diff --git a/src/types/mongoose/server.ts b/src/types/mongoose/server.ts index a385196..02fc372 100644 --- a/src/types/mongoose/server.ts +++ b/src/types/mongoose/server.ts @@ -1,15 +1,16 @@ import { Model, HydratedDocument } from 'mongoose'; export interface IServer { - ip: string; // Example: 1.1.1.1 - port: number; // Example: 60000 - service_name: string; // Example: friends - service_type: string; // Example: nex - game_server_id: string; // Example: 00003200 - title_ids: string[]; // Example: ["000500001018DB00", "000500001018DC00", "000500001018DD00"] - access_mode: string; // Example: prod - maintenance_mode: boolean; // Example: false - device: number; // Example: 1 (WiiU) + ip: string; + port: number; + service_name: string; + service_type: string; + game_server_id: string; + title_ids: string[]; + access_mode: string; + maintenance_mode: boolean; + device: number; + aes_key: string; } export interface IServerMethods {} diff --git a/src/util.ts b/src/util.ts index 16b1b08..a884cad 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,15 +1,12 @@ import crypto from 'node:crypto'; import path from 'node:path'; -import NodeRSA from 'node-rsa'; import aws from 'aws-sdk'; import fs from 'fs-extra'; import express from 'express'; import mongoose from 'mongoose'; import { ParsedQs } from 'qs'; import { sendMail } from '@/mailer'; -import { getServiceAESKey, getServicePrivateKey, getServiceSecretKey, getServicePublicKey } from '@/cache'; import { config, disabledFeatures } from '@/config-manager'; -import { CryptoOptions } from '@/types/common/crypto-options'; import { TokenOptions } from '@/types/common/token-options'; import { Token } from '@/types/common/token'; import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid'; @@ -50,178 +47,61 @@ export function nintendoBase64Encode(decoded: string | Buffer): string { return encoded.replaceAll('+', '.').replaceAll('/', '-').replaceAll('=', '*'); } -export async function generateToken(cryptoOptions: CryptoOptions | null, tokenOptions: TokenOptions): Promise { - // Access and refresh tokens use a different format since they must be much smaller - // They take no extra crypto options - if (!cryptoOptions) { - const aesKey: Buffer = await getServiceAESKey('account', 'hex'); +export function generateToken(key: string, options: TokenOptions): Buffer | null { + let dataBuffer: Buffer = Buffer.alloc(1 + 1 + 4 + 8); - const dataBuffer: Buffer = Buffer.alloc(1 + 1 + 4 + 8); + dataBuffer.writeUInt8(options.system_type, 0x0); + dataBuffer.writeUInt8(options.token_type, 0x1); + dataBuffer.writeUInt32LE(options.pid, 0x2); + dataBuffer.writeBigUInt64LE(options.expire_time, 0x6); - dataBuffer.writeUInt8(tokenOptions.system_type, 0x0); - dataBuffer.writeUInt8(tokenOptions.token_type, 0x1); - dataBuffer.writeUInt32LE(tokenOptions.pid, 0x2); - dataBuffer.writeBigUInt64LE(tokenOptions.expire_time, 0x6); + if (options.token_type !== 0x1 && options.token_type !== 0x2) { + if (options.access_level === undefined || options.title_id === undefined) { + return null; + } - const iv: Buffer = Buffer.alloc(16); - const cipher: crypto.Cipher = crypto.createCipheriv('aes-128-cbc', aesKey, iv); + dataBuffer = Buffer.concat([ + dataBuffer, + Buffer.alloc(8 + 1) + ]); - let encryptedBody: Buffer = cipher.update(dataBuffer); - encryptedBody = Buffer.concat([encryptedBody, cipher.final()]); - - return encryptedBody.toString('base64'); - } else if (tokenOptions.access_level === undefined || tokenOptions.title_id === undefined) { - return null; + dataBuffer.writeBigUInt64LE(options.title_id, 0xE); + dataBuffer.writeUInt8(options.access_level, 0x16); } - const publicKey: NodeRSA = new NodeRSA(cryptoOptions.public_key, 'pkcs8-public-pem', { - environment: 'browser', - encryptionScheme: { - scheme: 'pkcs1_oaep', - hash: 'sha256' - } - }); + const iv: Buffer = Buffer.alloc(16); + const cipher: crypto.Cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(key, 'hex'), iv); - // Create the buffer containing the token data - const dataBuffer: Buffer = Buffer.alloc(1 + 1 + 4 + 1 + 8 + 8); - - dataBuffer.writeUInt8(tokenOptions.system_type, 0x0); - dataBuffer.writeUInt8(tokenOptions.token_type, 0x1); - dataBuffer.writeUInt32LE(tokenOptions.pid, 0x2); - dataBuffer.writeUInt8(tokenOptions.access_level, 0x6); - dataBuffer.writeBigUInt64LE(tokenOptions.title_id, 0x7); - dataBuffer.writeBigUInt64LE(tokenOptions.expire_time, 0xF); - - // Calculate the signature of the token body - const hmac: crypto.Hmac = crypto.createHmac('sha1', cryptoOptions.hmac_secret).update(dataBuffer); - const signature: Buffer = hmac.digest(); - - // You can thank the 3DS for the shit thats about to happen with the AES IV - // The 3DS only allows for strings up to 255 characters in NEX - // So this is done to reduce the token size as much as possible - // I am sorry, and have already asked every God I could think of for forgiveness - - // Generate random AES key - const key: Buffer = crypto.randomBytes(16); - - // Encrypt the AES key with RSA public key - const encryptedKey: Buffer = publicKey.encrypt(key); - - // Take two random points in the RSA encrypted key - const point1: number = ~~((encryptedKey.length - 8) * Math.random()); - const point2: number = ~~((encryptedKey.length - 8) * Math.random()); - - // Build an IV from each of the two points - const iv: Buffer = Buffer.concat([ - Buffer.from(encryptedKey.subarray(point1, point1 + 8)), - Buffer.from(encryptedKey.subarray(point2, point2 + 8)) - ]); - - const cipher: crypto.Cipher = crypto.createCipheriv('aes-128-cbc', key, iv); - - // Encrypt the token body with AES - const encryptedBody: Buffer = Buffer.concat([ + return Buffer.concat([ cipher.update(dataBuffer), cipher.final() ]); - - // Create crypto config token section - const cryptoConfig: Buffer = Buffer.concat([ - encryptedKey, - Buffer.from([point1, point2]) - ]); - - // Build the token - const token: Buffer = Buffer.concat([ - cryptoConfig, - signature, - encryptedBody - ]); - - return token.toString('base64'); // Encode to base64 for transport } -export async function decryptToken(token: Buffer): Promise { - // Access and refresh tokens use a different format since they must be much smaller - // Assume a small length means access or refresh token - if (token.length <= 32) { - const aesKey: Buffer = await getServiceAESKey('account', 'hex'); +export function decryptToken(key: string, token: Buffer): Buffer { + const iv: Buffer = Buffer.alloc(16); + const decipher: crypto.Decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(key, 'hex'), iv); - const iv: Buffer = Buffer.alloc(16); - - const decipher: crypto.Decipher = crypto.createDecipheriv('aes-128-cbc', aesKey, iv); - - const decryptedBody: Buffer = Buffer.concat([ - decipher.update(token), - decipher.final() - ]); - - return decryptedBody; - } - - const privateKeyBytes: Buffer = await getServicePrivateKey('account'); - const secretKey: Buffer = await getServiceSecretKey('account'); - - const privateKey: NodeRSA = new NodeRSA(privateKeyBytes, 'pkcs1-private-pem', { - environment: 'browser', - encryptionScheme: { - scheme: 'pkcs1_oaep', - hash: 'sha256' - } - }); - - const cryptoConfig: Buffer = token.subarray(0, 0x82); - const signature: Buffer = token.subarray(0x82, 0x96); - const encryptedBody: Buffer = token.subarray(0x96); - - const encryptedAESKey: Buffer = cryptoConfig.subarray(0, 128); - const point1: number = cryptoConfig.readInt8(0x80); - const point2: number = cryptoConfig.readInt8(0x81); - - const iv: Buffer = Buffer.concat([ - Buffer.from(encryptedAESKey.subarray(point1, point1 + 8)), - Buffer.from(encryptedAESKey.subarray(point2, point2 + 8)) - ]); - - const decryptedAESKey: Buffer = privateKey.decrypt(encryptedAESKey); - - const decipher: crypto.Decipher = crypto.createDecipheriv('aes-128-cbc', decryptedAESKey, iv); - - const decryptedBody: Buffer = Buffer.concat([ - decipher.update(encryptedBody), + return Buffer.concat([ + decipher.update(token), decipher.final() ]); - - const hmac: crypto.Hmac = crypto.createHmac('sha1', secretKey).update(decryptedBody); - const calculatedSignature: Buffer = hmac.digest(); - - if (!signature.equals(calculatedSignature)) { - // TODO - FIX THIS. ONLY DONE SO STRICT MODE DOESN'T YELL - console.log('Token signature did not match'); - return Buffer.alloc(0); - } - - return decryptedBody; } export function unpackToken(token: Buffer): Token { - if (token.length <= 14) { - return { - system_type: token.readUInt8(0x0), - token_type: token.readUInt8(0x1), - pid: token.readUInt32LE(0x2), - expire_time: token.readBigUInt64LE(0x6) - }; - } - - return { + const unpacked: Token = { system_type: token.readUInt8(0x0), token_type: token.readUInt8(0x1), pid: token.readUInt32LE(0x2), - access_level: token.readUInt8(0x6), - title_id: token.readBigUInt64LE(0x7), - expire_time: token.readBigUInt64LE(0xF) + expire_time: token.readBigUInt64LE(0x6) }; + + if (unpacked.token_type !== 0x1 && unpacked.token_type !== 0x2) { + unpacked.title_id = token.readBigUInt64LE(0xE); + unpacked.access_level = token.readUInt8(0x16); + } + + return unpacked; } export function fullUrl(request: express.Request): string { @@ -289,24 +169,17 @@ export async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument): Promise { - const publicKey: Buffer = await getServicePublicKey('account'); - const secretKey: Buffer = await getServiceSecretKey('account'); - - const cryptoOptions: CryptoOptions = { - public_key: publicKey, - hmac_secret: secretKey - }; - const tokenOptions: TokenOptions = { - system_type: 0xF, // API - token_type: 0x5, // Password reset + system_type: 0xF, // * API + token_type: 0x5, // * Password reset pid: pnid.pid, access_level: pnid.access_level, title_id: BigInt(0), expire_time: BigInt(Date.now() + (24 * 60 * 60 * 1000)) // Only valid for 24 hours }; - const passwordResetToken: string | null = await generateToken(cryptoOptions, tokenOptions); + const tokenBuffer: Buffer | null = await generateToken(config.aes_key, tokenOptions); + const passwordResetToken: string = tokenBuffer ? tokenBuffer.toString('hex') : ''; // TODO - Handle null token @@ -317,9 +190,9 @@ export async function sendForgotPasswordEmail(pnid: mongoose.HydratedDocument Date: Thu, 27 Apr 2023 14:35:27 -0400 Subject: [PATCH 61/65] Updated lint and build commands --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8e2b0dc..e0c005f 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "", "main": "./dist/server.js", "scripts": { - "lint": "./node_modules/.bin/eslint .", - "build": "npm run clean && tsc && tsc-alias && npm run copy-static", + "lint": "npx eslint .", + "build": "npm run lint && npm run clean && tsc && tsc-alias && npm run copy-static", "clean": "rm -rf ./dist", "copy-static": "npm run copy-assets && npm run copy-timezones", "copy-assets": "cp -r ./src/assets ./dist/assets", From bbf6a9340a0cea83bdc9399ee8d6853ee1612a86 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 27 Apr 2023 14:38:03 -0400 Subject: [PATCH 62/65] Fix linting issues --- src/types/common/mailer-options.ts | 2 +- src/types/common/signature-size.ts | 2 +- src/types/common/token-options.ts | 2 +- src/types/common/token.ts | 2 +- src/types/services/api/discord-connection-data.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/types/common/mailer-options.ts b/src/types/common/mailer-options.ts index 277cf33..265b42a 100644 --- a/src/types/common/mailer-options.ts +++ b/src/types/common/mailer-options.ts @@ -13,4 +13,4 @@ export interface MailerOptions { href: string; code: string; }; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/types/common/signature-size.ts b/src/types/common/signature-size.ts index 3fe755e..c9f9bbf 100644 --- a/src/types/common/signature-size.ts +++ b/src/types/common/signature-size.ts @@ -1,4 +1,4 @@ export interface SignatureSize { SIZE: number; PADDING_SIZE: number; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/types/common/token-options.ts b/src/types/common/token-options.ts index 4a9bb15..6dcc85e 100644 --- a/src/types/common/token-options.ts +++ b/src/types/common/token-options.ts @@ -5,4 +5,4 @@ export interface TokenOptions { access_level?: number; title_id?: bigint; expire_time: bigint; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/types/common/token.ts b/src/types/common/token.ts index 84673c2..4c7c558 100644 --- a/src/types/common/token.ts +++ b/src/types/common/token.ts @@ -5,4 +5,4 @@ export interface Token { access_level?: number; title_id?: bigint; expire_time: bigint; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/types/services/api/discord-connection-data.ts b/src/types/services/api/discord-connection-data.ts index b9ed367..0ee459a 100644 --- a/src/types/services/api/discord-connection-data.ts +++ b/src/types/services/api/discord-connection-data.ts @@ -1,3 +1,3 @@ export interface DiscordConnectionData { id: string; -}; \ No newline at end of file +} \ No newline at end of file From 36bf30a64a6a355b00a173dfc64cc5da1f898e4f Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 27 Apr 2023 14:38:28 -0400 Subject: [PATCH 63/65] Replace rm -rf with rimraf --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e0c005f..7128e53 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "lint": "npx eslint .", "build": "npm run lint && npm run clean && tsc && tsc-alias && npm run copy-static", - "clean": "rm -rf ./dist", + "clean": "rimraf ./dist", "copy-static": "npm run copy-assets && npm run copy-timezones", "copy-assets": "cp -r ./src/assets ./dist/assets", "copy-timezones": "cp ./src/services/nnid/timezones.json ./dist/services/nnid/timezones.json", From 84c2086da2b97c54886eb1d49f491729b3d64138 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 27 Apr 2023 14:39:02 -0400 Subject: [PATCH 64/65] Updated build command --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7128e53..535bcef 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "./dist/server.js", "scripts": { "lint": "npx eslint .", - "build": "npm run lint && npm run clean && tsc && tsc-alias && npm run copy-static", + "build": "npm run lint && npm run clean && npx tsc && npx tsc-alias && npm run copy-static", "clean": "rimraf ./dist", "copy-static": "npm run copy-assets && npm run copy-timezones", "copy-assets": "cp -r ./src/assets ./dist/assets", From d6d92ca27c1246cf2f8efd65b768186963e3fa2d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Thu, 27 Apr 2023 15:05:22 -0400 Subject: [PATCH 65/65] Added types to modules without types --- package-lock.json | 794 ++++++++++++----------- package.json | 4 + src/models/pnid.ts | 8 +- src/types/express-subdomain.d.ts | 17 +- src/types/image-pixels.d.ts | 35 +- src/types/mongoose-unique-validator.d.ts | 1 - src/types/tga.d.ts | 59 +- 7 files changed, 525 insertions(+), 393 deletions(-) delete mode 100644 src/types/mongoose-unique-validator.d.ts diff --git a/package-lock.json b/package-lock.json index 3c28cac..91b3c7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,15 +45,19 @@ "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", + "@types/mongoose-unique-validator": "^1.0.7", "@types/morgan": "^1.9.4", + "@types/ndarray": "^1.0.11", "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", "@types/nodemailer": "^6.4.7", "@types/qs": "^6.9.7", "@types/validator": "^13.7.14", + "@types/w3c-css-typed-object-model-level-1": "^20180410.0.5", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", "eslint": "^8.35.0", + "ndarray": "^1.0.19", "prompt": "^1.0.0", "typescript": "^4.9.5", "yesno": "^0.4.0" @@ -64,7 +68,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, - "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -74,7 +77,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, - "peer": true, "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -91,7 +93,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, - "peer": true, "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -103,7 +104,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, - "peer": true, "dependencies": { "tslib": "^1.11.1" } @@ -113,7 +113,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -125,7 +124,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.292.0.tgz", "integrity": "sha512-lf+OPptL01kvryIJy7+dvFux5KbJ6OTwLPPEekVKZ2AfEvwcVtOZWFUhyw3PJCBTVncjKB1Kjl3V/eTS3YuPXQ==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -138,15 +136,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/client-cognito-identity": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.294.0.tgz", "integrity": "sha512-QMk/QratNvAvmnJ77pu9KDjpfUf/5LOJplHcLKcY962ewJGBtFFY4XZVnmUgQMSG0phRODtex7pyH//FueGKLQ==", "optional": true, - "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -192,15 +188,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/client-sso": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.294.0.tgz", "integrity": "sha512-+FuxQTi5WvnaXM5JbNLkBIzQ3An4gA0ox61N1u+3xled+nywKb1yQ7WmRpyMG5bLbkmnj3aqoo5/uskFc4c4EA==", "optional": true, - "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -244,7 +238,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.294.0.tgz", "integrity": "sha512-/ZfDud76MdSPJ/TxjV2xLE30XbBQDZwKQ32axwoK1eziPvrAIUBYVgpBwj+m0quhoiQhBKkg3aFl6j39AF2thw==", "optional": true, - "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -287,22 +280,19 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/client-sso/node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/client-sts": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.294.0.tgz", "integrity": "sha512-AefqwhFjTDzelZuSYhriJbiI+GQwf2yKiKAnCt0gRj6rswewStM63Gtlhfb01sFPp+ZiqPcyQ47LqUaHp1mz/g==", "optional": true, - "peer": true, "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -349,15 +339,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/config-resolver": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.292.0.tgz", "integrity": "sha512-cB3twnNR7vYvlt2jvw8VlA1+iv/tVzl+/S39MKqw2tepU+AbJAM0EHwb/dkf1OKSmlrnANXhshx80MHF9zL4mA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/signature-v4": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -373,15 +361,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.294.0.tgz", "integrity": "sha512-YSPqHEbLC0dnbFF5LdlMH0B50sMSN/CyG/sHkPYUwL/hkbUk9URnVW7ZJlt6lRftT7X4C7muzLqUP8sJAaiJEA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -396,15 +382,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-env": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.292.0.tgz", "integrity": "sha512-YbafSG0ZEKE2969CJWVtUhh3hfOeLPecFVoXOtegCyAJgY5Ghtu4TsVhL4DgiGAgOC30ojAmUVQEXzd7xJF5xA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -418,15 +402,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-imds": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.292.0.tgz", "integrity": "sha512-W/peOgDSRYulgzFpUhvgi1pCm6piBz6xrVN17N4QOy+3NHBXRVMVzYk6ct2qpLPgJUSEZkcpP+Gds+bBm8ed1A==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -442,15 +424,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.294.0.tgz", "integrity": "sha512-pdTPbaAb5bWA+DnuKoL2TpXeNDp6Ejpv/OYt+bw2gdzl9w5r/ZCtUTTbW+Vvejr4WL5s3c1bY96kwdqCn7iLqA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -470,15 +450,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-node": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.294.0.tgz", "integrity": "sha512-zUL1Qhb4BsQIZCs/TPpG4oIYH/9YsGiS+Se1tasSGjTOLfBy7jhOZ0QIdpEeyAx/EP8blOBredM9xWfEXgiHVA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -499,15 +477,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-process": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.292.0.tgz", "integrity": "sha512-CFVXuMuUvg/a4tknzRikEDwZBnKlHs1LZCpTXIGjBdUTdosoi4WNzDLzGp93ZRTtcgFz+4wirz2f7P3lC0NrQw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -522,15 +498,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-sso": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.294.0.tgz", "integrity": "sha512-UxrcAA/0l7j9+3tolYcG5M61D/IE1Bjd/9H87H1i2A2BrwUUBhW1Dp/vvROEDrrywlMDG3CDF3T/7ADtTak+sg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/client-sso": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -547,15 +521,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.292.0.tgz", "integrity": "sha512-4DbtIEM9gGVfqYlMdYXg3XY+vBhemjB1zXIequottW8loLYM8Vuz4/uGxxKNze6evVVzowsA0wKrYclE1aj/Rg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -569,15 +541,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/credential-providers": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.294.0.tgz", "integrity": "sha512-CRGwCs6F31mQzjYi5YF2Z6c1T+UrFKtJSa6Ff/Q1rrPnROexyhBVnpP8WzpkODx/pZxKtTX50IX7ehIxbFDIyQ==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/client-sso": "3.294.0", @@ -603,15 +573,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/fetch-http-handler": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.292.0.tgz", "integrity": "sha512-zh3bhUJbL8RSa39ZKDcy+AghtUkIP8LwcNlwRIoxMQh3Row4D1s4fCq0KZCx98NJBEXoiTLyTQlZxxI//BOb1Q==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/querystring-builder": "3.292.0", @@ -624,15 +592,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/hash-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.292.0.tgz", "integrity": "sha512-1yLxmIsvE+eK36JXEgEIouTITdykQLVhsA5Oai//Lar6Ddgu1sFpLDbdkMtKbrh4I0jLN9RacNCkeVQjZPTCCQ==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-buffer-from": "3.292.0", @@ -647,15 +613,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/invalid-dependency": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.292.0.tgz", "integrity": "sha512-39OUV78CD3TmEbjhpt+V+Fk4wAGWhixqHxDSN8+4WL0uB4Fl7k5m3Z9hNY78AttHQSl2twR7WtLztnXPAFsriw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -665,15 +629,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/is-array-buffer": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.292.0.tgz", "integrity": "sha512-kW/G5T/fzI0sJH5foZG6XJiNCevXqKLxV50qIT4B1pMuw7regd4ALIy0HwSqj1nnn9mSbRWBfmby0jWCJsMcwg==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -685,15 +647,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-content-length": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.292.0.tgz", "integrity": "sha512-2gMWzQus5mj14menolpPDbYBeaOYcj7KNFZOjTjjI3iQ0KqyetG6XasirNrcJ/8QX1BRmpTol8Xjp2Ue3Gbzwg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -707,15 +667,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-endpoint": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.292.0.tgz", "integrity": "sha512-cPMkiSxpZGG6tYlW4OS+ucS6r43f9ddX9kcUoemJCY10MOuogdPjulCAjE0HTs2PLKSOrrG4CTP4Q4wWDrH4Bw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/middleware-serde": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -734,15 +692,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-host-header": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.292.0.tgz", "integrity": "sha512-mHuCWe3Yg2S5YZ7mB7sKU6C97XspfqrimWjMW9pfV2usAvLA3R0HrB03jpR5vpZ3P4q7HB6wK3S6CjYMGGRNag==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -756,15 +712,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-logger": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.292.0.tgz", "integrity": "sha512-yZNY1XYmG3NG+uonET7jzKXNiwu61xm/ZZ6i/l51SusuaYN+qQtTAhOFsieQqTehF9kP4FzbsWgPDwD8ZZX9lw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -777,15 +731,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.292.0.tgz", "integrity": "sha512-kA3VZpPko0Zqd7CYPTKAxhjEv0HJqFu2054L04dde1JLr43ro+2MTdX7vsHzeAFUVRphqatFFofCumvXmU6Mig==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -799,15 +751,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-retry": { "version": "3.293.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.293.0.tgz", "integrity": "sha512-7tiaz2GzRecNHaZ6YnF+Nrtk3au8qF6oiipf11R7MJiqJ0fkMLnz/iRrlakDziS9qF/a9v+3yxb4W4NHK3f4Tw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/service-error-classification": "3.292.0", @@ -825,15 +775,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-retry/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "optional": true, - "peer": true, "bin": { "uuid": "dist/bin/uuid" } @@ -843,7 +791,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.292.0.tgz", "integrity": "sha512-GN5ZHEqXZqDi+HkVbaXRX9HaW/vA5rikYpWKYsmxTUZ7fB7ijvEO3co3lleJv2C+iGYRtUIHC4wYNB5xgoTCxg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/middleware-signing": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -860,15 +807,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-serde": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.292.0.tgz", "integrity": "sha512-6hN9mTQwSvV8EcGvtXbS/MpK7WMCokUku5Wu7X24UwCNMVkoRHLIkYcxHcvBTwttuOU0d8hph1/lIX4dkLwkQw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -881,15 +826,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-signing": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.292.0.tgz", "integrity": "sha512-GVfoSjDjEQ4TaO6x9MffyP3uRV+2KcS5FtexLCYOM9pJcnE9tqq9FJOrZ1xl1g+YjUVKxo4x8lu3tpEtIb17qg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -906,15 +849,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-stack": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.292.0.tgz", "integrity": "sha512-WdQpRkuMysrEwrkByCM1qCn2PPpFGGQ2iXqaFha5RzCdZDlxJni9cVNb6HzWUcgjLEYVTXCmOR9Wxm3CNW44Qg==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -926,15 +867,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.293.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.293.0.tgz", "integrity": "sha512-gZ7/e6XwpKk9mvgA78q4Ffc796jTn02TUKx2qMDnkLVbeJXBNN2jnvYEKq8v70+o7fd/ALRudg8gBDmkkhM/Hw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -949,15 +888,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/node-config-provider": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.292.0.tgz", "integrity": "sha512-S3NnC9dQ5GIbJYSDIldZb4zdpCOEua1tM7bjYL3VS5uqCEM93kIi/o/UkIUveMp/eqTS2LJa5HjNIz5Te6je0A==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -972,15 +909,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/node-http-handler": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.292.0.tgz", "integrity": "sha512-L/E3UDSwXLXjt1XWWh0RBD55F+aZI1AEdPwdES9i1PjnZLyuxuDhEDptVibNN56+I9/4Q3SbmuVRVlOD0uzBag==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/abort-controller": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -996,15 +931,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/property-provider": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.292.0.tgz", "integrity": "sha512-dHArSvsiqhno/g55N815gXmAMrmN8DP7OeFNqJ4wJG42xsF2PFN3DAsjIuHuXMwu+7A3R1LHqIpvv0hA9KeoJQ==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1017,15 +950,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/protocol-http": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.292.0.tgz", "integrity": "sha512-NLi4fq3k41aXIh1I97yX0JTy+3p6aW1NdwFwdMa674z86QNfb4SfRQRZBQe9wEnAZ/eWHVnlKIuII+U1URk/Kg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1038,15 +969,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/querystring-builder": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.292.0.tgz", "integrity": "sha512-XElIFJaReIm24eEvBtV2dOtZvcm3gXsGu/ftG8MLJKbKXFKpAP1q+K6En0Bs7/T88voKghKdKpKT+eZUWgTqlg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-uri-escape": "3.292.0", @@ -1060,15 +989,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/querystring-parser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.292.0.tgz", "integrity": "sha512-iTYpYo7a8X9RxiPbjjewIpm6XQPx2EOcF1dWCPRII9EFlmZ4bwnX+PDI36fIo9oVs8TIKXmwNGODU9nsg7CSAw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1081,15 +1008,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/service-error-classification": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.292.0.tgz", "integrity": "sha512-X1k3sixCeC45XSNHBe+kRBQBwPDyTFtFITb8O5Qw4dS9XWGhrUJT4CX0qE5aj8qP3F9U5nRizs9c2mBVVP0Caw==", "optional": true, - "peer": true, "engines": { "node": ">=14.0.0" } @@ -1099,7 +1024,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.292.0.tgz", "integrity": "sha512-Av2TTYg1Jig2kbkD56ybiqZJB6vVrYjv1W5UQwY/q3nA/T2mcrgQ20ByCOt5Bv9VvY7FSgC+znj+L4a7RLGmBg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1112,15 +1036,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/signature-v4": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.292.0.tgz", "integrity": "sha512-+rw47VY5mvBecn13tDQTl1ipGWg5tE63faWgmZe68HoBL87ZiDzsd7bUKOvjfW21iMgWlwAppkaNNQayYRb2zg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/is-array-buffer": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1138,15 +1060,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/smithy-client": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.292.0.tgz", "integrity": "sha512-S8PKzjPkZ6SXYZuZiU787dMsvQ0d/LFEhw2OI4Oe2An9Fc2IwJ2FYukyHoQJOV2tV0DiuMebPo7eMyQyjKElvA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/middleware-stack": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1160,15 +1080,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/token-providers": { "version": "3.294.0", "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.294.0.tgz", "integrity": "sha512-6nwO04LtC5f4AsUvGZXyjaswuEK4Rr2VsuANpMKrPCgunRfI58a8YXLniudOSXN6e7CFJ6M3uo/h5YXqtnzGug==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/client-sso-oidc": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -1184,15 +1102,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/types": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.292.0.tgz", "integrity": "sha512-1teYAY2M73UXZxMAxqZxVS2qwXjQh0OWtt7qyLfha0TtIk/fZ1hRwFgxbDCHUFcdNBSOSbKH/ESor90KROXLCQ==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1204,15 +1120,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/url-parser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.292.0.tgz", "integrity": "sha512-NZeAuZCk1x6TIiWuRfbOU6wHPBhf0ly2qOHzWut4BCH+b4RrDmFF8EmXcH1auEfGhE7yRyR6XqIN0t3S+hYACA==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/querystring-parser": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1223,15 +1137,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-base64": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.292.0.tgz", "integrity": "sha512-zjNCwNdy617yFvEjZorepNWXB2sQCVfsShCwFy/kIQ5iW5tT2jQKaqc0K77diU9atkooxw9p1W9m9sOgrkOFNw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -1244,15 +1156,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-body-length-browser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.292.0.tgz", "integrity": "sha512-Wd/BM+JsMiKvKs/bN3z6TredVEHh2pKudGfg3CSjTRpqFpOG903KDfyHBD42yg5PuCHoHoewJvTPKwgn7/vhaw==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" } @@ -1261,15 +1171,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-body-length-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.292.0.tgz", "integrity": "sha512-BBgipZ2P6RhogWE/qj0oqpdlyd3iSBYmb+aD/TBXwB2lA/X8A99GxweBd/kp06AmcJRoMS9WIXgbWkiiBlRlSA==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1281,15 +1189,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-buffer-from": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.292.0.tgz", "integrity": "sha512-RxNZjLoXNxHconH9TYsk5RaEBjSgTtozHeyIdacaHPj5vlQKi4hgL2hIfKeeNiAfQEVjaUFF29lv81xpNMzVMQ==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/is-array-buffer": "3.292.0", "tslib": "^2.3.1" @@ -1302,15 +1208,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-config-provider": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.292.0.tgz", "integrity": "sha512-t3noYll6bPRSxeeNNEkC5czVjAiTPcsq00OwfJ2xyUqmquhLEfLwoJKmrT1uP7DjIEXdUtfoIQ2jWiIVm/oO5A==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1322,15 +1226,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-defaults-mode-browser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.292.0.tgz", "integrity": "sha512-7+zVUlMGfa8/KT++9humHo6IDxTnxMCmWUj5jVNlkpk6h7Ecmppf7aXotviyVIA43lhtz0p2AErs0N0ekEUK+w==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1345,15 +1247,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-defaults-mode-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.292.0.tgz", "integrity": "sha512-SSIw85eF4BVs0fOJRyshT+R3b/UmBPhiVKCUZm2rq6+lIGkDPiSwQU3d/80AhXtiL5SFT/IzAKKgQd8qMa7q3A==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/config-resolver": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -1370,15 +1270,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-endpoints": { "version": "3.293.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.293.0.tgz", "integrity": "sha512-R/99aNV49Refpv5guiUjEUrZYlvnfaNBniB+/ZtMO3ixxUopapssCrUivuJrmhccmrYaTCZw7dRzIWjU1jJhKg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -1391,15 +1289,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-hex-encoding": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.292.0.tgz", "integrity": "sha512-qBd5KFIUywQ3qSSbj814S2srk0vfv8A6QMI+Obs1y2LHZFdQN5zViptI4UhXhKOHe+NnrHWxSuLC/LMH6q3SmA==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1411,15 +1307,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-locate-window": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.292.0.tgz", "integrity": "sha512-6xnFJXZI9pKw5lQCDvuWA5PnOaUtNRKWwdxvGkkLx5orboFaoVMS6zowjSQxwVNRjW82u6dYNkhmj9mZ8VSjWg==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1431,15 +1325,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-middleware": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.292.0.tgz", "integrity": "sha512-KjhS7flfoBKDxbiBZjLjMvEizXgjfQb7GQEItgzGoI9rfGCmZtvqCcqQQoIlxb8bIzGRggAUHtBGWnlLbpb+GQ==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1451,15 +1343,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-retry": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.292.0.tgz", "integrity": "sha512-JEHyF7MpVeRF5uR4LDYgpOKcFpOPiAj8TqN46SVOQQcL1K+V7cSr7O7N7J6MwJaN9XOzAcBadeIupMm7/BFbgw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/service-error-classification": "3.292.0", "tslib": "^2.3.1" @@ -1472,15 +1362,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-uri-escape": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.292.0.tgz", "integrity": "sha512-hOQtUMQ4VcQ9iwKz50AoCp1XBD5gJ9nly/gJZccAM7zSA5mOO8RRKkbdonqquVHxrO0CnYgiFeCh3V35GFecUw==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" }, @@ -1492,15 +1380,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.292.0.tgz", "integrity": "sha512-dld+lpC3QdmTQHdBWJ0WFDkXDSrJgfz03q6mQ8+7H+BC12ZhT0I0g9iuvUjolqy7QR00OxOy47Y9FVhq8EC0Gg==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/types": "3.292.0", "bowser": "^2.11.0", @@ -1511,15 +1397,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-user-agent-node": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.292.0.tgz", "integrity": "sha512-f+NfIMal5E61MDc5WGhUEoicr7b1eNNhA+GgVdSB/Hg5fYhEZvFK9RZizH5rrtsLjjgcr9nPYSR7/nDKCJLumw==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -1541,15 +1425,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-utf8": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.292.0.tgz", "integrity": "sha512-FPkj+Z59/DQWvoVu2wFaRncc3KVwe/pgK3MfVb0Lx+Ibey5KUx+sNpJmYcVYHUAe/Nv/JeIpOtYuC96IXOnI6w==", "optional": true, - "peer": true, "dependencies": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -1563,7 +1445,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.3.1" } @@ -1572,15 +1453,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@aws-sdk/util-utf8/node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "node_modules/@colors/colors": { "version": "1.5.0", @@ -2108,6 +1987,132 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, + "node_modules/@types/mongoose-unique-validator": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/mongoose-unique-validator/-/mongoose-unique-validator-1.0.7.tgz", + "integrity": "sha512-wgPWN7x9mHdy8x1jcluDF7EDWFb/s8LD7skLr012C8i2Q3tUhdTlp3JxRhFbEM3TD7J1INaoTrWaSaguhuqilQ==", + "dev": true, + "dependencies": { + "mongoose": "^6.3.0" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dev": true, + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "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" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@types/mongoose-unique-validator/node_modules/mongodb": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", + "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", + "dev": true, + "dependencies": { + "bson": "^4.7.0", + "mongodb-connection-string-url": "^2.5.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "saslprep": "^1.0.3" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/mongoose": { + "version": "6.10.5", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.5.tgz", + "integrity": "sha512-y4HL4/9EySec7L0gJ+pCm9heLSF45uIIvRS4fSeAFWDfe4vXW1vRZJwTz7OGkra3ZoSfRnFTo9bNZkuggDVlVA==", + "dev": true, + "dependencies": { + "bson": "^4.7.0", + "kareem": "2.5.1", + "mongodb": "4.14.0", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mongoose" + } + }, + "node_modules/@types/mongoose-unique-validator/node_modules/mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dev": true, + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@types/mongoose-unique-validator/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==", + "dev": true + }, "node_modules/@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -2117,6 +2122,12 @@ "@types/node": "*" } }, + "node_modules/@types/ndarray": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.11.tgz", + "integrity": "sha512-hOZVTN24zDHwCHaW7mF9n1vHJt83fZhNZ0YYRBwQGhA96yBWWDPTDDlqJatagHIOJB0a4xoNkNc+t/Cxd+6qUA==", + "dev": true + }, "node_modules/@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -2182,6 +2193,12 @@ "integrity": "sha512-J6OAed6rhN6zyqL9Of6ZMamhlsOEU/poBVvbHr/dKOYKTeuYYMlDkMv+b6UUV0o2i0tw73cgyv/97WTWaUl0/g==", "dev": true }, + "node_modules/@types/w3c-css-typed-object-model-level-1": { + "version": "20180410.0.5", + "resolved": "https://registry.npmjs.org/@types/w3c-css-typed-object-model-level-1/-/w3c-css-typed-object-model-level-1-20180410.0.5.tgz", + "integrity": "sha512-khoqDQqA/fUdK6mEJtQEfMAPCKkk8E1D+ahM/0HCy3mc5L33wJinqQNXu9Uf4+mqzMvORljHg76jvrmwS0bEjA==", + "dev": true + }, "node_modules/@types/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -2864,8 +2881,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true, - "peer": true + "optional": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -4036,7 +4052,6 @@ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", "optional": true, - "peer": true, "dependencies": { "strnum": "^1.0.5" }, @@ -4686,6 +4701,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "node_modules/iota-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz", + "integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==", + "dev": true + }, "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -5459,6 +5480,22 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "node_modules/ndarray": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.19.tgz", + "integrity": "sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==", + "dev": true, + "dependencies": { + "iota-array": "^1.0.0", + "is-buffer": "^1.0.2" + } + }, + "node_modules/ndarray/node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -6540,8 +6577,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true, - "peer": true + "optional": true }, "node_modules/supports-color": { "version": "7.2.0", @@ -7090,7 +7126,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", "optional": true, - "peer": true, "requires": { "tslib": "^1.11.1" } @@ -7100,7 +7135,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", "optional": true, - "peer": true, "requires": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -7117,7 +7151,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", "optional": true, - "peer": true, "requires": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -7129,7 +7162,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", "optional": true, - "peer": true, "requires": { "tslib": "^1.11.1" } @@ -7139,7 +7171,6 @@ "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -7151,7 +7182,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/abort-controller/-/abort-controller-3.292.0.tgz", "integrity": "sha512-lf+OPptL01kvryIJy7+dvFux5KbJ6OTwLPPEekVKZ2AfEvwcVtOZWFUhyw3PJCBTVncjKB1Kjl3V/eTS3YuPXQ==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7161,8 +7191,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7171,7 +7200,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.294.0.tgz", "integrity": "sha512-QMk/QratNvAvmnJ77pu9KDjpfUf/5LOJplHcLKcY962ewJGBtFFY4XZVnmUgQMSG0phRODtex7pyH//FueGKLQ==", "optional": true, - "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7214,8 +7242,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7224,7 +7251,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.294.0.tgz", "integrity": "sha512-+FuxQTi5WvnaXM5JbNLkBIzQ3An4gA0ox61N1u+3xled+nywKb1yQ7WmRpyMG5bLbkmnj3aqoo5/uskFc4c4EA==", "optional": true, - "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7264,8 +7290,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7274,7 +7299,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.294.0.tgz", "integrity": "sha512-/ZfDud76MdSPJ/TxjV2xLE30XbBQDZwKQ32axwoK1eziPvrAIUBYVgpBwj+m0quhoiQhBKkg3aFl6j39AF2thw==", "optional": true, - "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7314,8 +7338,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7324,7 +7347,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.294.0.tgz", "integrity": "sha512-AefqwhFjTDzelZuSYhriJbiI+GQwf2yKiKAnCt0gRj6rswewStM63Gtlhfb01sFPp+ZiqPcyQ47LqUaHp1mz/g==", "optional": true, - "peer": true, "requires": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -7368,8 +7390,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7378,7 +7399,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/config-resolver/-/config-resolver-3.292.0.tgz", "integrity": "sha512-cB3twnNR7vYvlt2jvw8VlA1+iv/tVzl+/S39MKqw2tepU+AbJAM0EHwb/dkf1OKSmlrnANXhshx80MHF9zL4mA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/signature-v4": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7391,8 +7411,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7401,7 +7420,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.294.0.tgz", "integrity": "sha512-YSPqHEbLC0dnbFF5LdlMH0B50sMSN/CyG/sHkPYUwL/hkbUk9URnVW7ZJlt6lRftT7X4C7muzLqUP8sJAaiJEA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -7413,8 +7431,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7423,7 +7440,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.292.0.tgz", "integrity": "sha512-YbafSG0ZEKE2969CJWVtUhh3hfOeLPecFVoXOtegCyAJgY5Ghtu4TsVhL4DgiGAgOC30ojAmUVQEXzd7xJF5xA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7434,8 +7450,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7444,7 +7459,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-imds/-/credential-provider-imds-3.292.0.tgz", "integrity": "sha512-W/peOgDSRYulgzFpUhvgi1pCm6piBz6xrVN17N4QOy+3NHBXRVMVzYk6ct2qpLPgJUSEZkcpP+Gds+bBm8ed1A==", "optional": true, - "peer": true, "requires": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -7457,8 +7471,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7467,7 +7480,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.294.0.tgz", "integrity": "sha512-pdTPbaAb5bWA+DnuKoL2TpXeNDp6Ejpv/OYt+bw2gdzl9w5r/ZCtUTTbW+Vvejr4WL5s3c1bY96kwdqCn7iLqA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -7484,8 +7496,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7494,7 +7505,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.294.0.tgz", "integrity": "sha512-zUL1Qhb4BsQIZCs/TPpG4oIYH/9YsGiS+Se1tasSGjTOLfBy7jhOZ0QIdpEeyAx/EP8blOBredM9xWfEXgiHVA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/credential-provider-env": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -7512,8 +7522,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7522,7 +7531,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.292.0.tgz", "integrity": "sha512-CFVXuMuUvg/a4tknzRikEDwZBnKlHs1LZCpTXIGjBdUTdosoi4WNzDLzGp93ZRTtcgFz+4wirz2f7P3lC0NrQw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -7534,8 +7542,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7544,7 +7551,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.294.0.tgz", "integrity": "sha512-UxrcAA/0l7j9+3tolYcG5M61D/IE1Bjd/9H87H1i2A2BrwUUBhW1Dp/vvROEDrrywlMDG3CDF3T/7ADtTak+sg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/client-sso": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -7558,8 +7564,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7568,7 +7573,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.292.0.tgz", "integrity": "sha512-4DbtIEM9gGVfqYlMdYXg3XY+vBhemjB1zXIequottW8loLYM8Vuz4/uGxxKNze6evVVzowsA0wKrYclE1aj/Rg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7579,8 +7583,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7589,7 +7592,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.294.0.tgz", "integrity": "sha512-CRGwCs6F31mQzjYi5YF2Z6c1T+UrFKtJSa6Ff/Q1rrPnROexyhBVnpP8WzpkODx/pZxKtTX50IX7ehIxbFDIyQ==", "optional": true, - "peer": true, "requires": { "@aws-sdk/client-cognito-identity": "3.294.0", "@aws-sdk/client-sso": "3.294.0", @@ -7612,8 +7614,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7622,7 +7623,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/fetch-http-handler/-/fetch-http-handler-3.292.0.tgz", "integrity": "sha512-zh3bhUJbL8RSa39ZKDcy+AghtUkIP8LwcNlwRIoxMQh3Row4D1s4fCq0KZCx98NJBEXoiTLyTQlZxxI//BOb1Q==", "optional": true, - "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/querystring-builder": "3.292.0", @@ -7635,8 +7635,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7645,7 +7644,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/hash-node/-/hash-node-3.292.0.tgz", "integrity": "sha512-1yLxmIsvE+eK36JXEgEIouTITdykQLVhsA5Oai//Lar6Ddgu1sFpLDbdkMtKbrh4I0jLN9RacNCkeVQjZPTCCQ==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-buffer-from": "3.292.0", @@ -7657,8 +7655,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7667,7 +7664,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/invalid-dependency/-/invalid-dependency-3.292.0.tgz", "integrity": "sha512-39OUV78CD3TmEbjhpt+V+Fk4wAGWhixqHxDSN8+4WL0uB4Fl7k5m3Z9hNY78AttHQSl2twR7WtLztnXPAFsriw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7677,8 +7673,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7687,7 +7682,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/is-array-buffer/-/is-array-buffer-3.292.0.tgz", "integrity": "sha512-kW/G5T/fzI0sJH5foZG6XJiNCevXqKLxV50qIT4B1pMuw7regd4ALIy0HwSqj1nnn9mSbRWBfmby0jWCJsMcwg==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -7696,8 +7690,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7706,7 +7699,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-content-length/-/middleware-content-length-3.292.0.tgz", "integrity": "sha512-2gMWzQus5mj14menolpPDbYBeaOYcj7KNFZOjTjjI3iQ0KqyetG6XasirNrcJ/8QX1BRmpTol8Xjp2Ue3Gbzwg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7717,8 +7709,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7727,7 +7718,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint/-/middleware-endpoint-3.292.0.tgz", "integrity": "sha512-cPMkiSxpZGG6tYlW4OS+ucS6r43f9ddX9kcUoemJCY10MOuogdPjulCAjE0HTs2PLKSOrrG4CTP4Q4wWDrH4Bw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/middleware-serde": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -7743,8 +7733,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7753,7 +7742,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.292.0.tgz", "integrity": "sha512-mHuCWe3Yg2S5YZ7mB7sKU6C97XspfqrimWjMW9pfV2usAvLA3R0HrB03jpR5vpZ3P4q7HB6wK3S6CjYMGGRNag==", "optional": true, - "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7764,8 +7752,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7774,7 +7761,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.292.0.tgz", "integrity": "sha512-yZNY1XYmG3NG+uonET7jzKXNiwu61xm/ZZ6i/l51SusuaYN+qQtTAhOFsieQqTehF9kP4FzbsWgPDwD8ZZX9lw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7784,8 +7770,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7794,7 +7779,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.292.0.tgz", "integrity": "sha512-kA3VZpPko0Zqd7CYPTKAxhjEv0HJqFu2054L04dde1JLr43ro+2MTdX7vsHzeAFUVRphqatFFofCumvXmU6Mig==", "optional": true, - "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7805,8 +7789,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7815,7 +7798,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-retry/-/middleware-retry-3.293.0.tgz", "integrity": "sha512-7tiaz2GzRecNHaZ6YnF+Nrtk3au8qF6oiipf11R7MJiqJ0fkMLnz/iRrlakDziS9qF/a9v+3yxb4W4NHK3f4Tw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/service-error-classification": "3.292.0", @@ -7830,15 +7812,13 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7847,7 +7827,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.292.0.tgz", "integrity": "sha512-GN5ZHEqXZqDi+HkVbaXRX9HaW/vA5rikYpWKYsmxTUZ7fB7ijvEO3co3lleJv2C+iGYRtUIHC4wYNB5xgoTCxg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/middleware-signing": "3.292.0", "@aws-sdk/property-provider": "3.292.0", @@ -7861,8 +7840,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7871,7 +7849,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-serde/-/middleware-serde-3.292.0.tgz", "integrity": "sha512-6hN9mTQwSvV8EcGvtXbS/MpK7WMCokUku5Wu7X24UwCNMVkoRHLIkYcxHcvBTwttuOU0d8hph1/lIX4dkLwkQw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -7881,8 +7858,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7891,7 +7867,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.292.0.tgz", "integrity": "sha512-GVfoSjDjEQ4TaO6x9MffyP3uRV+2KcS5FtexLCYOM9pJcnE9tqq9FJOrZ1xl1g+YjUVKxo4x8lu3tpEtIb17qg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -7905,8 +7880,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7915,7 +7889,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-stack/-/middleware-stack-3.292.0.tgz", "integrity": "sha512-WdQpRkuMysrEwrkByCM1qCn2PPpFGGQ2iXqaFha5RzCdZDlxJni9cVNb6HzWUcgjLEYVTXCmOR9Wxm3CNW44Qg==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -7924,8 +7897,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7934,7 +7906,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.293.0.tgz", "integrity": "sha512-gZ7/e6XwpKk9mvgA78q4Ffc796jTn02TUKx2qMDnkLVbeJXBNN2jnvYEKq8v70+o7fd/ALRudg8gBDmkkhM/Hw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/protocol-http": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -7946,8 +7917,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7956,7 +7926,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/node-config-provider/-/node-config-provider-3.292.0.tgz", "integrity": "sha512-S3NnC9dQ5GIbJYSDIldZb4zdpCOEua1tM7bjYL3VS5uqCEM93kIi/o/UkIUveMp/eqTS2LJa5HjNIz5Te6je0A==", "optional": true, - "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/shared-ini-file-loader": "3.292.0", @@ -7968,8 +7937,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -7978,7 +7946,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/node-http-handler/-/node-http-handler-3.292.0.tgz", "integrity": "sha512-L/E3UDSwXLXjt1XWWh0RBD55F+aZI1AEdPwdES9i1PjnZLyuxuDhEDptVibNN56+I9/4Q3SbmuVRVlOD0uzBag==", "optional": true, - "peer": true, "requires": { "@aws-sdk/abort-controller": "3.292.0", "@aws-sdk/protocol-http": "3.292.0", @@ -7991,8 +7958,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8001,7 +7967,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/property-provider/-/property-provider-3.292.0.tgz", "integrity": "sha512-dHArSvsiqhno/g55N815gXmAMrmN8DP7OeFNqJ4wJG42xsF2PFN3DAsjIuHuXMwu+7A3R1LHqIpvv0hA9KeoJQ==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -8011,8 +7976,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8021,7 +7985,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/protocol-http/-/protocol-http-3.292.0.tgz", "integrity": "sha512-NLi4fq3k41aXIh1I97yX0JTy+3p6aW1NdwFwdMa674z86QNfb4SfRQRZBQe9wEnAZ/eWHVnlKIuII+U1URk/Kg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -8031,8 +7994,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8041,7 +8003,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-builder/-/querystring-builder-3.292.0.tgz", "integrity": "sha512-XElIFJaReIm24eEvBtV2dOtZvcm3gXsGu/ftG8MLJKbKXFKpAP1q+K6En0Bs7/T88voKghKdKpKT+eZUWgTqlg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "@aws-sdk/util-uri-escape": "3.292.0", @@ -8052,8 +8013,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8062,7 +8022,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/querystring-parser/-/querystring-parser-3.292.0.tgz", "integrity": "sha512-iTYpYo7a8X9RxiPbjjewIpm6XQPx2EOcF1dWCPRII9EFlmZ4bwnX+PDI36fIo9oVs8TIKXmwNGODU9nsg7CSAw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -8072,8 +8031,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8081,15 +8039,13 @@ "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/service-error-classification/-/service-error-classification-3.292.0.tgz", "integrity": "sha512-X1k3sixCeC45XSNHBe+kRBQBwPDyTFtFITb8O5Qw4dS9XWGhrUJT4CX0qE5aj8qP3F9U5nRizs9c2mBVVP0Caw==", - "optional": true, - "peer": true + "optional": true }, "@aws-sdk/shared-ini-file-loader": { "version": "3.292.0", "resolved": "https://registry.npmjs.org/@aws-sdk/shared-ini-file-loader/-/shared-ini-file-loader-3.292.0.tgz", "integrity": "sha512-Av2TTYg1Jig2kbkD56ybiqZJB6vVrYjv1W5UQwY/q3nA/T2mcrgQ20ByCOt5Bv9VvY7FSgC+znj+L4a7RLGmBg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -8099,8 +8055,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8109,7 +8064,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4/-/signature-v4-3.292.0.tgz", "integrity": "sha512-+rw47VY5mvBecn13tDQTl1ipGWg5tE63faWgmZe68HoBL87ZiDzsd7bUKOvjfW21iMgWlwAppkaNNQayYRb2zg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/is-array-buffer": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8124,8 +8078,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8134,7 +8087,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/smithy-client/-/smithy-client-3.292.0.tgz", "integrity": "sha512-S8PKzjPkZ6SXYZuZiU787dMsvQ0d/LFEhw2OI4Oe2An9Fc2IwJ2FYukyHoQJOV2tV0DiuMebPo7eMyQyjKElvA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/middleware-stack": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8145,8 +8097,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8155,7 +8106,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.294.0.tgz", "integrity": "sha512-6nwO04LtC5f4AsUvGZXyjaswuEK4Rr2VsuANpMKrPCgunRfI58a8YXLniudOSXN6e7CFJ6M3uo/h5YXqtnzGug==", "optional": true, - "peer": true, "requires": { "@aws-sdk/client-sso-oidc": "3.294.0", "@aws-sdk/property-provider": "3.292.0", @@ -8168,8 +8118,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8178,7 +8127,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.292.0.tgz", "integrity": "sha512-1teYAY2M73UXZxMAxqZxVS2qwXjQh0OWtt7qyLfha0TtIk/fZ1hRwFgxbDCHUFcdNBSOSbKH/ESor90KROXLCQ==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8187,8 +8135,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8197,7 +8144,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/url-parser/-/url-parser-3.292.0.tgz", "integrity": "sha512-NZeAuZCk1x6TIiWuRfbOU6wHPBhf0ly2qOHzWut4BCH+b4RrDmFF8EmXcH1auEfGhE7yRyR6XqIN0t3S+hYACA==", "optional": true, - "peer": true, "requires": { "@aws-sdk/querystring-parser": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8208,8 +8154,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8218,7 +8163,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-base64/-/util-base64-3.292.0.tgz", "integrity": "sha512-zjNCwNdy617yFvEjZorepNWXB2sQCVfsShCwFy/kIQ5iW5tT2jQKaqc0K77diU9atkooxw9p1W9m9sOgrkOFNw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -8228,8 +8172,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8238,7 +8181,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-browser/-/util-body-length-browser-3.292.0.tgz", "integrity": "sha512-Wd/BM+JsMiKvKs/bN3z6TredVEHh2pKudGfg3CSjTRpqFpOG903KDfyHBD42yg5PuCHoHoewJvTPKwgn7/vhaw==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8247,8 +8189,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8257,7 +8198,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-body-length-node/-/util-body-length-node-3.292.0.tgz", "integrity": "sha512-BBgipZ2P6RhogWE/qj0oqpdlyd3iSBYmb+aD/TBXwB2lA/X8A99GxweBd/kp06AmcJRoMS9WIXgbWkiiBlRlSA==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8266,8 +8206,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8276,7 +8215,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-buffer-from/-/util-buffer-from-3.292.0.tgz", "integrity": "sha512-RxNZjLoXNxHconH9TYsk5RaEBjSgTtozHeyIdacaHPj5vlQKi4hgL2hIfKeeNiAfQEVjaUFF29lv81xpNMzVMQ==", "optional": true, - "peer": true, "requires": { "@aws-sdk/is-array-buffer": "3.292.0", "tslib": "^2.3.1" @@ -8286,8 +8224,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8296,7 +8233,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-config-provider/-/util-config-provider-3.292.0.tgz", "integrity": "sha512-t3noYll6bPRSxeeNNEkC5czVjAiTPcsq00OwfJ2xyUqmquhLEfLwoJKmrT1uP7DjIEXdUtfoIQ2jWiIVm/oO5A==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8305,8 +8241,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8315,7 +8250,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-browser/-/util-defaults-mode-browser-3.292.0.tgz", "integrity": "sha512-7+zVUlMGfa8/KT++9humHo6IDxTnxMCmWUj5jVNlkpk6h7Ecmppf7aXotviyVIA43lhtz0p2AErs0N0ekEUK+w==", "optional": true, - "peer": true, "requires": { "@aws-sdk/property-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8327,8 +8261,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8337,7 +8270,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-defaults-mode-node/-/util-defaults-mode-node-3.292.0.tgz", "integrity": "sha512-SSIw85eF4BVs0fOJRyshT+R3b/UmBPhiVKCUZm2rq6+lIGkDPiSwQU3d/80AhXtiL5SFT/IzAKKgQd8qMa7q3A==", "optional": true, - "peer": true, "requires": { "@aws-sdk/config-resolver": "3.292.0", "@aws-sdk/credential-provider-imds": "3.292.0", @@ -8351,8 +8283,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8361,7 +8292,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.293.0.tgz", "integrity": "sha512-R/99aNV49Refpv5guiUjEUrZYlvnfaNBniB+/ZtMO3ixxUopapssCrUivuJrmhccmrYaTCZw7dRzIWjU1jJhKg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "tslib": "^2.3.1" @@ -8371,8 +8301,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8381,7 +8310,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-hex-encoding/-/util-hex-encoding-3.292.0.tgz", "integrity": "sha512-qBd5KFIUywQ3qSSbj814S2srk0vfv8A6QMI+Obs1y2LHZFdQN5zViptI4UhXhKOHe+NnrHWxSuLC/LMH6q3SmA==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8390,8 +8318,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8400,7 +8327,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.292.0.tgz", "integrity": "sha512-6xnFJXZI9pKw5lQCDvuWA5PnOaUtNRKWwdxvGkkLx5orboFaoVMS6zowjSQxwVNRjW82u6dYNkhmj9mZ8VSjWg==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8409,8 +8335,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8419,7 +8344,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-middleware/-/util-middleware-3.292.0.tgz", "integrity": "sha512-KjhS7flfoBKDxbiBZjLjMvEizXgjfQb7GQEItgzGoI9rfGCmZtvqCcqQQoIlxb8bIzGRggAUHtBGWnlLbpb+GQ==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8428,8 +8352,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8438,7 +8361,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-retry/-/util-retry-3.292.0.tgz", "integrity": "sha512-JEHyF7MpVeRF5uR4LDYgpOKcFpOPiAj8TqN46SVOQQcL1K+V7cSr7O7N7J6MwJaN9XOzAcBadeIupMm7/BFbgw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/service-error-classification": "3.292.0", "tslib": "^2.3.1" @@ -8448,8 +8370,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8458,7 +8379,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-uri-escape/-/util-uri-escape-3.292.0.tgz", "integrity": "sha512-hOQtUMQ4VcQ9iwKz50AoCp1XBD5gJ9nly/gJZccAM7zSA5mOO8RRKkbdonqquVHxrO0CnYgiFeCh3V35GFecUw==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8467,8 +8387,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8477,7 +8396,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.292.0.tgz", "integrity": "sha512-dld+lpC3QdmTQHdBWJ0WFDkXDSrJgfz03q6mQ8+7H+BC12ZhT0I0g9iuvUjolqy7QR00OxOy47Y9FVhq8EC0Gg==", "optional": true, - "peer": true, "requires": { "@aws-sdk/types": "3.292.0", "bowser": "^2.11.0", @@ -8488,8 +8406,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8498,7 +8415,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.292.0.tgz", "integrity": "sha512-f+NfIMal5E61MDc5WGhUEoicr7b1eNNhA+GgVdSB/Hg5fYhEZvFK9RZizH5rrtsLjjgcr9nPYSR7/nDKCJLumw==", "optional": true, - "peer": true, "requires": { "@aws-sdk/node-config-provider": "3.292.0", "@aws-sdk/types": "3.292.0", @@ -8509,8 +8425,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8519,7 +8434,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8/-/util-utf8-3.292.0.tgz", "integrity": "sha512-FPkj+Z59/DQWvoVu2wFaRncc3KVwe/pgK3MfVb0Lx+Ibey5KUx+sNpJmYcVYHUAe/Nv/JeIpOtYuC96IXOnI6w==", "optional": true, - "peer": true, "requires": { "@aws-sdk/util-buffer-from": "3.292.0", "tslib": "^2.3.1" @@ -8529,8 +8443,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8539,7 +8452,6 @@ "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", "optional": true, - "peer": true, "requires": { "tslib": "^2.3.1" }, @@ -8548,8 +8460,7 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "optional": true, - "peer": true + "optional": true } } }, @@ -8985,6 +8896,96 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, + "@types/mongoose-unique-validator": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/mongoose-unique-validator/-/mongoose-unique-validator-1.0.7.tgz", + "integrity": "sha512-wgPWN7x9mHdy8x1jcluDF7EDWFb/s8LD7skLr012C8i2Q3tUhdTlp3JxRhFbEM3TD7J1INaoTrWaSaguhuqilQ==", + "dev": true, + "requires": { + "mongoose": "^6.3.0" + }, + "dependencies": { + "bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dev": true, + "requires": { + "buffer": "^5.6.0" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "mongodb": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.14.0.tgz", + "integrity": "sha512-coGKkWXIBczZPr284tYKFLg+KbGPPLlSbdgfKAb6QqCFt5bo5VFZ50O3FFzsw4rnkqjwT6D8Qcoo9nshYKM7Mg==", + "dev": true, + "requires": { + "@aws-sdk/credential-providers": "^3.186.0", + "bson": "^4.7.0", + "mongodb-connection-string-url": "^2.5.4", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "mongoose": { + "version": "6.10.5", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-6.10.5.tgz", + "integrity": "sha512-y4HL4/9EySec7L0gJ+pCm9heLSF45uIIvRS4fSeAFWDfe4vXW1vRZJwTz7OGkra3ZoSfRnFTo9bNZkuggDVlVA==", + "dev": true, + "requires": { + "bson": "^4.7.0", + "kareem": "2.5.1", + "mongodb": "4.14.0", + "mpath": "0.9.0", + "mquery": "4.0.3", + "ms": "2.1.3", + "sift": "16.0.1" + } + }, + "mquery": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-4.0.3.tgz", + "integrity": "sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA==", + "dev": true, + "requires": { + "debug": "4.x" + } + }, + "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 + } + } + }, "@types/morgan": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", @@ -8994,6 +8995,12 @@ "@types/node": "*" } }, + "@types/ndarray": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.11.tgz", + "integrity": "sha512-hOZVTN24zDHwCHaW7mF9n1vHJt83fZhNZ0YYRBwQGhA96yBWWDPTDDlqJatagHIOJB0a4xoNkNc+t/Cxd+6qUA==", + "dev": true + }, "@types/node": { "version": "18.14.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.14.6.tgz", @@ -9059,6 +9066,12 @@ "integrity": "sha512-J6OAed6rhN6zyqL9Of6ZMamhlsOEU/poBVvbHr/dKOYKTeuYYMlDkMv+b6UUV0o2i0tw73cgyv/97WTWaUl0/g==", "dev": true }, + "@types/w3c-css-typed-object-model-level-1": { + "version": "20180410.0.5", + "resolved": "https://registry.npmjs.org/@types/w3c-css-typed-object-model-level-1/-/w3c-css-typed-object-model-level-1-20180410.0.5.tgz", + "integrity": "sha512-khoqDQqA/fUdK6mEJtQEfMAPCKkk8E1D+ahM/0HCy3mc5L33wJinqQNXu9Uf4+mqzMvORljHg76jvrmwS0bEjA==", + "dev": true + }, "@types/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -9543,8 +9556,7 @@ "version": "2.11.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", - "optional": true, - "peer": true + "optional": true }, "brace-expansion": { "version": "1.1.11", @@ -10477,7 +10489,6 @@ "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.1.2.tgz", "integrity": "sha512-CDYeykkle1LiA/uqQyNwYpFbyF6Axec6YapmpUP+/RHWIoR1zKjocdvNaTsxCxZzQ6v9MLXaSYm9Qq0thv0DHg==", "optional": true, - "peer": true, "requires": { "strnum": "^1.0.5" } @@ -10973,6 +10984,12 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "iota-array": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/iota-array/-/iota-array-1.0.0.tgz", + "integrity": "sha512-pZ2xT+LOHckCatGQ3DcG/a+QuEqvoxqkiL7tvE8nn3uuu+f6i1TtpB5/FtWFbxUuVr5PZCx8KskuGatbJDXOWA==", + "dev": true + }, "ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", @@ -11540,6 +11557,24 @@ "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", "dev": true }, + "ndarray": { + "version": "1.0.19", + "resolved": "https://registry.npmjs.org/ndarray/-/ndarray-1.0.19.tgz", + "integrity": "sha512-B4JHA4vdyZU30ELBw3g7/p9bZupyew5a7tX1Y/gGeF2hafrPaQZhgrGQfsvgfYbgdFZjYwuEcnaobeM/WMW+HQ==", + "dev": true, + "requires": { + "iota-array": "^1.0.0", + "is-buffer": "^1.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + } + } + }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -12352,8 +12387,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", - "optional": true, - "peer": true + "optional": true }, "supports-color": { "version": "7.2.0", diff --git a/package.json b/package.json index 535bcef..5409fc7 100644 --- a/package.json +++ b/package.json @@ -61,15 +61,19 @@ "@types/dicer": "^0.2.2", "@types/express": "^4.17.17", "@types/fs-extra": "^11.0.1", + "@types/mongoose-unique-validator": "^1.0.7", "@types/morgan": "^1.9.4", + "@types/ndarray": "^1.0.11", "@types/node": "^18.14.4", "@types/node-rsa": "^1.1.1", "@types/nodemailer": "^6.4.7", "@types/qs": "^6.9.7", "@types/validator": "^13.7.14", + "@types/w3c-css-typed-object-model-level-1": "^20180410.0.5", "@typescript-eslint/eslint-plugin": "^5.54.1", "@typescript-eslint/parser": "^5.54.1", "eslint": "^8.35.0", + "ndarray": "^1.0.19", "prompt": "^1.0.0", "typescript": "^4.9.5", "yesno": "^0.4.0" diff --git a/src/models/pnid.ts b/src/models/pnid.ts index 9fa984a..74613f6 100644 --- a/src/models/pnid.ts +++ b/src/models/pnid.ts @@ -176,12 +176,8 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi instanceCount: 1, }); const miiStudioNormalFaceImageData: Buffer = await got(miiStudioUrl).buffer(); - const pngData: { - width: number; - height: number; - data: Buffer; - } = await imagePixels(miiStudioNormalFaceImageData); - const tga: Buffer = TGA.createTgaBuffer(pngData.width, pngData.height, pngData.data); + const pngData: ImageData = await imagePixels(miiStudioNormalFaceImageData); + const tga: Buffer = TGA.createTgaBuffer(pngData.width, pngData.height, Uint8Array.from(pngData.data), false); const userMiiKey: string = `mii/${this.get('pid')}`; diff --git a/src/types/express-subdomain.d.ts b/src/types/express-subdomain.d.ts index cb1cbdc..933d1f0 100644 --- a/src/types/express-subdomain.d.ts +++ b/src/types/express-subdomain.d.ts @@ -1,3 +1,16 @@ -declare module 'express-subdomain'; +// * Credit to https://github.com/bmullan91/express-subdomain/pull/61 for the types! -// TODO - Add proper types \ No newline at end of file +declare module 'express-subdomain'{ + import type { Request, Response, Router } from 'express'; + + /** + * @description The subdomain function. + * @param subdomain The subdomain to listen on. + * @param fn The listener function, takes a response and request. + * @returns A function call to the value passed as FN, or void (the next function). + */ + export default function subdomain( + subdomain: string, + fn: Router | ((req: Request, res: Response) => void | any) + ): (req: Request, res: Response, next: () => void) => void | typeof fn; +} \ No newline at end of file diff --git a/src/types/image-pixels.d.ts b/src/types/image-pixels.d.ts index bd142c3..762209c 100644 --- a/src/types/image-pixels.d.ts +++ b/src/types/image-pixels.d.ts @@ -1,3 +1,34 @@ -declare module 'image-pixels'; +declare module 'image-pixels' { + import { NdArray } from 'ndarray'; -// TODO - Add proper types \ No newline at end of file + export interface ImagePixelsOptions { + source: ImageSource; + shape: [number, number]; + width: number; + height: number; + type: string; + mime: string; + clip: [number, number, number, number] | { + x?: number; + y?: number; + width?: number; + height?: number; + }; + cache: boolean; + } + + export type ImageSource = string | + HTMLImageElement | SVGImageElement | HTMLVideoElement | CSSImageValue | + typeof Image | ImageData | ImageBitmap | + File | Blob | + //Canvas | Context2D | + //WebGLContext | + Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | + Float32Array | Float64Array | Array | Array> | + NdArray | + ImagePixelsOptions; + + export default function pixels( + src: ImageSource | Promise + ): ImageData; +} \ No newline at end of file diff --git a/src/types/mongoose-unique-validator.d.ts b/src/types/mongoose-unique-validator.d.ts deleted file mode 100644 index 0909028..0000000 --- a/src/types/mongoose-unique-validator.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'mongoose-unique-validator'; \ No newline at end of file diff --git a/src/types/tga.d.ts b/src/types/tga.d.ts index e1c6188..16eb4a2 100644 --- a/src/types/tga.d.ts +++ b/src/types/tga.d.ts @@ -1,3 +1,58 @@ -declare module 'tga'; +declare module 'tga' { + export interface TGAHeader { + idLength: number; + colorMapType: number; + dataType: number; + colorMapOrigin: number; + colorMapLength: number; + colorMapDepth: number; + xOrigin: number; + yOrigin: number; + width: number; + height: number; + bitsPerPixel: number; + flags: number; + id: string; + } -// TODO - Add proper types \ No newline at end of file + export default class TGA { + constructor(buf: Buffer, opt?: { dontFixAlpha: boolean }); + + static createTgaBuffer(width: number, height: number, pixels: Uint8Array, dontFlipY: boolean): Buffer; + + parseHeader(): void; + parseFooter(): void; + parseExtension(extensionAreaOffset: number): void; + readColor(offset: number, bytesPerPixel: number): Uint8Array; + readColorWithColorMap(offset: number): Uint8Array; + readColorAuto(offset: number, bytesPerPixel: number, isUsingColorMap: boolean): Uint8Array; + parseColorMap(): void; + setPixel(pixels: Uint8Array, idx: number, color: Uint8Array): void; + parsePixels(): void; + parse(): void; + fixForAlpha(): void; + + public dontFixAlpha: boolean; + public _buff: Buffer; + public data: Uint8Array; + public currentOffset: number; + + public header: TGAHeader; + + public width: number; + public height: number; + + public isUsingColorMap: boolean; + public isUsingRLE: boolean; + public isGray: boolean; + + public hasAlpha: boolean; + + public isFlipX: boolean; + public isFlipY: boolean; + + public colorMap: Uint8Array; + + public pixels: Uint8Array; + } +} \ No newline at end of file