I use uppy/tus and tus-node-server in my project. On the server I have fastify which accepts uploads on endpoints where I have CORS enabled and handle the requests appropriately. It sends them to my TusServer which is connected to my S3 storage. On these endpoints I end up checking for an auth cookie and decrypt the user session, which leaves me with the userId and email. This all works well.
I’m struggling to add this user information to my S3 storage. Here’s what my code looks like currently:
- Frontend (React)
const [Uppy] = useState(() => {
const uppyInstance = new Uppy({
restrictions: {
maxNumberOfFiles: 1,
allowedFileTypes: ['.png', '.jpg', '.jpeg', '.gif'],
maxFileSize: 10 * 1024 * 1024,
},
onBeforeUpload(files) {
for (const [key, file] of Object.entries(files)) {
uppyInstance.setFileMeta(key, {
name: file.name,
type: file.type,
contentType: file.type,
})
}
return true
},
}).use(Tus, {
endpoint: endpointUrl,
withCredentials: useCredentials,
})
return uppyInstance.on('complete', (result) => {
setAvatar(result.successful[0]?.uploadURL || '')
})
})
- Server (Node)
server.all('/public', (req, res) => {
if (req.method === 'OPTIONS') {
handleOptionsRequest(res)
} else if (['GET'].includes(req.method)) {
tusS3.handle(req.raw, res.raw) // I let anyone see the images, this is fine
} else if (['POST', 'HEAD', 'PATCH'].includes(req.method)) {
if (req.headers.cookie) {
handleAuthenticatedRequest(req, res, tusS3)
} else {
res.raw.statusCode = 401
res.raw.end()
}
}
})
function handleAuthenticatedRequest(req, res, tusHandler) {
try {
const sessionCookie = extractSessionCookie(req.headers.cookie)
validateSessionCookie(sessionCookie)
const [userId, email] = decryptAndValidateSession(sessionCookie)
if (userId) {
res.raw.setHeader('Access-Control-Allow-Credentials', 'true')
// How do I pass userId and email to the handle to use it in the onUploadFinish callback?
tusHandler.handle(req.raw, res.raw)
} else {
res.raw.statusCode = 403
res.raw.end()
}
} catch (error) {
res.raw.statusCode = 403
res.raw.end()
}
}
const tusS3 = new TusServer({
path: '/public',
datastore: s3storePublic,
onResponseError: (error, req, res) => {
logger.error(res)
},
respectForwardedHeaders: true,
onUploadFinish: async (
req: IncomingMessage,
res: ServerResponse,
upload: Upload
) => {
const metadata = {
name: upload.metadata.name, // This works just fine but how do I add the userId and e-mail here? I have it in the authenticated function above
}
const key = upload.id
try {
await addMetadataToS3Object('public', key, metadata, upload.metadata.type)
return { res, status_code: 200 }
} catch (error) {
return { res, status_code: 500, body: 'Failed to add metadata' }
}
},
})
Yes I know I could add the userId and email on the frontend to the Uppy metadata, however this is not secure. I want to handle this server-side with the decrypted and validated cookie.
How do I pass the userId and email to the TusServer’s OnUploadFinish callback?