From 990fea7bd0da5fbb4c296bda378851da3b973d97 Mon Sep 17 00:00:00 2001 From: kyrea Date: Thu, 11 Jul 2024 00:47:10 +0530 Subject: [PATCH 1/8] Added stats route for internal statistics and status --- src/controllers/v4/internal/stats.js | 33 ++++++++++++++++++++++++++++ src/routes/v4/index.js | 16 ++++++++++++++ src/routes/v4/internal/stats.js | 28 +++++++++++++++++++++++ 3 files changed, 77 insertions(+) create mode 100644 src/controllers/v4/internal/stats.js create mode 100644 src/routes/v4/internal/stats.js diff --git a/src/controllers/v4/internal/stats.js b/src/controllers/v4/internal/stats.js new file mode 100644 index 0000000..0397357 --- /dev/null +++ b/src/controllers/v4/internal/stats.js @@ -0,0 +1,33 @@ +import createError from 'http-errors'; +import Stats from '../../../models/schemas/Stat.js'; + +// Get Internal Status or statistics +const getStats = async (req, res, next) => { + const key = req.headers.key; + // Check for valid access key in headers + if (!key || key !== process.env.ACCESS_KEY) { + return res.status(401).json({ + message: 'Unauthorized', + }); + } + try { + const [result] = await Stats.aggregate([ + // Select a random document from the results + { $sample: { size: 1 } }, + { $project: { __v: 0, _id: 0 } }, + ]); + + if (!result) { + return next(createError(404, 'Could not find any Stats')); + } + + res.status(200).json(result); + + await Stats.findOneAndUpdate({ _id: 'systemstats' }, { $inc: { stats: 1 } }); + } catch (error) { + await Stats.findOneAndUpdate({ _id: 'systemstats' }, { $inc: { failed_requests: 1 } }); + return next(error); + } +}; + +export { getStats }; diff --git a/src/routes/v4/index.js b/src/routes/v4/index.js index f79c929..d67da16 100644 --- a/src/routes/v4/index.js +++ b/src/routes/v4/index.js @@ -1192,6 +1192,22 @@ import yesRoutes from './interactions/yes.js'; */ router.use('/yes', yesRoutes); +import statsRoutes from './internal/stats.js'; + +/** + * @api {use} v4/stats Use Stats Routes + * @apiDescription Mount the stats-related routes for handling interactions. + * @apiName UseStatsRoutes + * @apiGroup Routes + * + * @apiSuccess {Object} routes Stats-related routes mounted on the parent router. + * + * @function createStatsRoutes + * @description Creates and returns a set of routes for handling interactions related to Stats. + * @returns {Object} Stats-related routes. + */ +router.use('/stats', statsRoutes); + /** * Exporting the router for use in other parts of the application. * @exports {Router} router - Express Router instance with mounted routes. diff --git a/src/routes/v4/internal/stats.js b/src/routes/v4/internal/stats.js new file mode 100644 index 0000000..025f9f6 --- /dev/null +++ b/src/routes/v4/internal/stats.js @@ -0,0 +1,28 @@ +import { Router } from 'express'; +import { getStats } from '../../../controllers/v4/internal/stats.js'; +import createRateLimiter from '../../../middlewares/rateLimit.js'; + +const router = Router(); + +router + .route('/') + /** + * @api {post} v4/stats Get Statistics + * @apiDescription Get statistics about the system usage. + * @apiName getStats + * @apiGroup Statistics + * @apiPermission user + * + * @apiHeader {String} Authorization System access token. + * + * @apiSuccess {Object} stats System statistics or status. + * + * @apiError (Unauthorized 401) Unauthorized Only authenticated users can access the data. + * @apiError (Forbidden 403) Forbidden Only authorized users can access the data. + * @apiError (Too Many Requests 429) TooManyRequests The client has exceeded the allowed number of requests within the time window. + * @apiError (Internal Server Error 500) InternalServerError An error occurred while processing the request. + */ + .get(createRateLimiter(), getStats); + +// Export the router +export default router; From eedd25bd15e0cb6bc253561ee6d198d03b1e80c4 Mon Sep 17 00:00:00 2001 From: kyrea Date: Thu, 11 Jul 2024 00:53:20 +0530 Subject: [PATCH 2/8] Added req_consumed to count exhausted quotas --- src/models/schemas/User.js | 45 +++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/models/schemas/User.js b/src/models/schemas/User.js index a24af91..445a88e 100644 --- a/src/models/schemas/User.js +++ b/src/models/schemas/User.js @@ -76,7 +76,7 @@ const UserSchema = new mongoose.Schema({ * @type {number} * @default 500 */ - req_quota: { type: Number, default: 500 }, + req_quota: { type: Number, required: true, default: 500 }, /** * Number of requests made by the user. @@ -85,6 +85,13 @@ const UserSchema = new mongoose.Schema({ */ req_count: { type: Number, default: 0 }, + /** + * Number of requests consumed by the user. + * @type {number} + * @default 0 + */ + req_consumed: { type: Number, default: 0 }, + /** * Date and time when the user account was created. * @type {Date} @@ -108,6 +115,42 @@ const UserSchema = new mongoose.Schema({ * @default ['user'] */ roles: { type: [String], default: ['user'] }, + + /** + * Subscription or plan type. + * @type {string} + */ + planType: { type: String, default: 'free' }, + + /** + * Subscription start date. + * @type {Date} + */ + subscriptionStart: { type: Date }, + + /** + * Subscription end date. + * @type {Date} + */ + subscriptionEnd: { type: Date }, + + /** + * Subscription status. + * @type {string} + * @enum ['active', 'expired', 'canceled', 'pending', 'suspended', 'trial', 'renewal due', 'grace period'] + * @default 'active' + */ + subscriptionStatus: { + type: String, + enum: ['active', 'expired', 'canceled', 'pending', 'suspended', 'trial', 'renewal due', 'grace period'], + default: 'active', + }, + + /** + * Metadata for subscription. + * @type {object} + */ + subscriptionMetadata: { type: Object }, }); /** From 96d34a1369f9b9e9d3b4ae288a7c8ae0c812a2d4 Mon Sep 17 00:00:00 2001 From: kyrea Date: Thu, 11 Jul 2024 00:56:50 +0530 Subject: [PATCH 3/8] Added a check if the requested endpoint is enabled or not [this feature is limited to the token based endpoints] --- src/middlewares/authorize.js | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/middlewares/authorize.js b/src/middlewares/authorize.js index ba6deda..4b7ac2c 100644 --- a/src/middlewares/authorize.js +++ b/src/middlewares/authorize.js @@ -16,6 +16,24 @@ import Stats from '../models/schemas/Stat.js'; */ const authorize = requiredRole => async (req, res, next) => { try { + /** + * Determine the endpoint based on the request URL. + */ + const endpoint = getEndpointFromUrl(req.originalUrl); + /** + * Check if the requested endpoint is disabled. + */ + const isEndpointEnabled = await isEndpointEnabledInStats(endpoint); + + if (!isEndpointEnabled) { + return next( + createError( + 403, + `The endpoint '${endpoint}' is currently disabled. Go to https://discord.gg/yyW389c for support.`, + ), + ); + } + /** * Extract API key from request headers. * @@ -49,6 +67,7 @@ const authorize = requiredRole => async (req, res, next) => { const updateData = { $inc: { req_quota: userData && userData.req_quota > 0 ? -1 : 0, + req_consumed: userData && userData.req_quota > 0 ? 1 : 0, req_count: userData ? 1 : 0, }, }; @@ -113,6 +132,46 @@ const authorize = requiredRole => async (req, res, next) => { } }; +/** + * Helper function to extract endpoint from the request URL. + * + * @param {string} url - The request URL. + * @returns {string} - The extracted endpoint. + */ +const getEndpointFromUrl = url => { + const urlSegments = url.split('/'); + return urlSegments[urlSegments.length - 1]; // Last segment is assumed to be the endpoint +}; + +/** + * Helper function to check if the endpoint is enabled in the Stats collection. + * + * @param {string} endpoint - The endpoint to check. + * @returns {Promise} - Promise resolving to true if enabled, false otherwise. + */ +const isEndpointEnabledInStats = async endpoint => { + try { + // Assuming 'Stats' is the correct model for endpoint settings + const settings = await Stats.findOne(); + + // Handle case where settings are not found + if (!settings) { + return false; + } + + // Check if endpoint exists in settings and isEnabled is defined + if (settings[endpoint] && typeof settings[endpoint].isEnabled !== 'undefined') { + return settings[endpoint].isEnabled; + } + + // Default to true if isEnabled is not defined or endpoint doesn't exist + return true; + } catch (error) { + console.error('Error fetching endpoint settings:', error); + return true; + } +}; + /** * Increment the specified statistics in the system stats collection. * From 3b46920856c88330990d0c7befdc3e57af8e346a Mon Sep 17 00:00:00 2001 From: kyrea Date: Thu, 11 Jul 2024 00:58:17 +0530 Subject: [PATCH 4/8] Bumped the versions --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e6aaf6..51bff2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "waifu.it", - "version": "4.6.0", + "version": "4.7.1", "lockfileVersion": 3, "requires": true, "packages": { @@ -2589,4 +2589,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 5f2fa35..65cd17e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "waifu.it", - "version": "4.6.0", + "version": "4.7.1", "description": "Random API Serving Anime stuff", "author": "Aeryk", "private": true, @@ -50,4 +50,4 @@ "weeb", "anime-girls" ] -} +} \ No newline at end of file From cbc60b63860aba4b4beb2727eb458f0da9c7d6b1 Mon Sep 17 00:00:00 2001 From: kyrea Date: Thu, 11 Jul 2024 01:00:04 +0530 Subject: [PATCH 5/8] Fixed a typo --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51bff2f..1ff7948 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "waifu.it", - "version": "4.7.1", + "version": "4.7.0", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/package.json b/package.json index 65cd17e..a5a8ab5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "waifu.it", - "version": "4.7.1", + "version": "4.7.0", "description": "Random API Serving Anime stuff", "author": "Aeryk", "private": true, From d01dbf1db48bef59ec06d783ee1c76418cb73e2f Mon Sep 17 00:00:00 2001 From: kyrea Date: Fri, 19 Jul 2024 02:01:37 +0530 Subject: [PATCH 6/8] Fixed the rate limit default to 20 req/sec --- src/middlewares/rateLimit.js | 58 +----------------------------------- src/models/schemas/Stat.js | 16 ++++++++++ 2 files changed, 17 insertions(+), 57 deletions(-) diff --git a/src/middlewares/rateLimit.js b/src/middlewares/rateLimit.js index d78e0c2..fd8a2b6 100644 --- a/src/middlewares/rateLimit.js +++ b/src/middlewares/rateLimit.js @@ -1,36 +1,11 @@ import rateLimit from 'express-rate-limit'; -import Users from '../models/schemas/User.js'; /** * @function createRateLimiter * @description Create and return the rate limiter middleware. * @returns {Function} Express middleware for rate limiting. - * - * @example - * // Basic usage - * const limiter = createRateLimiter(); - * app.use('/api/route', limiter); - * - * @example - * // Customized options - * const customOptions = { - * windowMs: 15 * 60 * 1000, // 15 minutes - * max: 100, // limit each IP to 100 requests per windowMs - * message: 'Too many requests from this IP, please try again after a few minutes.', - * }; - * const customLimiter = createRateLimiter(customOptions); - * app.use('/api/customRoute', customLimiter); */ const createRateLimiter = () => { - /** - * Default rate limiting options. - * @typedef {Object} RateLimitOptions - * @property {number} [windowMs=60000] - The time window for which the requests are checked/metered (in milliseconds). - * @property {number} [max=20] - The maximum number of allowed requests within the windowMs time frame. - * @property {Object} message - The message sent in the response when the limit is exceeded. - * @property {number} [message.status=429] - The HTTP status code to be set in the response. - * @property {string} [message.message='You've exhausted your ratelimit, please try again later.'] - The message to be sent in the response. - */ const defaultOptions = { windowMs: 60 * 1000, // 1 minute max: 20, // Default rate limit @@ -40,38 +15,7 @@ const createRateLimiter = () => { }, }; - // Create rate limiter middleware with default options - const limiter = rateLimit(defaultOptions); - - /** - * Express middleware function for rate limiting. - * @param {Object} req - Express request object. - * @param {Object} res - Express response object. - * @param {Function} next - Express next function. - */ - return async (req, res, next) => { - try { - // Extract token from request headers - const token = req.headers.authorization; - - // Find user data from the database based on token - const user = await Users.findOne({ token }); - - // Override default rate limit if user's rate limit is defined - if (user && user.rateLimit) { - limiter.options.max = user.rateLimit; - } - - // Apply rate limiting - limiter(req, res, next); - } catch (error) { - // Handle errors when fetching user data - console.error('Error fetching user data:', error.message); - - // Apply rate limiting as a fallback - limiter(req, res, next); - } - }; + return rateLimit(defaultOptions); }; export default createRateLimiter; diff --git a/src/models/schemas/Stat.js b/src/models/schemas/Stat.js index 18a1da6..4b284db 100644 --- a/src/models/schemas/Stat.js +++ b/src/models/schemas/Stat.js @@ -3,12 +3,28 @@ const { Schema, model } = mongoose; const StatSchema = new Schema({ _id: { type: String, required: true, default: 'system' }, + dashboard: { + isEnabled: { type: Boolean, default: true }, + }, + registrations: { + isEnabled: { type: Boolean, default: true }, + }, + login: { + isEnabled: { type: Boolean, default: true }, + }, + tokenReset: { + isEnabled: { type: Boolean, default: true }, + }, + quote: { + isEnabled: { type: Boolean, default: true }, + }, total_requests: { type: Number, default: 0 }, endpoints_requests: { type: Number, default: 0 }, failed_requests: { type: Number, default: 0 }, success_requests: { type: Number, default: 0 }, banned_requests: { type: Number, default: 0 }, daily_requests: { type: Number, default: 0 }, + stats: { type: Number, default: 0 }, run: { type: Number, default: 0 }, sad: { type: Number, default: 0 }, shoot: { type: Number, default: 0 }, From 404a6bb39e21b55daf44628a91a879865fed5958 Mon Sep 17 00:00:00 2001 From: kyrea Date: Fri, 19 Jul 2024 03:22:48 +0530 Subject: [PATCH 7/8] Added statistics for every user per endpoint --- src/middlewares/authorize.js | 30 ++++++++++++++++++++++++++++++ src/models/schemas/User.js | 12 ++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/middlewares/authorize.js b/src/middlewares/authorize.js index 4b7ac2c..11c69d5 100644 --- a/src/middlewares/authorize.js +++ b/src/middlewares/authorize.js @@ -20,6 +20,7 @@ const authorize = requiredRole => async (req, res, next) => { * Determine the endpoint based on the request URL. */ const endpoint = getEndpointFromUrl(req.originalUrl); + /** * Check if the requested endpoint is disabled. */ @@ -111,6 +112,11 @@ const authorize = requiredRole => async (req, res, next) => { return next(createError(403, 'Insufficient privileges to access this endpoint.')); } + /** + * Log the user request. + */ + await logUserRequest(userData._id, endpoint); + /** * Increment system stats for successful requests. */ @@ -184,4 +190,28 @@ const incrementSystemStats = async stats => { await Stats.findByIdAndUpdate({ _id: 'systemstats' }, { $inc: stats }); }; +/** + * Log the number of requests made by a user to a specific endpoint. + * + * @param {string} userId - The ID of the user. + * @param {string} endpoint - The endpoint being accessed. + * @returns {Promise} - Resolves when the log is updated. + */ +const logUserRequest = async (userId, endpoint) => { + try { + // Find the user and update the request count for the specific endpoint + await Users.findByIdAndUpdate( + userId, + { + $inc: { + [`statistics.requests.${endpoint}`]: 1, + }, + }, + { new: true, upsert: true }, // Create a new document if it doesn't exist + ); + } catch (error) { + console.error('Error logging user request:', error); + } +}; + export default authorize; diff --git a/src/models/schemas/User.js b/src/models/schemas/User.js index 445a88e..2d49305 100644 --- a/src/models/schemas/User.js +++ b/src/models/schemas/User.js @@ -151,6 +151,18 @@ const UserSchema = new mongoose.Schema({ * @type {object} */ subscriptionMetadata: { type: Object }, + + /** + * Object to store the count of requests made to each endpoint by the user. + * @type {Object} + */ + statistics: { + requests: { + type: Map, + of: Number, + default: {}, + }, + }, }); /** From 1d134ca5187bf7068d1ddd29aa8010cfa8910418 Mon Sep 17 00:00:00 2001 From: kyrea Date: Mon, 5 Aug 2024 23:54:54 +0530 Subject: [PATCH 8/8] Updated some package --- package-lock.json | 221 +++++++++++++++++++--------------------------- 1 file changed, 91 insertions(+), 130 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ff7948..7f3c23b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "waifu.it", - "version": "4.5.15", + "version": "4.7.0", "license": "AGPLv3", "dependencies": { "chalk": "^4.1.2", @@ -40,9 +40,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -88,11 +88,11 @@ } }, "node_modules/@types/node": { - "version": "20.11.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", - "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.1.0.tgz", + "integrity": "sha512-AOmuRF0R2/5j1knA3c6G3HOk523Ga+l+ZXltX8SF1+5oqcXijjfTd8fY3XRZqSihEu9XhtQnKYLmkFaoxgsJHw==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.13.0" } }, "node_modules/@types/triple-beam": { @@ -100,12 +100,6 @@ "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -194,12 +188,15 @@ ] }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { @@ -217,12 +214,12 @@ "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -230,7 +227,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -265,12 +262,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -395,9 +392,9 @@ } }, "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", "dependencies": { "string-width": "^4.2.0" }, @@ -565,9 +562,9 @@ } }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -768,16 +765,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -913,9 +910,9 @@ } }, "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==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -1094,9 +1091,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -1305,9 +1302,9 @@ } }, "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.1.tgz", + "integrity": "sha512-CdaO738xRapbKIMVn2m4F6KTj4j7ooJ8POVnebSgKo3KBz5axNXRAL7ZdRjIV6NOr2Uf4vjtRkxrFETOioCqSA==", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -1333,18 +1330,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1586,9 +1571,9 @@ } }, "node_modules/nodemon": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", - "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.4.tgz", + "integrity": "sha512-wjPBbFhtpJwmIeY2yP7QF+UKzPfltVGtfce1g/bB15/8vCGZj8uxD62b/b9M9/WVgme0NZudpownKN+c0plXlQ==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -1614,9 +1599,9 @@ } }, "node_modules/nodemon/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1657,21 +1642,6 @@ "node": ">=4" } }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "*" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -1698,9 +1668,12 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -1902,9 +1875,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -2060,13 +2033,10 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -2132,16 +2102,16 @@ } }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -2162,11 +2132,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -2318,13 +2288,10 @@ } }, "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, "bin": { "nodetouch": "bin/nodetouch.js" } @@ -2352,9 +2319,9 @@ } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/type-is": { @@ -2376,9 +2343,9 @@ "dev": true }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz", + "integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==" }, "node_modules/unpipe": { "version": "1.0.0", @@ -2445,21 +2412,21 @@ } }, "node_modules/winston": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", - "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.13.1.tgz", + "integrity": "sha512-SvZit7VFNvXRzbqGHsv5KSmgbEYR5EiQfDAL9gxYkRqa934Hnk++zze0wANKtMHcy/gI4W/3xmSDwlhf865WGw==", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.4.0", + "logform": "^2.6.0", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "safe-stable-stringify": "^2.3.1", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" + "winston-transport": "^4.7.0" }, "engines": { "node": ">= 12.0.0" @@ -2483,12 +2450,12 @@ } }, "node_modules/winston-transport": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", - "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.1.tgz", + "integrity": "sha512-wQCXXVgfv/wUPOfb2x0ruxzwkcZfxcktz6JIMUaPLmcNhO4bZTwA/WtDWK74xV3F2dKu8YadrFv0qhwYjVEwhA==", "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", + "logform": "^2.6.1", + "readable-stream": "^3.6.2", "triple-beam": "^1.3.0" }, "engines": { @@ -2555,12 +2522,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -2589,4 +2550,4 @@ } } } -} \ No newline at end of file +}