Compare commits

...

3 commits

Author SHA1 Message Date
amy
35476348e2
image upload now functional 2024-12-02 19:40:08 +03:30
amy
63b6adfdbe
auth 2024-12-01 23:46:27 +03:30
amy
f25011b10d
whole lotta shit 2024-12-01 22:19:33 +03:30
19 changed files with 701 additions and 209 deletions

3
.gitignore vendored
View file

@ -1,2 +1,5 @@
/node_modules/
/.idea/
.env
/src/uploads/
/uploads

View file

@ -5,16 +5,24 @@
"type": "module",
"main": "index.js",
"scripts": {
"dev": "node --no-warnings=ExperimentalWarning --loader ts-node/esm src/main.ts"
"dev": "node --no-warnings=ExperimentalWarning --loader ts-node/esm src/main.ts",
"migrate": "prisma migrate dev"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@9.12.3+sha512.cce0f9de9c5a7c95bef944169cc5dfe8741abfb145078c0d508b868056848a87c81e626246cb60967cbd7fd29a6c062ef73ff840d96b3c86c40ac92cf4a813ee",
"dependencies": {
"@fastify/cookie": "^11.0.1",
"@fastify/multipart": "^9.0.1",
"@fastify/oauth2": "^8.1.0",
"@prisma/client": "6.0.0",
"@types/node": "^22.10.1",
"dotenv": "^16.4.5",
"fastify": "^5.1.0",
"knex": "^3.1.0",
"file-type": "^19.6.0",
"pg": "^8.13.1",
"prisma": "^6.0.0",
"ts-node": "^10.9.2"
}
}

449
pnpm-lock.yaml generated
View file

