import fs from 'fs' import fsp from 'fs/promises' import path from 'path' // Minimal auth check using existing auth cookie/session function isAuthenticated(event) { try { const token = getCookie(event, 'auth_token') || getCookie(event, 'session_token') return token && String(token).trim() !== '' } catch (e) { return false } } // Resolve file path within a non-public internal media directory function resolveInternalPath(reqPath) { const baseDir = path.join(process.cwd(), 'server', 'private', 'gallery-internal') // prevent path traversal const safe = path.normalize(reqPath).replace(/^\/+/, '') return path.join(baseDir, safe) } export default defineEventHandler(async (event) => { // auth gate if (!isAuthenticated(event)) { throw createError({ statusCode: 401, statusMessage: 'Nicht autorisiert' }) } const param = event.context.params?.path const reqPath = Array.isArray(param) ? param.join('/') : String(param || '') if (!reqPath) { throw createError({ statusCode: 400, statusMessage: 'Bildpfad fehlt' }) } const filePath = resolveInternalPath(reqPath) // check existence and ensure it stays within baseDir const baseDir = path.join(process.cwd(), 'server', 'private', 'gallery-internal') const resolved = path.resolve(filePath) if (!resolved.startsWith(path.resolve(baseDir))) { throw createError({ statusCode: 400, statusMessage: 'Ungültiger Pfad' }) } try { const stat = await fsp.stat(resolved) if (!stat.isFile()) throw new Error('not a file') } catch (e) { throw createError({ statusCode: 404, statusMessage: 'Datei nicht gefunden' }) } // determine content type by extension const ext = path.extname(resolved).toLowerCase() const contentType = ( ext === '.jpg' || ext === '.jpeg' ? 'image/jpeg' : ext === '.png' ? 'image/png' : ext === '.gif' ? 'image/gif' : ext === '.webp' ? 'image/webp' : ext === '.svg' ? 'image/svg+xml' : 'application/octet-stream' ) // stream the file const stream = fs.createReadStream(resolved) setHeader(event, 'Content-Type', contentType) setHeader(event, 'Cache-Control', 'private, max-age=0, no-store') return sendStream(event, stream) })