From 92c06568b415c36b142c8a1902374af9ec3f6ffb Mon Sep 17 00:00:00 2001 From: "david.owusu" Date: Thu, 18 Jun 2026 17:39:07 +0200 Subject: [PATCH 1/3] [CC-3759] Change Keypair properties from private to protected to enable JSON serialization via expose(). Co-Authored-By: Claude Sonnet 4.6 --- src/Resources/Keypair.php | 20 ++++++++++---------- test/integration/Resources/KeypairTest.php | 21 +++++++++++++++++++-- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index 6308e6ea9..f7df8ed80 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -14,28 +14,28 @@ class Keypair extends AbstractUnzerResource { /** @var string $publicKey */ - private $publicKey; + protected $publicKey; /** @var string $privateKey */ - private $privateKey; + protected $privateKey; /** @var bool $detailed */ - private $detailed = false; + protected $detailed = false; /** @var array $paymentTypes */ - private $paymentTypes = []; + protected $paymentTypes = []; /** @var string $secureLevel */ - private $secureLevel; + protected $secureLevel; /** @var string $alias */ - private $alias; + protected $alias; /** @var string $merchantName */ - private $merchantName; + protected $merchantName; /** @var string $merchantAddress */ - private $merchantAddress; + protected $merchantAddress; /** * Credentials on File / Card on File @@ -43,10 +43,10 @@ class Keypair extends AbstractUnzerResource * * @var bool|null $cof */ - private $cof; + protected $cof; /** @var bool $validateBasket */ - private $validateBasket; + protected $validateBasket; /** * @return string|null diff --git a/test/integration/Resources/KeypairTest.php b/test/integration/Resources/KeypairTest.php index 523ac22cd..ea0eb6448 100644 --- a/test/integration/Resources/KeypairTest.php +++ b/test/integration/Resources/KeypairTest.php @@ -12,6 +12,7 @@ namespace UnzerSDK\test\integration\Resources; use RuntimeException; +use UnzerSDK\Resources\Keypair; use UnzerSDK\test\BaseIntegrationTest; use UnzerSDK\Unzer; @@ -52,14 +53,30 @@ public function invalidKeysShouldResultInException($key): void * * @test */ - public function keypairShouldReturnExpectedValues(): void + public function keypairShouldReturnExpectedValues(): Keypair { $keypair = $this->unzer->fetchKeypair(); $this->assertNotNull($keypair); $this->assertNotEmpty($keypair->getPublicKey()); - $this->assertNotEmpty($keypair->getPrivateKey()); $this->assertNotEmpty($keypair->getAvailablePaymentTypes()); $this->assertNotEmpty($keypair->getSecureLevel()); + return $keypair; + } + + /** + * Verify keypair can be fetched using the public key extracted from a previous fetch. + * + * @test + * + * @depends keypairShouldReturnExpectedValues + */ + public function keypairCanBeFetchedUsingPublicKey(Keypair $keypair): void + { + $publicKey = $keypair->getPublicKey(); + $fetchedKeypair = (new Unzer($publicKey))->fetchKeypair(); + $this->assertNotNull($fetchedKeypair); + $this->assertEquals($publicKey, $fetchedKeypair->getPublicKey()); + $this->assertNotEmpty($fetchedKeypair->getSecureLevel()); } /** From bce44ed29bb02c3e9fa6c763ec49f06fd605d020 Mon Sep 17 00:00:00 2001 From: "david.owusu" Date: Fri, 19 Jun 2026 10:12:56 +0200 Subject: [PATCH 2/3] [CC-3759] change private key visibility back to private. --- src/Resources/Keypair.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index f7df8ed80..edc217e64 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -2,8 +2,8 @@ namespace UnzerSDK\Resources; -use UnzerSDK\Adapter\HttpAdapterInterface; use stdClass; +use UnzerSDK\Adapter\HttpAdapterInterface; /** * This represents the key pair resource. @@ -17,7 +17,7 @@ class Keypair extends AbstractUnzerResource protected $publicKey; /** @var string $privateKey */ - protected $privateKey; + private $privateKey; /** @var bool $detailed */ protected $detailed = false; From f49b19162466e23e40e9ad757a677a71030e5fa9 Mon Sep 17 00:00:00 2001 From: "david.owusu" Date: Fri, 19 Jun 2026 11:29:34 +0200 Subject: [PATCH 3/3] [CC-3759] [CC-3759] Add expose() tests for Keypair and restrict detailed property visibility - Change `detailed` to private since it is a fetch-control flag and must not be serialized - Add unit test verifying expose() includes all protected properties with correct values and excludes privateKey and detailed - Add integration test verifying expose() reflects fetched keypair data including nested payment type objects Co-Authored-By: Claude Sonnet 4.6 --- src/Resources/Keypair.php | 2 +- test/integration/Resources/KeypairTest.php | 23 +++++++++++++ test/unit/Resources/KeypairTest.php | 38 ++++++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/Resources/Keypair.php b/src/Resources/Keypair.php index edc217e64..ef8db4d93 100755 --- a/src/Resources/Keypair.php +++ b/src/Resources/Keypair.php @@ -20,7 +20,7 @@ class Keypair extends AbstractUnzerResource private $privateKey; /** @var bool $detailed */ - protected $detailed = false; + private $detailed = false; /** @var array $paymentTypes */ protected $paymentTypes = []; diff --git a/test/integration/Resources/KeypairTest.php b/test/integration/Resources/KeypairTest.php index ea0eb6448..d3c40c846 100644 --- a/test/integration/Resources/KeypairTest.php +++ b/test/integration/Resources/KeypairTest.php @@ -93,4 +93,27 @@ public function keypairShouldBeFetchableWithDetails(): void $this->assertNotEmpty($keypair->getPaymentTypes()); $this->assertNotEmpty($keypair->getSecureLevel()); } + + /** + * Verify expose() reflects the fetched keypair's properties and excludes privateKey and detailed. + * + * @test + */ + public function exposeReflectsKeypairPropertiesAfterFetch(): void + { + $keypair = $this->unzer->fetchKeypair(true); + $exposed = $keypair->expose(); + + // Main scalar properties must match keypair getters + $this->assertEquals($keypair->getPublicKey(), $exposed['publicKey']); + $this->assertEquals($keypair->getSecureLevel(), $exposed['secureLevel']); + + // Nested payment type objects must be present and match + $this->assertNotEmpty($exposed['paymentTypes']); + $this->assertEquals($keypair->getPaymentTypes(), $exposed['paymentTypes']); + + // privateKey (private) and detailed (private) must never be exposed + $this->assertArrayNotHasKey('privateKey', $exposed); + $this->assertArrayNotHasKey('detailed', $exposed); + } } diff --git a/test/unit/Resources/KeypairTest.php b/test/unit/Resources/KeypairTest.php index 0abba0609..a7b696cff 100755 --- a/test/unit/Resources/KeypairTest.php +++ b/test/unit/Resources/KeypairTest.php @@ -135,4 +135,42 @@ public function aKeypairShouldBeUpdatedWithDetailsThroughResponseHandling(): voi $this->assertEquals('Unzer GmbH', $keypair->getMerchantName()); $this->assertEquals('Vangerowstraße 18, 69115 Heidelberg', $keypair->getMerchantAddress()); } + + /** + * Verify expose() contains all relevant key data but excludes privateKey and detailed. + * + * @test + */ + public function exposeContainsAllRelevantKeyDataExceptPrivateKeyAndDetailed(): void + { + $keypair = new Keypair(); + $paymentTypes = [(object)['type' => 'card'], (object)['type' => 'paypal']]; + $keypair->handleResponse((object)[ + 'publicKey' => 's-pub-1234', + 'privateKey' => 's-priv-4321', + 'paymentTypes' => $paymentTypes, + 'secureLevel' => 'SAQ-D', + 'alias' => 'Readme.io user', + 'merchantName' => 'Unzer GmbH', + 'merchantAddress' => 'Vangerowstraße 18, 69115 Heidelberg', + 'cof' => true, + 'validateBasket' => false, + ]); + + $exposed = $keypair->expose(); + + // All relevant protected key data should be exposed with correct values + $this->assertEquals('s-pub-1234', $exposed['publicKey']); + $this->assertEquals($paymentTypes, $exposed['paymentTypes']); + $this->assertEquals('SAQ-D', $exposed['secureLevel']); + $this->assertEquals('Readme.io user', $exposed['alias']); + $this->assertEquals('Unzer GmbH', $exposed['merchantName']); + $this->assertEquals('Vangerowstraße 18, 69115 Heidelberg', $exposed['merchantAddress']); + $this->assertTrue($exposed['cof']); + $this->assertFalse($exposed['validateBasket']); + + // privateKey (private) and detailed (private) must never be exposed + $this->assertArrayNotHasKey('privateKey', $exposed); + $this->assertArrayNotHasKey('detailed', $exposed); + } }