@ -8,15 +8,36 @@ importers:
.:
dependencies:
'@fastify/cookie':
specifier: ^11.0.1
version: 11.0.1
'@fastify/multipart':
specifier: ^9.0.1
version: 9.0.1
'@fastify/oauth2':
specifier: ^8.1.0
version: 8.1.0
'@prisma/client':
specifier: 6.0.0
version: 6.0.0(prisma@6.0.0)
'@types/node':
specifier: ^22.10.1
version: 22.10.1
dotenv:
specifier: ^16.4.5
version: 16.4.5
fastify:
specifier: ^5.1.0
version: 5.1.0
knex:
specifier: ^3.1.0
version: 3.1.0(pg@8.13.1)
file-type:
specifier: ^19.6.0
version: 19.6.0
pg:
specifier: ^8.13.1
version: 8.13.1
prisma:
specifier: ^6.0.0
version: 6.0.0
ts-node:
specifier: ^10.9.2
version: 10.9.2(@types/node@22.10.1)(typescript@5.7.2)
@ -30,6 +51,15 @@ packages:
'@fastify/ajv-compiler@4.0.1':
resolution: {integrity: sha512-DxrBdgsjNLP0YM6W5Hd6/Fmj43S8zMKiFJYgi+Ri3htTGAowPVG/tG1wpnWLMjufEnehRivUCKZ1pLDIoZdTuw==}
'@fastify/busboy@3.0.0':
resolution: {integrity: sha512-83rnH2nCvclWaPQQKvkJ2pdOjG4TZyEVuFDnlOF6KP08lDaaceVyw/W63mDuafQT+MKHCvXIPpE5uYWeM0rT4w==}
'@fastify/cookie@11.0.1':
resolution: {integrity: sha512-n1Ooz4bgQ5LcOlJQboWPfsMNxIrGV0SgU85UkctdpTlCQE0mtA3rlspOPUdqk9ubiiZn053ucnia4DjTquI4/g==}
'@fastify/deepmerge@2.0.0':
resolution: {integrity: sha512-fsaybTGDyQ5KpPsplQqb9yKdCf2x/pbNpMNk8Tvp3rRz7lVcupKysH4b2ELMN2P4Hak1+UqTYdTj/u4FNV2p0g==}
'@fastify/error@4.0.0':
resolution: {integrity: sha512-OO/SA8As24JtT1usTUTKgGH7uLvhfwZPwlptRi2Dp5P4KKmJI3gvsZ8MIHnNwDs4sLf/aai5LzTyl66xr7qMxA==}
@ -39,6 +69,30 @@ packages:
'@fastify/merge-json-schemas@0.1.1':
resolution: {integrity: sha512-fERDVz7topgNjtXsJTTW1JKLy0rhuLRcquYqNR9rF7OcVpCa2OVW49ZPDIhaRRCaUuvVxI+N416xUoF76HNSXA==}
'@fastify/multipart@9.0.1':
resolution: {integrity: sha512-vt2gOCw/O4EwpN4KlLVJxth4iQlDf7T5ggw2Db2C+UbO2WJBG7y0jEBvu/HT6JIW/lBYaqrrUy9MmTpCKgXEpw==}
'@fastify/oauth2@8.1.0':
resolution: {integrity: sha512-SMcvStTvhF+UcyH+7uLWvKrxM4g5evZafjtQWRAg02C/dlsOrqLK0s9/1aszhWY6PBklJ6jduFPpl+sB4l2DlQ==}
'@hapi/boom@10.0.1':
resolution: {integrity: sha512-ERcCZaEjdH3OgSJlyjVk8pHIFeus91CjKP3v+MpgBNp5IvGzP2l/bRiD78nqYcKPaZdbKkK5vDBVPd2ohHBlsA==}
'@hapi/bourne@3.0.0':
resolution: {integrity: sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==}
'@hapi/hoek@11.0.7':
resolution: {integrity: sha512-HV5undWkKzcB4RZUusqOpcgxOaq6VOAH7zhhIr2g3G8NF/MlFO75SjOr2NfuSx0Mh40+1FqCkagKLJRykUWoFQ==}
'@hapi/hoek@9.3.0':
resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==}
'@hapi/topo@5.1.0':
resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==}
'@hapi/wreck@18.1.0':
resolution: {integrity: sha512-0z6ZRCmFEfV/MQqkQomJ7sl/hyxvcZM7LtuVqN3vdAO4vM9eBbowl0kaqQj9EJJQab+3Uuh1GxbGIBFy4NfJ4w==}
'@jridgewell/resolve-uri@3.1.2':
resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==}
engines: {node: '>=6.0.0'}
@ -49,6 +103,45 @@ packages:
'@jridgewell/trace-mapping@0.3.9':
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
'@prisma/client@6.0.0':
resolution: {integrity: sha512-tOBhG35ozqZ/5Y6B0TNOa6cwULUW8ijXqBXcgb12bfozqf6eGMyGs+jphywCsj6uojv5lAZZnxVSoLMVebIP+g==}
engines: {node: '>=18.18'}
peerDependencies:
prisma: '*'
peerDependenciesMeta:
prisma:
optional: true
'@prisma/debug@6.0.0':
resolution: {integrity: sha512-eUjoNThlDXdyJ1iQ2d7U6aTVwm59EwvODb5zFVNJEokNoSiQmiYWNzZIwZyDmZ+j51j42/0iTaHIJ4/aZPKFRg==}
'@prisma/engines-version@5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e':
resolution: {integrity: sha512-JmIds0Q2/vsOmnuTJYxY4LE+sajqjYKhLtdOT6y4imojqv5d/aeVEfbBGC74t8Be1uSp0OP8lxIj2OqoKbLsfQ==}
'@prisma/engines@6.0.0':
resolution: {integrity: sha512-ZZCVP3q22ifN6Ex6C8RIcTDBlRtMJS2H1ljV0knCiWNGArvvkEbE88W3uDdq/l4+UvyvHpGzdf9ZsCWSQR7ZQQ==}
'@prisma/fetch-engine@6.0.0':
resolution: {integrity: sha512-j2m+iO5RDPRI7SUc7sHo8wX7SA4iTkJ+18Sxch8KinQM46YiCQD1iXKN6qU79C1Fliw5Bw/qDyTHaTsa3JMerA==}
'@prisma/get-platform@6.0.0':
resolution: {integrity: sha512-PS6nYyIm9g8C03E4y7LknOfdCw/t2KyEJxntMPQHQZCOUgOpF82Ma60mdlOD08w90I3fjLiZZ0+MadenR3naDQ==}
'@sec-ant/readable-stream@0.4.1':
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
'@sideway/address@4.1.5':
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
'@sideway/formula@3.0.1':
resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==}
'@sideway/pinpoint@2.0.0':
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
'@tokenizer/token@0.3.0':
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
'@tsconfig/node10@1.0.11':
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
@ -97,13 +190,6 @@ packages:
avvio@9.1.0:
resolution: {integrity: sha512-fYASnYi600CsH/j9EQov7lECAniYiBFiiAtBNuZYLA2leLe9qOvZzqYHFjtIj6gD2VMoMLP14834LFWvr4IfDw==}
colorette@2.0.19:
resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==}
commander@10.0.1:
resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==}
engines: {node: '>=14'}
cookie@1.0.2:
resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==}
engines: {node: '>=18'}
@ -111,8 +197,8 @@ packages:
create-require@1.1.1:
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
debug@4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
debug@4.3.7:
resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
@ -124,13 +210,9 @@ packages:
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
engines: {node: '>=0.3.1'}
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
esm@3.2.25:
resolution: {integrity: sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==}
engines: {node: '>=6'}
dotenv@16.4.5:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
fast-decode-uri-component@1.0.1:
resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==}
@ -154,12 +236,19 @@ packages:
fast-uri@3.0.3:
resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==}
fastify-plugin@5.0.1:
resolution: {integrity: sha512-HCxs+YnRaWzCl+cWRYFnHmeRFyR5GVnJTAaCJQiYzQSDwK9MgJdyAsuL3nh0EWRCYMgQ5MeziymvmAhUHYHDUQ==}
fastify@5.1.0:
resolution: {integrity: sha512-0SdUC5AoiSgMSc2Vxwv3WyKzyGMDJRAW/PgNsK1kZrnkO6MeqUIW9ovVg9F2UGIqtIcclYMyeJa4rK6OZc7Jxg==}
fastq@1.17.1:
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
file-type@19.6.0:
resolution: {integrity: sha512-VZR5I7k5wkD0HgFnMsq5hOsSc710MJMu5Nc5QYsbe38NN5iPV/XTObYLc/cpttRTf6lX538+5uO1ZQRhYibiZQ==}
engines: {node: '>=18'}
find-my-way@9.1.0:
resolution: {integrity: sha512-Y5jIsuYR4BwWDYYQ2A/RWWE6gD8a0FMgtU+HOq1WKku+Cwdz8M1v8wcAmRXXM1/iqtoqg06v+LjAxMYbCjViMw==}
engines: {node: '>=14'}
@ -168,31 +257,28 @@ packages:
resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==}
engines: {node: '>= 0.6'}
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
get-package-type@0.1.0:
resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
engines: {node: '>=8.0.0'}
get-stream@9.0.1:
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
engines: {node: '>=18'}
getopts@2.3.0:
resolution: {integrity: sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==}
hasown@2.0.2:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
interpret@2.2.0:
resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==}
engines: {node: '>= 0.10'}
ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
ipaddr.js@1.9.1:
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
engines: {node: '>= 0.10'}
is-core-module@2.15.1:
resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
engines: {node: '>= 0.4'}
is-stream@4.0.1:
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
engines: {node: '>=18'}
joi@17.13.3:
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
json-schema-ref-resolver@1.0.1:
resolution: {integrity: sha512-EJAj1pgHc1hxF6vo2Z3s69fMjO1INq6eGHXZ8Z6wCQeldCuwxGK9Sxf4/cScGn3FZubCVUehfWtcDM/PLteCQw==}
@ -200,59 +286,26 @@ packages:
json-schema-traverse@1.0.0:
resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==}
knex@3.1.0:
resolution: {integrity: sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==}
engines: {node: '>=16'}
hasBin: true
peerDependencies:
better-sqlite3: '*'
mysql: '*'
mysql2: '*'
pg: '*'
pg-native: '*'
sqlite3: '*'
tedious: '*'
peerDependenciesMeta:
better-sqlite3:
optional: true
mysql:
optional: true
mysql2:
optional: true
pg:
optional: true
pg-native:
optional: true
sqlite3:
optional: true
tedious:
optional: true
light-my-request@6.3.0:
resolution: {integrity: sha512-bWTAPJmeWQH5suJNYwG0f5cs0p6ho9e6f1Ppoxv5qMosY+s9Ir2+ZLvvHcgA7VTDop4zl/NCHhOVVqU+kd++Ow==}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
ms@2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
on-exit-leak-free@2.1.2:
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
engines: {node: '>=14.0.0'}
path-parse@1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
peek-readable@5.3.1:
resolution: {integrity: sha512-GVlENSDW6KHaXcd9zkZltB7tCLosKB/4Hg0fqBJkAoBgYG2Tn1xtMgXtSUuMU9AK/gCm/tTdT8mgAeF4YNeeqw==}
engines: {node: '>=14.16'}
pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
pg-connection-string@2.6.2:
resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
pg-connection-string@2.7.0:
resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==}
@ -310,6 +363,11 @@ packages:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
prisma@6.0.0:
resolution: {integrity: sha512-RX7KtbW7IoEByf7MR32JK1PkVYLVYFqeODTtiIX3cqekq1aKdsF3Eud4zp2sUShMLjvdb5Jow0LbUjRq5LVxPw==}
engines: {node: '>=18.18'}
hasBin: true
process-warning@4.0.0:
resolution: {integrity: sha512-/MyYDxttz7DfGMMHiysAsFE4qF+pQYAA8ziO/3NcRVrQ5fSk+Mns4QZA/oRPFzvcqNoVJXQNWNAsdwBXLUkQKw==}
@ -324,22 +382,10 @@ packages:
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
engines: {node: '>= 12.13.0'}
rechoir@0.8.0:
resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==}
engines: {node: '>= 10.13.0'}
require-from-string@2.0.2:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
resolve-from@5.0.0:
resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
engines: {node: '>=8'}
resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
ret@0.5.0:
resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==}
engines: {node: '>=10'}
@ -361,6 +407,9 @@ packages:
secure-json-parse@2.7.0:
resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==}
secure-json-parse@3.0.1:
resolution: {integrity: sha512-9QR7G96th4QJ2+dJwvZB+JoXyt8PN+DbEjOr6kL2/JU4KH8Eb2sFdU+gt8EDdzWDWoWH0uocDdfCoFzdVSixUA==}
semver@7.6.3:
resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==}
engines: {node: '>=10'}
@ -369,6 +418,9 @@ packages:
set-cookie-parser@2.7.1:
resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==}
simple-oauth2@5.1.0:
resolution: {integrity: sha512-gWDa38Ccm4MwlG5U7AlcJxPv3lvr80dU7ARJWrGdgvOKyzSj1gr3GBPN1rABTedAYvC/LsGYoFuFxwDBPtGEbw==}
sonic-boom@4.2.0:
resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==}
@ -376,25 +428,21 @@ packages:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
supports-preserve-symlinks-flag@1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
tarn@3.0.2:
resolution: {integrity: sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==}
engines: {node: '>=8.0.0'}
strtok3@9.1.1:
resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==}
engines: {node: '>=16'}
thread-stream@3.1.0:
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
tildify@2.0.0:
resolution: {integrity: sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==}
engines: {node: '>=8'}
toad-cache@3.7.0:
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
engines: {node: '>=12'}
token-types@6.0.0:
resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==}
engines: {node: '>=14.16'}
ts-node@10.9.2:
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true
@ -414,6 +462,10 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
uint8array-extras@1.4.0:
resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
engines: {node: '>=18'}
undici-types@6.20.0:
resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==}
@ -440,6 +492,15 @@ snapshots:
ajv-formats: 3.0.1(ajv@8.17.1)
fast-uri: 3.0.3
'@fastify/busboy@3.0.0': {}
'@fastify/cookie@11.0.1':
dependencies:
cookie: 1.0.2
fastify-plugin: 5.0.1
'@fastify/deepmerge@2.0.0': {}
'@fastify/error@4.0.0': {}
'@fastify/fast-json-stringify-compiler@5.0.1':
@ -450,6 +511,42 @@ snapshots:
dependencies:
fast-deep-equal: 3.1.3
'@fastify/multipart@9.0.1':
dependencies:
'@fastify/busboy': 3.0.0
'@fastify/deepmerge': 2.0.0
'@fastify/error': 4.0.0
fastify-plugin: 5.0.1
secure-json-parse: 3.0.1
'@fastify/oauth2@8.1.0':
dependencies:
'@fastify/cookie': 11.0.1
fastify-plugin: 5.0.1
simple-oauth2: 5.1.0
transitivePeerDependencies:
- supports-color
'@hapi/boom@10.0.1':
dependencies:
'@hapi/hoek': 11.0.7
'@hapi/bourne@3.0.0': {}
'@hapi/hoek@11.0.7': {}
'@hapi/hoek@9.3.0': {}
'@hapi/topo@5.1.0':
dependencies:
'@hapi/hoek': 9.3.0
'@hapi/wreck@18.1.0':
dependencies:
'@hapi/boom': 10.0.1
'@hapi/bourne': 3.0.0
'@hapi/hoek': 11.0.7
'@jridgewell/resolve-uri@3.1.2': {}
'@jridgewell/sourcemap-codec@1.5.0': {}
@ -459,6 +556,43 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.0
'@prisma/client@6.0.0(prisma@6.0.0)':
optionalDependencies:
prisma: 6.0.0
'@prisma/debug@6.0.0': {}
'@prisma/engines-version@5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e': {}
'@prisma/engines@6.0.0':
dependencies:
'@prisma/debug': 6.0.0
'@prisma/engines-version': 5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e
'@prisma/fetch-engine': 6.0.0
'@prisma/get-platform': 6.0.0
'@prisma/fetch-engine@6.0.0':
dependencies:
'@prisma/debug': 6.0.0
'@prisma/engines-version': 5.23.0-27.5dbef10bdbfb579e07d35cc85fb1518d357cb99e
'@prisma/get-platform': 6.0.0
'@prisma/get-platform@6.0.0':
dependencies:
'@prisma/debug': 6.0.0
'@sec-ant/readable-stream@0.4.1': {}
'@sideway/address@4.1.5':
dependencies:
'@hapi/hoek': 9.3.0
'@sideway/formula@3.0.1': {}
'@sideway/pinpoint@2.0.0': {}
'@tokenizer/token@0.3.0': {}
'@tsconfig/node10@1.0.11': {}
'@tsconfig/node12@1.0.11': {}
@ -499,23 +633,17 @@ snapshots:
'@fastify/error': 4.0.0
fastq: 1.17.1
colorette@2.0.19: {}
commander@10.0.1: {}
cookie@1.0.2: {}
create-require@1.1.1: {}
debug@4.3.4:
debug@4.3.7:
dependencies:
ms: 2.1.2
ms: 2.1.3
diff@4.0.2: {}
escalade@3.2.0: {}
esm@3.2.25: {}
dotenv@16.4.5: {}
fast-decode-uri-component@1.0.1: {}
@ -541,6 +669,8 @@ snapshots:
fast-uri@3.0.3: {}
fastify-plugin@5.0.1: {}
fastify@5.1.0:
dependencies:
'@fastify/ajv-compiler': 4.0.1
@ -563,6 +693,13 @@ snapshots:
dependencies:
reusify: 1.0.4
file-type@19.6.0:
dependencies:
get-stream: 9.0.1
strtok3: 9.1.1
token-types: 6.0.0
uint8array-extras: 1.4.0
find-my-way@9.1.0:
dependencies:
fast-deep-equal: 3.1.3
@ -571,23 +708,27 @@ snapshots:
forwarded@0.2.0: {}
function-bind@1.1.2: {}
fsevents@2.3.3:
optional: true
get-package-type@0.1.0: {}
getopts@2.3.0: {}
hasown@2.0.2:
get-stream@9.0.1:
dependencies:
function-bind: 1.1.2
'@sec-ant/readable-stream': 0.4.1
is-stream: 4.0.1
interpret@2.2.0: {}
ieee754@1.2.1: {}
ipaddr.js@1.9.1: {}
is-core-module@2.15.1:
is-stream@4.0.1: {}
joi@17.13.3:
dependencies:
hasown: 2.0.2
'@hapi/hoek': 9.3.0
'@hapi/topo': 5.1.0
'@sideway/address': 4.1.5
'@sideway/formula': 3.0.1
'@sideway/pinpoint': 2.0.0
json-schema-ref-resolver@1.0.1:
dependencies:
@ -595,48 +736,23 @@ snapshots:
json-schema-traverse@1.0.0: {}
knex@3.1.0(pg@8.13.1):
dependencies:
colorette: 2.0.19
commander: 10.0.1
debug: 4.3.4
escalade: 3.2.0
esm: 3.2.25
get-package-type: 0.1.0
getopts: 2.3.0
interpret: 2.2.0
lodash: 4.17.21
pg-connection-string: 2.6.2
rechoir: 0.8.0
resolve-from: 5.0.0
tarn: 3.0.2
tildify: 2.0.0
optionalDependencies:
pg: 8.13.1
transitivePeerDependencies:
- supports-color
light-my-request@6.3.0:
dependencies:
cookie: 1.0.2
process-warning: 4.0.0
set-cookie-parser: 2.7.1
lodash@4.17.21: {}
make-error@1.3.6: {}
ms@2.1.2: {}
ms@2.1.3: {}
on-exit-leak-free@2.1.2: {}
path-parse@1.0.7: {}
peek-readable@5.3.1: {}
pg-cloudflare@1.1.1:
optional: true
pg-connection-string@2.6.2: {}
pg-connection-string@2.7.0: {}
pg-int8@1.0.1: {}
@ -699,6 +815,12 @@ snapshots:
dependencies:
xtend: 4.0.2
prisma@6.0.0:
dependencies:
'@prisma/engines': 6.0.0
optionalDependencies:
fsevents: 2.3.3
process-warning@4.0.0: {}
proxy-addr@2.0.7:
@ -710,20 +832,8 @@ snapshots:
real-require@0.2.0: {}
rechoir@0.8.0:
dependencies:
resolve: 1.22.8
require-from-string@2.0.2: {}
resolve-from@5.0.0: {}
resolve@1.22.8:
dependencies:
is-core-module: 2.15.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
ret@0.5.0: {}
reusify@1.0.4: {}
@ -738,28 +848,43 @@ snapshots:
secure-json-parse@2.7.0: {}
secure-json-parse@3.0.1: {}
semver@7.6.3: {}
set-cookie-parser@2.7.1: {}
simple-oauth2@5.1.0:
dependencies:
'@hapi/hoek': 11.0.7
'@hapi/wreck': 18.1.0
debug: 4.3.7
joi: 17.13.3
transitivePeerDependencies:
- supports-color
sonic-boom@4.2.0:
dependencies:
atomic-sleep: 1.0.0
split2@4.2.0: {}
supports-preserve-symlinks-flag@1.0.0: {}
tarn@3.0.2: {}
strtok3@9.1.1:
dependencies:
'@tokenizer/token': 0.3.0
peek-readable: 5.3.1
thread-stream@3.1.0:
dependencies:
real-require: 0.2.0
tildify@2.0.0: {}
toad-cache@3.7.0: {}
token-types@6.0.0:
dependencies:
'@tokenizer/token': 0.3.0
ieee754: 1.2.1
ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2):
dependencies:
'@cspotcode/source-map-support': 0.8.1
@ -780,6 +905,8 @@ snapshots:
typescript@5.7.2: {}
uint8array-extras@1.4.0: {}
undici-types@6.20.0: {}
v8-compile-cache-lib@3.0.1: {}

