generated from nhcarrigan/template
feat: add endpoint for entitlement events
This commit is contained in:
@ -23,6 +23,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"fastify": "5.2.1",
|
"fastify": "5.2.1",
|
||||||
"nodemailer": "6.10.0"
|
"fastify-raw-body": "5.0.0",
|
||||||
|
"nodemailer": "6.10.0",
|
||||||
|
"tweetnacl": "1.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
107
pnpm-lock.yaml
generated
107
pnpm-lock.yaml
generated
@ -11,9 +11,15 @@ importers:
|
|||||||
fastify:
|
fastify:
|
||||||
specifier: 5.2.1
|
specifier: 5.2.1
|
||||||
version: 5.2.1
|
version: 5.2.1
|
||||||
|
fastify-raw-body:
|
||||||
|
specifier: 5.0.0
|
||||||
|
version: 5.0.0
|
||||||
nodemailer:
|
nodemailer:
|
||||||
specifier: 6.10.0
|
specifier: 6.10.0
|
||||||
version: 6.10.0
|
version: 6.10.0
|
||||||
|
tweetnacl:
|
||||||
|
specifier: 1.0.3
|
||||||
|
version: 1.0.3
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nhcarrigan/eslint-config':
|
'@nhcarrigan/eslint-config':
|
||||||
specifier: 5.1.0
|
specifier: 5.1.0
|
||||||
@ -711,6 +717,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
bytes@3.1.2:
|
||||||
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
cac@6.7.14:
|
cac@6.7.14:
|
||||||
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -823,6 +833,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
depd@2.0.0:
|
||||||
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
|
||||||
dequal@2.0.3:
|
dequal@2.0.3:
|
||||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
@ -1050,6 +1064,13 @@ packages:
|
|||||||
fast-uri@3.0.6:
|
fast-uri@3.0.6:
|
||||||
resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==}
|
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:
|
fastify@5.2.1:
|
||||||
resolution: {integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==}
|
resolution: {integrity: sha512-rslrNBF67eg8/Gyn7P2URV8/6pz8kSAscFL4EThZJ8JBMaXacVdVE4hmUcnPNKERl5o/xTiBSLfdowBRhVF1WA==}
|
||||||
|
|
||||||
@ -1184,6 +1205,14 @@ packages:
|
|||||||
hosted-git-info@2.8.9:
|
hosted-git-info@2.8.9:
|
||||||
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
|
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:
|
ignore@5.3.2:
|
||||||
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
@ -1200,6 +1229,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
inherits@2.0.4:
|
||||||
|
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||||
|
|
||||||
internal-slot@1.1.0:
|
internal-slot@1.1.0:
|
||||||
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
|
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
@ -1609,6 +1641,10 @@ packages:
|
|||||||
quick-format-unescaped@4.0.4:
|
quick-format-unescaped@4.0.4:
|
||||||
resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==}
|
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:
|
react-is@16.13.1:
|
||||||
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
|
||||||
|
|
||||||
@ -1703,6 +1739,12 @@ packages:
|
|||||||
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==}
|
||||||
engines: {node: '>=10'}
|
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:
|
secure-json-parse@3.0.2:
|
||||||
resolution: {integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==}
|
resolution: {integrity: sha512-H6nS2o8bWfpFEV6U38sOSjS7bTbdgbCGU9wEM6W14P5H0QOsz94KCusifV44GpHDTu2nqZbuDNhTzu+mjDSw1w==}
|
||||||
|
|
||||||
@ -1734,6 +1776,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==}
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
|
|
||||||
|
setprototypeof@1.2.0:
|
||||||
|
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
@ -1797,6 +1842,10 @@ packages:
|
|||||||
stackback@0.0.2:
|
stackback@0.0.2:
|
||||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
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:
|
std-env@3.8.0:
|
||||||
resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
|
resolution: {integrity: sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w==}
|
||||||
|
|
||||||
@ -1872,6 +1921,10 @@ packages:
|
|||||||
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
||||||
engines: {node: '>=12'}
|
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:
|
ts-api-utils@1.4.3:
|
||||||
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
|
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
|
||||||
engines: {node: '>=16'}
|
engines: {node: '>=16'}
|
||||||
@ -1890,6 +1943,9 @@ packages:
|
|||||||
tslib@2.8.1:
|
tslib@2.8.1:
|
||||||
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
|
||||||
|
|
||||||
|
tweetnacl@1.0.3:
|
||||||
|
resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==}
|
||||||
|
|
||||||
type-check@0.4.0:
|
type-check@0.4.0:
|
||||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@ -1934,6 +1990,10 @@ packages:
|
|||||||
undici-types@6.20.0:
|
undici-types@6.20.0:
|
||||||
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
|
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:
|
update-browserslist-db@1.1.2:
|
||||||
resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
|
resolution: {integrity: sha512-PPypAm5qvlD7XMZC3BujecnaOxwhrtoFR+Dqkk5Aa/6DssiH0ibKoketaj9w8LP7Bont1rYeoV5plxD7RTEPRg==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
@ -2719,6 +2779,8 @@ snapshots:
|
|||||||
|
|
||||||
builtin-modules@3.3.0: {}
|
builtin-modules@3.3.0: {}
|
||||||
|
|
||||||
|
bytes@3.1.2: {}
|
||||||
|
|
||||||
cac@6.7.14: {}
|
cac@6.7.14: {}
|
||||||
|
|
||||||
call-bind-apply-helpers@1.0.1:
|
call-bind-apply-helpers@1.0.1:
|
||||||
@ -2827,6 +2889,8 @@ snapshots:
|
|||||||
has-property-descriptors: 1.0.2
|
has-property-descriptors: 1.0.2
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
|
|
||||||
|
depd@2.0.0: {}
|
||||||
|
|
||||||
dequal@2.0.3: {}
|
dequal@2.0.3: {}
|
||||||
|
|
||||||
dir-glob@3.0.1:
|
dir-glob@3.0.1:
|
||||||
@ -3224,6 +3288,14 @@ snapshots:
|
|||||||
|
|
||||||
fast-uri@3.0.6: {}
|
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:
|
fastify@5.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@fastify/ajv-compiler': 4.0.2
|
'@fastify/ajv-compiler': 4.0.2
|
||||||
@ -3382,6 +3454,18 @@ snapshots:
|
|||||||
|
|
||||||
hosted-git-info@2.8.9: {}
|
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: {}
|
ignore@5.3.2: {}
|
||||||
|
|
||||||
import-fresh@3.3.1:
|
import-fresh@3.3.1:
|
||||||
@ -3393,6 +3477,8 @@ snapshots:
|
|||||||
|
|
||||||
indent-string@4.0.0: {}
|
indent-string@4.0.0: {}
|
||||||
|
|
||||||
|
inherits@2.0.4: {}
|
||||||
|
|
||||||
internal-slot@1.1.0:
|
internal-slot@1.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
@ -3801,6 +3887,13 @@ snapshots:
|
|||||||
|
|
||||||
quick-format-unescaped@4.0.4: {}
|
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-is@16.13.1: {}
|
||||||
|
|
||||||
react@19.0.0: {}
|
react@19.0.0: {}
|
||||||
@ -3924,6 +4017,10 @@ snapshots:
|
|||||||
|
|
||||||
safe-stable-stringify@2.5.0: {}
|
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@3.0.2: {}
|
||||||
|
|
||||||
semver@5.7.2: {}
|
semver@5.7.2: {}
|
||||||
@ -3956,6 +4053,8 @@ snapshots:
|
|||||||
es-errors: 1.3.0
|
es-errors: 1.3.0
|
||||||
es-object-atoms: 1.1.1
|
es-object-atoms: 1.1.1
|
||||||
|
|
||||||
|
setprototypeof@1.2.0: {}
|
||||||
|
|
||||||
shebang-command@2.0.0:
|
shebang-command@2.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
shebang-regex: 3.0.0
|
shebang-regex: 3.0.0
|
||||||
@ -4025,6 +4124,8 @@ snapshots:
|
|||||||
|
|
||||||
stackback@0.0.2: {}
|
stackback@0.0.2: {}
|
||||||
|
|
||||||
|
statuses@2.0.1: {}
|
||||||
|
|
||||||
std-env@3.8.0: {}
|
std-env@3.8.0: {}
|
||||||
|
|
||||||
string.prototype.matchall@4.0.12:
|
string.prototype.matchall@4.0.12:
|
||||||
@ -4110,6 +4211,8 @@ snapshots:
|
|||||||
|
|
||||||
toad-cache@3.7.0: {}
|
toad-cache@3.7.0: {}
|
||||||
|
|
||||||
|
toidentifier@1.0.1: {}
|
||||||
|
|
||||||
ts-api-utils@1.4.3(typescript@5.7.3):
|
ts-api-utils@1.4.3(typescript@5.7.3):
|
||||||
dependencies:
|
dependencies:
|
||||||
typescript: 5.7.3
|
typescript: 5.7.3
|
||||||
@ -4127,6 +4230,8 @@ snapshots:
|
|||||||
|
|
||||||
tslib@2.8.1: {}
|
tslib@2.8.1: {}
|
||||||
|
|
||||||
|
tweetnacl@1.0.3: {}
|
||||||
|
|
||||||
type-check@0.4.0:
|
type-check@0.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
@ -4181,6 +4286,8 @@ snapshots:
|
|||||||
|
|
||||||
undici-types@6.20.0: {}
|
undici-types@6.20.0: {}
|
||||||
|
|
||||||
|
unpipe@1.0.0: {}
|
||||||
|
|
||||||
update-browserslist-db@1.1.2(browserslist@4.24.4):
|
update-browserslist-db@1.1.2(browserslist@4.24.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
browserslist: 4.24.4
|
browserslist: 4.24.4
|
||||||
|
96
src/config/applicationData.ts
Normal file
96
src/config/applicationData.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
/* eslint-disable @typescript-eslint/naming-convention -- We are using the numerical ids as the keys.*/
|
||||||
|
export const applicationData: Record<string, { name: string; key: string }> = {
|
||||||
|
"1235128719836712970": {
|
||||||
|
key: "e255cd3a348ce604e18e2f2c0f5a59a9273a420ca732630d569ef5f839f2143e",
|
||||||
|
name: "Celestine",
|
||||||
|
},
|
||||||
|
"1338596130207957035": {
|
||||||
|
key: "ef9d2a3c8e9a4d165a12ca798be93d719dd51cc7ff901ade8136cb992cd7fe3e",
|
||||||
|
name: "Aria Iuvo",
|
||||||
|
},
|
||||||
|
"1338664192714211459": {
|
||||||
|
key: "a28c9c2683acb209341e04d5b43bd2a24bc81f5b263095a1bf487e94ca6a3ff9",
|
||||||
|
name: "Cordelia Taryne",
|
||||||
|
},
|
||||||
|
"1338753576583041074": {
|
||||||
|
key: "62468252371a68791c650b5aaa599ef2b7b148a7169bb5fa9f56075705ac405e",
|
||||||
|
name: "Melody Iuvo",
|
||||||
|
},
|
||||||
|
"1343341112437248041": {
|
||||||
|
key: "3ccf23b9c10dda9a7af434e0c5fc116d05aba66caf2ebd8c738c60ba9875436f",
|
||||||
|
name: "Becca Lyria",
|
||||||
|
},
|
||||||
|
"1343370633916059668": {
|
||||||
|
key: "a9146e39ab5f69129e3c50db5d5848c56bc4a2cb90bba10e492e08355acd3d12",
|
||||||
|
name: "Maylin Taryne",
|
||||||
|
},
|
||||||
|
"1343413943447584819": {
|
||||||
|
key: "6d95c7132ee9f28a4ea5fffbc8dd33ecaffe0f50add0c631d5ef51cc071bd2df",
|
||||||
|
name: "Gwen Abalise",
|
||||||
|
},
|
||||||
|
"1347642447643017289": {
|
||||||
|
key: "091be058344e543e87baafeb9fe20b004bd170ca5ee57b17afff595271080a27",
|
||||||
|
name: "Mommy",
|
||||||
|
},
|
||||||
|
"1386862413936328796": {
|
||||||
|
key: "831e3981135a4c9d30e8c02e6f8cba73436d30c36b1a14f1fb7bc7147cd4cb75",
|
||||||
|
name: "Maribelle",
|
||||||
|
},
|
||||||
|
"1391117878182281316": {
|
||||||
|
key: "b182039c954ba57216bf53bdc4d5ba3d89efc2b41c850cbf7f3430fbb6cc0c56",
|
||||||
|
name: "Hikari",
|
||||||
|
},
|
||||||
|
"1391488058913718374": {
|
||||||
|
key: "fc1a838c3102351602221f2db63d997f9e4495510044d5ec436844038b9a5bd5",
|
||||||
|
name: "Rosalia Nightsong",
|
||||||
|
},
|
||||||
|
"1391489982887362761": {
|
||||||
|
key: "ef173a181d6fcf506b72795812fca8ecc3a81c2ff382bfd39564bab63fd90eee",
|
||||||
|
name: "Sorielle",
|
||||||
|
},
|
||||||
|
"1391491102657482863": {
|
||||||
|
key: "a412583e5d5510aebb6d54eb49f36797e62f9567efd79108863adbb93cf00236",
|
||||||
|
name: "Verena",
|
||||||
|
},
|
||||||
|
"1391492296222179459": {
|
||||||
|
key: "aab61af4411fc1dc710d5b5aba5d16fba9effaad9415b878a3f1595428dbebcd",
|
||||||
|
name: "Liora",
|
||||||
|
},
|
||||||
|
"1391493722176356434": {
|
||||||
|
key: "3dc2abd018271a5a1f65c09597738a711b2fc619d34da59189279d6c2a1922f4",
|
||||||
|
name: "Thessalia",
|
||||||
|
},
|
||||||
|
"1391494389477412906": {
|
||||||
|
key: "8d11517cf954779e4645b8c10432697a0572dcfcecc0bb14d0fe2397f5a03453",
|
||||||
|
name: "Callista",
|
||||||
|
},
|
||||||
|
"1391495288421879849": {
|
||||||
|
key: "fb0894e2dcd3e736addd70a675b40d5681d39c133289cdfe4f7378006163e817",
|
||||||
|
name: "Eirene",
|
||||||
|
},
|
||||||
|
"1391497269177483405": {
|
||||||
|
key: "0887f7e12053d559f8944a06ed323ec237d34f8e15860b672fb7abe6dc32d192",
|
||||||
|
name: "Sybil",
|
||||||
|
},
|
||||||
|
"1391503229287928000": {
|
||||||
|
key: "8a4d4f18dae4e2d0ec610e3da47254a812c39cfac6ee986cfaa20eb848a2db92",
|
||||||
|
name: "Clarion",
|
||||||
|
},
|
||||||
|
"1391503834073006181": {
|
||||||
|
key: "60ffe0a3503d5166c1e4b7370753793dff60d75a28ebf4ace8b6623ad5207821",
|
||||||
|
name: "Evangeline",
|
||||||
|
},
|
||||||
|
"1391504577811185744": {
|
||||||
|
key: "33bb085873b46199facfbfae00b7d71ed04d55377deeaa2a0c8afa303c68a75d",
|
||||||
|
name: "Theodora",
|
||||||
|
},
|
||||||
|
"1391505285465509978": {
|
||||||
|
key: "edce882890078d52c00c653b9e305565a909a0807abf86b36f1d7679434b80fa",
|
||||||
|
name: "Veluna",
|
||||||
|
},
|
||||||
|
};
|
31
src/interfaces/entitlement.ts
Normal file
31
src/interfaces/entitlement.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/naming-convention -- Needs to match Discord's structure. */
|
||||||
|
export interface Entitlement {
|
||||||
|
application_id: string;
|
||||||
|
event: {
|
||||||
|
data: {
|
||||||
|
application_id: string;
|
||||||
|
consumed: boolean;
|
||||||
|
deleted: boolean;
|
||||||
|
ends_at: string;
|
||||||
|
gift_code_flags: number;
|
||||||
|
guild_id: string;
|
||||||
|
id: string;
|
||||||
|
promotion_id: string | null;
|
||||||
|
sku_id: string;
|
||||||
|
starts_at: string;
|
||||||
|
subscription_id: string;
|
||||||
|
type: number;
|
||||||
|
user_id: string;
|
||||||
|
};
|
||||||
|
timestamp: string;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
type: number;
|
||||||
|
version: number;
|
||||||
|
}
|
@ -17,6 +17,7 @@ export const sendDiscord = async(
|
|||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention -- Needs to match Discord's structure.
|
||||||
accent_color: 15_418_782,
|
accent_color: 15_418_782,
|
||||||
components: [
|
components: [
|
||||||
{
|
{
|
||||||
@ -40,6 +41,7 @@ export const sendDiscord = async(
|
|||||||
flags: 32_768,
|
flags: 32_768,
|
||||||
}),
|
}),
|
||||||
headers: {
|
headers: {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention -- Needs to match Discord's structure.
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
|
46
src/modules/validateWebhook.ts
Normal file
46
src/modules/validateWebhook.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* @copyright nhcarrigan
|
||||||
|
* @license Naomi's Public License
|
||||||
|
* @author Naomi Carrigan
|
||||||
|
*/
|
||||||
|
import nacl from "tweetnacl";
|
||||||
|
import { applicationData } from "../config/applicationData.js";
|
||||||
|
import type { Entitlement } from "../interfaces/entitlement.js";
|
||||||
|
import type { FastifyRequest } from "fastify";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates that the webhook request is from Discord by checking the signature.
|
||||||
|
* @param request - The Fastify request object containing the webhook data.
|
||||||
|
* @returns A boolean indicating whether the webhook signature is valid.
|
||||||
|
*/
|
||||||
|
export const validateWebhook = (
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention -- Body must be capitalised for Fastify.
|
||||||
|
request: FastifyRequest<{ Body: Entitlement }>,
|
||||||
|
): boolean => {
|
||||||
|
const { application_id: applicationId } = request.body;
|
||||||
|
const appData = applicationData[applicationId];
|
||||||
|
if (appData === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const signature = request.headers["x-signature-ed25519"];
|
||||||
|
const timestamp = request.headers["x-signature-timestamp"];
|
||||||
|
const { rawBody } = request;
|
||||||
|
if (
|
||||||
|
signature === undefined
|
||||||
|
|| timestamp === undefined
|
||||||
|
|| rawBody === undefined
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return nacl.sign.detached.verify(
|
||||||
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- Being lazy here, tbh.
|
||||||
|
Buffer.from(`${timestamp}${rawBody}`),
|
||||||
|
Buffer.from(
|
||||||
|
Array.isArray(signature)
|
||||||
|
? signature[0] ?? signature.join("")
|
||||||
|
: signature,
|
||||||
|
"hex",
|
||||||
|
),
|
||||||
|
Buffer.from(process.env.DISCORD_PUBLIC_KEY ?? "", "hex"),
|
||||||
|
);
|
||||||
|
};
|
@ -5,12 +5,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import fastify from "fastify";
|
import fastify from "fastify";
|
||||||
|
import fastifyRawBody from "fastify-raw-body";
|
||||||
|
import { applicationData } from "../config/applicationData.js";
|
||||||
import { auth } from "../modules/auth.js";
|
import { auth } from "../modules/auth.js";
|
||||||
import { sendDiscord } from "../modules/discord.js";
|
import { sendDiscord } from "../modules/discord.js";
|
||||||
import { sendMail } from "../modules/sendMail.js";
|
import { sendMail } from "../modules/sendMail.js";
|
||||||
|
import { validateWebhook } from "../modules/validateWebhook.js";
|
||||||
import { errorSchema } from "../schemas/errorSchema.js";
|
import { errorSchema } from "../schemas/errorSchema.js";
|
||||||
import { logSchema } from "../schemas/logSchema.js";
|
import { logSchema } from "../schemas/logSchema.js";
|
||||||
import { uptimeSchema } from "../schemas/uptimeSchema.js";
|
import { uptimeSchema } from "../schemas/uptimeSchema.js";
|
||||||
|
import type { Entitlement } from "../interfaces/entitlement.js";
|
||||||
import type { Error } from "../interfaces/error.js";
|
import type { Error } from "../interfaces/error.js";
|
||||||
import type { Log } from "../interfaces/log.js";
|
import type { Log } from "../interfaces/log.js";
|
||||||
import type { Uptime } from "../interfaces/uptime.js";
|
import type { Uptime } from "../interfaces/uptime.js";
|
||||||
@ -63,6 +67,15 @@ export const instantiateServer = (): void => {
|
|||||||
logger: false,
|
logger: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.register(fastifyRawBody, {
|
||||||
|
encoding: "utf8",
|
||||||
|
field: "rawBody",
|
||||||
|
global: false,
|
||||||
|
jsonContentTypes: [],
|
||||||
|
routes: [],
|
||||||
|
runFirst: true,
|
||||||
|
});
|
||||||
|
|
||||||
server.get("/", (_request, response) => {
|
server.get("/", (_request, response) => {
|
||||||
response.header("Content-Type", "text/html");
|
response.header("Content-Type", "text/html");
|
||||||
response.send(html);
|
response.send(html);
|
||||||
@ -90,7 +103,10 @@ export const instantiateServer = (): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { application, context, stack, message } = request.body;
|
const { application, context, stack, message } = request.body;
|
||||||
await sendMail(`[ERROR]: ${context} - ${application}`, `${message}\n\n${stack}`);
|
await sendMail(
|
||||||
|
`[ERROR]: ${context} - ${application}`,
|
||||||
|
`${message}\n\n${stack}`,
|
||||||
|
);
|
||||||
await sendDiscord(
|
await sendDiscord(
|
||||||
`[ERROR]: ${context} - ${application}`,
|
`[ERROR]: ${context} - ${application}`,
|
||||||
`${message}\n\n\`\`\`\n${stack}\n\`\`\``,
|
`${message}\n\n\`\`\`\n${stack}\n\`\`\``,
|
||||||
@ -115,13 +131,68 @@ export const instantiateServer = (): void => {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention -- Body must be capitalised for Fastify.
|
||||||
|
server.post<{ Body: Entitlement }>(
|
||||||
|
"/entitlement",
|
||||||
|
{ config: { rawBody: true } },
|
||||||
|
async(request, response) => {
|
||||||
|
if (!validateWebhook(request)) {
|
||||||
|
await response.status(401).send({ success: false });
|
||||||
|
void sendDiscord(
|
||||||
|
"[NOTIFICATION]: Entitlement Event",
|
||||||
|
"An invalid webhook signature was received.",
|
||||||
|
);
|
||||||
|
void sendMail(
|
||||||
|
"[NOTIFICATION]: Entitlement Event",
|
||||||
|
"An invalid webhook signature was received.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { type } = request.body;
|
||||||
|
if (type === 0) {
|
||||||
|
await response.status(204).send();
|
||||||
|
void sendDiscord(
|
||||||
|
"[NOTIFICATION]: Entitlement Event",
|
||||||
|
"Received a ping from Discord.",
|
||||||
|
);
|
||||||
|
void sendMail(
|
||||||
|
"[NOTIFICATION]: Entitlement Event",
|
||||||
|
"Received a ping from Discord.",
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await response.status(204).send();
|
||||||
|
const { application_id: applicationId, event } = request.body;
|
||||||
|
const {
|
||||||
|
user_id: userId,
|
||||||
|
guild_id: guildId,
|
||||||
|
ends_at: endsAt,
|
||||||
|
} = event.data;
|
||||||
|
const appInfo = applicationData[applicationId];
|
||||||
|
await sendDiscord(
|
||||||
|
`[ENTITLEMENT]: ${appInfo?.name ?? applicationId}`,
|
||||||
|
`Entitlement purchased!\n- **User ID**: ${userId}\n- **Guild ID**: ${guildId}\n- **Ends At**: ${endsAt}`,
|
||||||
|
);
|
||||||
|
await sendMail(
|
||||||
|
`[ENTITLEMENT]: ${appInfo?.name ?? applicationId}`,
|
||||||
|
`Entitlement purchased!\n- **User ID**: ${userId}\n- **Guild ID**: ${guildId}\n- **Ends At**: ${endsAt}`,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
server.listen({ port: 5003 }, (error) => {
|
server.listen({ port: 5003 }, (error) => {
|
||||||
const application = "Alert Server";
|
const application = "Alert Server";
|
||||||
if (error) {
|
if (error) {
|
||||||
const { message, stack } = error;
|
const { message, stack } = error;
|
||||||
const context = "Server Startup";
|
const context = "Server Startup";
|
||||||
void sendMail(`[ERROR]: ${context} - ${application}`, `${message}\n\n${String(stack)}`);
|
void sendMail(
|
||||||
void sendDiscord(`[ERROR]: ${context} - ${application}`, `${message}\n\n\`\`\`\n${String(stack)}\n\`\`\``);
|
`[ERROR]: ${context} - ${application}`,
|
||||||
|
`${message}\n\n${String(stack)}`,
|
||||||
|
);
|
||||||
|
void sendDiscord(
|
||||||
|
`[ERROR]: ${context} - ${application}`,
|
||||||
|
`${message}\n\n\`\`\`\n${String(stack)}\n\`\`\``,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const level = "debug";
|
const level = "debug";
|
||||||
@ -134,7 +205,13 @@ export const instantiateServer = (): void => {
|
|||||||
const context = "Server Startup";
|
const context = "Server Startup";
|
||||||
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Totally being lazy.
|
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- Totally being lazy.
|
||||||
const { message, stack } = error as Error;
|
const { message, stack } = error as Error;
|
||||||
void sendMail(`[ERROR]: ${context} - ${application}`, `${message}\n\n${stack}`);
|
void sendMail(
|
||||||
void sendDiscord(`[ERROR]: ${context} - ${application}`, `${message}\n\n\`\`\`\n${stack}\n\`\`\``);
|
`[ERROR]: ${context} - ${application}`,
|
||||||
|
`${message}\n\n${stack}`,
|
||||||
|
);
|
||||||
|
void sendDiscord(
|
||||||
|
`[ERROR]: ${context} - ${application}`,
|
||||||
|
`${message}\n\n\`\`\`\n${stack}\n\`\`\``,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user