From be3d62a836a7e48ac6461db6252242b3cf8a9604 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 1 Oct 2022 17:00:57 -0400 Subject: [PATCH 01/10] Added password reset support --- locales/en_US.json | 13 +++ package.json | 6 +- public/assets/css/forgot-password.css | 132 +++++++++++++++++++++++ public/assets/css/reset-password.css | 132 +++++++++++++++++++++++ public/assets/js/forgot-password.js | 26 +++++ public/assets/js/reset-password.js | 32 ++++++ src/routes/account.js | 14 ++- src/server.js | 2 +- src/util.js | 1 - views/account/forgot-password.handlebars | 22 ++++ views/account/login.handlebars | 2 +- views/account/reset-password.handlebars | 26 +++++ 12 files changed, 403 insertions(+), 5 deletions(-) create mode 100644 public/assets/css/forgot-password.css create mode 100644 public/assets/css/reset-password.css create mode 100644 public/assets/js/forgot-password.js create mode 100644 public/assets/js/reset-password.js create mode 100644 views/account/forgot-password.handlebars create mode 100644 views/account/reset-password.handlebars diff --git a/locales/en_US.json b/locales/en_US.json index 0946d15..0970ef5 100644 --- a/locales/en_US.json +++ b/locales/en_US.json @@ -261,6 +261,19 @@ "registerPrompt": "Don't have an account?", "loginPrompt": "Already have an account?" }, + "forgotPassword": { + "header": "Forgot Password", + "sub": "Enter your email address/PNID below", + "input": "Email address or PNID", + "submit": "Submit" + }, + "resetPassword": { + "header": "Reset Password", + "sub": "Enter new password below", + "password": "Password", + "confirmPassword": "Confirm password", + "submit": "Submit" + }, "settings": { "downloadFiles": "Download account files", "downloadFilesDescription": "(will not work on Nintendo Network)", diff --git a/package.json b/package.json index e3896dd..eb1b948 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,11 @@ "description": "", "main": "src/server.js", "scripts": { - "start": "browserify ./public/assets/js/miieditor.js -o ./public/assets/js/miieditor.bundled.js && node src/server.js" + "start": "npm run build && node src/server.js", + "build": "npm run build-miieditor && npm run build-forgot-password && npm run build-reset-password", + "build-miieditor": "browserify ./public/assets/js/miieditor.js -o ./public/assets/js/miieditor.bundled.js", + "build-forgot-password": "browserify ./public/assets/js/forgot-password.js -o ./public/assets/js/forgot-password.bundled.js", + "build-reset-password": "browserify ./public/assets/js/reset-password.js -o ./public/assets/js/reset-password.bundled.js" }, "repository": { "type": "git", diff --git a/public/assets/css/forgot-password.css b/public/assets/css/forgot-password.css new file mode 100644 index 0000000..1a0572a --- /dev/null +++ b/public/assets/css/forgot-password.css @@ -0,0 +1,132 @@ +.wrapper { + display: flex; + flex-flow: column; + min-height: 100vh; +} +header { + margin: 35px 0; +} + +.account-form-wrapper { + margin: auto; + width: fit-content; + overflow: hidden; +} + +form.account { + display: block; + padding: 40px 48px; + background-color: var(--bg-shade-2); + color: var(--text-shade-1); + border-radius: 12px; + width: min(480px, 90vw); + box-sizing: border-box; +} + +form.account h2 { + margin: 0; + color: var(--text-shade-3); +} + +form.account p { + margin: 12px 0; +} + +form.account div { + margin-top: 24px; +} + +form.account label { + display: block; + margin-bottom: 6px; + text-transform: uppercase; + font-size: 12px; +} + +form.account button { + width: 100%; + background: var(--accent-shade-0); +} + +form.account a { + text-decoration: none; + display: block; + color: var(--text-shade-1); + text-align: right; + margin: 6px 0; + width: fit-content; +} +form.account a:hover { + color: var(--text-shade-3); +} + +form.account a.pwdreset { + margin-left: auto; + font-size: 14px; +} + +form.account a.register { + margin: auto; + margin-top: 18px; +} + +@keyframes banner-notice { + 0% { + top: -150px; + } + 20% { + top: 35px; + } + 80% { + top: 35px; + } + 100% { + top: -150px; + } +} +.banner-notice { + display: flex; + justify-content: center; + position: fixed; + top: -150px; + width: 100%; + animation: banner-notice 5s; +} +.banner-notice div { + padding: 4px 36px; + border-radius: 5px; + z-index: 3; +} +.banner-notice.success div { + background: var(--green-shade-0); +} + +form.account.register { + display: grid; + grid-template-columns: repeat(2, 1fr); + width: min(780px, 90vw); + column-gap: 24px; + margin-bottom: 48px; +} +form.account.register div.h-captcha { + grid-column: 1 / span 2; + display: flex; + justify-content: center; +} +form.account.register p, +form.account.register div.email, +form.account.register div.buttons { + grid-column: 1 / span 2; +} + +@media screen and (max-width: 720px) { + form.account.register { + grid-template-columns: 1fr; + } + form.account.register div.h-captcha, + form.account.register p, + form.account.register div.email, + form.account.register div.buttons { + grid-column: unset; + } +} diff --git a/public/assets/css/reset-password.css b/public/assets/css/reset-password.css new file mode 100644 index 0000000..1a0572a --- /dev/null +++ b/public/assets/css/reset-password.css @@ -0,0 +1,132 @@ +.wrapper { + display: flex; + flex-flow: column; + min-height: 100vh; +} +header { + margin: 35px 0; +} + +.account-form-wrapper { + margin: auto; + width: fit-content; + overflow: hidden; +} + +form.account { + display: block; + padding: 40px 48px; + background-color: var(--bg-shade-2); + color: var(--text-shade-1); + border-radius: 12px; + width: min(480px, 90vw); + box-sizing: border-box; +} + +form.account h2 { + margin: 0; + color: var(--text-shade-3); +} + +form.account p { + margin: 12px 0; +} + +form.account div { + margin-top: 24px; +} + +form.account label { + display: block; + margin-bottom: 6px; + text-transform: uppercase; + font-size: 12px; +} + +form.account button { + width: 100%; + background: var(--accent-shade-0); +} + +form.account a { + text-decoration: none; + display: block; + color: var(--text-shade-1); + text-align: right; + margin: 6px 0; + width: fit-content; +} +form.account a:hover { + color: var(--text-shade-3); +} + +form.account a.pwdreset { + margin-left: auto; + font-size: 14px; +} + +form.account a.register { + margin: auto; + margin-top: 18px; +} + +@keyframes banner-notice { + 0% { + top: -150px; + } + 20% { + top: 35px; + } + 80% { + top: 35px; + } + 100% { + top: -150px; + } +} +.banner-notice { + display: flex; + justify-content: center; + position: fixed; + top: -150px; + width: 100%; + animation: banner-notice 5s; +} +.banner-notice div { + padding: 4px 36px; + border-radius: 5px; + z-index: 3; +} +.banner-notice.success div { + background: var(--green-shade-0); +} + +form.account.register { + display: grid; + grid-template-columns: repeat(2, 1fr); + width: min(780px, 90vw); + column-gap: 24px; + margin-bottom: 48px; +} +form.account.register div.h-captcha { + grid-column: 1 / span 2; + display: flex; + justify-content: center; +} +form.account.register p, +form.account.register div.email, +form.account.register div.buttons { + grid-column: 1 / span 2; +} + +@media screen and (max-width: 720px) { + form.account.register { + grid-template-columns: 1fr; + } + form.account.register div.h-captcha, + form.account.register p, + form.account.register div.email, + form.account.register div.buttons { + grid-column: unset; + } +} diff --git a/public/assets/js/forgot-password.js b/public/assets/js/forgot-password.js new file mode 100644 index 0000000..7eacb42 --- /dev/null +++ b/public/assets/js/forgot-password.js @@ -0,0 +1,26 @@ +const config = require('../../../config.json'); + +const input = document.querySelector('#input'); +document.querySelector('form').addEventListener('submit', function (event) { + event.preventDefault(); + + fetch(`${config.api_base}/v1/forgot-password`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + input: input.value + }) + }) + .then(response => response.json()) + .then(body => { + if (body.error) { + alert(`Error: ${body.error}. TODO: red error message thing`); + } else { + alert('If an account exists with the provided username/email address an email has been sent. TODO: reword this and green success'); + } + }) + .catch(console.log); +}); \ No newline at end of file diff --git a/public/assets/js/reset-password.js b/public/assets/js/reset-password.js new file mode 100644 index 0000000..7e7275a --- /dev/null +++ b/public/assets/js/reset-password.js @@ -0,0 +1,32 @@ +const config = require('../../../config.json'); + +const passwordInput = document.querySelector('#password'); +const passwordConfirmInput = document.querySelector('#password_confirm'); +const tokenInput = document.querySelector('#token'); + +document.querySelector('form').addEventListener('submit', function (event) { + event.preventDefault(); + + fetch(`${config.api_base}/v1/reset-password`, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + password: passwordInput.value, + password_confirm: passwordConfirmInput.value, + token: tokenInput.value + }) + }) + .then(response => response.json()) + .then(body => { + if (body.error) { + alert(`Error: ${body.error}. TODO: red error message thing`); + } else { + alert('Password reset. TODO: reword this and green success'); + window.location.assign('/account/login'); + } + }) + .catch(console.log); +}); \ No newline at end of file diff --git a/src/routes/account.js b/src/routes/account.js index 8af363f..590cbfe 100644 --- a/src/routes/account.js +++ b/src/routes/account.js @@ -143,7 +143,7 @@ router.post('/register', async (request, response) => { } }); -router.get('/logout', async(_request, response) => { +router.get('/logout', async (_request, response) => { response.clearCookie('refresh_token', { domain: '.pretendo.network' }); response.clearCookie('access_token', { domain: '.pretendo.network' }); response.clearCookie('token_type', { domain: '.pretendo.network' }); @@ -151,6 +151,18 @@ router.get('/logout', async(_request, response) => { response.redirect('/'); }); +router.get('/forgot-password', async (request, response) => { + response.render('account/forgot-password'); +}); + +router.get('/reset-password', async (request, response) => { + const renderData = { + token: decodeURIComponent(request.query.token) + }; + + response.render('account/reset-password', renderData); +}); + router.get('/connect/discord', requireLoginMiddleware, async (request, response) => { const { pnid } = request; let tokens; diff --git a/src/server.js b/src/server.js index c26f332..7b4bc0d 100644 --- a/src/server.js +++ b/src/server.js @@ -151,7 +151,7 @@ database.connect().then(() => { }); for (const event of events.data) { - await util.handleStripeEvent(event); + //await util.handleStripeEvent(event); } logger.success(`Server listening on http://localhost:${port}`); diff --git a/src/util.js b/src/util.js index 05e9e83..ea57f12 100644 --- a/src/util.js +++ b/src/util.js @@ -284,7 +284,6 @@ async function handleStripeEvent(event) { logger.error(`Error refunding subscription | ${customer.id}, ${subscription.id} | - ${error.message}`); } - try { await mailer.sendMail({ to: customer.email, diff --git a/views/account/forgot-password.handlebars b/views/account/forgot-password.handlebars new file mode 100644 index 0000000..1a4f540 --- /dev/null +++ b/views/account/forgot-password.handlebars @@ -0,0 +1,22 @@ + + +{{> header}} + +
+ + +
+ + \ No newline at end of file diff --git a/views/account/login.handlebars b/views/account/login.handlebars index 4c2461f..43a773b 100644 --- a/views/account/login.handlebars +++ b/views/account/login.handlebars @@ -15,7 +15,7 @@
- {{ locale.account.loginForm.forgotPassword }} + {{ locale.account.loginForm.forgotPassword }}
diff --git a/views/account/reset-password.handlebars b/views/account/reset-password.handlebars new file mode 100644 index 0000000..f2000c2 --- /dev/null +++ b/views/account/reset-password.handlebars @@ -0,0 +1,26 @@ + + +{{> header}} + +
+ +
+ + \ No newline at end of file From f2305b8c9fd25d1959f4af05cb00a939daf92f34 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Sat, 1 Oct 2022 17:01:54 -0400 Subject: [PATCH 02/10] Uncomment Stripe webhook handling --- src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server.js b/src/server.js index 7b4bc0d..c26f332 100644 --- a/src/server.js +++ b/src/server.js @@ -151,7 +151,7 @@ database.connect().then(() => { }); for (const event of events.data) { - //await util.handleStripeEvent(event); + await util.handleStripeEvent(event); } logger.success(`Server listening on http://localhost:${port}`); From 4b9d1c34dea4f3bbfba3fc4efaa9e117e230a11b Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 15 Feb 2023 10:53:45 -0500 Subject: [PATCH 03/10] Updated package-lock.json --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index abe7838..e8ebcf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3186,9 +3186,9 @@ } }, "node_modules/neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/node-fetch": { "version": "2.6.7", @@ -7022,9 +7022,9 @@ "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" }, "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node-fetch": { "version": "2.6.7", From aae1897a4cecee6768a82b475eed62329385a021 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 15 Feb 2023 15:57:16 -0500 Subject: [PATCH 04/10] Comment out Stripe event check at boot. Very bug prone, needs fixing later --- src/server.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/server.js b/src/server.js index c26f332..201ec45 100644 --- a/src/server.js +++ b/src/server.js @@ -146,6 +146,7 @@ app.set('view engine', 'handlebars'); logger.info('Starting server'); database.connect().then(() => { app.listen(port, async () => { + /* const events = await stripe.events.list({ delivery_success: false // failed webhooks }); @@ -153,6 +154,7 @@ database.connect().then(() => { for (const event of events.data) { await util.handleStripeEvent(event); } + */ logger.success(`Server listening on http://localhost:${port}`); }); From e727edadd48e9ee1dc1e3439a00bf2910f4281fd Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 15 Feb 2023 15:58:01 -0500 Subject: [PATCH 05/10] Comment out Stripe imports in server.js --- src/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server.js b/src/server.js index 201ec45..b1dd1cc 100644 --- a/src/server.js +++ b/src/server.js @@ -5,7 +5,7 @@ const handlebars = require('express-handlebars'); const morgan = require('morgan'); const expressLocale = require('express-locale'); const cookieParser = require('cookie-parser'); -const Stripe = require('stripe'); +//const Stripe = require('stripe'); const redirectMiddleware = require('./middleware/redirect'); const renderDataMiddleware = require('./middleware/render-data'); const database = require('./database'); @@ -15,7 +15,7 @@ const config = require('../config.json'); const { http: { port } } = config; const app = express(); -const stripe = new Stripe(config.stripe.secret_key); +//const stripe = new Stripe(config.stripe.secret_key); logger.info('Setting up Middleware'); app.use(morgan('dev')); From 8e169ecb41004a6b9058f780b8f5e56876392530 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Wed, 15 Feb 2023 16:28:52 -0500 Subject: [PATCH 06/10] Removed entire config from client in reset password page --- public/assets/js/forgot-password.js | 6 ++---- src/routes/account.js | 7 ++++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/public/assets/js/forgot-password.js b/public/assets/js/forgot-password.js index 7eacb42..006177c 100644 --- a/public/assets/js/forgot-password.js +++ b/public/assets/js/forgot-password.js @@ -1,10 +1,8 @@ -const config = require('../../../config.json'); - const input = document.querySelector('#input'); document.querySelector('form').addEventListener('submit', function (event) { event.preventDefault(); - fetch(`${config.api_base}/v1/forgot-password`, { + fetch('/account/forgot-password', { method: 'POST', headers: { 'Accept': 'application/json', @@ -23,4 +21,4 @@ document.querySelector('form').addEventListener('submit', function (event) { } }) .catch(console.log); -}); \ No newline at end of file +}); diff --git a/src/routes/account.js b/src/routes/account.js index 590cbfe..432f16b 100644 --- a/src/routes/account.js +++ b/src/routes/account.js @@ -155,6 +155,11 @@ router.get('/forgot-password', async (request, response) => { response.render('account/forgot-password'); }); +router.post('/forgot-password', async (request, response) => { + const apiResponse = await util.apiPostRequest('/v1/forgot-password', {}, request.body); + response.json(apiResponse.body); +}); + router.get('/reset-password', async (request, response) => { const renderData = { token: decodeURIComponent(request.query.token) @@ -227,7 +232,7 @@ router.get('/remove/discord', requireLoginMiddleware, async (request, response) await util.removeDiscordMemberTesterRole(discordId); } } - + response.cookie('success_message', 'Discord account removed successfully', { domain: '.pretendo.network' }); return response.redirect('/account'); } catch (error) { From 2ad0375f1c527d79dcd3d32572281731aa9a06c6 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Fri, 24 Feb 2023 10:44:10 -0500 Subject: [PATCH 07/10] Use whole connection string in mongoose config --- src/database.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/database.js b/src/database.js index b54a1ed..751b649 100644 --- a/src/database.js +++ b/src/database.js @@ -3,12 +3,12 @@ const PNIDSchema = require('./schema/pnid'); const config = require('../config.json'); const accountServerConfig = config.database.account; -const { uri, database, options } = accountServerConfig; +const { connection_string, options } = accountServerConfig; let accountServerDBConnection; let PNID; async function connect() { - accountServerDBConnection = await mongoose.createConnection(`${uri}/${database}`, options); + accountServerDBConnection = await mongoose.createConnection(connection_string, options); accountServerDBConnection.on('error', console.error.bind(console, 'Mongoose connection error:')); accountServerDBConnection.on('close', () => { accountServerDBConnection.removeAllListeners(); From f68c96dd570c052eb537a44c9e54e69b827e0f74 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 27 Feb 2023 22:00:21 -0500 Subject: [PATCH 08/10] Removed unused and updated npm modules --- package-lock.json | 886 ++++++++++++++++++++++++++-------------------- package.json | 2 +- 2 files changed, 494 insertions(+), 394 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8ebcf6..9b5f53f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "got": "^11.8.5", "graphql-request": "^4.3.0", "gray-matter": "^4.0.3", - "kaitai-struct": "^0.9.0", + "lodash.merge": "^4.6.2", "marked": "^4.0.10", "mii-js": "github:PretendoNetwork/mii-js#v1.0.4", "mongoose": "^6.4.0", @@ -346,12 +346,12 @@ } }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" @@ -586,6 +586,40 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -744,11 +778,6 @@ "safe-buffer": "^5.2.0" } }, - "node_modules/browserify-sign/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "node_modules/browserify-sign/node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -852,6 +881,25 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -1028,20 +1076,39 @@ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "node_modules/content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "dependencies": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" }, "engines": { "node": ">= 0.6" } }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } @@ -1248,11 +1315,11 @@ } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/deps-sort": { @@ -1279,9 +1346,13 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detective": { "version": "5.2.0", @@ -1378,11 +1449,6 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, - "node_modules/elliptic/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1392,7 +1458,7 @@ "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { "node": ">= 0.8" } @@ -1469,7 +1535,7 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { "version": "4.0.0", @@ -1707,7 +1773,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "engines": { "node": ">= 0.6" } @@ -1730,37 +1796,38 @@ } }, "node_modules/express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -1787,47 +1854,43 @@ "resolved": "https://registry.npmjs.org/express-locale/-/express-locale-2.0.0.tgz", "integrity": "sha512-SUwsgOTV8lplAkgyfKSwKH3ZVSKUrAa+b48acPGXpwWX211WZ/BYWX2WcZO57+xLOqPYb6rSNpWCFnhGrt0moA==" }, - "node_modules/express/node_modules/body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "ee-first": "1.1.1" }, "engines": { "node": ">= 0.8" } }, - "node_modules/express/node_modules/bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "dependencies": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/extend-shallow": { "version": "2.0.1", @@ -1887,22 +1950,33 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" } }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -1941,9 +2015,9 @@ } }, "node_modules/forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "engines": { "node": ">= 0.6" } @@ -1951,7 +2025,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "engines": { "node": ">= 0.6" } @@ -2230,11 +2304,6 @@ "node": ">=4" } }, - "node_modules/hash-base/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "node_modules/hash-base/node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -2295,23 +2364,23 @@ } }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "node_modules/http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/http2-wrapper": { @@ -2405,9 +2474,9 @@ } }, "node_modules/inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/inline-source-map": { "version": "0.6.2", @@ -2790,11 +2859,6 @@ "node": "*" } }, - "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.4.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz", @@ -2852,8 +2916,7 @@ "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==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.truncate": { "version": "4.4.2", @@ -2905,7 +2968,7 @@ "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "engines": { "node": ">= 0.6" } @@ -2966,19 +3029,19 @@ } }, "node_modules/mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.44.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -3003,9 +3066,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -3118,14 +3181,6 @@ "node": ">= 0.8.0" } }, - "node_modules/morgan/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", @@ -3178,9 +3233,9 @@ "dev": true }, "node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { "node": ">= 0.6" } @@ -3477,11 +3532,11 @@ } }, "node_modules/proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dependencies": { - "forwarded": "~0.1.2", + "forwarded": "0.2.0", "ipaddr.js": "1.9.1" }, "engines": { @@ -3524,11 +3579,17 @@ } }, "node_modules/qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/querystring": { @@ -3584,6 +3645,20 @@ "node": ">= 0.6" } }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -3743,51 +3818,62 @@ } }, "node_modules/send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/send/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } }, "node_modules/serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/sha.js": { "version": "2.4.11", @@ -3929,11 +4015,11 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/stream-browserify": { @@ -3945,11 +4031,6 @@ "readable-stream": "^3.5.0" } }, - "node_modules/stream-browserify/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "node_modules/stream-browserify/node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -3983,11 +4064,6 @@ "xtend": "^4.0.2" } }, - "node_modules/stream-http/node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "node_modules/stream-http/node_modules/readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -4010,6 +4086,14 @@ "readable-stream": "^2.0.2" } }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4119,20 +4203,6 @@ "node": "^8.1 || >=10.*" } }, - "node_modules/stripe/node_modules/qs": { - "version": "6.10.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.5.tgz", - "integrity": "sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/subarg": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", @@ -4232,9 +4302,9 @@ } }, "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { "node": ">=0.6" } @@ -4354,9 +4424,12 @@ } }, "node_modules/undici": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.10.0.tgz", - "integrity": "sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", + "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "dependencies": { + "busboy": "^1.6.0" + }, "engines": { "node": ">=12.18" } @@ -4372,7 +4445,7 @@ "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "engines": { "node": ">= 0.8" } @@ -4809,12 +4882,12 @@ } }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "acorn": { @@ -4993,6 +5066,35 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" }, + "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==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5149,11 +5251,6 @@ "safe-buffer": "^5.2.0" }, "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -5222,6 +5319,19 @@ "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, "cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -5367,17 +5477,24 @@ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" }, "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", "requires": { - "safe-buffer": "5.1.2" + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } } }, "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "convert-source-map": { "version": "1.1.3", @@ -5549,9 +5666,9 @@ "integrity": "sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ==" }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "deps-sort": { "version": "2.0.1", @@ -5574,9 +5691,9 @@ } }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, "detective": { "version": "5.2.0", @@ -5660,11 +5777,6 @@ "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" } } }, @@ -5677,7 +5789,7 @@ "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, "end-of-stream": { "version": "1.4.4", @@ -5736,7 +5848,7 @@ "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "escape-string-regexp": { "version": "4.0.0", @@ -5915,7 +6027,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "events": { "version": "3.3.0", @@ -5932,74 +6044,60 @@ } }, "express": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", - "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.0", - "content-disposition": "0.5.3", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.0", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.5", - "qs": "6.7.0", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", "range-parser": "~1.2.1", - "safe-buffer": "5.1.2", - "send": "0.17.1", - "serve-static": "1.14.1", - "setprototypeof": "1.1.1", - "statuses": "~1.5.0", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { - "body-parser": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", - "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { - "bytes": "3.1.0", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.7.0", - "raw-body": "2.4.0", - "type-is": "~1.6.17" + "ee-first": "1.1.1" } }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "raw-body": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", - "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.2", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" } } }, @@ -6064,17 +6162,27 @@ } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" + }, + "dependencies": { + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } } }, "flat-cache": { @@ -6109,14 +6217,14 @@ } }, "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" }, "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" }, "fs-extra": { "version": "9.1.0", @@ -6312,11 +6420,6 @@ "safe-buffer": "^5.2.0" }, "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -6359,20 +6462,20 @@ "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" }, "http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "http-errors": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", - "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" } }, "http2-wrapper": { @@ -6434,9 +6537,9 @@ } }, "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "inline-source-map": { "version": "0.6.2", @@ -6705,11 +6808,6 @@ "through": ">=2.2.7 <3" } }, - "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.4.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.4.1.tgz", @@ -6761,8 +6859,7 @@ "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==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.truncate": { "version": "4.4.2", @@ -6802,7 +6899,7 @@ "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, "memory-pager": { "version": "1.5.0", @@ -6849,16 +6946,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.44.0" + "mime-db": "1.52.0" } }, "mimic-response": { @@ -6877,9 +6974,9 @@ "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } @@ -6968,13 +7065,6 @@ "depd": "~2.0.0", "on-finished": "~2.3.0", "on-headers": "~1.0.2" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } } }, "mpath": { @@ -7017,9 +7107,9 @@ "dev": true }, "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" }, "neo-async": { "version": "2.6.2", @@ -7241,11 +7331,11 @@ "dev": true }, "proxy-addr": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", - "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "requires": { - "forwarded": "~0.1.2", + "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, @@ -7284,9 +7374,12 @@ "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } }, "querystring": { "version": "0.2.0", @@ -7325,6 +7418,17 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "read-only-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", @@ -7453,47 +7557,55 @@ } }, "send": { - "version": "0.17.1", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", - "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "~1.7.2", + "http-errors": "2.0.0", "mime": "1.6.0", - "ms": "2.1.1", - "on-finished": "~2.3.0", + "ms": "2.1.3", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } } } }, "serve-static": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", - "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.1" + "send": "0.18.0" } }, "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "sha.js": { "version": "2.4.11", @@ -7592,9 +7704,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "stream-browserify": { "version": "3.0.0", @@ -7605,11 +7717,6 @@ "readable-stream": "^3.5.0" }, "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -7642,11 +7749,6 @@ "xtend": "^4.0.2" }, "dependencies": { - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, "readable-stream": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", @@ -7668,6 +7770,11 @@ "readable-stream": "^2.0.2" } }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -7739,16 +7846,6 @@ "requires": { "@types/node": ">=8.1.0", "qs": "^6.10.3" - }, - "dependencies": { - "qs": { - "version": "6.10.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.5.tgz", - "integrity": "sha512-O5RlPh0VFtR78y79rgcgKK4wbAI0C5zGVLztOIdpWX6ep368q5Hv6XRxDvXuZ9q3C6v+e3n8UfZZJw7IIG27eQ==", - "requires": { - "side-channel": "^1.0.4" - } - } } }, "subarg": { @@ -7839,9 +7936,9 @@ } }, "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, "tr46": { "version": "3.0.0", @@ -7928,9 +8025,12 @@ } }, "undici": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.10.0.tgz", - "integrity": "sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==" + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.20.0.tgz", + "integrity": "sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==", + "requires": { + "busboy": "^1.6.0" + } }, "universalify": { "version": "2.0.0", @@ -7940,7 +8040,7 @@ "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" }, "uri-js": { "version": "4.4.1", diff --git a/package.json b/package.json index eb1b948..b2cea1f 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "got": "^11.8.5", "graphql-request": "^4.3.0", "gray-matter": "^4.0.3", - "kaitai-struct": "^0.9.0", + "lodash.merge": "^4.6.2", "marked": "^4.0.10", "mii-js": "github:PretendoNetwork/mii-js#v1.0.4", "mongoose": "^6.4.0", From 99ee7ebe0aa1c2b632526f1de42f9f8b0d15940d Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 27 Feb 2023 22:03:38 -0500 Subject: [PATCH 09/10] Bring Stripe event handler to own file --- src/routes/account.js | 3 +- src/stripe.js | 275 ++++++++++++++++++++++++++++++++++++++++++ src/util.js | 272 +---------------------------------------- 3 files changed, 278 insertions(+), 272 deletions(-) create mode 100644 src/stripe.js diff --git a/src/routes/account.js b/src/routes/account.js index 432f16b..2bf6fac 100644 --- a/src/routes/account.js +++ b/src/routes/account.js @@ -10,6 +10,7 @@ const requireLoginMiddleware = require('../middleware/require-login'); const database = require('../database'); const cache = require('../cache'); const util = require('../util'); +const { handleStripeEvent } = require('../stripe'); const logger = require('../logger'); const config = require('../../config.json'); const editorJSON = require('../json/miieditor.json'); @@ -443,7 +444,7 @@ router.post('/stripe/webhook', async (request, response) => { return response.status(400).send(`Webhook Error: ${error.message}`); } - await util.handleStripeEvent(event); + await handleStripeEvent(event); response.json({ received: true }); }); diff --git a/src/stripe.js b/src/stripe.js new file mode 100644 index 0000000..0fef5d4 --- /dev/null +++ b/src/stripe.js @@ -0,0 +1,275 @@ +const Stripe = require('stripe'); +const mailer = require('./mailer'); +const util = require('./util'); +const database = require('./database'); +const logger = require('./logger'); +const config = require('../config.json'); + +const stripe = new Stripe(config.stripe.secret_key); + +async function handleStripeEvent(event) { + if (event.type === 'customer.subscription.updated' || event.type === 'customer.subscription.deleted') { + const subscription = event.data.object; + const product = await stripe.products.retrieve(subscription.plan.product); + const customer = await stripe.customers.retrieve(subscription.customer); + + if (!customer?.metadata?.pnid_pid) { + // No PNID PID linked to customer + if (subscription.status !== 'canceled' && subscription.status !== 'unpaid') { + // Abort and refund! + logger.error(`Stripe user ${customer.id} has no PNID linked! Refunding order`); + + try { + await stripe.subscriptions.del(subscription.id); + + const invoice = await stripe.invoices.retrieve(subscription.latest_invoice); + await stripe.refunds.create({ + payment_intent: invoice.payment_intent + }); + } catch (error) { + logger.error(`Error refunding subscription | ${customer.id}, ${subscription.id} | - ${error.message}`); + } + + try { + await mailer.sendMail({ + to: customer.email, + subject: 'Pretendo Network Subscription Failed - No Linked PNID', + text: `Your recent subscription to Pretendo Network has failed.\nThis is due to no PNID PID being linked to the Stripe customer account used. The subscription has been canceled and refunded. Please contact Jon immediately.\nStripe Customer ID: ${customer.id}` + }); + } catch (error) { + logger.error(`Error sending email | ${customer.id}, ${customer.email} | - ${error.message}`); + } + } else { + logger.error(`Stripe user ${customer.id} has no PNID linked!`); + } + + return; + } + + const pid = Number(customer.metadata.pnid_pid); + const pnid = await database.PNID.findOne({ pid }); + + if (!pnid) { + // PNID does not exist + if (subscription.status !== 'canceled' && subscription.status !== 'unpaid') { + // Abort and refund! + logger.error(`PNID PID ${pid} does not exist! Found on Stripe user ${customer.id}! Refunding order`); + + try { + await stripe.subscriptions.del(subscription.id); + + const invoice = await stripe.invoices.retrieve(subscription.latest_invoice); + await stripe.refunds.create({ + payment_intent: invoice.payment_intent + }); + } catch (error) { + logger.error(`Error refunding subscription | ${customer.id}, ${subscription.id} | - ${error.message}`); + } + + try { + await mailer.sendMail({ + to: customer.email, + subject: 'Pretendo Network Subscription Failed - PNID Not Found', + text: `Your recent subscription to Pretendo Network has failed.\nThis is due to the provided PNID not being found. The subscription has been canceled and refunded. Please contact Jon immediately.\nStripe Customer ID: ${customer.id}\nPNID PID: ${pid}` + }); + } catch (error) { + logger.error(`Error sending email | ${customer.id}, ${customer.email} | - ${error.message}`); + } + } else { + logger.error(`PNID PID ${pid} does not exist! Found on Stripe user ${customer.id}!`); + } + + return; + } + + const latestWebhookTimestamp = pnid.get('connections.stripe.latest_webhook_timestamp'); + + if (latestWebhookTimestamp && latestWebhookTimestamp >= event.created) { + // Do nothing, this webhook is older than the latest seen + return; + } + + const currentSubscriptionId = pnid.get('connections.stripe.subscription_id'); + const discordId = pnid.get('connections.discord.id'); + + if (subscription.status === 'canceled' && currentSubscriptionId && subscription.id !== currentSubscriptionId) { + // Canceling old subscription, do nothing but update webhook date and remove Discord roles + if (product.metadata.beta === 'true') { + util.removeDiscordMemberTesterRole(discordId).catch(error => { + logger.error(`Error removing user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); + }); + } + + util.removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); + + const updateData = { + 'connections.stripe.latest_webhook_timestamp': event.created + }; + + await database.PNID.updateOne({ + pid, + 'connections.stripe.latest_webhook_timestamp': { + $lte: event.created + } + }, { $set: updateData }).exec(); + + return; + } + + const updateData = { + 'connections.stripe.subscription_id': subscription.status === 'active' ? subscription.id : null, + 'connections.stripe.price_id': subscription.status === 'active' ? subscription.plan.id : null, + 'connections.stripe.tier_level': subscription.status === 'active' ? Number(product.metadata.tier_level || 0) : 0, + 'connections.stripe.tier_name': subscription.status === 'active' ? product.name : null, + 'connections.stripe.latest_webhook_timestamp': event.created, + }; + + if (product.metadata.beta === 'true') { + switch (subscription.status) { + case 'active': + if (pnid.access_level < 2) { // only change access level if not staff member + updateData.access_level = 1; + } + + util.assignDiscordMemberTesterRole(discordId).catch(error => { + logger.error(`Error assigning user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); + }); + break; + + case 'canceled': // Subscription was canceled + case 'unpaid': // User missed too many payments + if (pnid.access_level < 2) { // only change access level if not staff member + updateData.access_level = 0; + } + + util.removeDiscordMemberTesterRole(discordId).catch(error => { + logger.error(`Error removing user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); + }); + break; + + default: + break; + } + } + + await database.PNID.updateOne({ + pid, + 'connections.stripe.latest_webhook_timestamp': { + $lte: event.created + } + }, { $set: updateData }).exec(); + + if (subscription.status === 'active') { + // Get all the customers active subscriptions + const { data: activeSubscriptions } = await stripe.subscriptions.list({ + limit: 100, + status: 'active', + customer: customer.id + }); + + // Order subscriptions by creation time and remove the latest one + const orderedActiveSubscriptions = activeSubscriptions.sort((a, b) => b.created - a.created); + const pastSubscriptions = orderedActiveSubscriptions.slice(1); + + // Remove any old past subscriptions that might still be hanging around + for (const pastSubscription of pastSubscriptions) { + try { + await stripe.subscriptions.del(pastSubscription.id); + } catch (error) { + logger.error(`Error canceling old user subscription | ${customer.id}, ${pid}, ${pastSubscription.id} | - ${error.message}`); + } + } + + try { + await mailer.sendMail({ + to: customer.email, + subject: 'Pretendo Network Subscription - Active', + text: `Thank you for purchasing the ${product.name} tier! We greatly value your support, thank you for helping keep Pretendo Network alive!\nIt may take a moment for your account dashboard to reflect these changes. Please wait a moment and refresh the dashboard to see them!` + }); + } catch (error) { + logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); + } + + util.assignDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error assigning user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); + + for (const email of config.stripe.notification_emails) { + // * Send notification emails for new sub + try { + await mailer.sendMail({ + to: email, + subject: `[Pretendo] - New ${product.name} subscription`, + text: `${pnid.get('username')} just became a ${product.name} tier subscriber` + }); + } catch (error) { + logger.error(`Error sending notification email | ${email} | - ${error.message}`); + } + } + } + + if (subscription.status === 'canceled') { + try { + await mailer.sendMail({ + to: customer.email, + subject: 'Pretendo Network Subscription - Canceled', + text: `Your subscription for the ${product.name} tier has been canceled. We thank for your previous support, and hope you still enjoy the network! ` + }); + } catch (error) { + logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); + } + + util.removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); + + for (const email of config.stripe.notification_emails) { + // * Send notification emails for new sub + try { + await mailer.sendMail({ + to: email, + subject: `[Pretendo] - Canceled ${product.name} subscription`, + text: `${pnid.get('username')} just canceled their ${product.name} tier subscription` + }); + } catch (error) { + logger.error(`Error sending notification email | ${email} | - ${error.message}`); + } + } + } + + if (subscription.status === 'unpaid') { + try { + await mailer.sendMail({ + to: customer.email, + subject: 'Pretendo Network Subscription - Unpaid', + text: `Your subscription for the ${product.name} tier has been canceled due to non payment. We thank for your previous support, and hope you still enjoy the network! ` + }); + } catch (error) { + logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); + } + + util.removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { + logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); + }); + + for (const email of config.stripe.notification_emails) { + // * Send notification emails for new sub + try { + await mailer.sendMail({ + to: email, + subject: `[Pretendo] - Removed ${product.name} subscription`, + text: `${pnid.get('username')}'s ${product.name} tier subscription has been canceled due to non payment` + }); + } catch (error) { + logger.error(`Error sending notification email | ${email} | - ${error.message}`); + } + } + } + } +} + +module.exports = { + handleStripeEvent +}; diff --git a/src/util.js b/src/util.js index f7681d5..718b084 100644 --- a/src/util.js +++ b/src/util.js @@ -2,21 +2,15 @@ const path = require('path'); const fs = require('fs-extra'); const got = require('got'); const crypto = require('crypto'); -const Stripe = require('stripe'); const { marked } = require('marked'); const { REST: DiscordRest } = require('@discordjs/rest'); const { Routes: DiscordRoutes } = require('discord-api-types/v10'); const merge = require('lodash.merge'); - -const mailer = require('./mailer'); -const database = require('./database'); const logger = require('./logger'); - const config = require('../config.json'); const baseLocale = require(`${__dirname}/../locales/en_US.json`); -const discordRest = new DiscordRest({ version: '10' }).setToken(config.discord.bot_token); -const stripe = new Stripe(config.stripe.secret_key); +const discordRest = new DiscordRest({ version: '10' }).setToken(config.discord.bot_token); function fullUrl(request) { return `${request.protocol}://${request.hostname}${request.originalUrl}`; @@ -225,269 +219,6 @@ function nintendoPasswordHash(password, pid) { return hashed; } -async function handleStripeEvent(event) { - if (event.type === 'customer.subscription.updated' || event.type === 'customer.subscription.deleted') { - const subscription = event.data.object; - const product = await stripe.products.retrieve(subscription.plan.product); - const customer = await stripe.customers.retrieve(subscription.customer); - - if (!customer?.metadata?.pnid_pid) { - // No PNID PID linked to customer - if (subscription.status !== 'canceled' && subscription.status !== 'unpaid') { - // Abort and refund! - logger.error(`Stripe user ${customer.id} has no PNID linked! Refunding order`); - - try { - await stripe.subscriptions.del(subscription.id); - - const invoice = await stripe.invoices.retrieve(subscription.latest_invoice); - await stripe.refunds.create({ - payment_intent: invoice.payment_intent - }); - } catch (error) { - logger.error(`Error refunding subscription | ${customer.id}, ${subscription.id} | - ${error.message}`); - } - - try { - await mailer.sendMail({ - to: customer.email, - subject: 'Pretendo Network Subscription Failed - No Linked PNID', - text: `Your recent subscription to Pretendo Network has failed.\nThis is due to no PNID PID being linked to the Stripe customer account used. The subscription has been canceled and refunded. Please contact Jon immediately.\nStripe Customer ID: ${customer.id}` - }); - } catch (error) { - logger.error(`Error sending email | ${customer.id}, ${customer.email} | - ${error.message}`); - } - } else { - logger.error(`Stripe user ${customer.id} has no PNID linked!`); - } - - return; - } - - const pid = Number(customer.metadata.pnid_pid); - const pnid = await database.PNID.findOne({ pid }); - - if (!pnid) { - // PNID does not exist - if (subscription.status !== 'canceled' && subscription.status !== 'unpaid') { - // Abort and refund! - logger.error(`PNID PID ${pid} does not exist! Found on Stripe user ${customer.id}! Refunding order`); - - try { - await stripe.subscriptions.del(subscription.id); - - const invoice = await stripe.invoices.retrieve(subscription.latest_invoice); - await stripe.refunds.create({ - payment_intent: invoice.payment_intent - }); - } catch (error) { - logger.error(`Error refunding subscription | ${customer.id}, ${subscription.id} | - ${error.message}`); - } - - try { - await mailer.sendMail({ - to: customer.email, - subject: 'Pretendo Network Subscription Failed - PNID Not Found', - text: `Your recent subscription to Pretendo Network has failed.\nThis is due to the provided PNID not being found. The subscription has been canceled and refunded. Please contact Jon immediately.\nStripe Customer ID: ${customer.id}\nPNID PID: ${pid}` - }); - } catch (error) { - logger.error(`Error sending email | ${customer.id}, ${customer.email} | - ${error.message}`); - } - } else { - logger.error(`PNID PID ${pid} does not exist! Found on Stripe user ${customer.id}!`); - } - - return; - } - - const latestWebhookTimestamp = pnid.get('connections.stripe.latest_webhook_timestamp'); - - if (latestWebhookTimestamp && latestWebhookTimestamp >= event.created) { - // Do nothing, this webhook is older than the latest seen - return; - } - - const currentSubscriptionId = pnid.get('connections.stripe.subscription_id'); - const discordId = pnid.get('connections.discord.id'); - - if (subscription.status === 'canceled' && currentSubscriptionId && subscription.id !== currentSubscriptionId) { - // Canceling old subscription, do nothing but update webhook date and remove Discord roles - if (product.metadata.beta === 'true') { - removeDiscordMemberTesterRole(discordId).catch(error => { - logger.error(`Error removing user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); - }); - } - - removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { - logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); - }); - - const updateData = { - 'connections.stripe.latest_webhook_timestamp': event.created - }; - - await database.PNID.updateOne({ - pid, - 'connections.stripe.latest_webhook_timestamp': { - $lte: event.created - } - }, { $set: updateData }).exec(); - - return; - } - - const updateData = { - 'connections.stripe.subscription_id': subscription.status === 'active' ? subscription.id : null, - 'connections.stripe.price_id': subscription.status === 'active' ? subscription.plan.id : null, - 'connections.stripe.tier_level': subscription.status === 'active' ? Number(product.metadata.tier_level || 0) : 0, - 'connections.stripe.tier_name': subscription.status === 'active' ? product.name : null, - 'connections.stripe.latest_webhook_timestamp': event.created, - }; - - if (product.metadata.beta === 'true') { - switch (subscription.status) { - case 'active': - if (pnid.access_level < 2) { // only change access level if not staff member - updateData.access_level = 1; - } - - assignDiscordMemberTesterRole(discordId).catch(error => { - logger.error(`Error assigning user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); - }); - break; - - case 'canceled': // Subscription was canceled - case 'unpaid': // User missed too many payments - if (pnid.access_level < 2) { // only change access level if not staff member - updateData.access_level = 0; - } - - removeDiscordMemberTesterRole(discordId).catch(error => { - logger.error(`Error removing user Discord tester role | ${customer.id}, ${discordId}, ${pid} | - ${error.message}`); - }); - break; - - default: - break; - } - } - - await database.PNID.updateOne({ - pid, - 'connections.stripe.latest_webhook_timestamp': { - $lte: event.created - } - }, { $set: updateData }).exec(); - - if (subscription.status === 'active') { - // Get all the customers active subscriptions - const { data: activeSubscriptions } = await stripe.subscriptions.list({ - limit: 100, - status: 'active', - customer: customer.id - }); - - // Order subscriptions by creation time and remove the latest one - const orderedActiveSubscriptions = activeSubscriptions.sort((a, b) => b.created - a.created); - const pastSubscriptions = orderedActiveSubscriptions.slice(1); - - // Remove any old past subscriptions that might still be hanging around - for (const pastSubscription of pastSubscriptions) { - try { - await stripe.subscriptions.del(pastSubscription.id); - } catch (error) { - logger.error(`Error canceling old user subscription | ${customer.id}, ${pid}, ${pastSubscription.id} | - ${error.message}`); - } - } - - try { - await mailer.sendMail({ - to: customer.email, - subject: 'Pretendo Network Subscription - Active', - text: `Thank you for purchasing the ${product.name} tier! We greatly value your support, thank you for helping keep Pretendo Network alive!\nIt may take a moment for your account dashboard to reflect these changes. Please wait a moment and refresh the dashboard to see them!` - }); - } catch (error) { - logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); - } - - assignDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { - logger.error(`Error assigning user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); - }); - - for (const email of config.stripe.notification_emails) { - // * Send notification emails for new sub - try { - await mailer.sendMail({ - to: email, - subject: `[Pretendo] - New ${product.name} subscription`, - text: `${pnid.get('username')} just became a ${product.name} tier subscriber` - }); - } catch (error) { - logger.error(`Error sending notification email | ${email} | - ${error.message}`); - } - } - } - - if (subscription.status === 'canceled') { - try { - await mailer.sendMail({ - to: customer.email, - subject: 'Pretendo Network Subscription - Canceled', - text: `Your subscription for the ${product.name} tier has been canceled. We thank for your previous support, and hope you still enjoy the network! ` - }); - } catch (error) { - logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); - } - - removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { - logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); - }); - - for (const email of config.stripe.notification_emails) { - // * Send notification emails for new sub - try { - await mailer.sendMail({ - to: email, - subject: `[Pretendo] - Canceled ${product.name} subscription`, - text: `${pnid.get('username')} just canceled their ${product.name} tier subscription` - }); - } catch (error) { - logger.error(`Error sending notification email | ${email} | - ${error.message}`); - } - } - } - - if (subscription.status === 'unpaid') { - try { - await mailer.sendMail({ - to: customer.email, - subject: 'Pretendo Network Subscription - Unpaid', - text: `Your subscription for the ${product.name} tier has been canceled due to non payment. We thank for your previous support, and hope you still enjoy the network! ` - }); - } catch (error) { - logger.error(`Error sending email | ${customer.id}, ${customer.email}, ${pid} | - ${error.message}`); - } - - removeDiscordMemberSupporterRole(discordId, product.metadata.discord_role_id).catch(error => { - logger.error(`Error removing user Discord supporter role | ${customer.id}, ${discordId}, ${pid}, ${product.metadata.discord_role_id} | - ${error.message}`); - }); - - for (const email of config.stripe.notification_emails) { - // * Send notification emails for new sub - try { - await mailer.sendMail({ - to: email, - subject: `[Pretendo] - Removed ${product.name} subscription`, - text: `${pnid.get('username')}'s ${product.name} tier subscription has been canceled due to non payment` - }); - } catch (error) { - logger.error(`Error sending notification email | ${email} | - ${error.message}`); - } - } - } - } -} - async function assignDiscordMemberSupporterRole(memberId, roleId) { if (memberId && memberId.trim() !== '') { await discordRest.put(DiscordRoutes.guildMemberRole(config.discord.guild_id, memberId, config.discord.roles.supporter)); @@ -529,7 +260,6 @@ module.exports = { updateDiscordConnection, removeDiscordConnection, nintendoPasswordHash, - handleStripeEvent, assignDiscordMemberSupporterRole, assignDiscordMemberTesterRole, removeDiscordMemberSupporterRole, From 02b6e7cc29cd4fd606d29076f4bd2584f5c87d6e Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 27 Feb 2023 22:04:58 -0500 Subject: [PATCH 10/10] Update users environment automatically --- src/stripe.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/stripe.js b/src/stripe.js index 0fef5d4..ab98f3c 100644 --- a/src/stripe.js +++ b/src/stripe.js @@ -131,6 +131,7 @@ async function handleStripeEvent(event) { case 'active': if (pnid.access_level < 2) { // only change access level if not staff member updateData.access_level = 1; + updateData.server_access_level = 'test'; } util.assignDiscordMemberTesterRole(discordId).catch(error => { @@ -142,6 +143,7 @@ async function handleStripeEvent(event) { case 'unpaid': // User missed too many payments if (pnid.access_level < 2) { // only change access level if not staff member updateData.access_level = 0; + updateData.server_access_level = 'prod'; } util.removeDiscordMemberTesterRole(discordId).catch(error => {