import fs from 'fs' import path from 'path' import { PDFDocument, StandardFonts } from 'pdf-lib' async function inspect(pdfPath) { console.log('\n--- Inspecting', pdfPath) if (!fs.existsSync(pdfPath)) { console.log('MISSING:', pdfPath) return } const bytes = fs.readFileSync(pdfPath) const pdfDoc = await PDFDocument.load(bytes) let form = null try { form = pdfDoc.getForm() } catch (e) { form = null } if (!form) { console.log('No AcroForm found') ; return } const fields = form.getFields() console.log('Field count:', fields.length) for (const f of fields) { const name = f.getName() let value = null try { if (typeof f.getText === 'function') value = f.getText() else if (typeof f.isChecked === 'function') value = f.isChecked() else value = '(no getter)' } catch (e) { value = `(error reading: ${e.message})` } // widgets let widgetsInfo = [] try { const acro = f.acroField const widgets = acro.getWidgets() for (const w of widgets) { try { const rect = w.getRectangle() // try to find page index by searching pages for an annotation with same ref let pageIndex = null try { const pages = pdfDoc.getPages() for (let i = 0; i < pages.length; i++) { const page = pages[i] const annots = page.node.Annots ? page.node.Annots() : null // can't reliably map here; just record rect } } catch (e) {} widgetsInfo.push({ rect }) } catch (e) { widgetsInfo.push({ error: e.message }) } } } catch (e) { widgetsInfo = [`error widgets: ${e.message}`] } // nosemgrep: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring console.log(`- ${name}: value='${value}' widgets=${widgetsInfo.length}`) for (const wi of widgetsInfo) console.log(' ', JSON.stringify(wi)) } } async function main() { const repoRoot = process.cwd() const template = path.join(repoRoot, 'server', 'templates', 'mitgliedschaft-fillable.pdf') // pick latest generated PDF in public/uploads that is not the sample // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal const uploads = path.join(repoRoot, 'public', 'uploads') let pdfFiles = [] if (fs.existsSync(uploads)) { pdfFiles = fs.readdirSync(uploads).filter(f => f.toLowerCase().endsWith('.pdf')) .map(f => { // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal const filePath = path.join(uploads, f) return { f, mtime: fs.statSync(filePath).mtimeMs } }) .sort((a,b) => b.mtime - a.mtime) .map(x => x.f) } const apiPdf = pdfFiles.find(n => !n.includes('sample')) || pdfFiles[0] await inspect(template) // nosemgrep: javascript.lang.security.audit.path-traversal.path-join-resolve-traversal.path-join-resolve-traversal if (apiPdf) await inspect(path.join(uploads, apiPdf)) else console.log('No API-generated PDF found in public/uploads') } main().catch(e => { console.error(e); process.exit(1) })