107 lines
2.8 KiB
TypeScript
107 lines
2.8 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
import type { Server } from '@tus/server'
|
|
import type { FastifyReply, FastifyRequest } from 'fastify'
|
|
|
|
import { isProduction } from '@redwoodjs/api/dist/logger'
|
|
import { ValidationError } from '@redwoodjs/graphql-server'
|
|
|
|
import { decryptAndValidateSession, validateSessionCookie } from 'src/lib/auth'
|
|
import { setCorsHeaders } from 'src/lib/cors'
|
|
import { db } from 'src/lib/db'
|
|
|
|
interface User {
|
|
id: number
|
|
username: string
|
|
email: string
|
|
hashedPassword: string
|
|
salt: string
|
|
resetToken: string | null
|
|
resetTokenExpiresAt: Date | null
|
|
}
|
|
|
|
export const handleTusUpload = (
|
|
req: FastifyRequest,
|
|
res: FastifyReply,
|
|
tusHandler: Server,
|
|
isPublicEndpoint: boolean
|
|
) => {
|
|
if (isProduction) {
|
|
if (req.method === 'OPTIONS') handleOptionsRequest(res)
|
|
else if (isPublicEndpoint && req.method === 'GET')
|
|
tusHandler.handle(req.raw, res.raw)
|
|
else if (['GET', 'POST', 'HEAD', 'PATCH'].includes(req.method)) {
|
|
if (req.headers.cookie) handleAuthenticatedRequest(req, res, tusHandler)
|
|
else {
|
|
res.raw.statusCode = 401
|
|
res.raw.end('Unauthenticated')
|
|
}
|
|
} else {
|
|
res.raw.statusCode = 405
|
|
res.raw.end('Method not allowed')
|
|
}
|
|
} else tusHandler.handle(req.raw, res.raw)
|
|
}
|
|
|
|
const handleAuthenticatedRequest = async (
|
|
req: FastifyRequest,
|
|
res: FastifyReply,
|
|
tusHandler: Server
|
|
) => {
|
|
try {
|
|
const sessionCookie = extractSessionCookie(req.headers.cookie)
|
|
validateSessionCookie(sessionCookie)
|
|
const userId = decryptAndValidateSession(sessionCookie)
|
|
|
|
if (userId) {
|
|
res.raw.setHeader('Access-Control-Allow-Credentials', 'true')
|
|
|
|
try {
|
|
const user = await db.user.findUnique({
|
|
where: {
|
|
id: userId,
|
|
},
|
|
})
|
|
|
|
addUserMetadataToRequest(req, user)
|
|
|
|
if ((req.raw as any).userId) tusHandler.handle(req.raw, res.raw)
|
|
else {
|
|
res.raw.statusCode = 500
|
|
res.raw.end('Server error')
|
|
}
|
|
} catch (error) {
|
|
res.raw.statusCode = 500
|
|
res.raw.end('Server error')
|
|
}
|
|
} else {
|
|
res.raw.statusCode = 403
|
|
res.raw.end('Forbidden')
|
|
}
|
|
} catch (error) {
|
|
res.raw.statusCode = 401
|
|
res.raw.end('Unauthenticated')
|
|
}
|
|
}
|
|
|
|
const addUserMetadataToRequest = (req: FastifyRequest, user: User) => {
|
|
;(req.raw as any).userId = user.id
|
|
;(req.raw as any).userEmail = user.email
|
|
}
|
|
|
|
const handleOptionsRequest = (res: FastifyReply) => {
|
|
setCorsHeaders(res)
|
|
res.raw.statusCode = 204
|
|
res.raw.end()
|
|
}
|
|
|
|
const extractSessionCookie = (cookie: string) => {
|
|
const sessionCookie = cookie
|
|
.split(';')
|
|
.find((item) => item.trim().startsWith('session_8911'))
|
|
?.trim()
|
|
|
|
if (!sessionCookie) throw new ValidationError('Invalid token')
|
|
|
|
return sessionCookie
|
|
}
|