85 lines
3.2 KiB
JavaScript
85 lines
3.2 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')
|
|
// 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) })
|