diff --git a/package-lock.json b/package-lock.json index b569b57..5023f18 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "better-sqlite3": "^12.6.2", "jsdom": "^27.4.0", "onnxruntime-node": "^1.30.0", - "pdfjs-dist": "^5.4.530", + "pdfjs-dist": "^6.3.289", "sharp": "^0.35.4", "sqlite-vec": "0.1.7-alpha.2" }, @@ -3314,9 +3314,9 @@ } }, "node_modules/@napi-rs/canvas": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas/-/canvas-0.1.100.tgz", - "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas/-/canvas-1.0.9.tgz", + "integrity": "sha512-QviPdJImDi/jMAvBfqaw+19BndMd/sizXVW3NnpMd3VJGz++QXkOHcP9kWR/smHG0hNjHeyuHFyrx/5lD0oNcQ==", "license": "MIT", "optional": true, "workspaces": [ @@ -3330,23 +3330,23 @@ "url": "https://github.com/sponsors/Brooooooklyn" }, "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.100", - "@napi-rs/canvas-darwin-arm64": "0.1.100", - "@napi-rs/canvas-darwin-x64": "0.1.100", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", - "@napi-rs/canvas-linux-arm64-musl": "0.1.100", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", - "@napi-rs/canvas-linux-x64-gnu": "0.1.100", - "@napi-rs/canvas-linux-x64-musl": "0.1.100", - "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", - "@napi-rs/canvas-win32-x64-msvc": "0.1.100" + "@napi-rs/canvas-android-arm64": "1.0.9", + "@napi-rs/canvas-darwin-arm64": "1.0.9", + "@napi-rs/canvas-darwin-x64": "1.0.9", + "@napi-rs/canvas-linux-arm-gnueabihf": "1.0.9", + "@napi-rs/canvas-linux-arm64-gnu": "1.0.9", + "@napi-rs/canvas-linux-arm64-musl": "1.0.9", + "@napi-rs/canvas-linux-riscv64-gnu": "1.0.9", + "@napi-rs/canvas-linux-x64-gnu": "1.0.9", + "@napi-rs/canvas-linux-x64-musl": "1.0.9", + "@napi-rs/canvas-win32-arm64-msvc": "1.0.9", + "@napi-rs/canvas-win32-x64-msvc": "1.0.9" } }, "node_modules/@napi-rs/canvas-android-arm64": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", - "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-1.0.9.tgz", + "integrity": "sha512-4LGXk2/0HVzE29K8SzML5WubgCp++B1FH3qgl35XmSZE+lLdr6P9VRQEnZ0MCLZMTSuJP41yyhtoiVNEuvrTIA==", "cpu": [ "arm64" ], @@ -3364,9 +3364,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", - "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-1.0.9.tgz", + "integrity": "sha512-YNdfLBzY0W/Pep9fo2L6RmoNlNksnn05LRnX66W63R3ij58S25QOTcjdtEt2v8+PnCESzqZsYzUo+QPeIR44NA==", "cpu": [ "arm64" ], @@ -3384,9 +3384,9 @@ } }, "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", - "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-1.0.9.tgz", + "integrity": "sha512-ceZQSknTEcy3dOXoekv59LTCkXjvnLsq+VW5PeNNDHEPQbRS5Ervkm1EaDa7WLAjiYWMLuSQTRTHao1dEX4prg==", "cpu": [ "x64" ], @@ -3404,9 +3404,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", - "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-1.0.9.tgz", + "integrity": "sha512-XhfI0Wwv4llhd6nnWDtY3kQKjq0r+y1i91PlJlJI24ag2U9WrnwbG1qS3+fDLEyouwEVFchiKkTEHozK+5iUNA==", "cpu": [ "arm" ], @@ -3424,9 +3424,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", - "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-1.0.9.tgz", + "integrity": "sha512-012oiYtKaE7i9oxc8q7nraT7kDOpLcaCmFLzVe9Ty34RHDdoDzbWLrVh827CNxYh/EADX1eSikA3ymLjo/nNuw==", "cpu": [ "arm64" ], @@ -3447,9 +3447,9 @@ } }, "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", - "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-1.0.9.tgz", + "integrity": "sha512-Ls5UWYFFn63casTZEczbeyEg3vRDRkv9lscuGwfchtY5yLLQhgOB8SN4YGxmfJ5vTaBwZ2YUxBS3NtmjJmFXdA==", "cpu": [ "arm64" ], @@ -3470,9 +3470,9 @@ } }, "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", - "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-1.0.9.tgz", + "integrity": "sha512-hLKEGxV7ZiRHqndePTokgDMdBlo/rDfzg7P4p4QIv9pUhuYobnu3R2NIFLCRghG0nwfo+s2sw+c1xZFeCmEAsw==", "cpu": [ "riscv64" ], @@ -3493,9 +3493,9 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", - "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-1.0.9.tgz", + "integrity": "sha512-6kaz3w0QMy77PDWk6rJ1ksIihdad3qzEyX2o2oGT8GwCaypfT5mhjr8buOO5hstyLxcWXDScuz56RsINLtBPIQ==", "cpu": [ "x64" ], @@ -3516,9 +3516,9 @@ } }, "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", - "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-1.0.9.tgz", + "integrity": "sha512-xrGvmS3v55hmZ86ls/kBLVNMUTYio3f6Ik0DireemG994VfPAwiA3ZXA0Uf1bByctkB3NQ1Sfb+H5bkdUnnzfQ==", "cpu": [ "x64" ], @@ -3539,9 +3539,9 @@ } }, "node_modules/@napi-rs/canvas-win32-arm64-msvc": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", - "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-1.0.9.tgz", + "integrity": "sha512-yjmVS3ArZeRVCP7jqbPq4rpZa/BhTeI7ELE2XqJg3snICQBDevLZyArxswHkiTnT34KRic33/4fLirrHI+SY8A==", "cpu": [ "arm64" ], @@ -3559,9 +3559,9 @@ } }, "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.100", - "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", - "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", + "version": "1.0.9", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-1.0.9.tgz", + "integrity": "sha512-QlSYQdMQslB81nlABo9wNfQ6npFhE7/O+saCZdqVGueGanyRk4jCogD5EwQenfP3kIq9e+mm6GreQBjX5MrA8g==", "cpu": [ "x64" ], @@ -14225,6 +14225,296 @@ "officeparser": "officeParser.js" } }, + "node_modules/officeparser/node_modules/@napi-rs/canvas": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas/-/canvas-0.1.100.tgz", + "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", + "dev": true, + "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.100", + "@napi-rs/canvas-darwin-arm64": "0.1.100", + "@napi-rs/canvas-darwin-x64": "0.1.100", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", + "@napi-rs/canvas-linux-arm64-musl": "0.1.100", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-musl": "0.1.100", + "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", + "@napi-rs/canvas-win32-x64-msvc": "0.1.100" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", + "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", + "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", + "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", + "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", + "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", + "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", + "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", + "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", + "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-win32-arm64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", + "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmmirror.com/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", + "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/officeparser/node_modules/pdfjs-dist": { + "version": "5.7.284", + "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-5.7.284.tgz", + "integrity": "sha512-h4EdYQczmGhbOlqc3PPZwxevn7ApdWPbovAuWXOB/DjIyigSnwfy2oze7c6mRcSr9XgLp3eN3EeL4DyySTPMFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=22.13.0 || >=24" + }, + "optionalDependencies": { + "@napi-rs/canvas": "^0.1.100" + } + }, "node_modules/officeparser/node_modules/yauzl": { "version": "3.4.0", "resolved": "https://registry.npmmirror.com/yauzl/-/yauzl-3.4.0.tgz", @@ -14589,15 +14879,15 @@ "license": "MIT" }, "node_modules/pdfjs-dist": { - "version": "5.7.284", - "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-5.7.284.tgz", - "integrity": "sha512-h4EdYQczmGhbOlqc3PPZwxevn7ApdWPbovAuWXOB/DjIyigSnwfy2oze7c6mRcSr9XgLp3eN3EeL4DyySTPMFw==", + "version": "6.3.289", + "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-6.3.289.tgz", + "integrity": "sha512-ZHjSVpDa3D6izMq8/04lvkhkATUmL9px6ChPaXc1k6nU2Mrhlg1/7F0bdUqCwUjw3NsPTfPZsMDUU6ZIcRaeQw==", "license": "Apache-2.0", "engines": { "node": ">=22.13.0 || >=24" }, "optionalDependencies": { - "@napi-rs/canvas": "^0.1.100" + "@napi-rs/canvas": "^1.0.0" } }, "node_modules/pe-library": { diff --git a/package.json b/package.json index cc748ea..6460bde 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "better-sqlite3": "^12.6.2", "jsdom": "^27.4.0", "onnxruntime-node": "^1.30.0", - "pdfjs-dist": "^5.4.530", + "pdfjs-dist": "^6.3.289", "sharp": "^0.35.4", "sqlite-vec": "0.1.7-alpha.2" }, diff --git a/src/main/services/loaders/PdfLoader.ts b/src/main/services/loaders/PdfLoader.ts index 36aceb7..f7dcec3 100644 --- a/src/main/services/loaders/PdfLoader.ts +++ b/src/main/services/loaders/PdfLoader.ts @@ -65,6 +65,13 @@ export class PdfLoader implements IDocumentLoader { try { // 加载 PDF 文档 + // + // 这里刻意不建 AnnotationLayer,也不导入 `pdfjs-dist/web/*`(#121 / GHSA-hq66-cqwq-w95j)。 + // 真正执行文档内 JS 的 `PDFScriptingManager` 只在 viewer build 里,而 `enableScripting` + // 也不在 `getDocument` 的参数里 —— 它在 AnnotationLayer / viewer 上。所以这条 API 路径 + // **在当前检查过的调用点下漏洞路径不可达**,而这个前提由 + // `test/pdfjsScriptingBoundary.test.ts` 守着:一旦有人把 annotation layer 或 viewer + // 拉进来,那个测试会失败。 const loadingTask = pdfjsLib.getDocument({ data: new Uint8Array(buffer), password: opts.password @@ -136,8 +143,11 @@ export class PdfLoader implements IDocumentLoader { } // 清理文档 + // + // `destroy()` 在 pdfjs-dist 6.x 从 `PDFDocumentProxy` 移到了 + // `PDFDocumentLoadingTask`(doc 上只剩 `cleanup()`),所以这里销毁的是 loading task。 await pdfDoc.cleanup() - await pdfDoc.destroy() + await loadingTask.destroy() return { content: fullText.trim(), diff --git a/src/renderer/src/components/notebook/source/reader/PdfSourceReader.tsx b/src/renderer/src/components/notebook/source/reader/PdfSourceReader.tsx index 852982f..c9f9162 100644 --- a/src/renderer/src/components/notebook/source/reader/PdfSourceReader.tsx +++ b/src/renderer/src/components/notebook/source/reader/PdfSourceReader.tsx @@ -10,7 +10,7 @@ import { type ReactElement } from 'react' import * as pdfjs from 'pdfjs-dist' -import type { PDFDocumentProxy, RenderTask } from 'pdfjs-dist' +import type { PDFDocumentLoadingTask, PDFDocumentProxy, RenderTask } from 'pdfjs-dist' import workerUrl from 'pdfjs-dist/build/pdf.worker.min.mjs?url' import { useTranslation } from 'react-i18next' import { Minus, Plus, Loader2 } from 'lucide-react' @@ -202,18 +202,29 @@ const PdfSourceReader = forwardRef(function useEffect(() => { let cancelled = false - let loaded: PDFDocumentProxy | null = null + // pdfjs-dist 6.x moved `destroy()` off `PDFDocumentProxy` and onto the loading task, + // so the task is what has to be held on to for teardown (the document keeps only + // `cleanup()`). + let loaded: PDFDocumentLoadingTask | null = null const load = async (): Promise => { const response = await fetch(documentUrl(documentId)) if (!response.ok) throw new Error(`Document request failed: ${response.status}`) const data = new Uint8Array(await response.arrayBuffer()) - const doc = await pdfjs.getDocument({ data }).promise + // 这个 reader 只做 `page.render()`(canvas)和 `TextLayer`,刻意不构造 AnnotationLayer、 + // 也不导入 `pdfjs-dist/web/*` —— 而 `enableScripting` 只存在于 AnnotationLayer / viewer + // 上,不在 `getDocument` 参数里,所以这里没有可以传的开关(#121 / + // GHSA-hq66-cqwq-w95j)。也就是说**在当前检查过的调用点下漏洞路径不可达**, + // 前提由 `test/pdfjsScriptingBoundary.test.ts` 守住。 + const task = pdfjs.getDocument({ data }) + loaded = task + const doc = await task.promise if (cancelled) { - await doc.destroy() + // 置空再销毁,让卸载路径不再重复销毁同一个 task。 + loaded = null + await task.destroy() return } - loaded = doc setPdf(doc) setNumPages(doc.numPages) setStatus('ready') diff --git a/test/pdfjsScriptingBoundary.test.ts b/test/pdfjsScriptingBoundary.test.ts new file mode 100644 index 0000000..dabbceb --- /dev/null +++ b/test/pdfjsScriptingBoundary.test.ts @@ -0,0 +1,136 @@ +import { test } from 'node:test' +import assert from 'node:assert/strict' +import { readFileSync, readdirSync, statSync } from 'node:fs' +import { join } from 'node:path' + +/** + * 守住 PDF 脚本执行的边界(#121 / GHSA-hq66-cqwq-w95j)。 + * + * 这条漏洞的官方 workaround 是「把 `enableScripting` 设为 false 或加 CSP」。但对这个仓库 + * 来说那个开关**不存在**:`enableScripting` 只声明在 `annotation_layer.d.ts`、 + * `annotation_layer_builder.d.ts` 和 `pdf_viewer.d.ts` 上,**不在 `getDocument` 的参数里** —— + * 它是 viewer / AnnotationLayer 的参数,不是 API 的参数。真正执行文档内 JavaScript 的 + * `PDFScriptingManager` 也只在 viewer build(`pdfjs-dist/web/*`)里,而 API build + * `build/pdf.mjs` 里根本没有它。 + * + * 于是 KnowNote 的 mitigation 是结构性的:**不构造 AnnotationLayer,也不引入 viewer**。 + * 这个前提一直是成立的,但它此前只是「我们碰巧没写」,没人守着 —— 而它正是 #121 里 + * 「当前检查过的调用点下漏洞路径不可达」这个结论唯一依赖的东西。这个测试把那条结论从 + * 一次性检查变成持续保证:谁把 annotation layer 或 viewer 拉进来,CI 会在这里失败。 + * + * 失败时该怎么做:如果确实需要 AnnotationLayer,就给它的参数显式传 + * `enableScripting: false`,然后回到 #121 重新评估可达性 —— 不要只是把这个测试改绿。 + */ + +/** 仓库里的渲染进程/主进程源码;测试与脚本不在扫描范围内。 */ +const SCAN_ROOTS = ['src'] + +const walk = (dir: string, files: string[] = []): string[] => { + for (const entry of readdirSync(dir)) { + const path = join(dir, entry) + if (statSync(path).isDirectory()) walk(path, files) + else if (/\.(ts|tsx|mts|cts|js|mjs|cjs)$/.test(path)) files.push(path) + } + return files +} + +const sourceFiles = (): string[] => SCAN_ROOTS.flatMap((root) => walk(root)) + +/** 只取 import / require / 动态 import 位置上的说明符,避免匹配到注释里的普通提及。 */ +const importSpecifiers = (source: string): string[] => { + const pattern = /(?:from\s*|import\s*\(\s*|require\s*\(\s*|import\s+)['"]([^'"\n]+)['"]/g + return [...source.matchAll(pattern)].map((match) => match[1]) +} + +/** viewer build —— `PDFScriptingManager` 只存在于这里。 */ +const isViewerImport = (specifier: string): boolean => + specifier === 'pdfjs-dist/web' || + specifier.startsWith('pdfjs-dist/web/') || + specifier.includes('pdf_viewer') + +test('no source file imports the pdfjs viewer build, where the scripting manager lives', () => { + const offenders: string[] = [] + + for (const file of sourceFiles()) { + for (const specifier of importSpecifiers(readFileSync(file, 'utf8'))) { + if (isViewerImport(specifier)) offenders.push(`${file} imports ${specifier}`) + } + } + + assert.deepEqual( + offenders, + [], + 'The pdfjs viewer build carries PDFScriptingManager, which is what executes JavaScript ' + + 'embedded in a PDF. Importing it puts that path back in scope for GHSA-hq66-cqwq-w95j ' + + '(#121). If it is genuinely needed, pass `enableScripting: false` explicitly and re-assess.' + ) +}) + +test('no source file constructs the annotation layer or the scripting manager', () => { + const forbidden = new Set([ + 'AnnotationLayer', + 'AnnotationLayerBuilder', + 'PDFScriptingManager', + 'ScriptingManager' + ]) + const offenders: string[] = [] + + for (const file of sourceFiles()) { + // Collect every constructed name with one static pattern and filter, rather than + // building a regex per name. Comments are naturally exempt: `new X(` is what + // matters, so prose explaining why we avoid these classes stays valid. + for (const match of readFileSync(file, 'utf8').matchAll(/\bnew\s+([A-Za-z_$][\w$]*)\s*\(/g)) { + if (forbidden.has(match[1])) offenders.push(`${file} constructs ${match[1]}`) + } + } + + assert.deepEqual( + offenders, + [], + 'These classes consume `enableScripting`, and the manager is what runs document JavaScript. ' + + 'Constructing one re-enables the path described in #121; if that is intended, the ' + + '`enableScripting: false` option must be passed explicitly and the reachability analysis redone.' + ) +}) + +test('`enableScripting` is never left on', () => { + const offenders: string[] = [] + + for (const file of sourceFiles()) { + const source = readFileSync(file, 'utf8') + if (/enableScripting\s*:\s*true/.test(source)) offenders.push(file) + } + + assert.deepEqual( + offenders, + [], + '`enableScripting: true` is the precondition of GHSA-hq66-cqwq-w95j (#121). It is not a ' + + '`getDocument` option either, so seeing it here means an annotation layer or viewer was added.' + ) +}) + +test('the guard actually scans the source tree', () => { + // A boundary test that silently scans nothing is worse than no test: it would report the + // invariant as enforced while checking no files at all. + const files = sourceFiles() + + assert.ok(files.length > 50, `expected to scan the source tree, got ${files.length} files`) + assert.ok( + files.some((file) => file.endsWith(join('source', 'reader', 'PdfSourceReader.tsx'))), + 'the PDF reader itself must be inside the scanned set' + ) + assert.ok( + files.some((file) => file.endsWith(join('loaders', 'PdfLoader.ts'))), + 'the main-process PDF loader must be inside the scanned set' + ) + + // And the extraction really finds imports, including the pdfjs one that is allowed. + const reader = files.find((file) => + file.endsWith(join('source', 'reader', 'PdfSourceReader.tsx')) + ) + assert.ok(reader) + assert.ok( + importSpecifiers(readFileSync(reader, 'utf8')).includes('pdfjs-dist'), + 'import extraction found no pdfjs specifier in the reader' + ) +})