Files
harheimertc/scripts/inspect-forms.js
2026-02-11 11:42:24 +01:00

94 lines
3.4 KiB
JavaScript

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')
// Prefer internal upload directory used by the API (server/data/uploads).
// If legacy files exist in public/uploads, warn and inspect them as well.
const internalUploads = path.join(repoRoot, 'server', 'data', 'uploads')
const publicUploads = path.join(repoRoot, 'public', 'uploads')
let pdfFiles = []
if (fs.existsSync(internalUploads)) {
pdfFiles = fs.readdirSync(internalUploads).filter(f => f.toLowerCase().endsWith('.pdf'))
.map(f => {
const filePath = path.join(internalUploads, f)
return { f, mtime: fs.statSync(filePath).mtimeMs, dir: internalUploads }
})
}
// Do NOT fall back to public/uploads to avoid encouraging public exposure.
if (pdfFiles.length === 0) {
if (fs.existsSync(publicUploads)) {
console.warn('WARN: PDFs exist in public/uploads. Please migrate them to server/data/uploads using scripts/migrate-public-galerie-to-metadata.js')
}
}
pdfFiles = pdfFiles.sort((a, b) => b.mtime - a.mtime)
const apiPdfEntry = pdfFiles.find(e => !e.f.includes('sample')) || pdfFiles[0]
await inspect(template)
if (apiPdfEntry) await inspect(path.join(apiPdfEntry.dir, apiPdfEntry.f))
else console.log('No API-generated PDF found in server/data/uploads or public/uploads')
}
main().catch(e => { console.error(e); process.exit(1) })