diff --git a/package.json b/package.json index a07516b..570d76d 100644 --- a/package.json +++ b/package.json @@ -49,9 +49,9 @@ "@eartharoid/dbf": "^0.4.2", "@eartharoid/dtf": "^2.0.1", "@eartharoid/i18n": "^1.2.1", - "@fastify/cookie": "^6.0.0", - "@fastify/jwt": "^5.0.1", - "@fastify/oauth2": "^5.1.0", + "@fastify/cookie": "^9.3.1", + "@fastify/jwt": "^8.0.0", + "@fastify/oauth2": "^7.8.0", "@prisma/client": "^4.16.2", "boxen": "^7.1.1", "cryptr": "^6.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 798cd28..d6549f6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,14 +18,14 @@ dependencies: specifier: ^1.2.1 version: 1.2.1 '@fastify/cookie': - specifier: ^6.0.0 - version: 6.0.0 + specifier: ^9.3.1 + version: 9.3.1 '@fastify/jwt': - specifier: ^5.0.1 - version: 5.0.1 + specifier: ^8.0.0 + version: 8.0.0 '@fastify/oauth2': - specifier: ^5.1.0 - version: 5.1.0 + specifier: ^7.8.0 + version: 7.8.0 '@prisma/client': specifier: ^4.16.2 version: 4.16.2(prisma@4.16.2) @@ -181,6 +181,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.1 + dev: true /@commitlint/cli@17.8.1: resolution: {integrity: sha512-ay+WbzQesE0Rv4EQKfNbSMiJJ12KdKTDzIt0tcK4k11FdsWmtwP0Kp1NWMOUswfIWo6Eb7p7Ln721Nx9FLNBjg==} @@ -515,11 +516,11 @@ packages: engines: {node: '>=14'} dev: false - /@fastify/cookie@6.0.0: - resolution: {integrity: sha512-Luy3Po3dOJmqAuPCiPcWsX0tV5+C3AOnULSdlsGjNGOvyE7jqzysp8kT9ICfsUvove+TeUMgTWl1y9XS3ZPPMg==} + /@fastify/cookie@9.3.1: + resolution: {integrity: sha512-h1NAEhB266+ZbZ0e9qUE6NnNR07i7DnNXWG9VbbZ8uC6O/hxHpl+Zoe5sw1yfdZ2U6XhToUGDnzQtWJdCaPwfg==} dependencies: cookie-signature: 1.2.1 - fastify-plugin: 3.0.1 + fastify-plugin: 4.5.1 dev: false /@fastify/deepmerge@1.3.0: @@ -536,22 +537,22 @@ packages: fast-json-stringify: 5.10.0 dev: false - /@fastify/jwt@5.0.1: - resolution: {integrity: sha512-BF2JrhSRcMRwHim2pbFEgWLJE8DdRh0NaGeAgU+ZFICj2AHxGvrHSOaYRaXNUQixgmGjVaTrbRFl3bSBc6Pj+g==} - engines: {node: '>=10'} + /@fastify/jwt@8.0.0: + resolution: {integrity: sha512-pJHjmZaokteZFMbsVVt7pbyJpbDogTnpl/aD7eR3vLOPgfktp4k4gUM6cd7RtjL/Ol1qDwL5mup+vdNlZI3K0Q==} dependencies: + '@fastify/error': 3.4.0 '@lukeed/ms': 2.0.2 - fast-jwt: 1.7.2 - fastify-plugin: 3.0.1 - http-errors: 2.0.0 + fast-jwt: 3.3.2 + fastify-plugin: 4.5.1 steed: 1.1.3 dev: false - /@fastify/oauth2@5.1.0: - resolution: {integrity: sha512-Z/2ZR8v2BB+vwFm1t0DnavxAKymCGvJiGD/lTtNV/dTPHTHRQ1X68hFs/Nl2Rd0Gv9AlSlrpYsX9hfoNjTSiYQ==} + /@fastify/oauth2@7.8.0: + resolution: {integrity: sha512-piQldGFUfAH0+SXM7Cw6hlanFmYnTWYtDC3EcbxNiQedAbr9SbGNxJynTHsvyKzRO7dupdxIdWA81k1egxKftQ==} dependencies: + '@fastify/cookie': 9.3.1 fastify-plugin: 4.5.1 - simple-oauth2: 3.4.0 + simple-oauth2: 5.0.0 transitivePeerDependencies: - supports-color dev: false @@ -562,63 +563,40 @@ packages: requiresBuild: true dev: false - /@hapi/address@2.1.4: - resolution: {integrity: sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==} - deprecated: Moved to 'npm install @sideway/address' - dev: false - - /@hapi/boom@7.4.11: - resolution: {integrity: sha512-VSU/Cnj1DXouukYxxkes4nNJonCnlogHvIff1v1RVoN4xzkKhMXX+GRmb3NyH1iar10I9WFPDv2JPwfH3GaV0A==} - deprecated: This version has been deprecated and is no longer supported or maintained + /@hapi/boom@10.0.1: + resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==} dependencies: - '@hapi/hoek': 8.5.1 + '@hapi/hoek': 11.0.2 dev: false - /@hapi/bourne@1.3.2: - resolution: {integrity: sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==} - deprecated: This version has been deprecated and is no longer supported or maintained + /@hapi/bourne@3.0.0: + resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==} dev: false - /@hapi/formula@1.2.0: - resolution: {integrity: sha512-UFbtbGPjstz0eWHb+ga/GM3Z9EzqKXFWIbSOFURU0A/Gku0Bky4bCk9/h//K2Xr3IrCfjFNhMm4jyZ5dbCewGA==} - deprecated: Moved to 'npm install @sideway/formula' + /@hapi/hoek@10.0.1: + resolution: {integrity: sha512-CvlW7jmOhWzuqOqiJQ3rQVLMcREh0eel4IBnxDx2FAcK8g7qoJRQK4L1CPBASoCY6y8e6zuCy3f2g+HWdkzcMw==} dev: false - /@hapi/hoek@8.5.1: - resolution: {integrity: sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==} - deprecated: This version has been deprecated and is no longer supported or maintained + /@hapi/hoek@11.0.2: + resolution: {integrity: sha512-aKmlCO57XFZ26wso4rJsW4oTUnrgTFw2jh3io7CAtO9w4UltBNwRXvXIVzzyfkaaLRo3nluP/19msA8vDUUuKw==} dev: false - /@hapi/joi@16.1.8: - resolution: {integrity: sha512-wAsVvTPe+FwSrsAurNt5vkg3zo+TblvC5Bb1zMVK6SJzZqw9UrJnexxR+76cpePmtUZKHAPxcQ2Bf7oVHyahhg==} - deprecated: Switch to 'npm install joi' + /@hapi/hoek@9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: false + + /@hapi/topo@5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} dependencies: - '@hapi/address': 2.1.4 - '@hapi/formula': 1.2.0 - '@hapi/hoek': 8.5.1 - '@hapi/pinpoint': 1.0.2 - '@hapi/topo': 3.1.6 + '@hapi/hoek': 9.3.0 dev: false - /@hapi/pinpoint@1.0.2: - resolution: {integrity: sha512-dtXC/WkZBfC5vxscazuiJ6iq4j9oNx1SHknmIr8hofarpKUZKmlUVYVIhNVzIEgK5Wrc4GMHL5lZtt1uS2flmQ==} - deprecated: Moved to 'npm install @sideway/pinpoint' - dev: false - - /@hapi/topo@3.1.6: - resolution: {integrity: sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==} - deprecated: This version has been deprecated and is no longer supported or maintained + /@hapi/wreck@18.0.1: + resolution: {integrity: sha512-OLHER70+rZxvDl75xq3xXOfd3e8XIvz8fWY0dqg92UvhZ29zo24vQgfqgHSYhB5ZiuFpSLeriOisAlxAo/1jWg==} dependencies: - '@hapi/hoek': 8.5.1 - dev: false - - /@hapi/wreck@15.1.0: - resolution: {integrity: sha512-tQczYRTTeYBmvhsek/D49En/5khcShaBEmzrAaDjMrFXKJRuF8xA8+tlq1ETLBFwGd6Do6g2OC74rt11kzawzg==} - deprecated: This version has been deprecated and is no longer supported or maintained - dependencies: - '@hapi/boom': 7.4.11 - '@hapi/bourne': 1.3.2 - '@hapi/hoek': 8.5.1 + '@hapi/boom': 10.0.1 + '@hapi/bourne': 3.0.0 + '@hapi/hoek': 11.0.2 dev: false /@humanwhocodes/config-array@0.11.14: @@ -1575,11 +1553,6 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dev: false - /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1886,10 +1859,11 @@ packages: rfdc: 1.3.0 dev: false - /fast-jwt@1.7.2: - resolution: {integrity: sha512-OEInypGXJhtURzq9GbFM5KaALUu9+4IV3kJEbWPuqOBN5JBe7A51Tx0CaQYHGC9GNfZnr5npA0lCIMaWiZmz/A==} - engines: {node: '>=14 <20'} + /fast-jwt@3.3.2: + resolution: {integrity: sha512-H+JYxaFy2LepiC1AQWM/2hzKlQOWaWUkEnu/yebhYu4+ameb3qG77WiRZ1Ct6YBk6d/ESsNguBfTT5+q0XMtKg==} + engines: {node: '>=16 <22'} dependencies: + '@lukeed/ms': 2.0.1 asn1.js: 5.4.1 ecdsa-sig-formatter: 1.0.11 mnemonist: 0.39.7 @@ -1921,10 +1895,6 @@ packages: reusify: 1.0.4 dev: false - /fastify-plugin@3.0.1: - resolution: {integrity: sha512-qKcDXmuZadJqdTm6vlCqioEbyewF60b/0LOFCcYN1B6BIZGlYJumWWOYs70SFYLDAH4YqdE1cxH/RKMG7rFxgA==} - dev: false - /fastify-plugin@4.5.1: resolution: {integrity: sha512-stRHYGeuqpEZTL1Ef0Ovr2ltazUT9g844X5z/zEBFLG8RYlpDiOCIG+ATvYEp+/zmc7sN29mcIMp8gvYplYPIQ==} dev: false @@ -2239,17 +2209,6 @@ packages: lru-cache: 6.0.0 dev: true - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - dev: false - /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -2435,6 +2394,16 @@ packages: resolution: {integrity: sha512-4dG1D1x/7g8PwHS9aK6QV5V94+ZvyP4+d19qDv43EzImmrndysIl4prmJ1hWWIGCqrZHyaHBm6BSEWHOLnpoNw==} dev: false + /joi@17.11.0: + resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: false + /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -3216,6 +3185,10 @@ packages: resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} dev: false + /process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + dev: false + /process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -3493,10 +3466,6 @@ packages: resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} dev: false - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - dev: false - /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -3518,15 +3487,13 @@ packages: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true - /simple-oauth2@3.4.0: - resolution: {integrity: sha512-gDPCC/xjq82FJnzF7+XGUUMWWfHeibuGsp3OYOV7yHwIibxHkq4+WSxywY63/3BF9j8SfIDygGqBrPLynx/iuQ==} - deprecated: simple-oauth2 v3 is no longer supported. Use simple-oauth2 v4 or higher for continued support + /simple-oauth2@5.0.0: + resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==} dependencies: - '@hapi/hoek': 8.5.1 - '@hapi/joi': 16.1.8 - '@hapi/wreck': 15.1.0 - date-fns: 2.30.0 + '@hapi/hoek': 10.0.1 + '@hapi/wreck': 18.0.1 debug: 4.3.4 + joi: 17.11.0 transitivePeerDependencies: - supports-color dev: false @@ -3609,11 +3576,6 @@ packages: through: 2.3.8 dev: true - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - dev: false - /steed@1.1.3: resolution: {integrity: sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==} dependencies: diff --git a/src/http.js b/src/http.js index 82cb214..a43cf34 100644 --- a/src/http.js +++ b/src/http.js @@ -9,16 +9,34 @@ const { PermissionsBitField } = require('discord.js'); process.env.ORIGIN = process.env.HTTP_INTERNAL || process.env.HTTP_EXTERNAL; module.exports = async client => { + // cookies plugin, must be registered before oauth2 since oauth2@7.2.0 + fastify.register(require('@fastify/cookie')); + + // jwt plugin + fastify.register(require('@fastify/jwt'), { + cookie: { + cookieName: 'token', + signed: false, + }, + secret: process.env.ENCRYPTION_KEY, + }); + // oauth2 plugin fastify.states = new Map(); fastify.register(oauth, { callbackUri: `${process.env.HTTP_EXTERNAL}/auth/callback`, - checkStateFunction: (state, callback) => { - if (fastify.states.has(state)) { - callback(); - return; + // checkStateFunction: (req, callback) => { + // if (req.query.state === req.cookies['oauth2-redirect-state']) { + // callback(); + // return; + // } + // callback(new Error('Invalid state')); + // }, + checkStateFunction: async req => { + if (req.query.state !== req.cookies['oauth2-redirect-state']) { + throw new Error('Invalid state'); } - callback(new Error('Invalid state')); + return true; }, credentials: { auth: oauth.DISCORD_CONFIGURATION, @@ -37,17 +55,6 @@ module.exports = async client => { startRedirectPath: '/auth/login', }); - // cookies plugin - fastify.register(require('@fastify/cookie')); - - // jwt plugin - fastify.register(require('@fastify/jwt'), { - cookie: { - cookieName: 'token', - signed: false, - }, - secret: process.env.ENCRYPTION_KEY, - }); // auth fastify.decorate('authenticate', async (req, res) => { @@ -122,13 +129,13 @@ module.exports = async client => { : responseTime >= 10 ? '&e' : '&a') + responseTime + 'ms'; - const level = req.routerPath === '/status' + const level = req.routeOptions.url === '/status' ? 'debug' - : req.routerPath === '/*' + : req.routeOptions.url === '/*' ? 'verbose' : 'info'; - client.log[level].http(short(`${req.id} ${req.ip} ${req.method} ${req.routerPath ?? '*'} &m-+>&r ${status}&b in ${responseTime}`)); - if (!req.routerPath) client.log.verbose.http(`${req.id} ${req.method} ${req.url}`); + client.log[level].http(short(`${req.id} ${req.ip} ${req.method} ${req.routeOptions.url ?? '*'} &m-+>&r ${status}&b in ${responseTime}`)); + if (!req.routeOptions.url) client.log.verbose.http(`${req.id} ${req.method} ${req.url}`); done(); }); diff --git a/src/routes/api/admin/guilds/[guild]/categories/[category]/index.js b/src/routes/api/admin/guilds/[guild]/categories/[category]/index.js index 6e70ebf..4ed51f2 100644 --- a/src/routes/api/admin/guilds/[guild]/categories/[category]/index.js +++ b/src/routes/api/admin/guilds/[guild]/categories/[category]/index.js @@ -5,7 +5,7 @@ const { ApplicationCommandPermissionType } = require('discord.js'); module.exports.delete = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guild = client.guilds.cache.get(req.params.guild); const categoryId = Number(req.params.category); const original = categoryId && await client.prisma.category.findUnique({ where: { id: categoryId } }); @@ -33,7 +33,7 @@ module.exports.delete = fastify => ({ module.exports.get = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guildId = req.params.guild; const categoryId = Number(req.params.category); const category = await client.prisma.category.findUnique({ @@ -68,7 +68,7 @@ module.exports.get = fastify => ({ module.exports.patch = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guildId = req.params.guild; const categoryId = Number(req.params.category); /** @type {import('discord.js').Guild} */ diff --git a/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js b/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js index 160c20b..6533740 100644 --- a/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js +++ b/src/routes/api/admin/guilds/[guild]/categories/[category]/questions/[question].js @@ -3,7 +3,7 @@ const { logAdminEvent } = require('../../../../../../../../lib/logging'); module.exports.delete = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guildId = req.params.guild; const categoryId = Number(req.params.category); const questionId = req.params.question; diff --git a/src/routes/api/admin/guilds/[guild]/categories/index.js b/src/routes/api/admin/guilds/[guild]/categories/index.js index 409baa2..d8da7d7 100644 --- a/src/routes/api/admin/guilds/[guild]/categories/index.js +++ b/src/routes/api/admin/guilds/[guild]/categories/index.js @@ -12,9 +12,9 @@ const { } = require('../../../../../../lib/stats'); module.exports.get = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; let { categories } = await client.prisma.guild.findUnique({ select: { @@ -54,9 +54,9 @@ module.exports.get = fastify => ({ }); module.exports.post = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const user = await client.users.fetch(req.user.id); const guild = client.guilds.cache.get(req.params.guild); diff --git a/src/routes/api/admin/guilds/[guild]/data.js b/src/routes/api/admin/guilds/[guild]/data.js index 0a3e8c8..fa7d082 100644 --- a/src/routes/api/admin/guilds/[guild]/data.js +++ b/src/routes/api/admin/guilds/[guild]/data.js @@ -1,7 +1,7 @@ module.exports.get = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const id = req.params.guild; const guild = client.guilds.cache.get(id) ?? {}; const { query } = req.query; diff --git a/src/routes/api/admin/guilds/[guild]/index.js b/src/routes/api/admin/guilds/[guild]/index.js index bb787fd..39e49b9 100644 --- a/src/routes/api/admin/guilds/[guild]/index.js +++ b/src/routes/api/admin/guilds/[guild]/index.js @@ -6,9 +6,9 @@ const { const ms = require('ms'); module.exports.get = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import("client")} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const id = req.params.guild; const cacheKey = `cache/stats/guild:${id}`; let cached = await client.keyv.get(cacheKey); diff --git a/src/routes/api/admin/guilds/[guild]/panels.js b/src/routes/api/admin/guilds/[guild]/panels.js index 50991c4..b8d1223 100644 --- a/src/routes/api/admin/guilds/[guild]/panels.js +++ b/src/routes/api/admin/guilds/[guild]/panels.js @@ -14,9 +14,9 @@ const emoji = require('node-emoji'); const { logAdminEvent } = require('../../../../../lib/logging'); module.exports.post = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guild = client.guilds.cache.get(req.params.guild); const data = req.body; diff --git a/src/routes/api/admin/guilds/[guild]/problems.js b/src/routes/api/admin/guilds/[guild]/problems.js index 130d6de..7522b7c 100644 --- a/src/routes/api/admin/guilds/[guild]/problems.js +++ b/src/routes/api/admin/guilds/[guild]/problems.js @@ -1,9 +1,9 @@ const { PermissionsBitField } = require('discord.js'); module.exports.get = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const id = req.params.guild; const guild = client.guilds.cache.get(id); const settings = await client.prisma.guild.findUnique({ where: { id } }) ?? diff --git a/src/routes/api/admin/guilds/[guild]/settings.js b/src/routes/api/admin/guilds/[guild]/settings.js index 2c14ad9..2f5af99 100644 --- a/src/routes/api/admin/guilds/[guild]/settings.js +++ b/src/routes/api/admin/guilds/[guild]/settings.js @@ -2,9 +2,9 @@ const { logAdminEvent } = require('../../../../../lib/logging.js'); const { Colors } = require('discord.js'); module.exports.delete = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const id = req.params.guild; await client.prisma.guild.delete({ where: { id } }); const settings = await client.prisma.guild.create({ data: { id } }); @@ -24,9 +24,9 @@ module.exports.delete = fastify => ({ }); module.exports.get = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const id = req.params.guild; const settings = await client.prisma.guild.findUnique({ where: { id } }) ?? await client.prisma.guild.create({ data: { id } }); @@ -37,7 +37,7 @@ module.exports.get = fastify => ({ }); module.exports.patch = fastify => ({ - handler: async (req, res) => { + handler: async req => { const data = req.body; if (data.hasOwnProperty('id')) delete data.id; if (data.hasOwnProperty('createdAt')) delete data.createdAt; @@ -49,7 +49,7 @@ module.exports.patch = fastify => ({ } /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const id = req.params.guild; const original = await client.prisma.guild.findUnique({ where: { id } }); const settings = await client.prisma.guild.update({ diff --git a/src/routes/api/admin/guilds/[guild]/tags/[tag].js b/src/routes/api/admin/guilds/[guild]/tags/[tag].js index 13fb25d..ed2b692 100644 --- a/src/routes/api/admin/guilds/[guild]/tags/[tag].js +++ b/src/routes/api/admin/guilds/[guild]/tags/[tag].js @@ -4,7 +4,7 @@ const { logAdminEvent } = require('../../../../../../lib/logging'); module.exports.delete = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guildId = req.params.guild; const tagId = Number(req.params.tag); const original = tagId && await client.prisma.tag.findUnique({ where: { id: tagId } }); @@ -41,7 +41,7 @@ module.exports.delete = fastify => ({ module.exports.get = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guildId = req.params.guild; const tagId = Number(req.params.tag); const tag = await client.prisma.tag.findUnique({ where: { id: tagId } }); @@ -56,7 +56,7 @@ module.exports.get = fastify => ({ module.exports.patch = fastify => ({ handler: async (req, res) => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guildId = req.params.guild; const tagId = Number(req.params.tag); const guild = client.guilds.cache.get(req.params.guild); diff --git a/src/routes/api/admin/guilds/[guild]/tags/index.js b/src/routes/api/admin/guilds/[guild]/tags/index.js index 46a84e8..b887794 100644 --- a/src/routes/api/admin/guilds/[guild]/tags/index.js +++ b/src/routes/api/admin/guilds/[guild]/tags/index.js @@ -2,9 +2,9 @@ const ms = require('ms'); const { logAdminEvent } = require('../../../../../../lib/logging'); module.exports.get = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const { tags } = await client.prisma.guild.findUnique({ select: { tags: true }, @@ -18,9 +18,9 @@ module.exports.get = fastify => ({ module.exports.post = fastify => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import('client')} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const guild = client.guilds.cache.get(req.params.guild); const data = req.body; const tag = await client.prisma.tag.create({ diff --git a/src/routes/api/admin/guilds/index.js b/src/routes/api/admin/guilds/index.js index 9b6dc06..c635440 100644 --- a/src/routes/api/admin/guilds/index.js +++ b/src/routes/api/admin/guilds/index.js @@ -2,7 +2,7 @@ const { PermissionsBitField } = require('discord.js'); module.exports.get = fastify => ({ handler: async (req, res) => { - const { client } = res.context.config; + const { client } = req.routeOptions.config; const guilds = await (await fetch('https://discordapp.com/api/users/@me/guilds', { headers: { 'Authorization': `Bearer ${req.user.accessToken}` } })).json(); res.send( guilds diff --git a/src/routes/api/client.js b/src/routes/api/client.js index e18c1df..7efa8a6 100644 --- a/src/routes/api/client.js +++ b/src/routes/api/client.js @@ -4,9 +4,9 @@ const { const ms = require('ms'); module.exports.get = () => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import("client")} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; const cacheKey = 'cache/stats/client'; let cached = await client.keyv.get(cacheKey); diff --git a/src/routes/api/locales.js b/src/routes/api/locales.js index 2da51c1..57589e5 100644 --- a/src/routes/api/locales.js +++ b/src/routes/api/locales.js @@ -1,7 +1,7 @@ module.exports.get = () => ({ - handler: async (req, res) => { + handler: async req => { /** @type {import("client")} */ - const client = res.context.config.client; + const client = req.routeOptions.config.client; return client.i18n.locales; }, -}); \ No newline at end of file +}); diff --git a/src/routes/auth/callback.js b/src/routes/auth/callback.js index 12c0622..6205c81 100644 --- a/src/routes/auth/callback.js +++ b/src/routes/auth/callback.js @@ -2,18 +2,25 @@ const { domain } = require('../../lib/http'); module.exports.get = () => ({ handler: async function (req, res) { // MUST NOT use arrow function syntax - const { - access_token: accessToken, - expires_in: expiresIn, - } = await this.discord.getAccessTokenFromAuthorizationCodeFlow(req); + const data = await (await fetch('https://discord.com/api/oauth2/token', { + body: new URLSearchParams({ + client_id: req.routeOptions.config.client.user.id, + client_secret: process.env.DISCORD_SECRET, + code: req.query.code, + grant_type: 'authorization_code', + redirect_uri: `${process.env.HTTP_EXTERNAL}/auth/callback`, + }).toString(), + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + method: 'POST', + })).json(); const redirect = this.states.get(req.query.state) || '/'; this.states.delete(req.query.state); - const user = await (await fetch('https://discordapp.com/api/users/@me', { headers: { 'Authorization': `Bearer ${accessToken}` } })).json(); + const user = await (await fetch('https://discordapp.com/api/users/@me', { headers: { 'Authorization': `Bearer ${data.access_token}` } })).json(); const token = this.jwt.sign({ - accessToken, + accessToken: data.access_token, avatar: user.avatar, discriminator: user.discriminator, - expiresAt: Date.now() + (expiresIn * 1000), + expiresAt: Date.now() + (data.expires_in * 1000), id: user.id, locale: user.locale, username: user.username, @@ -21,7 +28,7 @@ module.exports.get = () => ({ res.setCookie('token', token, { domain, httpOnly: true, - maxAge: expiresIn, + maxAge: data.expires_in, path: '/', sameSite: 'Lax', secure: false,