diff --git a/server/api/membership/download/[id].get.js b/server/api/membership/download/[id].get.js index c677e18..a63c58f 100644 --- a/server/api/membership/download/[id].get.js +++ b/server/api/membership/download/[id].get.js @@ -13,12 +13,12 @@ export default defineEventHandler(async (event) => { }) } - // Upload-Verzeichnis finden - const uploadDir = path.join(process.cwd(), 'public', 'uploads') - console.log('Upload-Verzeichnis:', uploadDir) + // Upload-Verzeichnis finden (intern) + const uploadDir = path.join(process.cwd(), '..', 'server', 'data', 'uploads') + console.log('Upload-Verzeichnis:', uploadDir) - // Alle Dateien im Upload-Verzeichnis durchsuchen - const files = await fs.readdir(uploadDir) + // Alle Dateien im Upload-Verzeichnis durchsuchen + const files = await fs.readdir(uploadDir) console.log('Verfügbare Dateien:', files) console.log('Gesuchte Datei-ID:', fileId) @@ -71,7 +71,7 @@ export default defineEventHandler(async (event) => { }) } - const filePath = path.join(uploadDir, matchingFile) + const filePath = path.join(uploadDir, matchingFile) // Datei lesen const fileBuffer = await fs.readFile(filePath) diff --git a/server/api/membership/generate-pdf.post.js b/server/api/membership/generate-pdf.post.js index b7c36f0..9bae67d 100644 --- a/server/api/membership/generate-pdf.post.js +++ b/server/api/membership/generate-pdf.post.js @@ -299,7 +299,7 @@ Volljährig: ${data.isVolljaehrig ? 'Ja' : 'Nein'} Das ausgefüllte Formular ist als Anhang verfügbar.` // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - const textPath = path.join(process.cwd(), 'public', 'uploads', `${filename}.txt`) + const textPath = path.join(getDataPath('uploads'), `${filename}.txt`) await fs.writeFile(textPath, textContent, 'utf8') return `${filename}.txt` @@ -659,28 +659,17 @@ export default defineEventHandler(async (event) => { return Buffer.from(pdfBytes) } - let usedTemplate = false - const uploadsDir = path.join(process.cwd(), 'public', 'uploads') - await fs.mkdir(uploadsDir, { recursive: true }) + let usedTemplate = false + const uploadsDir = getDataPath('uploads') + await fs.mkdir(uploadsDir, { recursive: true }) try { const filled = await fillPdfTemplate(data) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal // filename is generated from timestamp, not user input, path traversal prevented // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - const finalPdfPath = path.join(uploadsDir, `${filename}.pdf`) - await fs.writeFile(finalPdfPath, filled) - // Zusätzlich: Kopie ins repo-root public/uploads legen, falls Nitro cwd anders ist - try { - const repoRoot = path.resolve(process.cwd(), '..') - const repoUploads = path.join(repoRoot, 'public', 'uploads') - await fs.mkdir(repoUploads, { recursive: true }) - // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - // filename is generated from timestamp, not user input, path traversal prevented - // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - await fs.copyFile(finalPdfPath, path.join(repoUploads, `${filename}.pdf`)) - } catch (_e) { - console.warn('Kopie in repo public/uploads fehlgeschlagen:', e.message) - } + const finalPdfPath = path.join(uploadsDir, `${filename}.pdf`) + await fs.writeFile(finalPdfPath, filled) + // Do NOT copy filled PDFs into public repo uploads to avoid accidental exposure. usedTemplate = true } catch (templateError) { // Template konnte nicht verwendet werden -> weiter zum LaTeX-Fallback @@ -720,7 +709,7 @@ export default defineEventHandler(async (event) => { // LaTeX-Inhalt generieren const latexContent = generateLaTeXContent(data) - // LaTeX-Datei schreiben + // LaTeX-Datei schreiben // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal // filename is generated from timestamp, not user input, path traversal prevented // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal @@ -733,30 +722,14 @@ export default defineEventHandler(async (event) => { const command = `cd "${tempDir}" && pdflatex -interaction=nonstopmode "${filename}.tex"` await execAsync(command) - // PDF-Datei in Uploads-Verzeichnis kopieren + // PDF-Datei in Uploads-Verzeichnis kopieren // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal // filename is generated from timestamp, not user input, path traversal prevented // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal const pdfPath = path.join(tempDir, `${filename}.pdf`) - await fs.mkdir(uploadsDir, { recursive: true }) - - // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - // filename is generated from timestamp, not user input, path traversal prevented - // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - const finalPdfPath = path.join(uploadsDir, `${filename}.pdf`) - await fs.copyFile(pdfPath, finalPdfPath) - // Kopie ins repo-root public/uploads für bessere Auffindbarkeit - try { - const repoRoot = path.resolve(process.cwd(), '..') - const repoUploads = path.join(repoRoot, 'public', 'uploads') - await fs.mkdir(repoUploads, { recursive: true }) - // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - // filename is generated from timestamp, not user input, path traversal prevented - // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal - await fs.copyFile(finalPdfPath, path.join(repoUploads, `${filename}.pdf`)) - } catch (e) { - console.warn('Kopie in repo public/uploads fehlgeschlagen:', e.message) - } + await fs.mkdir(uploadsDir, { recursive: true }) + const finalPdfPath = path.join(uploadsDir, `${filename}.pdf`) + await fs.copyFile(pdfPath, finalPdfPath) // E-Mail senden emailResult = await sendMembershipEmail(data, filename, event) @@ -793,14 +766,14 @@ export default defineEventHandler(async (event) => { // E-Mail senden (Fallback) const emailResult = await sendMembershipEmail(data, filename, event) - console.log('LaTeX nicht verfügbar, verwende Fallback-Lösung') - console.log('E-Mail würde gesendet werden an:', emailResult.recipients || []) - console.log('Betreff:', emailResult.subject || '') - console.log('Nachricht:', emailResult.message || '') - console.log('Upload-Verzeichnis:', path.join(process.cwd(), 'public', 'uploads')) + console.log('LaTeX nicht verfügbar, verwende Fallback-Lösung') + console.log('E-Mail würde gesendet werden an:', emailResult.recipients || []) + console.log('Betreff:', emailResult.subject || '') + console.log('Nachricht:', emailResult.message || '') + console.log('Upload-Verzeichnis:', getDataPath('uploads')) // Verfügbare Dateien auflisten - const uploadsDir = path.join(process.cwd(), 'public', 'uploads') + const uploadsDir = getDataPath('uploads') try { const files = await fs.readdir(uploadsDir) console.log('Verfügbare Dateien:', files)