image upload now functional
This commit is contained in:
parent
63b6adfdbe
commit
35476348e2
10 changed files with 261 additions and 74 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
||||||
/node_modules/
|
/node_modules/
|
||||||
/.idea/
|
/.idea/
|
||||||
.env
|
.env
|
||||||
./src/uploads
|
/src/uploads/
|
||||||
|
/uploads
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
"@fastify/multipart": "^9.0.1",
|
"@fastify/multipart": "^9.0.1",
|
||||||
"@fastify/oauth2": "^8.1.0",
|
"@fastify/oauth2": "^8.1.0",
|
||||||
"@prisma/client": "6.0.0",
|
"@prisma/client": "6.0.0",
|
||||||
|
"@types/node": "^22.10.1",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"fastify": "^5.1.0",
|
"fastify": "^5.1.0",
|
||||||
|
"file-type": "^19.6.0",
|
||||||
"pg": "^8.13.1",
|
"pg": "^8.13.1",
|
||||||
"prisma": "^6.0.0",
|
"prisma": "^6.0.0",
|
||||||
"ts-node": "^10.9.2"
|
"ts-node": "^10.9.2"
|
||||||
|
|
77
pnpm-lock.yaml
generated
77
pnpm-lock.yaml
generated
|
@ -20,12 +20,18 @@ importers:
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
specifier: 6.0.0
|
specifier: 6.0.0
|
||||||
version: 6.0.0(prisma@6.0.0)
|
version: 6.0.0(prisma@6.0.0)
|
||||||
|
'@types/node':
|
||||||
|
specifier: ^22.10.1
|
||||||
|
version: 22.10.1
|
||||||
dotenv:
|
dotenv:
|
||||||
specifier: ^16.4.5
|
specifier: ^16.4.5
|
||||||
version: 16.4.5
|
version: 16.4.5
|
||||||
fastify:
|
fastify:
|
||||||
specifier: ^5.1.0
|
specifier: ^5.1.0
|
||||||
version: 5.1.0
|
version: 5.1.0
|
||||||
|
file-type:
|
||||||
|
specifier: ^19.6.0
|
||||||
|
version: 19.6.0
|
||||||
pg:
|
pg:
|
||||||
specifier: ^8.13.1
|
specifier: ^8.13.1
|
||||||
version: 8.13.1
|
version: 8.13.1
|
||||||
|
@ -121,6 +127,9 @@ packages:
|
||||||
'@prisma/get-platform@6.0.0':
|
'@prisma/get-platform@6.0.0':
|
||||||
resolution: {integrity: sha512-PS6nYyIm9g8C03E4y7LknOfdCw/t2KyEJxntMPQHQZCOUgOpF82Ma60mdlOD08w90I3fjLiZZ0+MadenR3naDQ==}
|
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':
|
'@sideway/address@4.1.5':
|
||||||
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
|
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
|
||||||
|
|
||||||
|
@ -130,6 +139,9 @@ packages:
|
||||||
'@sideway/pinpoint@2.0.0':
|
'@sideway/pinpoint@2.0.0':
|
||||||
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
|
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
|
||||||
|
|
||||||
|
'@tokenizer/token@0.3.0':
|
||||||
|
resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==}
|
||||||
|
|
||||||
'@tsconfig/node10@1.0.11':
|
'@tsconfig/node10@1.0.11':
|
||||||
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
|
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
|
||||||
|
|
||||||
|
@ -233,6 +245,10 @@ packages:
|
||||||
fastq@1.17.1:
|
fastq@1.17.1:
|
||||||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==}
|
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:
|
find-my-way@9.1.0:
|
||||||
resolution: {integrity: sha512-Y5jIsuYR4BwWDYYQ2A/RWWE6gD8a0FMgtU+HOq1WKku+Cwdz8M1v8wcAmRXXM1/iqtoqg06v+LjAxMYbCjViMw==}
|
resolution: {integrity: sha512-Y5jIsuYR4BwWDYYQ2A/RWWE6gD8a0FMgtU+HOq1WKku+Cwdz8M1v8wcAmRXXM1/iqtoqg06v+LjAxMYbCjViMw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
@ -246,10 +262,21 @@ packages:
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
|
||||||
|
get-stream@9.0.1:
|
||||||
|
resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
|
ieee754@1.2.1:
|
||||||
|
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||||
|
|
||||||
ipaddr.js@1.9.1:
|
ipaddr.js@1.9.1:
|
||||||
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==}
|
||||||
engines: {node: '>= 0.10'}
|
engines: {node: '>= 0.10'}
|
||||||
|
|
||||||
|
is-stream@4.0.1:
|
||||||
|
resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
joi@17.13.3:
|
joi@17.13.3:
|
||||||
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
|
resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==}
|
||||||
|
|
||||||
|
@ -272,6 +299,10 @@ packages:
|
||||||
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||||
engines: {node: '>=14.0.0'}
|
engines: {node: '>=14.0.0'}
|
||||||
|
|
||||||
|
peek-readable@5.3.1:
|
||||||
|
resolution: {integrity: sha512-GVlENSDW6KHaXcd9zkZltB7tCLosKB/4Hg0fqBJkAoBgYG2Tn1xtMgXtSUuMU9AK/gCm/tTdT8mgAeF4YNeeqw==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
pg-cloudflare@1.1.1:
|
pg-cloudflare@1.1.1:
|
||||||
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
|
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
|
||||||
|
|
||||||
|
@ -397,6 +428,10 @@ packages:
|
||||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||||
engines: {node: '>= 10.x'}
|
engines: {node: '>= 10.x'}
|
||||||
|
|
||||||
|
strtok3@9.1.1:
|
||||||
|
resolution: {integrity: sha512-FhwotcEqjr241ZbjFzjlIYg6c5/L/s4yBGWSMvJ9UoExiSqL+FnFA/CaeZx17WGaZMS/4SOZp8wH18jSS4R4lw==}
|
||||||
|
engines: {node: '>=16'}
|
||||||
|
|
||||||
thread-stream@3.1.0:
|
thread-stream@3.1.0:
|
||||||
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
|
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
|
||||||
|
|
||||||
|
@ -404,6 +439,10 @@ packages:
|
||||||
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
token-types@6.0.0:
|
||||||
|
resolution: {integrity: sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA==}
|
||||||
|
engines: {node: '>=14.16'}
|
||||||
|
|
||||||
ts-node@10.9.2:
|
ts-node@10.9.2:
|
||||||
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -423,6 +462,10 @@ packages:
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
uint8array-extras@1.4.0:
|
||||||
|
resolution: {integrity: sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ==}
|
||||||
|
engines: {node: '>=18'}
|
||||||
|
|
||||||
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==}
|
||||||
|
|
||||||
|
@ -538,6 +581,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@prisma/debug': 6.0.0
|
'@prisma/debug': 6.0.0
|
||||||
|
|
||||||
|
'@sec-ant/readable-stream@0.4.1': {}
|
||||||
|
|
||||||
'@sideway/address@4.1.5':
|
'@sideway/address@4.1.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@hapi/hoek': 9.3.0
|
'@hapi/hoek': 9.3.0
|
||||||
|
@ -546,6 +591,8 @@ snapshots:
|
||||||
|
|
||||||
'@sideway/pinpoint@2.0.0': {}
|
'@sideway/pinpoint@2.0.0': {}
|
||||||
|
|
||||||
|
'@tokenizer/token@0.3.0': {}
|
||||||
|
|
||||||
'@tsconfig/node10@1.0.11': {}
|
'@tsconfig/node10@1.0.11': {}
|
||||||
|
|
||||||
'@tsconfig/node12@1.0.11': {}
|
'@tsconfig/node12@1.0.11': {}
|
||||||
|
@ -646,6 +693,13 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
reusify: 1.0.4
|
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:
|
find-my-way@9.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-deep-equal: 3.1.3
|
fast-deep-equal: 3.1.3
|
||||||
|
@ -657,8 +711,17 @@ snapshots:
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
get-stream@9.0.1:
|
||||||
|
dependencies:
|
||||||
|
'@sec-ant/readable-stream': 0.4.1
|
||||||
|
is-stream: 4.0.1
|
||||||
|
|
||||||
|
ieee754@1.2.1: {}
|
||||||
|
|
||||||
ipaddr.js@1.9.1: {}
|
ipaddr.js@1.9.1: {}
|
||||||
|
|
||||||
|
is-stream@4.0.1: {}
|
||||||
|
|
||||||
joi@17.13.3:
|
joi@17.13.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@hapi/hoek': 9.3.0
|
'@hapi/hoek': 9.3.0
|
||||||
|
@ -685,6 +748,8 @@ snapshots:
|
||||||
|
|
||||||
on-exit-leak-free@2.1.2: {}
|
on-exit-leak-free@2.1.2: {}
|
||||||
|
|
||||||
|
peek-readable@5.3.1: {}
|
||||||
|
|
||||||
pg-cloudflare@1.1.1:
|
pg-cloudflare@1.1.1:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
@ -804,12 +869,22 @@ snapshots:
|
||||||
|
|
||||||
split2@4.2.0: {}
|
split2@4.2.0: {}
|
||||||
|
|
||||||
|
strtok3@9.1.1:
|
||||||
|
dependencies:
|
||||||
|
'@tokenizer/token': 0.3.0
|
||||||
|
peek-readable: 5.3.1
|
||||||
|
|
||||||
thread-stream@3.1.0:
|
thread-stream@3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
real-require: 0.2.0
|
real-require: 0.2.0
|
||||||
|
|
||||||
toad-cache@3.7.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):
|
ts-node@10.9.2(@types/node@22.10.1)(typescript@5.7.2):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cspotcode/source-map-support': 0.8.1
|
'@cspotcode/source-map-support': 0.8.1
|
||||||
|
@ -830,6 +905,8 @@ snapshots:
|
||||||
|
|
||||||
typescript@5.7.2: {}
|
typescript@5.7.2: {}
|
||||||
|
|
||||||
|
uint8array-extras@1.4.0: {}
|
||||||
|
|
||||||
undici-types@6.20.0: {}
|
undici-types@6.20.0: {}
|
||||||
|
|
||||||
v8-compile-cache-lib@3.0.1: {}
|
v8-compile-cache-lib@3.0.1: {}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import {DiscordUser} from "./types.ts";
|
import {DiscordUser} from "./types.ts";
|
||||||
import {FastifyRequest} from "fastify";
|
import {FastifyRequest} from "fastify";
|
||||||
|
import {PrismaClient} from "@prisma/client";
|
||||||
|
|
||||||
export function getAdmins(): string[] {
|
export function getAdmins(): string[] {
|
||||||
return process.env.ADMINS.split(",")
|
return process.env.ADMINS.split(",")
|
||||||
|
@ -11,7 +12,7 @@ export async function isTokenValid(token: string):Promise<boolean> {
|
||||||
"Authorization": `Bearer ${token}`
|
"Authorization": `Bearer ${token}`
|
||||||
})
|
})
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
return !res.ok;
|
return res.ok;
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
22
src/endpoints/admin.ts
Normal file
22
src/endpoints/admin.ts
Normal 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');
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
59
src/endpoints/fileupload.ts
Normal file
59
src/endpoints/fileupload.ts
Normal 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
21
src/endpoints/user.ts
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
109
src/main.ts
109
src/main.ts
|
@ -6,22 +6,36 @@ import fs from 'fs'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import {fileURLToPath} from 'url';
|
import {fileURLToPath} from 'url';
|
||||||
import {checkadmin} from "./middleware.ts";
|
import {checkadmin, checkAuthenticatedDiscordToken} from "./middleware.ts";
|
||||||
import {getUser} from "./authHelper.ts";
|
import {getUser} from "./authHelper.ts";
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
|
||||||
if (!process.env.ADMINS) {
|
if (!process.env.ADMINS) {
|
||||||
console.error("no admin account found");
|
console.error("no admin account found");
|
||||||
process.exit(1);
|
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 __filename = fileURLToPath(import.meta.url);
|
||||||
export const __dirname = path.dirname(__filename);
|
export const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
const prisma = new PrismaClient()
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
|
|
||||||
const fastify = Fastify({logger: true})
|
const fastify = Fastify({logger: true})
|
||||||
|
|
||||||
|
|
||||||
fastify.register(fastifyMultipart)
|
fastify.register(fastifyMultipart)
|
||||||
fastify.register(fastifyOauth2, {
|
fastify.register(fastifyOauth2, {
|
||||||
name: 'discordOAuth2',
|
name: 'discordOAuth2',
|
||||||
|
@ -37,28 +51,26 @@ fastify.register(fastifyOauth2, {
|
||||||
callbackUri: req => `${req.protocol}://${req.host}/login/callback`,
|
callbackUri: req => `${req.protocol}://${req.host}/login/callback`,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const uploadDir = path.join(__dirname, 'uploads')
|
|
||||||
if (!fs.existsSync(uploadDir)) {
|
|
||||||
fs.mkdirSync(uploadDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
fastify.get('/login/callback', async function (request, reply) {
|
fastify.get('/login/callback', async function (request, reply) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const {token} = await this.discordOAuth2?.getAccessTokenFromAuthorizationCodeFlow(request)
|
const {token} = await this.discordOAuth2?.getAccessTokenFromAuthorizationCodeFlow(request)
|
||||||
//this is funny
|
//this is funny
|
||||||
const discordAccount = await getUser(token.access_token)
|
const discordAccount = await getUser(token.access_token)
|
||||||
if (!await prisma.whitelistedUsers.findUnique({
|
const test = await prisma.whitelistedUsers.findUnique({
|
||||||
where: {
|
where: {discordId: discordAccount.id},
|
||||||
discordId: discordAccount.id
|
});
|
||||||
}
|
|
||||||
})) {
|
console.log(token)
|
||||||
return reply.status(401).send("Not Authorized")
|
|
||||||
|
if (!test) {
|
||||||
|
return reply.status(401).send("Not Authorized");
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const existingUser = await prisma.users.findUnique({
|
const existingUser = await prisma.user.findUnique({
|
||||||
where: {id: discordAccount.id},
|
where: {id: discordAccount.id},
|
||||||
});
|
});
|
||||||
|
console.log(existingUser)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const {token: refreshToken} = await this.discordOAuth2?.getNewAccessTokenUsingRefreshToken(token)
|
const {token: refreshToken} = await this.discordOAuth2?.getNewAccessTokenUsingRefreshToken(token)
|
||||||
if (!existingUser) {
|
if (!existingUser) {
|
||||||
|
@ -66,69 +78,30 @@ fastify.get('/login/callback', async function (request, reply) {
|
||||||
data: {
|
data: {
|
||||||
id: discordAccount.id,
|
id: discordAccount.id,
|
||||||
discordToken: refreshToken.access_token,
|
discordToken: refreshToken.access_token,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
reply.send({access_token: refreshToken.access_token})
|
|
||||||
reply.setCookie('access_token', refreshToken.access_token)
|
|
||||||
} else {
|
} else {
|
||||||
|
prisma.user.update({
|
||||||
}
|
where: {id: discordAccount.id},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
fastify.post('/api/admin/addwhitelist', async (request, reply) => {
|
|
||||||
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: {
|
data: {
|
||||||
discordId: id,
|
discordToken: refreshToken.access_token,
|
||||||
}
|
},
|
||||||
}).then(() => {
|
|
||||||
reply.status(200).send('User added successfully');
|
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
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) => {
|
fastify.get('/', async (request, reply) => {
|
||||||
return reply.status(200).send('ok')
|
return reply.status(200).send('ok')
|
||||||
})
|
})
|
||||||
|
|
||||||
fastify.post('/api/upload', async (request, reply) => {
|
|
||||||
const data = await request.file()
|
|
||||||
const fileName = `${Date.now()}-${data.filename}`
|
|
||||||
const filePath = path.join(uploadDir, fileName)
|
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
|
||||||
const fileStream = fs.createWriteStream(filePath)
|
|
||||||
data.file.pipe(fileStream)
|
|
||||||
fileStream.on('finish', resolve)
|
|
||||||
fileStream.on('error', reject)
|
|
||||||
})
|
|
||||||
|
|
||||||
try {
|
|
||||||
// const newImagePost = await prisma.filePost.create({
|
|
||||||
// data: {
|
|
||||||
// fileName,
|
|
||||||
// user: {
|
|
||||||
// connect: {id: bew.id}
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
// reply.code(201).send(newImagePost)
|
|
||||||
} catch (error) {
|
|
||||||
fastify.log.error(error)
|
|
||||||
reply.code(500).send({error: 'Error uploading file or saving record'})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fastify.listen({port: 3000}, (err, address) => {
|
fastify.listen({port: 3000}, (err, address) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
@ -1,10 +1,41 @@
|
||||||
import {FastifyRequest} from "fastify";
|
import {FastifyRequest} from "fastify";
|
||||||
import {isAdmin} from "./authHelper.ts";
|
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> {
|
export async function checkadmin(request: FastifyRequest): Promise<boolean> {
|
||||||
const Authheader = request.headers.authorization
|
const Authheader = request.headers.authorization
|
||||||
if (!Authheader) {
|
if (!Authheader) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return isAdmin(Authheader)
|
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}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -15,5 +15,5 @@
|
||||||
"module": "ESNext"
|
"module": "ESNext"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/*"]
|
"include": ["src/**/*"]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue