From 9a264da8f02f825df2cd549ff2813318d8284834 Mon Sep 17 00:00:00 2001 From: PuLLi <112799107+the-pulli@users.noreply.github.com> Date: Wed, 3 May 2023 09:23:14 +0200 Subject: [PATCH 1/4] Add PGP feature to MIME component --- .../Component/Mime/Crypto/PGPEncrypter.php | 190 ++++++++++++++++++ .../Mime/Helper/PGPSigningPreparer.php | 71 +++++++ .../Mime/Part/Multipart/PGPEncryptedPart.php | 25 +++ .../Mime/Part/Multipart/PGPSignedPart.php | 52 +++++ .../Part/PGPEncryptedInitializationPart.php | 36 ++++ .../Mime/Part/PGPEncryptedMessagePart.php | 46 +++++ .../Component/Mime/Part/PGPKeyPart.php | 45 +++++ .../Component/Mime/Part/PGPSignaturePart.php | 48 +++++ .../Mime/Tests/Crypto/PGPEncryptorTest.php | 72 +++++++ .../Mime/Tests/Fixtures/_data/pgp.asc | 158 +++++++++++++++ .../Part/Multipart/PGPEncryptedPartTest.php | 20 ++ .../Part/Multipart/PGPSignedPartTest.php | 22 ++ .../PGPEncryptedInitializationPartTest.php | 19 ++ .../Part/PGPEncryptedMessagePartTest.php | 19 ++ .../Mime/Tests/Part/PGPKeyPartTest.php | 31 +++ .../Mime/Tests/Part/PGPSignaturePartTest.php | 22 ++ src/Symfony/Component/Mime/composer.json | 3 +- 17 files changed, 878 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Mime/Crypto/PGPEncrypter.php create mode 100644 src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php create mode 100644 src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php create mode 100644 src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php create mode 100644 src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php create mode 100644 src/Symfony/Component/Mime/Part/PGPKeyPart.php create mode 100644 src/Symfony/Component/Mime/Part/PGPSignaturePart.php create mode 100644 src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Fixtures/_data/pgp.asc create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php create mode 100644 src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php diff --git a/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php b/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php new file mode 100644 index 0000000000000..ad3e03e921bb4 --- /dev/null +++ b/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php @@ -0,0 +1,190 @@ + + */ +class PGPEncrypter +{ + use PGPSigningPreparer; + + private Crypt_GPG $gpg; + + private Headers $headers; + + private ?string $signingKey = null; + + public string $signature = ''; + + public string $signed = ''; + + /** + * @throws Crypt_GPG_FileException + * @throws PEAR_Exception + */ + public function __construct(array $options = []) + { + $this->gpg = new Crypt_GPG( + array_merge( + $options, + [ + 'cipher-algo' => 'AES256', + 'digest-algo' => 'SHA512', + ] + ) + ); + } + + public function signingKey(string $keyIdentifier): void + { + $this->signingKey = $keyIdentifier; + } + + /** + * @throws Crypt_GPG_Exception + * @throws Crypt_GPG_KeyNotFoundException + */ + public function encrypt(Message $message, bool $attachKey = false): Message + { + return $this->encryptWithOrWithoutSigning($message, false, null, $attachKey); + } + + /** + * @throws Crypt_GPG_Exception + * @throws Crypt_GPG_KeyNotFoundException + * @throws Crypt_GPG_BadPassphraseException + */ + public function encryptAndSign(Message $message, ?string $passphrase = null, bool $attachKey = false): Message + { + return $this->encryptWithOrWithoutSigning($message, true, $passphrase, $attachKey); + } + + /** + * @throws Crypt_GPG_Exception + * @throws Crypt_GPG_KeyNotFoundException + * @throws Crypt_GPG_BadPassphraseException + */ + private function encryptWithOrWithoutSigning(Message $message, bool $sign = false, ?string $passphrase = null, bool $attachKey = false): Message + { + $this->headers = $message->getHeaders(); + $body = $message->getBody(); + + foreach ($this->getRecipients() as $recipient) { + $this->gpg->addEncryptKey($recipient); + } + + if ($attachKey) { + $body = $this->attachPublicKey($message); + } + + if ($sign) { + $this->gpg->addSignKey($this->determineSigningKey(), $passphrase); + $body = $this->gpg->encryptAndSign($body->toString()); + } else { + $body = $this->gpg->encrypt($body->toString()); + } + + $part = new PGPEncryptedPart( + new PGPEncryptedInitializationPart(), + new PGPEncryptedMessagePart($body) + ); + + return new Message($this->headers, $part); + } + + /** + * @throws Crypt_GPG_Exception + * @throws Crypt_GPG_KeyNotFoundException + * @throws Crypt_GPG_BadPassphraseException + */ + public function sign(Message $message, ?string $passphrase = null, bool $attachKey = false): Message + { + $this->headers = $message->getHeaders(); + $body = $message->getBody()->toString(); + $messagePart = $message->getBody(); + + if ($attachKey) { + $mixed = $this->attachPublicKey($message); + $body = $mixed->toString(); + $messagePart = $mixed; + } + // TODO: find a way to normalize Message body and pass it along to PGPSignedPart + $body = $this->prepareMessageForSigning($messagePart, $body); + $this->signed = $body; + + $this->gpg->addSignKey($this->determineSigningKey(), $passphrase); + $signature = $this->gpg->sign($body, Crypt_GPG::SIGN_MODE_DETACHED); + $this->signature = $signature; + $part = new PGPSignedPart( + $messagePart, + new PGPSignaturePart($signature) + ); + + return new Message($this->headers, $part); + } + + /** + * @throws Crypt_GPG_Exception + * @throws Crypt_GPG_KeyNotFoundException + */ + private function attachPublicKey(Message $message): MixedPart + { + $publicKey = $this->gpg->exportPublicKey($this->determineSigningKey()); + $key = new PGPKeyPart($publicKey); + + // TODO: find more elegant way than to create another MixedPart, if Message is already a MixedPart + return new MixedPart($message->getBody(), $key); + } + + private function getRecipients(): array + { + $recipients = [ + $this->getAddresses('to'), + $this->getAddresses('cc'), + $this->getAddresses('bcc') + ]; + + return array_merge(...$recipients); + } + + private function getFrom(): string + { + return $this->getAddresses('from')[0]; + } + + private function getAddresses(string $type): array + { + $addresses = []; + $addressType = $this->headers->get($type); + if ($addressType) { + foreach ($addressType->getAddresses() as $address) { + $addresses[] = $address->getAddress(); + } + } + + return $addresses; + } + + private function determineSigningKey(): string + { + return $this->signingKey ?? $this->getFrom(); + } +} diff --git a/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php b/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php new file mode 100644 index 0000000000000..6c0f73d803f8d --- /dev/null +++ b/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php @@ -0,0 +1,71 @@ + + * + */ +trait PGPSigningPreparer +{ + /** + * @param string $text + * @return string + */ + protected function normalizeLineEnding(string $text): string + { + return str_replace("\n", "\r\n", str_replace(["\r\n", "\r"], "\n", $text)); + } + + /** + * @param AbstractPart $part + * @param string $msg + * @return string + */ + protected function prepareMessageForSigning(AbstractPart $part, string $msg): string + { + // Only text part + if ($part->getMediaType() === 'text') { + $msg = $this->getMessage($part, $msg); + } elseif ($part->getMediaType() === 'multipart') { + // Find the text part inside the multipart + $msg = $this->findTextPart($part->getParts(), $msg); + } + + return $msg; + } + + /** + * @param AbstractPart[] $parts + * @param string $msg + * @return string + */ + protected function findTextPart(array $parts, string $msg): string + { + foreach ($parts as $part) { + $msg = $this->prepareMessageForSigning($part, $msg); + } + + return $msg; + } + + /** + * @param AbstractPart $part + * @param string $msg + * @return string + */ + protected function getMessage(AbstractPart $part, string $msg): string + { + $textPart = $part->toString(); + $normalizedText = $this->normalizeLineEnding($textPart); + + // If text part has no extra line endings, add them + if (str_contains("\r\n--", $textPart)) { + return str_replace("$textPart\r\n--", "$normalizedText\r\n\r\n--", $msg); + } + + return str_replace($textPart, "$normalizedText\r\n", $msg); + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php b/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php new file mode 100644 index 0000000000000..b75486aaef5fb --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php @@ -0,0 +1,25 @@ + + */ +class PGPEncryptedPart extends AbstractMultipartPart +{ + public function __construct(AbstractPart ...$parts) + { + parent::__construct(...$parts); + $this->getHeaders()->addParameterizedHeader('Content-Type', 'multipart/encrypted', [ + 'protocol' => 'application/pgp-encrypted', + ]); + } + + public function getMediaSubtype(): string + { + return 'encrypted'; + } +} diff --git a/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php b/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php new file mode 100644 index 0000000000000..cda66bc4b914b --- /dev/null +++ b/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php @@ -0,0 +1,52 @@ + + */ +class PGPSignedPart extends AbstractMultipartPart +{ + use PGPSigningPreparer; + + public function __construct(AbstractPart ...$parts) + { + parent::__construct(...$parts); + $this->getHeaders()->addParameterizedHeader('Content-Type', 'multipart/signed', [ + 'micalg' => 'pgp-sha512', + 'protocol' => 'application/pgp-signature', + ]); + } + + public function getMediaSubtype(): string + { + return 'signed'; + } + + public function toString(): string + { + // We only have a text/multipart and the signature + $parts = $this->getParts(); + + return $this->prepareMessageForSigning($parts[0], parent::toString()); + } + + public function toIterable(): iterable + { + yield $this->toString(); + } + + public function bodyToString(): string + { + return "This is an OpenPGP/MIME signed message (RFC 3156 and 4880).\r\n\r\n" . parent::bodyToString(); + } + + public function bodyToIterable(): iterable + { + yield $this->bodyToString(); + } +} diff --git a/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php b/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php new file mode 100644 index 0000000000000..08e7fc941f896 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php @@ -0,0 +1,36 @@ + + */ +class PGPEncryptedInitializationPart extends AbstractPart +{ + public function __construct() + { + parent::__construct(); + $this->getHeaders()->addTextHeader('Content-Disposition', 'attachment'); + } + public function bodyToString(): string + { + return "Version: 1\r\n"; + } + + public function bodyToIterable(): iterable + { + yield $this->bodyToString(); + } + + public function getMediaType(): string + { + return 'application'; + } + + public function getMediaSubtype(): string + { + return 'pgp-encrypted'; + } +} diff --git a/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php b/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php new file mode 100644 index 0000000000000..d9c0cd4413abf --- /dev/null +++ b/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php @@ -0,0 +1,46 @@ + + */ +class PGPEncryptedMessagePart extends AbstractPart +{ + use PGPSigningPreparer; + + private string $body; + + public function __construct(string $body) + { + parent::__construct(); + + $this->body = $this->normalizeLineEnding($body); + $this->getHeaders()->addParameterizedHeader('Content-Disposition', 'inline', [ + 'filename' => 'msg.asc', + ]); + } + + public function bodyToString(): string + { + return $this->body; + } + + public function bodyToIterable(): iterable + { + yield $this->body; + } + + public function getMediaType(): string + { + return 'application'; + } + + public function getMediaSubtype(): string + { + return 'octet-stream'; + } +} diff --git a/src/Symfony/Component/Mime/Part/PGPKeyPart.php b/src/Symfony/Component/Mime/Part/PGPKeyPart.php new file mode 100644 index 0000000000000..d169a58dc81d5 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/PGPKeyPart.php @@ -0,0 +1,45 @@ + + */ +class PGPKeyPart extends AbstractPart +{ + private string $key; + + public function __construct(string $key, string $keyName = 'public-key.asc') + { + parent::__construct(); + $this->key = $key; + $headers = $this->getHeaders(); + $headers->addParameterizedHeader('Content-Disposition', 'attachment', [ + 'filename' => $keyName, + ]); + $headers->addTextHeader('Content-Transfer-Encoding', 'base64'); + $headers->addTextHeader('MIME-Version', '1.0'); + } + + public function bodyToString(): string + { + return $this->key; + } + + public function bodyToIterable(): iterable + { + yield $this->key; + } + + public function getMediaType(): string + { + return 'application'; + } + + public function getMediaSubtype(): string + { + return 'pgp-keys'; + } +} diff --git a/src/Symfony/Component/Mime/Part/PGPSignaturePart.php b/src/Symfony/Component/Mime/Part/PGPSignaturePart.php new file mode 100644 index 0000000000000..409df900f26b1 --- /dev/null +++ b/src/Symfony/Component/Mime/Part/PGPSignaturePart.php @@ -0,0 +1,48 @@ + + */ +class PGPSignaturePart extends AbstractPart +{ + private string $signature; + + public function __construct(string $signature) + { + parent::__construct(); + $this->signature = $signature; + $headers = $this->getHeaders(); + $headers->addParameterizedHeader('Content-Type', 'application/pgp-signature', [ + 'name' => 'OpenPGP_signature.asc', + ]); + $headers->addParameterizedHeader('Content-Disposition', 'attachment', [ + 'filename' => 'OpenPGP_signature', + ]); + $headers->addTextHeader('Content-Description', 'OpenPGP digital signature'); + $headers->addTextHeader('MIME-Version', '1.0'); + } + + public function bodyToString(): string + { + return $this->signature; + } + + public function bodyToIterable(): iterable + { + yield $this->signature; + } + + public function getMediaType(): string + { + return 'application'; + } + + public function getMediaSubtype(): string + { + return 'pgp-signature'; + } +} diff --git a/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php b/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php new file mode 100644 index 0000000000000..6dccddc5381eb --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php @@ -0,0 +1,72 @@ +gpg = new Crypt_GPG(); + $this->gpg->importKeyFile(__DIR__ . '/../Fixtures/_data/pgp.asc'); + $this->email = (new Email()) + ->from(new Address('pgp@pulli.dev', 'PuLLi')) + ->to(new Address('pgp@pulli.dev', 'PuLLi')) + ->text("Hello there!\n\nHow are you?") + ->subject('PGP Mail'); + $this->encrypter = new PGPEncrypter(); + } + + public function tearDown(): void + { + $this->removeKey('pgp@pulli.dev'); + parent::tearDown(); + } + + public function testEncrypting() + { + $encrypted = ($this->encrypter->encrypt($this->email))->toString(); + $this->assertStringContainsString('-----BEGIN PGP MESSAGE-----', $encrypted); + $this->assertStringContainsString('-----END PGP MESSAGE-----', $encrypted); + } + + public function testEncryptingAndSigning() + { + $encrypted = ($this->encrypter->encryptAndSign($this->email, 'test1234'))->toString(); + $this->assertStringContainsString('-----BEGIN PGP MESSAGE-----', $encrypted); + $this->assertStringContainsString('-----END PGP MESSAGE-----', $encrypted); + $this->assertStringNotContainsString('-----BEGIN PGP SIGNATURE-----', $encrypted); + $this->assertStringNotContainsString('-----END PGP SIGNATURE-----', $encrypted); + } + + public function testSigning() + { + $this->encrypter->sign($this->email, 'test1234'); + $this->assertStringContainsString('-----BEGIN PGP SIGNATURE-----', $this->encrypter->signature); + $this->assertStringContainsString('-----END PGP SIGNATURE-----', $this->encrypter->signature); + + $key = $this->gpg->verify($this->encrypter->signed, $this->encrypter->signature); + $this->assertCount(1, $key); + $this->assertEquals('pgp@pulli.dev', $key[0]->getUserId()->getEmail()); + } + + private function removeKey(string $name) + { + $this->gpg->deletePrivateKey($name); + $this->gpg->deletePublicKey($name); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/_data/pgp.asc b/src/Symfony/Component/Mime/Tests/Fixtures/_data/pgp.asc new file mode 100644 index 0000000000000..b5436430b9087 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Fixtures/_data/pgp.asc @@ -0,0 +1,158 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +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 +cvLFBoHiJ0sMhrEfncqtBJnOCw== +=cAza +-----END PGP PRIVATE KEY BLOCK----- +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +=w8wH +-----END PGP PUBLIC KEY BLOCK----- diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php new file mode 100644 index 0000000000000..7a4a9791c02d3 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php @@ -0,0 +1,20 @@ +toString(); + $this->assertStringContainsString('Content-Type: multipart/encrypted', $part, 'Content-Type not found.'); + $this->assertStringContainsString('protocol="application/pgp-encrypted"', $part, 'Protocol not found'); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php new file mode 100644 index 0000000000000..2e747d34090f4 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php @@ -0,0 +1,22 @@ +toString(); + $this->assertStringContainsString('Content-Type: multipart/signed', $part, 'Content-Type not found'); + $this->assertStringContainsString('micalg=pgp-sha512', $part, 'micalg not found'); + $this->assertStringContainsString('protocol="application/pgp-signature"', $part, 'protocol not found'); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php new file mode 100644 index 0000000000000..f88898c93d86b --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php @@ -0,0 +1,19 @@ +toString(); + $this->assertStringContainsString('Content-Type: application/pgp-encrypted', $part, 'Content-Type not found'); + $this->assertStringContainsString('Content-Disposition: attachment', $part, 'Content-Disposition not found'); + $this->assertStringContainsString("\r\n\r\nVersion: 1\r\n", $part, 'Version not found'); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php new file mode 100644 index 0000000000000..fbfc7cbabe184 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php @@ -0,0 +1,19 @@ +toString(); + $this->assertStringContainsString('Content-Type: application/octet-stream', $part, 'Content-Type not found'); + $this->assertStringContainsString('Content-Disposition: inline', $part, 'Content-Disposition not found'); + $this->assertStringContainsString('filename=msg.asc', $part, 'filename not found'); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php new file mode 100644 index 0000000000000..a91d7443f9a19 --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php @@ -0,0 +1,31 @@ +toString(); + $this->assertStringContainsString('Content-Type: application/pgp-key', $part, 'Content-Type not found'); + $this->assertStringContainsString('Content-Disposition: attachment', $part, 'Content-Disposition not found'); + $this->assertStringContainsString('filename=public-key.asc', $part, 'filename not found'); + $this->assertStringContainsString('Content-Transfer-Encoding: base64', $part, 'Content-Transfer-Encoding not found'); + $this->assertStringContainsString('MIME-Version: 1.0', $part, 'MIME-Version not found'); + } + + public function testPGPKeyPartWithCustomKeyName() + { + $part = (new PGPKeyPart('', 'custom.asc'))->toString(); + $this->assertStringContainsString('Content-Type: application/pgp-key', $part, 'Content-Type not found'); + $this->assertStringContainsString('Content-Disposition: attachment', $part, 'Content-Disposition not found'); + $this->assertStringContainsString('filename=custom.asc', $part, 'filename not found'); + $this->assertStringContainsString('Content-Transfer-Encoding: base64', $part, 'Content-Transfer-Encoding not found'); + $this->assertStringContainsString('MIME-Version: 1.0', $part, 'MIME-Version not found'); + } +} diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php new file mode 100644 index 0000000000000..202502306536d --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php @@ -0,0 +1,22 @@ +toString(); + $this->assertStringContainsString('Content-Type: application/pgp-signature', $part, 'Content-Type not found'); + $this->assertStringContainsString('name=OpenPGP_signature.asc', $part, 'name not found'); + $this->assertStringContainsString('Content-Disposition: attachment', $part, 'Content-Disposition not found'); + $this->assertStringContainsString('filename=OpenPGP_signature', $part, 'filename not found'); + $this->assertStringContainsString('Content-Description: OpenPGP digital signature', $part, 'Content-Description not found'); + $this->assertStringContainsString('MIME-Version: 1.0', $part, 'MIME-Version not found'); + } +} diff --git a/src/Symfony/Component/Mime/composer.json b/src/Symfony/Component/Mime/composer.json index adaf43852f9fa..d4866c0ebceb1 100644 --- a/src/Symfony/Component/Mime/composer.json +++ b/src/Symfony/Component/Mime/composer.json @@ -18,7 +18,8 @@ "require": { "php": ">=8.1", "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0" + "symfony/polyfill-mbstring": "^1.0", + "pear/crypt_gpg": "^1.6" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", From d1e43744b6383237a57e2fe273900f28c8d9f295 Mon Sep 17 00:00:00 2001 From: PuLLi <112799107+the-pulli@users.noreply.github.com> Date: Wed, 3 May 2023 12:47:40 +0200 Subject: [PATCH 2/4] Add pear/crypt_gpg to global composer.json --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5d10d8b2a366e..5f2c67d2a5bea 100644 --- a/composer.json +++ b/composer.json @@ -54,7 +54,8 @@ "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php83": "^1.27", - "symfony/polyfill-uuid": "^1.15" + "symfony/polyfill-uuid": "^1.15", + "pear/crypt_gpg": "^1.6" }, "replace": { "symfony/asset": "self.version", From c02db65c331f01d696732c94928216541ba1c018 Mon Sep 17 00:00:00 2001 From: PuLLi <112799107+the-pulli@users.noreply.github.com> Date: Wed, 3 May 2023 15:43:18 +0200 Subject: [PATCH 3/4] Applying style changes, license info and psalm --- composer.json | 4 +- .../Component/Mime/Crypto/PGPEncrypter.php | 68 ++++++++++--------- .../Mime/Helper/PGPSigningPreparer.php | 30 ++++---- .../Mime/Part/Multipart/PGPSignedPart.php | 2 +- .../Part/PGPEncryptedInitializationPart.php | 12 +++- .../Mime/Part/PGPEncryptedMessagePart.php | 10 ++- .../Component/Mime/Part/PGPKeyPart.php | 11 ++- .../Component/Mime/Part/PGPSignaturePart.php | 11 ++- .../Mime/Tests/Crypto/PGPEncryptorTest.php | 24 ++++--- .../Part/Multipart/PGPEncryptedPartTest.php | 9 ++- .../Part/Multipart/PGPSignedPartTest.php | 9 ++- .../PGPEncryptedInitializationPartTest.php | 9 +++ .../Part/PGPEncryptedMessagePartTest.php | 9 +++ .../Mime/Tests/Part/PGPKeyPartTest.php | 9 +++ .../Mime/Tests/Part/PGPSignaturePartTest.php | 9 +++ .../Mime/Tests/{Fixtures => }/_data/pgp.asc | 0 src/Symfony/Component/Mime/composer.json | 4 +- 17 files changed, 158 insertions(+), 72 deletions(-) rename src/Symfony/Component/Mime/Tests/{Fixtures => }/_data/pgp.asc (100%) diff --git a/composer.json b/composer.json index 5f2c67d2a5bea..a5cd0093b1ea7 100644 --- a/composer.json +++ b/composer.json @@ -40,6 +40,7 @@ "doctrine/event-manager": "^1.2|^2", "doctrine/persistence": "^2|^3", "twig/twig": "^2.13|^3.0.4", + "pear/crypt_gpg": "^1.6", "psr/cache": "^2.0|^3.0", "psr/clock": "^1.0", "psr/container": "^1.1|^2.0", @@ -54,8 +55,7 @@ "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php83": "^1.27", - "symfony/polyfill-uuid": "^1.15", - "pear/crypt_gpg": "^1.6" + "symfony/polyfill-uuid": "^1.15" }, "replace": { "symfony/asset": "self.version", diff --git a/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php b/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php index ad3e03e921bb4..2e0113fcbcdae 100644 --- a/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php +++ b/src/Symfony/Component/Mime/Crypto/PGPEncrypter.php @@ -1,23 +1,27 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Crypto; -use Crypt_GPG; -use Crypt_GPG_BadPassphraseException; -use Crypt_GPG_Exception; -use Crypt_GPG_FileException; -use Crypt_GPG_KeyNotFoundException; -use PEAR_Exception; +use Symfony\Component\Mime\Header\Headers; +use Symfony\Component\Mime\Header\MailboxListHeader; use Symfony\Component\Mime\Helper\PGPSigningPreparer; +use Symfony\Component\Mime\Message; +use Symfony\Component\Mime\Part\Multipart\MixedPart; use Symfony\Component\Mime\Part\Multipart\PGPEncryptedPart; use Symfony\Component\Mime\Part\Multipart\PGPSignedPart; use Symfony\Component\Mime\Part\PGPEncryptedInitializationPart; use Symfony\Component\Mime\Part\PGPEncryptedMessagePart; use Symfony\Component\Mime\Part\PGPKeyPart; use Symfony\Component\Mime\Part\PGPSignaturePart; -use Symfony\Component\Mime\Header\Headers; -use Symfony\Component\Mime\Message; -use Symfony\Component\Mime\Part\Multipart\MixedPart; /* * @author PuLLi @@ -26,7 +30,7 @@ class PGPEncrypter { use PGPSigningPreparer; - private Crypt_GPG $gpg; + private \Crypt_GPG $gpg; private Headers $headers; @@ -37,12 +41,12 @@ class PGPEncrypter public string $signed = ''; /** - * @throws Crypt_GPG_FileException - * @throws PEAR_Exception + * @throws \Crypt_GPG_FileException + * @throws \PEAR_Exception */ public function __construct(array $options = []) { - $this->gpg = new Crypt_GPG( + $this->gpg = new \Crypt_GPG( array_merge( $options, [ @@ -59,8 +63,8 @@ public function signingKey(string $keyIdentifier): void } /** - * @throws Crypt_GPG_Exception - * @throws Crypt_GPG_KeyNotFoundException + * @throws \Crypt_GPG_Exception + * @throws \Crypt_GPG_KeyNotFoundException */ public function encrypt(Message $message, bool $attachKey = false): Message { @@ -68,21 +72,21 @@ public function encrypt(Message $message, bool $attachKey = false): Message } /** - * @throws Crypt_GPG_Exception - * @throws Crypt_GPG_KeyNotFoundException - * @throws Crypt_GPG_BadPassphraseException + * @throws \Crypt_GPG_Exception + * @throws \Crypt_GPG_KeyNotFoundException + * @throws \Crypt_GPG_BadPassphraseException */ - public function encryptAndSign(Message $message, ?string $passphrase = null, bool $attachKey = false): Message + public function encryptAndSign(Message $message, string $passphrase = null, bool $attachKey = false): Message { return $this->encryptWithOrWithoutSigning($message, true, $passphrase, $attachKey); } /** - * @throws Crypt_GPG_Exception - * @throws Crypt_GPG_KeyNotFoundException - * @throws Crypt_GPG_BadPassphraseException + * @throws \Crypt_GPG_Exception + * @throws \Crypt_GPG_KeyNotFoundException + * @throws \Crypt_GPG_BadPassphraseException */ - private function encryptWithOrWithoutSigning(Message $message, bool $sign = false, ?string $passphrase = null, bool $attachKey = false): Message + private function encryptWithOrWithoutSigning(Message $message, bool $sign = false, string $passphrase = null, bool $attachKey = false): Message { $this->headers = $message->getHeaders(); $body = $message->getBody(); @@ -111,11 +115,11 @@ private function encryptWithOrWithoutSigning(Message $message, bool $sign = fals } /** - * @throws Crypt_GPG_Exception - * @throws Crypt_GPG_KeyNotFoundException - * @throws Crypt_GPG_BadPassphraseException + * @throws \Crypt_GPG_Exception + * @throws \Crypt_GPG_KeyNotFoundException + * @throws \Crypt_GPG_BadPassphraseException */ - public function sign(Message $message, ?string $passphrase = null, bool $attachKey = false): Message + public function sign(Message $message, string $passphrase = null, bool $attachKey = false): Message { $this->headers = $message->getHeaders(); $body = $message->getBody()->toString(); @@ -131,7 +135,7 @@ public function sign(Message $message, ?string $passphrase = null, bool $attachK $this->signed = $body; $this->gpg->addSignKey($this->determineSigningKey(), $passphrase); - $signature = $this->gpg->sign($body, Crypt_GPG::SIGN_MODE_DETACHED); + $signature = $this->gpg->sign($body, \Crypt_GPG::SIGN_MODE_DETACHED); $this->signature = $signature; $part = new PGPSignedPart( $messagePart, @@ -142,8 +146,8 @@ public function sign(Message $message, ?string $passphrase = null, bool $attachK } /** - * @throws Crypt_GPG_Exception - * @throws Crypt_GPG_KeyNotFoundException + * @throws \Crypt_GPG_Exception + * @throws \Crypt_GPG_KeyNotFoundException */ private function attachPublicKey(Message $message): MixedPart { @@ -159,7 +163,7 @@ private function getRecipients(): array $recipients = [ $this->getAddresses('to'), $this->getAddresses('cc'), - $this->getAddresses('bcc') + $this->getAddresses('bcc'), ]; return array_merge(...$recipients); @@ -174,7 +178,7 @@ private function getAddresses(string $type): array { $addresses = []; $addressType = $this->headers->get($type); - if ($addressType) { + if ($addressType instanceof MailboxListHeader) { foreach ($addressType->getAddresses() as $address) { $addresses[] = $address->getAddress(); } diff --git a/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php b/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php index 6c0f73d803f8d..12076772812d9 100644 --- a/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php +++ b/src/Symfony/Component/Mime/Helper/PGPSigningPreparer.php @@ -1,7 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Helper; +use Symfony\Component\Mime\Part\AbstractMultipartPart; use Symfony\Component\Mime\Part\AbstractPart; /* @@ -10,26 +20,17 @@ */ trait PGPSigningPreparer { - /** - * @param string $text - * @return string - */ protected function normalizeLineEnding(string $text): string { return str_replace("\n", "\r\n", str_replace(["\r\n", "\r"], "\n", $text)); } - /** - * @param AbstractPart $part - * @param string $msg - * @return string - */ protected function prepareMessageForSigning(AbstractPart $part, string $msg): string { // Only text part - if ($part->getMediaType() === 'text') { + if ('text' === $part->getMediaType()) { $msg = $this->getMessage($part, $msg); - } elseif ($part->getMediaType() === 'multipart') { + } elseif ($part instanceof AbstractMultipartPart) { // Find the text part inside the multipart $msg = $this->findTextPart($part->getParts(), $msg); } @@ -39,8 +40,6 @@ protected function prepareMessageForSigning(AbstractPart $part, string $msg): st /** * @param AbstractPart[] $parts - * @param string $msg - * @return string */ protected function findTextPart(array $parts, string $msg): string { @@ -51,11 +50,6 @@ protected function findTextPart(array $parts, string $msg): string return $msg; } - /** - * @param AbstractPart $part - * @param string $msg - * @return string - */ protected function getMessage(AbstractPart $part, string $msg): string { $textPart = $part->toString(); diff --git a/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php b/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php index cda66bc4b914b..3b185d2041857 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php @@ -42,7 +42,7 @@ public function toIterable(): iterable public function bodyToString(): string { - return "This is an OpenPGP/MIME signed message (RFC 3156 and 4880).\r\n\r\n" . parent::bodyToString(); + return "This is an OpenPGP/MIME signed message (RFC 3156 and 4880).\r\n\r\n".parent::bodyToString(); } public function bodyToIterable(): iterable diff --git a/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php b/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php index 08e7fc941f896..f79e1c2d01c36 100644 --- a/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php +++ b/src/Symfony/Component/Mime/Part/PGPEncryptedInitializationPart.php @@ -1,8 +1,15 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -use Symfony\Component\Mime\Part\AbstractPart; +namespace Symfony\Component\Mime\Part; /* * @author PuLLi @@ -14,6 +21,7 @@ public function __construct() parent::__construct(); $this->getHeaders()->addTextHeader('Content-Disposition', 'attachment'); } + public function bodyToString(): string { return "Version: 1\r\n"; diff --git a/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php b/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php index d9c0cd4413abf..0646b842bbf13 100644 --- a/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php +++ b/src/Symfony/Component/Mime/Part/PGPEncryptedMessagePart.php @@ -1,9 +1,17 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Part; use Symfony\Component\Mime\Helper\PGPSigningPreparer; -use Symfony\Component\Mime\Part\AbstractPart; /* * @author PuLLi diff --git a/src/Symfony/Component/Mime/Part/PGPKeyPart.php b/src/Symfony/Component/Mime/Part/PGPKeyPart.php index d169a58dc81d5..0219b5fe92f4d 100644 --- a/src/Symfony/Component/Mime/Part/PGPKeyPart.php +++ b/src/Symfony/Component/Mime/Part/PGPKeyPart.php @@ -1,8 +1,15 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -use Symfony\Component\Mime\Part\AbstractPart; +namespace Symfony\Component\Mime\Part; /* * @author PuLLi diff --git a/src/Symfony/Component/Mime/Part/PGPSignaturePart.php b/src/Symfony/Component/Mime/Part/PGPSignaturePart.php index 409df900f26b1..9402baa973ffc 100644 --- a/src/Symfony/Component/Mime/Part/PGPSignaturePart.php +++ b/src/Symfony/Component/Mime/Part/PGPSignaturePart.php @@ -1,8 +1,15 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ -use Symfony\Component\Mime\Part\AbstractPart; +namespace Symfony\Component\Mime\Part; /* * @author PuLLi diff --git a/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php b/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php index 6dccddc5381eb..1f25e68a3ae5f 100644 --- a/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php +++ b/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php @@ -1,8 +1,16 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Tests\Crypto; -use Crypt_GPG; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Address; @@ -12,17 +20,17 @@ #[CoversClass(PGPEncrypter::class)] final class PGPEncryptorTest extends TestCase { - private Crypt_GPG $gpg; + private \Crypt_GPG $gpg; private Email $email; private PGPEncrypter $encrypter; - public function setUp(): void + protected function setUp(): void { parent::setUp(); - $this->gpg = new Crypt_GPG(); - $this->gpg->importKeyFile(__DIR__ . '/../Fixtures/_data/pgp.asc'); + $this->gpg = new \Crypt_GPG(); + $this->gpg->importKeyFile(__DIR__ . '/../_data/pgp.asc'); $this->email = (new Email()) ->from(new Address('pgp@pulli.dev', 'PuLLi')) ->to(new Address('pgp@pulli.dev', 'PuLLi')) @@ -31,7 +39,7 @@ public function setUp(): void $this->encrypter = new PGPEncrypter(); } - public function tearDown(): void + protected function tearDown(): void { $this->removeKey('pgp@pulli.dev'); parent::tearDown(); @@ -39,14 +47,14 @@ public function tearDown(): void public function testEncrypting() { - $encrypted = ($this->encrypter->encrypt($this->email))->toString(); + $encrypted = $this->encrypter->encrypt($this->email)->toString(); $this->assertStringContainsString('-----BEGIN PGP MESSAGE-----', $encrypted); $this->assertStringContainsString('-----END PGP MESSAGE-----', $encrypted); } public function testEncryptingAndSigning() { - $encrypted = ($this->encrypter->encryptAndSign($this->email, 'test1234'))->toString(); + $encrypted = $this->encrypter->encryptAndSign($this->email, 'test1234')->toString(); $this->assertStringContainsString('-----BEGIN PGP MESSAGE-----', $encrypted); $this->assertStringContainsString('-----END PGP MESSAGE-----', $encrypted); $this->assertStringNotContainsString('-----BEGIN PGP SIGNATURE-----', $encrypted); diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php index 7a4a9791c02d3..79af3535e335f 100644 --- a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php @@ -1,6 +1,13 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Symfony\Component\Mime\Tests\Part\Multipart; diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php index 2e747d34090f4..96a17889ddc13 100644 --- a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php @@ -1,6 +1,13 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ namespace Symfony\Component\Mime\Tests\Part\Multipart; diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php index f88898c93d86b..9304a37ae114c 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Tests\Part; use PHPUnit\Framework\Attributes\CoversClass; diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php index fbfc7cbabe184..19ebd93a61228 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Tests\Part; use PHPUnit\Framework\Attributes\CoversClass; diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php index a91d7443f9a19..c62b6177c9844 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Tests\Part; use PHPUnit\Framework\Attributes\CoversClass; diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php index 202502306536d..f985eb401c893 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Tests\Part; use PHPUnit\Framework\Attributes\CoversClass; diff --git a/src/Symfony/Component/Mime/Tests/Fixtures/_data/pgp.asc b/src/Symfony/Component/Mime/Tests/_data/pgp.asc similarity index 100% rename from src/Symfony/Component/Mime/Tests/Fixtures/_data/pgp.asc rename to src/Symfony/Component/Mime/Tests/_data/pgp.asc diff --git a/src/Symfony/Component/Mime/composer.json b/src/Symfony/Component/Mime/composer.json index d4866c0ebceb1..ece17b79c5c4c 100644 --- a/src/Symfony/Component/Mime/composer.json +++ b/src/Symfony/Component/Mime/composer.json @@ -17,9 +17,9 @@ ], "require": { "php": ">=8.1", + "pear/crypt_gpg": "^1.6", "symfony/polyfill-intl-idn": "^1.10", - "symfony/polyfill-mbstring": "^1.0", - "pear/crypt_gpg": "^1.6" + "symfony/polyfill-mbstring": "^1.0" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", From d5b9214a7832b152cbdb27b9c7b68bdfc07cc0df Mon Sep 17 00:00:00 2001 From: PuLLi <112799107+the-pulli@users.noreply.github.com> Date: Thu, 4 May 2023 12:29:46 +0200 Subject: [PATCH 4/4] [Mime] Move crypt_gpg to dev, rm attr from tests --- composer.json | 2 +- .../Component/Mime/Part/Multipart/PGPEncryptedPart.php | 9 +++++++++ .../Component/Mime/Part/Multipart/PGPSignedPart.php | 9 +++++++++ .../Component/Mime/Tests/Crypto/PGPEncryptorTest.php | 6 ++---- .../Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php | 2 -- .../Mime/Tests/Part/Multipart/PGPSignedPartTest.php | 2 -- .../Tests/Part/PGPEncryptedInitializationPartTest.php | 4 +--- .../Mime/Tests/Part/PGPEncryptedMessagePartTest.php | 6 ++---- src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php | 4 +--- .../Component/Mime/Tests/Part/PGPSignaturePartTest.php | 4 +--- 10 files changed, 26 insertions(+), 22 deletions(-) diff --git a/composer.json b/composer.json index 815748d03f1cd..e4eaedee5744c 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,6 @@ "doctrine/event-manager": "^1.2|^2", "doctrine/persistence": "^2|^3", "twig/twig": "^2.13|^3.0.4", - "pear/crypt_gpg": "^1.6", "psr/cache": "^2.0|^3.0", "psr/clock": "^1.0", "psr/container": "^1.1|^2.0", @@ -142,6 +141,7 @@ "monolog/monolog": "^1.25.1|^2", "nyholm/psr7": "^1.0", "pda/pheanstalk": "^4.0", + "pear/crypt_gpg": "^1.6", "php-http/discovery": "^1.15", "php-http/httplug": "^1.0|^2.0", "php-http/message-factory": "^1.0", diff --git a/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php b/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php index b75486aaef5fb..7877c0014a4fa 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/PGPEncryptedPart.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Part\AbstractMultipartPart; diff --git a/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php b/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php index 3b185d2041857..c393f50c1d3f0 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/PGPSignedPart.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Component\Mime\Part\Multipart; use Symfony\Component\Mime\Helper\PGPSigningPreparer; diff --git a/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php b/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php index 1f25e68a3ae5f..e1ebcf0d429b2 100644 --- a/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php +++ b/src/Symfony/Component/Mime/Tests/Crypto/PGPEncryptorTest.php @@ -11,14 +11,12 @@ namespace Symfony\Component\Mime\Tests\Crypto; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Address; use Symfony\Component\Mime\Crypto\PGPEncrypter; use Symfony\Component\Mime\Email; -#[CoversClass(PGPEncrypter::class)] -final class PGPEncryptorTest extends TestCase +class PGPEncryptorTest extends TestCase { private \Crypt_GPG $gpg; @@ -30,7 +28,7 @@ protected function setUp(): void { parent::setUp(); $this->gpg = new \Crypt_GPG(); - $this->gpg->importKeyFile(__DIR__ . '/../_data/pgp.asc'); + $this->gpg->importKeyFile(__DIR__.'/../_data/pgp.asc'); $this->email = (new Email()) ->from(new Address('pgp@pulli.dev', 'PuLLi')) ->to(new Address('pgp@pulli.dev', 'PuLLi')) diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php index 79af3535e335f..bb89d95a3bc7d 100644 --- a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPEncryptedPartTest.php @@ -11,11 +11,9 @@ namespace Symfony\Component\Mime\Tests\Part\Multipart; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Part\Multipart\PGPEncryptedPart; -#[CoversClass(PGPEncryptedPart::class)] final class PGPEncryptedPartTest extends TestCase { public function testPGPEncryptedPart() diff --git a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php index 96a17889ddc13..653debc4213cc 100644 --- a/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/Multipart/PGPSignedPartTest.php @@ -11,12 +11,10 @@ namespace Symfony\Component\Mime\Tests\Part\Multipart; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Part\Multipart\PGPSignedPart; use Symfony\Component\Mime\Part\TextPart; -#[CoversClass(PGPSignedPart::class)] final class PGPSignedPartTest extends TestCase { public function testPGPSignedPart() diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php index 9304a37ae114c..2e2fb4993ced2 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedInitializationPartTest.php @@ -11,12 +11,10 @@ namespace Symfony\Component\Mime\Tests\Part; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Part\PGPEncryptedInitializationPart; -#[CoversClass(PGPEncryptedInitializationPart::class)] -final class PGPEncryptedInitializationPartTest extends TestCase +class PGPEncryptedInitializationPartTest extends TestCase { public function testPGPEncryptedInitializationPart() { diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php index 19ebd93a61228..4b2e3442621d8 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPEncryptedMessagePartTest.php @@ -9,14 +9,12 @@ * file that was distributed with this source code. */ -namespace Tests\Part; +namespace Symfony\Component\Mime\Tests\Part; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Part\PGPEncryptedMessagePart; -#[CoversClass(PGPEncryptedMessagePart::class)] -final class PGPEncryptedMessagePartTest extends TestCase +class PGPEncryptedMessagePartTest extends TestCase { public function testPGPEncryptedMessagePart() { diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php index c62b6177c9844..0e09c9656948c 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPKeyPartTest.php @@ -11,12 +11,10 @@ namespace Symfony\Component\Mime\Tests\Part; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Part\PGPKeyPart; -#[CoversClass(PGPKeyPart::class)] -final class PGPKeyPartTest extends TestCase +class PGPKeyPartTest extends TestCase { public function testPGPKeyPartWithStandardKeyName() { diff --git a/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php b/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php index f985eb401c893..e7b7cd637d970 100644 --- a/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/PGPSignaturePartTest.php @@ -11,12 +11,10 @@ namespace Symfony\Component\Mime\Tests\Part; -use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; use Symfony\Component\Mime\Part\PGPSignaturePart; -#[CoversClass(PGPSignaturePart::class)] -final class PGPSignaturePartTest extends TestCase +class PGPSignaturePartTest extends TestCase { public function testPGPSignaturePart() {