import { writeFileSync, mkdirSync, existsSync } from 'fs'; import { fail } from '@sveltejs/kit'; import type { RequestEvent } from './$types'; import safePath, { storagePath, log } from '$lib'; import { hash } from 'crypto'; import path from 'path'; const mkdirIfNotExists = (path: string) => { if (!existsSync(path)) { mkdirSync(path); } }; export const actions = { default: async ({ request, locals }: RequestEvent) => { let context: { [key: string]: string | string[] } = { requestId: locals.requestId }; const data = await request.formData(); const formFiles = data.getAll('files'); if (!formFiles) { log.debug(context, 'missing files'); return fail(400, { field: 'files', files: formFiles, missing: true }); } else if (!(formFiles as File[])) { log.debug(context, 'invalid files'); return fail(400, { field: 'files', files: formFiles, incorrect: true }); } const files = formFiles as File[]; const fileNames = files.map((file) => file.name); context = { fileNames, ...context }; if (files.length === 0) { log.debug(context, 'empty files'); return fail(400, { field: 'files', files: formFiles, empty: true }); } const formName = data.get('name'); if (!formName) { log.debug(context, 'missing name'); return fail(400, { field: 'name', name: formName, missing: true }); } else if (!(formName as string)) { log.debug(context, 'invalid name'); return fail(400, { field: 'name', name: formName, incorrect: true }); } const name = formName as string; context = { name, ...context }; if (!safePath(storagePath, name)) { log.warn(context, 'Supplied name would cause dir traversal. Rejecting...'); return fail(400, { field: 'name', name: name, incorrect: true }); } log.info(context, 'Uploading files'); files.forEach(async (file) => { const outPath = `${storagePath}/${name}`; const content = Buffer.from(await file.arrayBuffer()); const ext = path.extname(file.name); mkdirIfNotExists(outPath); const filename = `${hash('sha1', content)}${ext}`; const fullPath = `${outPath}/${filename}`; context = { file: fullPath, ...context }; if (existsSync(fullPath)) { log.debug(context, 'File has already been uploaded. Skipping...'); } else { log.debug(context, 'saving file'); writeFileSync(fullPath, Buffer.from(await file.arrayBuffer()), { flag: 'a+' }); } }); return { success: true, }; }, };