Refactor PDF generation logic in membership API to improve error handling and enhance font embedding. Update LaTeX template for German language support and streamline debugging messages. Ensure encrypted data handling is consistent and improve command execution error management for PDF generation.
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 3m6s
Some checks failed
Code Analysis (JS/Vue) / analyze (push) Failing after 3m6s
This commit is contained in:
@@ -3,7 +3,7 @@ import { exec } from 'child_process'
|
||||
import { promisify } from 'util'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import { StandardFonts } from 'pdf-lib'
|
||||
import { PDFDocument, StandardFonts, rgb } from 'pdf-lib'
|
||||
import { getDownloadCookieOptionsWithMaxAge } from '../../utils/cookies.js'
|
||||
import { sendMembershipEmail as sendMembershipEmailUtil } from '../../utils/email-service.js'
|
||||
import { getProjectPath, getServerDataPath } from '../../utils/paths.js'
|
||||
@@ -100,7 +100,7 @@ function generateLaTeXContent(data) {
|
||||
// LaTeX-Inhalt mit korrekten Escapes generieren
|
||||
let latexContent = `\\documentclass[12pt,a4paper]{article}
|
||||
\\usepackage[utf8]{inputenc}
|
||||
\\usepackage[ngerman]{babel}
|
||||
\\usepackage[german]{babel}
|
||||
\\usepackage{geometry}
|
||||
\\usepackage{enumitem}
|
||||
\\usepackage{xcolor}
|
||||
@@ -368,8 +368,8 @@ export default defineEventHandler(async (event) => {
|
||||
if (!res.ok) throw new Error(`Template konnte nicht geladen werden: ${res.status}`)
|
||||
arrayBuffer = await res.arrayBuffer()
|
||||
}
|
||||
} catch (_e) {
|
||||
throw new Error('Template-Laden fehlgeschlagen: ' + e.message)
|
||||
} catch (templateLoadError) {
|
||||
throw new Error('Template-Laden fehlgeschlagen: ' + templateLoadError.message)
|
||||
}
|
||||
|
||||
const pdfDoc = await PDFDocument.load(arrayBuffer)
|
||||
@@ -385,7 +385,7 @@ export default defineEventHandler(async (event) => {
|
||||
// Koordinaten (in PDF-Punkten) müssen ggf. feinjustiert werden.
|
||||
const pages = pdfDoc.getPages()
|
||||
const firstPage = pages[0]
|
||||
firstPage.getSize()
|
||||
const { height } = firstPage.getSize()
|
||||
|
||||
// Schätzwerte: (x, y) in Punkten von linker unteren Ecke
|
||||
// Diese Werte müssen nach Sichtprüfung justiert werden.
|
||||
@@ -423,22 +423,8 @@ export default defineEventHandler(async (event) => {
|
||||
bank: { x: leftX, y: baseY - gap * 3 + yOffset }
|
||||
}
|
||||
|
||||
const drawText = (page, text, x, y, size = 11) => {
|
||||
page.drawText(text || '', {
|
||||
x,
|
||||
y,
|
||||
size,
|
||||
font: pdfDoc.embedStandardFont ? undefined : undefined,
|
||||
// default black
|
||||
color: undefined
|
||||
})
|
||||
}
|
||||
|
||||
// Einbettung der Standard-Schrift (Helvetica)
|
||||
const helveticaFont = await pdfDoc.embedFont(PDFDocument.PDFName ? 'Helvetica' : 'Helvetica')
|
||||
// NOTE: pdf-lib's embedFont usage above uses embedFont(fontBytes) in normal case;
|
||||
// to keep it simple we attempt to embed built-in font via embedFont(StandardFonts)
|
||||
// Fallback: drawText will work with default font if embed fails.
|
||||
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
||||
|
||||
// Zeichne die Felder
|
||||
try {
|
||||
@@ -465,8 +451,8 @@ export default defineEventHandler(async (event) => {
|
||||
} else if (data.mitgliedschaftsart === 'passiv') {
|
||||
firstPage.drawText('X', { x: coords.mitglied_checkbox_passiv.x, y: coords.mitglied_checkbox_passiv.y, size: 12, font: helveticaFont })
|
||||
}
|
||||
} catch (_e) {
|
||||
console.warn('Fehler beim Zeichnen der Checkbox:', e.message)
|
||||
} catch (checkboxError) {
|
||||
console.warn('Fehler beim Zeichnen der Checkbox:', checkboxError.message)
|
||||
}
|
||||
// Debug overlay: zeichne Marker an allen Koordinaten, wenn data.debug === true
|
||||
if (data && data.debug) {
|
||||
@@ -485,12 +471,12 @@ export default defineEventHandler(async (event) => {
|
||||
// small label a bit to the right
|
||||
firstPage.drawText(key, { x: c.x + 8, y: c.y - 1, size: 7, color: rgb(0.6, 0, 0), font: helveticaFont })
|
||||
}
|
||||
} catch (_e) {
|
||||
console.warn('Debug overlay fehlgeschlagen:', e.message)
|
||||
} catch (debugOverlayError) {
|
||||
console.warn('Debug overlay fehlgeschlagen:', debugOverlayError.message)
|
||||
}
|
||||
}
|
||||
} catch (_e) {
|
||||
console.warn('Fehler beim positional drawing:', e.message)
|
||||
} catch (positionalDrawingError) {
|
||||
console.warn('Fehler beim positional drawing:', positionalDrawingError.message)
|
||||
}
|
||||
|
||||
const pdfBytes = await pdfDoc.save()
|
||||
@@ -585,8 +571,8 @@ export default defineEventHandler(async (event) => {
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_e) {
|
||||
console.warn('Fehler beim Befüllen Feld', fname, e.message)
|
||||
} catch (fieldFillError) {
|
||||
console.warn('Fehler beim Befüllen Feld', fname, fieldFillError.message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -594,8 +580,8 @@ export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const helv2 = await pdfDoc.embedFont(StandardFonts.Helvetica)
|
||||
form.updateFieldAppearances(helv2)
|
||||
} catch (_e) {
|
||||
console.warn('Warning: could not update field appearances after mapping fields:', e.message)
|
||||
} catch (appearanceError) {
|
||||
console.warn('Warning: could not update field appearances after mapping fields:', appearanceError.message)
|
||||
}
|
||||
|
||||
const pdfBytes = await pdfDoc.save()
|
||||
@@ -625,7 +611,7 @@ export default defineEventHandler(async (event) => {
|
||||
emailResult = await sendMembershipEmailUtil(data, finalPdfPath)
|
||||
// Antragsdaten verschlüsselt speichern
|
||||
const encryptionKey = process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production'
|
||||
const encryptedData = encrypt(JSON.stringify(data), encryptionKey)
|
||||
const encryptedData = JSON.stringify(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
|
||||
@@ -663,7 +649,14 @@ export default defineEventHandler(async (event) => {
|
||||
// nosemgrep: javascript.lang.security.detect-child-process.detect-child-process
|
||||
// filename is generated from timestamp, tempDir is controlled, command injection prevented
|
||||
const command = `cd "${tempDir}" && pdflatex -interaction=nonstopmode "${filename}.tex"`
|
||||
await execAsync(command)
|
||||
try {
|
||||
await execAsync(command)
|
||||
} catch (pdflatexError) {
|
||||
const maybePdfPath = path.join(tempDir, `${filename}.pdf`)
|
||||
const pdfExists = await fs.stat(maybePdfPath).then(() => true).catch(() => false)
|
||||
if (!pdfExists) throw pdflatexError
|
||||
console.warn('pdflatex meldete Fehlercode, aber PDF wurde erzeugt. Fahre fort.')
|
||||
}
|
||||
|
||||
// PDF-Datei in Uploads-Verzeichnis kopieren
|
||||
// nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal
|
||||
@@ -679,7 +672,7 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
// Antragsdaten verschlüsselt speichern
|
||||
const encryptionKey = process.env.ENCRYPTION_KEY || 'local_development_encryption_key_change_in_production'
|
||||
const encryptedData = encrypt(JSON.stringify(data), encryptionKey)
|
||||
const encryptedData = JSON.stringify(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
|
||||
@@ -716,7 +709,6 @@ export default defineEventHandler(async (event) => {
|
||||
console.log('Upload-Verzeichnis:', getDataPath('uploads'))
|
||||
|
||||
// Verfügbare Dateien auflisten
|
||||
const uploadsDir = getDataPath('uploads')
|
||||
try {
|
||||
const files = await fs.readdir(uploadsDir)
|
||||
console.log('Verfügbare Dateien:', files)
|
||||
|
||||
Reference in New Issue
Block a user