Files
yihuiyong-ui/apps/web-ele/src/views/database/info/components/pdf.ts
2026-04-23 11:37:37 +08:00

244 lines
6.0 KiB
TypeScript

let PDFLib: any = null
interface PDFLibModule {
PDFDocument: {
load(bytes: ArrayBuffer, options?: { ignoreEncryption?: boolean }): Promise<any>
}
PDFName: {
of(name: string): any
}
PDFDict: any
PDFArray: any
}
const loadPdfLib = (): Promise<PDFLibModule> => {
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<boolean> => {
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,
}