View file

@ -0,0 +1,15 @@
-- CreateTable
CREATE TABLE "User" (
"id" TEXT NOT NULL,
"discordToken" TEXT NOT NULL,
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "ImagePost" (
"id" UUID NOT NULL,
"fileName" TEXT NOT NULL,
CONSTRAINT "ImagePost_pkey" PRIMARY KEY ("id")
);

View file

@ -0,0 +1,11 @@
/*
Warnings:
- Added the required column `userId` to the `ImagePost` table without a default value. This is not possible if the table is not empty.
*/
-- AlterTable
ALTER TABLE "ImagePost" ADD COLUMN "userId" TEXT NOT NULL;
-- AddForeignKey
ALTER TABLE "ImagePost" ADD CONSTRAINT "ImagePost_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -0,0 +1,23 @@
/*
Warnings:
- You are about to drop the `ImagePost` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "ImagePost" DROP CONSTRAINT "ImagePost_userId_fkey";
-- DropTable
DROP TABLE "ImagePost";
-- CreateTable
CREATE TABLE "FilePost" (
"id" UUID NOT NULL,
"fileName" TEXT NOT NULL,
"userId" TEXT NOT NULL,
CONSTRAINT "FilePost_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "FilePost" ADD CONSTRAINT "FilePost_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -0,0 +1,6 @@
-- CreateTable
CREATE TABLE "WhitelistedUsers" (
"discordId" TEXT NOT NULL,
CONSTRAINT "WhitelistedUsers_pkey" PRIMARY KEY ("discordId")
);

View file

@ -0,0 +1,8 @@
/*
Warnings:
- The required column `apiToken` was added to the `User` table with a prisma-level default value. This is not possible if the table is not empty. Please add this column as optional, then populate it before making it required.
*/
-- AlterTable
ALTER TABLE "User" ADD COLUMN "apiToken" UUID NOT NULL;

View file

@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"

32
prisma/schema.prisma Normal file
View file

@ -0,0 +1,32 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model WhitelistedUsers {
discordId String @id
}
model User {
id String @id
discordToken String
apiToken String @default(uuid()) @db.Uuid
imagePosts FilePost[]
}
model FilePost {
id String @id @default(uuid()) @db.Uuid
fileName String
userId String
user User @relation(fields: [userId], references: [id])
}

40
src/authHelper.ts Normal file
View file

@ -0,0 +1,40 @@
import {DiscordUser} from "./types.ts";
import {FastifyRequest} from "fastify";
import {PrismaClient} from "@prisma/client";
export function getAdmins(): string[] {
return process.env.ADMINS.split(",")
}
export async function isTokenValid(token: string):Promise<boolean> {
return fetch("https://discord.com/api/users/@me", {
headers: new Headers({
"Authorization": `Bearer ${token}`
})
}).then(res => {
return res.ok;
}).catch(() => {
return false;
});
}
export async function getUser(token: string): Promise<DiscordUser> {
const response = await fetch("https://discord.com/api/users/@me", {
headers: new Headers({
"Authorization": `Bearer ${token}`
})
});
return response.json();
}
export async function isAdmin(token: string): Promise<boolean> {
const response = await fetch("https://discord.com/api/users/@me", {
headers: new Headers({
"Authorization": `Bearer ${token}`
})
});
const user: DiscordUser = await response.json();
return getAdmins().includes(user.id);
}

22
src/endpoints/admin.ts Normal file
View file

@ -0,0 +1,22 @@
import {FastifyInstance} from "fastify";
import {PrismaClient} from "@prisma/client";
import {checkadmin} from "../middleware.ts";
export default function (fastify: FastifyInstance, prisma: PrismaClient) {
fastify.post('/api/admin/addwhitelist', async (request, reply) => {
console.log("sdkfj")
const test = await checkadmin(request)
if (!test) return reply.status(401).send('Not Authorized');
const {id} = request.query as { id?: string };
if (!id) {
reply.status(400).send('Bad Request');
}
await prisma.whitelistedUsers.create({
data: {
discordId: id,
}
}).then(() => {
reply.status(200).send('User added successfully');
})
})
}

View file

@ -0,0 +1,59 @@
import {getUserFromApiToken} from "../middleware.ts";
import {FastifyInstance} from "fastify";
import {PrismaClient} from "@prisma/client";
import path from 'path'
import fs from 'fs'
import {fileURLToPath} from 'url';
import {fileTypeFromFile} from "file-type";
export const __filename = fileURLToPath(import.meta.url);
export const __dirname = path.dirname(__filename);
export default function (fastify: FastifyInstance, prisma: PrismaClient) {
const uploadDir = path.join(__dirname, "../","../", 'uploads')
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir)
}
fastify.get('/api/file/:fileId', async (request, reply) => {
const {fileId} = request.params as {fileId: string};
const filePath = path.resolve(uploadDir, fileId);
const mime = await fileTypeFromFile(filePath);
const stream = fs.readFileSync(filePath);
reply.type(mime.mime).send(stream);
})
fastify.post('/api/upload', async (request, reply) => {
const user = await getUserFromApiToken(request.headers.authorization, prisma);
if (Object.keys(user).length==0) return reply.status(401).send('Not Authorized');
const data = await request.file({
limits: {
fileSize: 10 * 1024 * 1024,
}
})
const fileName = Array.from({length: 15}, () => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'[Math.floor(Math.random() * 62)]).join('');
try {
const newImagePost = await prisma.filePost.create({
data: {
fileName,
user: {
connect: {id: user.id},
}
}
})
const filePath = path.join(uploadDir, newImagePost.id)
await new Promise((resolve, reject) => {
const fileStream = fs.createWriteStream(filePath)
data.file.pipe(fileStream)
fileStream.on('finish', resolve)
fileStream.on('error', reject)
})
reply.code(201).send(newImagePost)
} catch (error) {
fastify.log.error(error)
reply.code(500).send({error: 'Error uploading file or saving record'})
}
})
}

