diff --git a/package.json b/package.json index 7dfa4de..071edfa 100644 --- a/package.json +++ b/package.json @@ -23,8 +23,8 @@ }, "dependencies": { "fastify": "5.2.1", - "fastify-raw-body": "5.0.0", "nodemailer": "6.10.0", + "secure-json-parse": "4.0.0", "tweetnacl": "1.0.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd48888..20a703b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,12 +11,12 @@ importers: fastify: specifier: 5.2.1 version: 5.2.1 - fastify-raw-body: - specifier: 5.0.0 - version: 5.0.0 nodemailer: specifier: 6.10.0 version: 6.10.0 + secure-json-parse: + specifier: 4.0.0 + version: 4.0.0 tweetnacl: specifier: 1.0.3 version: 1.0.3 @@ -717,10 +717,6 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -833,10 +829,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1064,13 +1056,6 @@ packages: fast-uri@3.0.6: resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - fastify-plugin@5.0.1: - resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==} - - fastify-raw-body@5.0.0: - resolution: {integrity: sha512-2qfoaQ3BQDhZ1gtbkKZd6n0kKxJISJGM6u/skD9ljdWItAscjXrtZ1lnjr7PavmXX9j4EyCPmBDiIsLn07d5vA==} - engines: {node: '>= 10'} - fastify@5.2.1: resolution: {integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==} @@ -1205,14 +1190,6 @@ packages: hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1229,9 +1206,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -1641,10 +1615,6 @@ packages: quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - raw-body@3.0.0: - resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} - engines: {node: '>= 0.8'} - react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -1739,15 +1709,12 @@ packages: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} engines: {node: '>=10'} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - secure-json-parse@3.0.2: resolution: {integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==} + secure-json-parse@4.0.0: + resolution: {integrity: sha512-dxtLJO6sc35jWidmLxo7ij+Eg48PM/kleBsxpC8QJE0qJICe+KawkDQmvCMZUr9u7WKVHgMW6vy3fQ7zMiFZMA==} + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true @@ -1776,9 +1743,6 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -1842,10 +1806,6 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - std-env@3.8.0: resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==} @@ -1921,10 +1881,6 @@ packages: resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} engines: {node: '>=12'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - ts-api-utils@1.4.3: resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} engines: {node: '>=16'} @@ -1990,10 +1946,6 @@ packages: undici-types@6.20.0: resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - update-browserslist-db@1.1.2: resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==} hasBin: true @@ -2779,8 +2731,6 @@ snapshots: builtin-modules@3.3.0: {} - bytes@3.1.2: {} - cac@6.7.14: {} call-bind-apply-helpers@1.0.1: @@ -2889,8 +2839,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - depd@2.0.0: {} - dequal@2.0.3: {} dir-glob@3.0.1: @@ -3288,14 +3236,6 @@ snapshots: fast-uri@3.0.6: {} - fastify-plugin@5.0.1: {} - - fastify-raw-body@5.0.0: - dependencies: - fastify-plugin: 5.0.1 - raw-body: 3.0.0 - secure-json-parse: 2.7.0 - fastify@5.2.1: dependencies: '@fastify/ajv-compiler': 4.0.2 @@ -3454,18 +3394,6 @@ snapshots: hosted-git-info@2.8.9: {} - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - ignore@5.3.2: {} import-fresh@3.3.1: @@ -3477,8 +3405,6 @@ snapshots: indent-string@4.0.0: {} - inherits@2.0.4: {} - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 @@ -3887,13 +3813,6 @@ snapshots: quick-format-unescaped@4.0.4: {} - raw-body@3.0.0: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - unpipe: 1.0.0 - react-is@16.13.1: {} react@19.0.0: {} @@ -4017,12 +3936,10 @@ snapshots: safe-stable-stringify@2.5.0: {} - safer-buffer@2.1.2: {} - - secure-json-parse@2.7.0: {} - secure-json-parse@3.0.2: {} + secure-json-parse@4.0.0: {} + semver@5.7.2: {} semver@6.3.1: {} @@ -4053,8 +3970,6 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 - setprototypeof@1.2.0: {} - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -4124,8 +4039,6 @@ snapshots: stackback@0.0.2: {} - statuses@2.0.1: {} - std-env@3.8.0: {} string.prototype.matchall@4.0.12: @@ -4211,8 +4124,6 @@ snapshots: toad-cache@3.7.0: {} - toidentifier@1.0.1: {} - ts-api-utils@1.4.3(typescript@5.7.3): dependencies: typescript: 5.7.3 @@ -4286,8 +4197,6 @@ snapshots: undici-types@6.20.0: {} - unpipe@1.0.0: {} - update-browserslist-db@1.1.2(browserslist@4.24.4): dependencies: browserslist: 4.24.4 diff --git a/src/modules/validateWebhook.ts b/src/modules/validateWebhook.ts index ad461b9..dc73686 100644 --- a/src/modules/validateWebhook.ts +++ b/src/modules/validateWebhook.ts @@ -3,6 +3,7 @@ * @license Naomi's Public License * @author Naomi Carrigan */ +import secureJson from "secure-json-parse"; import nacl from "tweetnacl"; import { applicationData } from "../config/applicationData.js"; import { sendDiscord } from "./discord.js"; @@ -26,7 +27,8 @@ export const validateWebhook = ( } const signature = request.headers["x-signature-ed25519"]; const timestamp = request.headers["x-signature-timestamp"]; - const rawBody = request.rawBody ?? request.body; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Later. + const rawBody = secureJson.parse(JSON.stringify(request.body)); if ( signature === undefined || timestamp === undefined @@ -47,7 +49,7 @@ export const validateWebhook = ( : signature, "hex", ), - Buffer.from(process.env.DISCORD_PUBLIC_KEY ?? "", "hex"), + Buffer.from(appData.key, "hex"), ); if (!isValid) { void sendDiscord( diff --git a/src/server/serve.ts b/src/server/serve.ts index c95d717..2435863 100644 --- a/src/server/serve.ts +++ b/src/server/serve.ts @@ -5,7 +5,6 @@ */ import fastify from "fastify"; -import fastifyRawBody from "fastify-raw-body"; import { applicationData } from "../config/applicationData.js"; import { auth } from "../modules/auth.js"; import { sendDiscord } from "../modules/discord.js"; @@ -67,13 +66,6 @@ export const instantiateServer = (): void => { logger: false, }); - server.register(fastifyRawBody, { - encoding: "utf8", - field: "rawBody", - global: true, - runFirst: true, - }); - server.get("/", (_request, response) => { response.header("Content-Type", "text/html"); response.send(html); @@ -146,9 +138,9 @@ export const instantiateServer = (): void => { ); return; } + await response.status(204).send(); const { type } = request.body; if (type === 0) { - await response.status(204).send(); void sendDiscord( "[NOTIFICATION]: Entitlement Event", "Received a ping from Discord.", @@ -159,7 +151,6 @@ export const instantiateServer = (): void => { ); return; } - await response.status(204).send(); const { application_id: applicationId, event } = request.body; const { user_id: userId,