244 lines
6.0 KiB
TypeScript
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,
|
|
}
|