Enhanced file uploading for production (thanks citrinitas3421!)
This commit is contained in:
106
api/src/lib/tus.ts
Normal file
106
api/src/lib/tus.ts
Normal file
@ -0,0 +1,106 @@
|
||||
/* 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
|
||||
}
|
Reference in New Issue
Block a user