let PDFLib: any = null interface PDFLibModule { PDFDocument: { load(bytes: ArrayBuffer, options?: { ignoreEncryption?: boolean }): Promise } PDFName: { of(name: string): any } PDFDict: any PDFArray: any } const loadPdfLib = (): Promise => { return new Promise((resolve, reject) => { if (PDFLib) { resolve(PDFLib) return } const script = document.createElement('script') script.src = '/static/js/pdf-lib.min.js' script.onload = () => { PDFLib = (window as any).PDFLib resolve(PDFLib) } script.onerror = reject document.head.appendChild(script) }) } const checkActionForJavaScript = ( action: any, PDFDict: any, PDFName: any, PDFArray: any, ): boolean => { if (!(action instanceof PDFDict)) return false const subtype = action.lookup(PDFName.of('S')) if (subtype?.toString() === '/JavaScript') { return true } const js = action.lookup(PDFName.of('JS')) if (js) { return true } const next = action.lookup(PDFName.of('Next')) if (next instanceof PDFArray) { for (let i = 0; i < next.size(); i++) { if (checkActionForJavaScript(next.lookup(i), PDFDict, PDFName, PDFArray)) { return true } } } else if (next instanceof PDFDict) { if (checkActionForJavaScript(next, PDFDict, PDFName, PDFArray)) { return true } } return false } const checkFieldForJavaScript = ( field: any, PDFDict: any, PDFName: any, PDFArray: any, ): boolean => { if (!(field instanceof PDFDict)) return false const aa = field.lookup(PDFName.of('AA')) if (aa instanceof PDFDict) { const actionKeys = ['K', 'F', 'V', 'C', 'E', 'X', 'D', 'U', 'Fo', 'PO', 'PC', 'PV', 'PI'] for (const key of actionKeys) { const action = aa.lookup(PDFName.of(key)) if (action && checkActionForJavaScript(action, PDFDict, PDFName, PDFArray)) { return true } } } const kids = field.lookup(PDFName.of('Kids')) if (kids instanceof PDFArray) { for (let i = 0; i < kids.size(); i++) { if (checkFieldForJavaScript(kids.lookup(i), PDFDict, PDFName, PDFArray)) { return true } } } return false } const checkAcroFormForJavaScript = ( acroForm: any, PDFDict: any, PDFName: any, PDFArray: any, ): boolean => { if (!(acroForm instanceof PDFDict)) return false const co = acroForm.lookup(PDFName.of('CO')) if (co instanceof PDFArray) { for (let i = 0; i < co.size(); i++) { if (checkFieldForJavaScript(co.lookup(i), PDFDict, PDFName, PDFArray)) { return true } } } const fields = acroForm.lookup(PDFName.of('Fields')) if (fields instanceof PDFArray) { for (let i = 0; i < fields.size(); i++) { if (checkFieldForJavaScript(fields.lookup(i), PDFDict, PDFName, PDFArray)) { return true } } } return false } const checkAnnotationForJavaScript = ( annot: any, PDFDict: any, PDFName: any, PDFArray: any, ): boolean => { if (!(annot instanceof PDFDict)) return false const aa = annot.lookup(PDFName.of('AA')) if (aa instanceof PDFDict) { const actionKeys = ['E', 'X', 'D', 'U', 'Fo', 'Bl', 'PO', 'PC', 'PV', 'PI'] for (const key of actionKeys) { const action = aa.lookup(PDFName.of(key)) if (action && checkActionForJavaScript(action, PDFDict, PDFName, PDFArray)) { return true } } } const action = annot.lookup(PDFName.of('A')) if (action && checkActionForJavaScript(action, PDFDict, PDFName, PDFArray)) { return true } return false } const checkPageForJavaScript = ( page: any, PDFDict: any, PDFName: any, PDFArray: any, ): boolean => { if (!(page instanceof PDFDict)) return false const aa = page.lookup(PDFName.of('AA')) if (aa instanceof PDFDict) { const actionKeys = ['O', 'C'] for (const key of actionKeys) { const action = aa.lookup(PDFName.of(key)) if (action && checkActionForJavaScript(action, PDFDict, PDFName, PDFArray)) { return true } } } const annots = page.lookup(PDFName.of('Annots')) if (annots instanceof PDFArray) { for (let i = 0; i < annots.size(); i++) { if (checkAnnotationForJavaScript(annots.lookup(i), PDFDict, PDFName, PDFArray)) { return true } } } return false } const checkPdfJavaScript = async (bytes: ArrayBuffer): Promise => { if (!PDFLib) { console.error('PDFLib not loaded') return false } try { const { PDFDocument, PDFName, PDFDict, PDFArray } = PDFLib const pdfDoc = await PDFDocument.load(bytes, { ignoreEncryption: true }) const catalog = pdfDoc.catalog const names = catalog.lookup(PDFName.of('Names')) if (names instanceof PDFDict) { const javaScriptDict = names.lookup(PDFName.of('JavaScript')) if (javaScriptDict instanceof PDFDict) { console.log('检测到文档级 JavaScript') return true } } const openAction = catalog.lookup(PDFName.of('OpenAction')) if (openAction && checkActionForJavaScript(openAction, PDFDict, PDFName, PDFArray)) { console.log('检测到 OpenAction 中的 JavaScript') return true } const acroForm = catalog.lookup(PDFName.of('AcroForm')) if (acroForm && checkAcroFormForJavaScript(acroForm, PDFDict, PDFName, PDFArray)) { console.log('检测到表单中的 JavaScript') return true } const pages = catalog.lookup(PDFName.of('Pages')) if (pages instanceof PDFDict) { const kids = pages.lookup(PDFName.of('Kids')) if (kids instanceof PDFArray) { for (let i = 0; i < kids.size(); i++) { const page = kids.lookup(i) if (page instanceof PDFDict && checkPageForJavaScript(page, PDFDict, PDFName, PDFArray)) { console.log('检测到页面中的 JavaScript') return true } } } } return false } catch (error) { console.error('Error checking JavaScript:', error) return false } } export { loadPdfLib, checkPdfJavaScript, }