21
src/endpoints/user.ts Normal file
View file

@ -0,0 +1,21 @@
import {FastifyInstance} from "fastify";
import {PrismaClient} from "@prisma/client";
import {getUser, isTokenValid} from "../authHelper.ts";
export default function (fastify: FastifyInstance, prisma: PrismaClient) {
fastify.get('/api/token', async (request, reply) => {
const token = request.headers.authorization
if (!await isTokenValid(token)){
reply.status(401).send('Not authorized')
return
}
const user = await getUser(token);
const prismaanswer = await prisma.user.findUnique({
where: {
"id": user.id
}
})
console.log(prismaanswer)
reply.status(200).send(prismaanswer)
})
}

View file

@ -1,16 +0,0 @@
export async function getAccountInfoBasedOnCode(code: string, clientId: string, clientSecret: string) {
await fetch('https://discord.com/api/oauth2/token', {
method: 'POST',
body: new URLSearchParams({
client_id: clientId,
client_secret: clientSecret,
code,
grant_type: 'authorization_code',
redirect_uri: `http://localhost:${3000}`,
scope: 'identify',
}).toString(),
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
}).then(res => res.json().then(console.log))
}

View file

@ -1,41 +1,112 @@
import Fastify from 'fastify'
import {getAccountInfoBasedOnCode} from "./helper.ts";
import {PrismaClient} from '@prisma/client'
import fastifyMultipart from "@fastify/multipart";
import fastifyOauth2 from "@fastify/oauth2";
import fs from 'fs'
import path from 'path'
import dotenv from 'dotenv';
import {fileURLToPath} from 'url';
import {checkadmin, checkAuthenticatedDiscordToken} from "./middleware.ts";
import {getUser} from "./authHelper.ts";
import Knex from 'knex';
dotenv.config();
const knex = Knex({
client: 'pg',
connection: {
host: '127.0.0.1',
user: 'postgres',
password: 'postgres',
database: 'ether'
},
migrations: {
directory: './migrations'
},
seeds: {
directory: './seeds'
}
})
const fastify = Fastify({
logger: true
})
// Declare a route
fastify.get('/', async (request, reply) => {
getAccountInfoBasedOnCode("0FvE4z2uFfpil8PHV9bqrQu1Ioo70N", "1312585635361718272", "aiZqJoBCEqAOmTVsjnEGmr1qoVxXBYTR")
})
fastify.get('/balls', async (request, reply) => {
reply.redirect("https://google.com")
})
try {
await fastify.listen({port: 3000})
} catch (err) {
fastify.log.error(err)
process.exit(1)
if (!process.env.ADMINS) {
console.error("no admin account found");
process.exit(1);
}
const FILESIZE = process.env.FILESIZE_LIMIT
if (!FILESIZE) {
console.error("no file size detected");
process.exit(1);
} else if (isNaN(Number(FILESIZE)) && FILESIZE.trim() !== '') {
console.error("file size cannot be parsed.");
process.exit(1);
}
export const __filename = fileURLToPath(import.meta.url);
export const __dirname = path.dirname(__filename);
const prisma = new PrismaClient()
const fastify = Fastify({logger: true})
fastify.register(fastifyMultipart)
fastify.register(fastifyOauth2, {
name: 'discordOAuth2',
credentials: {
client: {
id: process.env.DISCORD_CLIENT,
secret: process.env.DISCORD_SECRET,
},
auth: fastifyOauth2.DISCORD_CONFIGURATION
},
scope: ["identify"],
startRedirectPath: '/login',
callbackUri: req => `${req.protocol}://${req.host}/login/callback`,
})
fastify.get('/login/callback', async function (request, reply) {
// @ts-ignore
const {token} = await this.discordOAuth2?.getAccessTokenFromAuthorizationCodeFlow(request)
//this is funny
const discordAccount = await getUser(token.access_token)
const test = await prisma.whitelistedUsers.findUnique({
where: {discordId: discordAccount.id},
});
console.log(token)
if (!test) {
return reply.status(401).send("Not Authorized");
}
// @ts-ignore
const existingUser = await prisma.user.findUnique({
where: {id: discordAccount.id},
});
console.log(existingUser)
// @ts-ignore
const {token: refreshToken} = await this.discordOAuth2?.getNewAccessTokenUsingRefreshToken(token)
if (!existingUser) {
await prisma.user.create({
data: {
id: discordAccount.id,
discordToken: refreshToken.access_token,
},
});
} else {
prisma.user.update({
where: {id: discordAccount.id},
data: {
discordToken: refreshToken.access_token,
},
})
}
reply.setCookie('access_token', refreshToken.discordToken);
return reply.send({access_token: refreshToken.access_token});
});
for (const file of fs.readdirSync(path.resolve(__dirname, "endpoints"))) {
const endpoint = await import(path.resolve(__dirname, "endpoints", file));
endpoint.default(fastify, prisma);
}
fastify.get('/', async (request, reply) => {
return reply.status(200).send('ok')
})
fastify.listen({port: 3000}, (err, address) => {
if (err) {
fastify.log.error(err)
process.exit(1)
}
fastify.log.info(`Server running at ${address}`)
})

41
src/middleware.ts Normal file
View file

@ -0,0 +1,41 @@
import {FastifyRequest} from "fastify";
import {getUser, isAdmin, isTokenValid} from "./authHelper.ts";
import {PrismaClient} from "@prisma/client";
import {DiscordUser} from "./types.ts";
export async function checkadmin(request: FastifyRequest): Promise<boolean> {
const Authheader = request.headers.authorization
if (!Authheader) {
return false
}
return isAdmin(Authheader)
}
export async function checkAuthenticatedDiscordToken(request: FastifyRequest | string, prisma: PrismaClient): Promise<boolean | DiscordUser> {
let token = ""
if (typeof request === "string") {
token = request
} else {
token = request.headers.authorization
}
if (!request) {
return false
}
if (await isTokenValid(token)) {
const user = await getUser(token);
return !!prisma.user.findUnique({
where: {id: user.id}
})
} else {
return false;
}
}
export async function getUserFromApiToken(token: string, prisma: PrismaClient): Promise<{id: string, discordToken: string, apiToken: string}> {
return await prisma.user.findFirst({
where: {apiToken: token}
})
}

18
src/types.ts Normal file
View file

@ -0,0 +1,18 @@
export interface DiscordUser {
id: string;
username: string;
avatar: string;
discriminator: string;
public_flags: number;
flags: number;
banner: string | null;
accent_color: string | null;
global_name: string;
avatar_decoration_data: any | null;
banner_color: string | null;
clan: any | null;
primary_guild: any | null;
mfa_enabled: boolean;
locale: string;
premium_type: number;
}

View file

@ -15,5 +15,5 @@
"module": "ESNext"
}
},
"include": ["src/*"]
"include": ["src/**/*"]
}