From 6cff0564e9e1f3f64035a2bcb2758855c2f9353c Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:43:04 +0100 Subject: [PATCH 1/3] Fix incorrect user/ownerPassword entries in sample tests --- tests/Samples/SamplesTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/Samples/SamplesTest.php b/tests/Samples/SamplesTest.php index 625b24b7..7544a316 100644 --- a/tests/Samples/SamplesTest.php +++ b/tests/Samples/SamplesTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\Attributes\CoversNothing; use PHPUnit\Framework\Attributes\DataProviderExternal; use PHPUnit\Framework\TestCase; +use PrinsFrank\PdfParser\Document\Security\StandardSecurity; use PrinsFrank\PdfParser\Document\Version\Version; use PrinsFrank\PdfParser\PdfParser; use PrinsFrank\PdfParser\Tests\Samples\Info\FileInfo; @@ -19,7 +20,9 @@ class SamplesTest extends TestCase { /** @throws TypeError|ValueError|RuntimeException */ #[DataProviderExternal(SampleProvider::class, 'samples')] public function testExternalSourcePDFs(FileInfo $fileInfo): void { - $document = (new PdfParser())->parseFile($fileInfo->pdfPath); + $document = (new PdfParser()) + ->parseFile($fileInfo->pdfPath, security: new StandardSecurity($fileInfo->userPassword, $fileInfo->ownerPassword)); + static::assertSame(Version::from(number_format($fileInfo->version / 10, 1)), $document->version); static::assertSame($fileInfo->title, $document->getInformationDictionary()?->getTitle()); static::assertSame($fileInfo->producer, $document->getInformationDictionary()?->getProducer()); From f0a10bd3291b157b68da898fa008ba6e3e055ab7 Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:43:33 +0100 Subject: [PATCH 2/3] Update test name now that samples are no longer external --- tests/Samples/SamplesTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Samples/SamplesTest.php b/tests/Samples/SamplesTest.php index 7544a316..e4b69768 100644 --- a/tests/Samples/SamplesTest.php +++ b/tests/Samples/SamplesTest.php @@ -19,7 +19,7 @@ class SamplesTest extends TestCase { /** @throws TypeError|ValueError|RuntimeException */ #[DataProviderExternal(SampleProvider::class, 'samples')] - public function testExternalSourcePDFs(FileInfo $fileInfo): void { + public function testSamples(FileInfo $fileInfo): void { $document = (new PdfParser()) ->parseFile($fileInfo->pdfPath, security: new StandardSecurity($fileInfo->userPassword, $fileInfo->ownerPassword)); From 04bff0b61c2f1307ff5572393680b23d9731a782 Mon Sep 17 00:00:00 2001 From: PrinsFrank <25006490+PrinsFrank@users.noreply.github.com> Date: Tue, 4 Nov 2025 20:44:08 +0100 Subject: [PATCH 3/3] Re-enable support for encrypted documents --- src/Document/Document.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Document/Document.php b/src/Document/Document.php index 7dbc6348..f4db05dc 100644 --- a/src/Document/Document.php +++ b/src/Document/Document.php @@ -20,6 +20,7 @@ use PrinsFrank\PdfParser\Document\Object\Item\UncompressedObject\UncompressedObjectParser; use PrinsFrank\PdfParser\Document\Security\StandardSecurity; use PrinsFrank\PdfParser\Document\Version\Version; +use PrinsFrank\PdfParser\Exception\AuthenticationFailedException; use PrinsFrank\PdfParser\Exception\NotImplementedException; use PrinsFrank\PdfParser\Exception\ParseFailureException; use PrinsFrank\PdfParser\Exception\PdfParserException; @@ -40,8 +41,16 @@ public function __construct( public readonly CrossReferenceSource $crossReferenceSource, public ?StandardSecurity $security, ) { - if ($this->getEncryptDictionary() !== null) { - throw new NotImplementedException('Encrypted documents are not supported yet'); + if (($encryptDictionary = $this->getEncryptDictionary()) !== null) { + if ($encryptDictionary->getSecurityHandler() === null) { + throw new NotImplementedException('Empty security handler is not supported'); + } + + $this->security ??= new StandardSecurity(); + if ($this->security->isUserPasswordValid($encryptDictionary, $crossReferenceSource->getFirstId()) === false + && $this->security->isOwnerPasswordValid($encryptDictionary, $crossReferenceSource->getFirstId()) === false) { + throw new AuthenticationFailedException($security === null ? 'Document could not be decrypted using default credentials, please supply an owner or user password' : 'User and owner password are invalid, please supply valid credentials'); + } } }