From 17f04968460e4b29e232da6197dc83be96f3d0d8 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:42:28 -0400 Subject: [PATCH 01/11] =?UTF-8?q?Added=20native=20JWK/JWS/JWE=20handling.?= =?UTF-8?q?=20Preserved=20RS256,=20RSA-OAEP-256,=20and=20A256CBC-HS512=20s?= =?UTF-8?q?upport.=20Removed=20the=20Composer-time=20JOSE=20patch=20and=20?= =?UTF-8?q?obsolete=20source=20files.=20Raised=20the=20minimum=20PHP=20ver?= =?UTF-8?q?sion=20to=208.1.=20Updated=20CI=20to=20test=20PHP=208.1?= =?UTF-8?q?=E2=80=938.4.=20Updated=20documentation=20generation=20to=20PHP?= =?UTF-8?q?=208.4.=20Updated=20README=20prerequisites.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 8 +- .github/workflows/documentation.yml | 2 +- README.md | 2 +- composer.json | 16 +- .../RsaOaep256AlgorithmInstaller.php | 19 -- .../Util/HyperwalletEncryption.php | 135 +++----- src/JWE | 296 ------------------ 7 files changed, 50 insertions(+), 428 deletions(-) delete mode 100644 src/ComposerScript/RsaOaep256AlgorithmInstaller.php delete mode 100644 src/JWE diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3211e6f4..16b1863b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: fail-fast: false matrix: operating-system: [ 'ubuntu-latest' ] - php-versions: [ '7.1', '7.2', '7.3', '7.4', '8.0', '8.1' ] + php-versions: [ '8.1', '8.2', '8.3', '8.4' ] steps: - uses: actions/checkout@master @@ -58,7 +58,7 @@ jobs: fail-fast: false matrix: operating-system: ['ubuntu-latest'] - php-versions: ['5.6', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1'] + php-versions: ['8.1', '8.2', '8.3', '8.4'] steps: - uses: actions/checkout@master @@ -91,7 +91,7 @@ jobs: fail-fast: false matrix: operating-system: [ 'ubuntu-latest' ] - php-versions: [ '5.6' ] + php-versions: [ '8.1' ] steps: - uses: actions/checkout@master @@ -118,4 +118,4 @@ jobs: - name: Upload coverage results to Coveralls env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: ./vendor/bin/php-coveralls -v --exclude-no-stmt \ No newline at end of file + run: ./vendor/bin/php-coveralls -v --exclude-no-stmt diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index ab214f63..71015ad9 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: operating-system: [ 'ubuntu-latest' ] - php-versions: [ '8.1' ] + php-versions: [ '8.4' ] steps: - uses: actions/checkout@master diff --git a/README.md b/README.md index 51bbe516..e49bb8f1 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ For Hyperwallet v3 API calls, please use the latest SDK version 1.x.x. See [here Prerequisites ------------ -Hyperwallet's PHP server SDK requires at minimum PHP 5.6 and above. +Hyperwallet's PHP server SDK requires PHP 8.1 or later. Installation ------------ diff --git a/composer.json b/composer.json index a687e7b9..fc50100b 100644 --- a/composer.json +++ b/composer.json @@ -20,24 +20,24 @@ } ], "require": { - "php": ">=5.6.0", + "php": ">=8.1.0", "ext-json": "*", "guzzlehttp/guzzle": "^6.2.1 || ^7.0.1", - "phpseclib/phpseclib": "^2.0.11", - "gree/jose": "^2.2.1" + "web-token/jwt-core": "^4.0", + "web-token/jwt-signature-algorithm-rsa": "^4.0", + "web-token/jwt-encryption": "^4.0", + "web-token/jwt-encryption-algorithm-rsa": "^4.0", + "web-token/jwt-encryption-algorithm-aescbc": "^4.0" }, "autoload": { - "psr-4": { "Hyperwallet\\": "src/Hyperwallet", "ComposerScript\\" : "src/ComposerScript" } + "psr-4": { "Hyperwallet\\": "src/Hyperwallet" } }, "autoload-dev" : { - "psr-4": { "Hyperwallet\\Tests\\" : "tests/Hyperwallet/Tests", "ComposerScript\\" : "src/ComposerScript" } + "psr-4": { "Hyperwallet\\Tests\\" : "tests/Hyperwallet/Tests" } }, "require-dev": { "phpunit/phpunit": "^5.7 || ^7.0.0 || ^9.0", "phake/phake": "^2.3 || ^4.2", "php-coveralls/php-coveralls": "^2.5" - }, - "scripts": { - "post-install-cmd": "ComposerScript\\RsaOaep256AlgorithmInstaller::install" } } diff --git a/src/ComposerScript/RsaOaep256AlgorithmInstaller.php b/src/ComposerScript/RsaOaep256AlgorithmInstaller.php deleted file mode 100644 index d622ba02..00000000 --- a/src/ComposerScript/RsaOaep256AlgorithmInstaller.php +++ /dev/null @@ -1,19 +0,0 @@ -getComposer()->getConfig()->get('vendor-dir'); - file_put_contents($vendorDir . "/gree/jose/src/JOSE/JWE.php", file_get_contents(__DIR__ . "/../JWE")); - } -} diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index 73cb6529..43b7eb4b 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -8,15 +8,17 @@ use Hyperwallet\Exception\HyperwalletException; use Hyperwallet\Model\BaseModel; use Hyperwallet\Response\ErrorResponse; -use Composer\Autoload\ClassLoader; -use phpseclib\Crypt\RSA; -use phpseclib\Math\BigInteger; -use phpseclib\Crypt\Hash; -use JOSE_URLSafeBase64; -use JOSE_JWS; -use JOSE_JWE; -use JOSE_JWK; -use JOSE_JWT; +use Jose\Component\Core\AlgorithmManager; +use Jose\Component\Core\JWK; +use Jose\Component\Signature\Algorithm\RS256; +use Jose\Component\Signature\JWSBuilder; +use Jose\Component\Signature\JWSVerifier; +use Jose\Component\Signature\Serializer\CompactSerializer as JWSCompactSerializer; +use Jose\Component\Encryption\Algorithm\KeyEncryption\RSAOAEP256; +use Jose\Component\Encryption\Algorithm\ContentEncryption\A256CBCHS512; +use Jose\Component\Encryption\JWEBuilder; +use Jose\Component\Encryption\JWEDecrypter; +use Jose\Component\Encryption\Serializer\CompactSerializer as JWECompactSerializer; /** * The encryption service for Hyperwallet client's requests/responses @@ -100,7 +102,6 @@ public function __construct($clientPrivateKeySetLocation, $hyperwalletKeySetLoca $this->signAlgorithm = $signAlgorithm; $this->encryptionMethod = $encryptionMethod; $this->jwsExpirationMinutes = $jwsExpirationMinutes; - file_put_contents($this->getVendorPath() . "/gree/jose/src/JOSE/JWE.php", file_get_contents(__DIR__ . "/../../JWE")); } /** @@ -113,16 +114,18 @@ public function __construct($clientPrivateKeySetLocation, $hyperwalletKeySetLoca */ public function encrypt($body) { $privateJwsKey = $this->getPrivateJwsKey(); - $jws = new JOSE_JWS(new JOSE_JWT($body)); - $jws->header['exp'] = $this->getSignatureExpirationTime(); - $jws->header['kid'] = $this->jwsKid; - $jws->sign($privateJwsKey, $this->signAlgorithm); + $jws = (new JWSBuilder(new AlgorithmManager([new RS256()])))->create() + ->withPayload($body) + ->addSignature($privateJwsKey, ['alg' => $this->signAlgorithm, 'kid' => $this->jwsKid, 'exp' => $this->getSignatureExpirationTime()]) + ->build(); + $jwsToken = (new JWSCompactSerializer())->serialize($jws); $publicJweKey = $this->getPublicJweKey(); - $jwe = new JOSE_JWE($jws); - $jwe->header['kid'] = $this->jweKid; - $jwe->encrypt($publicJweKey, $this->encryptionAlgorithm, $this->encryptionMethod); - return $jwe->toString(); + $jwe = (new JWEBuilder(new AlgorithmManager([new RSAOAEP256(), new A256CBCHS512()]))) + ->create()->withPayload($jwsToken) + ->withSharedProtectedHeader(['alg' => $this->encryptionAlgorithm, 'enc' => $this->encryptionMethod, 'kid' => $this->jweKid]) + ->addRecipient($publicJweKey)->build(); + return (new JWECompactSerializer())->serialize($jwe, 0); } /** @@ -135,15 +138,19 @@ public function encrypt($body) { */ public function decrypt($body) { $privateJweKey = $this->getPrivateJweKey(); - $jwe = JOSE_JWT::decode($body); - $this->checkJweHeaderAlgorithm($jwe->header); - $decryptedBody = $jwe->decrypt($privateJweKey); + $serializer = new JWECompactSerializer(); + $jwe = $serializer->unserialize($body); + $this->checkJweHeaderAlgorithm($jwe->getSharedProtectedHeader()); + (new JWEDecrypter(new AlgorithmManager([new RSAOAEP256(), new A256CBCHS512()])))->decryptUsingKey($jwe, $privateJweKey, 0); $publicJwsKey = $this->getPublicJwsKey(); - $jwsToVerify = JOSE_JWT::decode($decryptedBody->plain_text); - $this->checkJwsExpiration($jwsToVerify->header); - $jwsVerificationResult = $jwsToVerify->verify($publicJwsKey, $this->signAlgorithm); - return $jwsVerificationResult->claims; + $jwsToVerify = (new JWSCompactSerializer())->unserialize($jwe->getPayload()); + $header = $jwsToVerify->getSignature(0)->getProtectedHeader(); + $this->checkJwsExpiration($header); + if (!(new JWSVerifier(new AlgorithmManager([new RS256()])))->verifyWithKey($jwsToVerify, $publicJwsKey, 0)) { + throw new HyperwalletException('Signature verification failed'); + } + return json_decode($jwsToVerify->getPayload(), true); } /** @@ -156,7 +163,7 @@ public function decrypt($body) { private function getPrivateJwsKey() { $privateKeyData = $this->getJwk($this->clientPrivateKeySetLocation, $this->signAlgorithm); $this->jwsKid = $privateKeyData['kid']; - return $this->getPrivateKey($privateKeyData); + return new JWK($privateKeyData); } /** @@ -169,7 +176,7 @@ private function getPrivateJwsKey() { private function getPublicJweKey() { $publicKeyData = $this->getJwk($this->hyperwalletKeySetLocation, $this->encryptionAlgorithm); $this->jweKid = $publicKeyData['kid']; - return $this->getPublicKey($this->convertPrivateKeyToPublic($publicKeyData)); + return new JWK($this->convertPrivateKeyToPublic($publicKeyData)); } /** @@ -181,7 +188,7 @@ private function getPublicJweKey() { */ private function getPrivateJweKey() { $privateKeyData = $this->getJwk($this->clientPrivateKeySetLocation, $this->encryptionAlgorithm); - return $this->getPrivateKey($privateKeyData); + return new JWK($privateKeyData); } /** @@ -193,7 +200,7 @@ private function getPrivateJweKey() { */ private function getPublicJwsKey() { $publicKeyData = $this->getJwk($this->hyperwalletKeySetLocation, $this->signAlgorithm); - return $this->getPublicKey($this->convertPrivateKeyToPublic($publicKeyData)); + return new JWK($this->convertPrivateKeyToPublic($publicKeyData)); } /** @@ -202,61 +209,6 @@ private function getPublicJwsKey() { * @param array $privateKeyData The JWK key data * @return RSA */ - private function getPrivateKey($privateKeyData) { - $n = $this->keyParamToBigInteger($privateKeyData['n']); - $e = $this->keyParamToBigInteger($privateKeyData['e']); - $d = $this->keyParamToBigInteger($privateKeyData['d']); - $p = $this->keyParamToBigInteger($privateKeyData['p']); - $q = $this->keyParamToBigInteger($privateKeyData['q']); - $qi = $this->keyParamToBigInteger($privateKeyData['qi']); - $dp = $this->keyParamToBigInteger($privateKeyData['dp']); - $dq = $this->keyParamToBigInteger($privateKeyData['dq']); - $primes = array($p, $q); - $exponents = array($dp, $dq); - $coefficients = array($qi, $qi); - array_unshift($primes, "phoney"); - unset($primes[0]); - array_unshift($exponents, "phoney"); - unset($exponents[0]); - array_unshift($coefficients, "phoney"); - unset($coefficients[0]); - - $pemData = (new RSA())->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients); - $privateKey = new RSA(); - $privateKey->loadKey($pemData); - if ($privateKeyData['alg'] == 'RSA-OAEP-256') { - $privateKey->setHash('sha256'); - $privateKey->setMGFHash('sha256'); - } - return $privateKey; - } - - /** - * Converts base 64 encoded string to BigInteger - * - * @param string $param base 64 encoded string - * @return BigInteger - */ - private function keyParamToBigInteger($param) { - return new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($param)), 16); - } - - /** - * Retrieves RSA public key by JWK key data - * - * @param array $publicKeyData The JWK key data - * @return RSA - */ - private function getPublicKey($publicKeyData) { - $publicKeyRaw = new JOSE_JWK($publicKeyData); - $publicKey = $publicKeyRaw->toKey(); - if ($publicKeyData['alg'] == 'RSA-OAEP-256') { - $publicKey->setHash('sha256'); - $publicKey->setMGFHash('sha256'); - } - return $publicKey; - } - /** * Retrieves JWK key by JWK key set location and algorithm * @@ -371,19 +323,4 @@ public function checkJweHeaderAlgorithm($header) { } } - /** - * Finds the path of composer vendor directory - * - * @return string - * - * @throws HyperwalletException - */ - public function getVendorPath() { - $reflector = new \ReflectionClass(ClassLoader::class); - $vendorPath = preg_replace('/^(.*)\/composer\/ClassLoader\.php$/', '$1', $reflector->getFileName() ); - if($vendorPath && is_dir($vendorPath)) { - return $vendorPath . '/'; - } - throw new HyperwalletException('Failed to find a vendor path'); - } } diff --git a/src/JWE b/src/JWE deleted file mode 100644 index 4b69a77c..00000000 --- a/src/JWE +++ /dev/null @@ -1,296 +0,0 @@ -raw = $input->toString(); - } else { - $this->raw = $input; - } - unset($this->header['typ']); - } - - function encrypt($public_key_or_secret, $algorithm = 'RSA1_5', $encryption_method = 'A128CBC-HS256') { - $this->header['alg'] = $algorithm; - $this->header['enc'] = $encryption_method; - if ( - $public_key_or_secret instanceof JOSE_JWK && - !array_key_exists('kid', $this->header) && - array_key_exists('kid', $public_key_or_secret->components) - ) { - $this->header['kid'] = $public_key_or_secret->components['kid']; - } - $this->plain_text = $this->raw; - $this->generateContentEncryptionKey($public_key_or_secret); - $this->encryptContentEncryptionKey($public_key_or_secret); - $this->generateIv(); - $this->deriveEncryptionAndMacKeys(); - $this->encryptCipherText(); - $this->generateAuthenticationTag(); - return $this; - } - - function decrypt($private_key_or_secret) { - $this->decryptContentEncryptionKey($private_key_or_secret); - $this->deriveEncryptionAndMacKeys(); - $this->decryptCipherText(); - $this->checkAuthenticationTag(); - return $this; - } - - function toString() { - return implode('.', array( - $this->compact((object) $this->header), - $this->compact($this->jwe_encrypted_key), - $this->compact($this->iv), - $this->compact($this->cipher_text), - $this->compact($this->authentication_tag) - )); - } - - private function rsa($public_or_private_key, $padding_mode) { - if ($public_or_private_key instanceof JOSE_JWK) { - $rsa = $public_or_private_key->toKey(); - } else if ($public_or_private_key instanceof RSA) { - $rsa = $public_or_private_key; - } else { - $rsa = new RSA(); - $rsa->loadKey($public_or_private_key); - } - $rsa->setEncryptionMode($padding_mode); - return $rsa; - } - - private function cipher() { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A256GCM': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - case 'A128CBC-HS256': - case 'A256CBC-HS512': - $cipher = new AES(AES::MODE_CBC); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - switch ($this->header['enc']) { - case 'A128GCM': - case 'A128CBC-HS256': - $cipher->setBlockLength(128); - break; - case 'A256GCM': - case 'A256CBC-HS512': - $cipher->setBlockLength(256); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - return $cipher; - } - - private function generateRandomBytes($length) { - return Random::string($length); - } - - private function generateIv() { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A128CBC-HS256': - case 'A256CBC-HS512': - $this->iv = $this->generateRandomBytes(128 / 8); - break; - case 'A256GCM': - //case 'A256CBC-HS512': - $this->iv = $this->generateRandomBytes(256 / 8); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - } - - private function generateContentEncryptionKey($public_key_or_secret) { - if ($this->header['alg'] == 'dir') { - $this->content_encryption_key = $public_key_or_secret; - } else { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A128CBC-HS256': - $this->content_encryption_key = $this->generateRandomBytes(256 / 8); - break; - case 'A256GCM': - case 'A256CBC-HS512': - $this->content_encryption_key = $this->generateRandomBytes(512 / 8); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - } - } - - private function encryptContentEncryptionKey($public_key_or_secret) { - switch ($this->header['alg']) { - case 'RSA1_5': - $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_PKCS1); - $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); - break; - case 'RSA-OAEP-256': - case 'RSA-OAEP': - $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_OAEP); - $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); - break; - case 'dir': - $this->jwe_encrypted_key = ''; - return; - case 'A128KW': - case 'A256KW': - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A256KW': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - if (!$this->jwe_encrypted_key) { - throw new JOSE_Exception_EncryptionFailed('Master key encryption failed'); - } - } - - private function decryptContentEncryptionKey($private_key_or_secret) { - $this->generateContentEncryptionKey(null); # NOTE: run this always not to make timing difference - $fake_content_encryption_key = $this->content_encryption_key; - switch ($this->header['alg']) { - case 'RSA1_5': - $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_PKCS1); - $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); - break; - case 'RSA-OAEP-256': - case 'RSA-OAEP': - $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_OAEP); - $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); - break; - case 'dir': - $this->content_encryption_key = $private_key_or_secret; - break; - case 'A128KW': - case 'A256KW': - case 'ECDH-ES': - case 'ECDH-ES+A128KW': - case 'ECDH-ES+A256KW': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - if (!$this->content_encryption_key) { - # NOTE: - # Not to disclose timing difference between CEK decryption error and others. - # Mitigating Bleichenbacher Attack on PKCS#1 v1.5 - # ref.) http://inaz2.hatenablog.com/entry/2016/01/26/222303 - $this->content_encryption_key = $fake_content_encryption_key; - } - } - - private function deriveEncryptionAndMacKeys() { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A256GCM': - $this->encryption_key = $this->content_encryption_key; - $this->mac_key = "won't be used"; - break; - case 'A128CBC-HS256': - $this->deriveEncryptionAndMacKeysCBC(256); - break; - case 'A256CBC-HS512': - $this->deriveEncryptionAndMacKeysCBC(512); - break; - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - if (!$this->encryption_key || !$this->mac_key) { - throw new JOSE_Exception_DecryptionFailed('Encryption/Mac key derivation failed'); - } - } - - private function deriveEncryptionAndMacKeysCBC($sha_size) { - $this->mac_key = substr($this->content_encryption_key, 0, $sha_size / 2 / 8); - $this->encryption_key = substr($this->content_encryption_key, $sha_size / 2 / 8); - } - - private function encryptCipherText() { - $cipher = $this->cipher(); - $cipher->setKey($this->encryption_key); - $cipher->setIV($this->iv); - $this->cipher_text = $cipher->encrypt($this->plain_text); - if (!$this->cipher_text) { - throw new JOSE_Exception_DecryptionFailed('Payload encryption failed'); - } - } - - private function decryptCipherText() { - $cipher = $this->cipher(); - $cipher->setKey($this->encryption_key); - $cipher->setIV($this->iv); - $this->plain_text = $cipher->decrypt($this->cipher_text); - if (!$this->plain_text) { - throw new JOSE_Exception_DecryptionFailed('Payload decryption failed'); - } - } - - private function generateAuthenticationTag() { - $this->authentication_tag = $this->calculateAuthenticationTag(); - } - - private function calculateAuthenticationTag($use_raw = false) { - switch ($this->header['enc']) { - case 'A128GCM': - case 'A256GCM': - throw new JOSE_Exception_UnexpectedAlgorithm('Algorithm not supported'); - case 'A128CBC-HS256': - return $this->calculateAuthenticationTagCBC(256); - case 'A256CBC-HS512': - return $this->calculateAuthenticationTagCBC(512); - default: - throw new JOSE_Exception_UnexpectedAlgorithm('Unknown algorithm'); - } - } - - private function calculateAuthenticationTagCBC($sha_size) { - if (!$this->auth_data) { - $this->auth_data = $this->compact((object) $this->header); - } - $auth_data_length = strlen($this->auth_data); - $max_32bit = 2147483647; - $secured_input = implode('', array( - $this->auth_data, - $this->iv, - $this->cipher_text, - // NOTE: PHP doesn't support 64bit big endian, so handling upper & lower 32bit. - pack('N2', ($auth_data_length / $max_32bit) * 8, ($auth_data_length % $max_32bit) * 8) - )); - return substr( - hash_hmac('sha' . $sha_size, $secured_input, $this->mac_key, true), - 0, $sha_size / 2 / 8 - ); - } - - private function checkAuthenticationTag() { - if (hash_equals($this->authentication_tag, $this->calculateAuthenticationTag())) { - return true; - } else { - throw new JOSE_Exception_UnexpectedAlgorithm('Invalid authentication tag'); - } - } -} From e7e92989af7a37a7c1e23849143247cbbc29e767 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:45:38 -0400 Subject: [PATCH 02/11] =?UTF-8?q?Added=20native=20JWK/JWS/JWE=20handling.?= =?UTF-8?q?=20Preserved=20RS256,=20RSA-OAEP-256,=20and=20A256CBC-HS512=20s?= =?UTF-8?q?upport.=20Removed=20the=20Composer-time=20JOSE=20patch=20and=20?= =?UTF-8?q?obsolete=20source=20files.=20Raised=20the=20minimum=20PHP=20ver?= =?UTF-8?q?sion=20to=208.1.=20Updated=20CI=20to=20test=20PHP=208.1?= =?UTF-8?q?=E2=80=938.4.=20Updated=20documentation=20generation=20to=20PHP?= =?UTF-8?q?=208.4.=20Updated=20README=20prerequisites.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 6 +++--- .github/workflows/documentation.yml | 4 ++-- composer.json | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16b1863b..da5ff49c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,7 @@ jobs: - name: Install dependencies env: COMPOSER_NO_BLOCKING: 1 - run: composer install --prefer-dist --no-progress --no-suggest + run: composer install --prefer-dist --no-progress #get static analysis tool - name: Install static analysis tool @@ -76,7 +76,7 @@ jobs: - name: Install dependencies env: COMPOSER_NO_BLOCKING: 1 - run: composer install --prefer-dist --no-progress --no-suggest + run: composer install --prefer-dist --no-progress - name: Run test suite run: | @@ -108,7 +108,7 @@ jobs: - name: Install dependencies env: COMPOSER_NO_BLOCKING: 1 - run: composer install --prefer-dist --no-progress --no-suggest + run: composer install --prefer-dist --no-progress - name: Run test suite run: | diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 71015ad9..9d4afa66 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -28,12 +28,12 @@ jobs: - name: Install dependencies env: COMPOSER_NO_BLOCKING: 1 - run: composer install --prefer-dist --no-progress --no-suggest + run: composer install --prefer-dist --no-progress - name: Install API doc generator tool env: COMPOSER_NO_BLOCKING: 1 - run: composer create-project --no-dev apigen/apigen:^7.0@alpha tools/apigen + run: composer create-project --no-dev apigen/apigen:^7.0 tools/apigen - name: Generate Documentation run: tools/apigen/bin/apigen src --output docs diff --git a/composer.json b/composer.json index fc50100b..01e50c2d 100644 --- a/composer.json +++ b/composer.json @@ -23,11 +23,11 @@ "php": ">=8.1.0", "ext-json": "*", "guzzlehttp/guzzle": "^6.2.1 || ^7.0.1", - "web-token/jwt-core": "^4.0", - "web-token/jwt-signature-algorithm-rsa": "^4.0", - "web-token/jwt-encryption": "^4.0", - "web-token/jwt-encryption-algorithm-rsa": "^4.0", - "web-token/jwt-encryption-algorithm-aescbc": "^4.0" + "web-token/jwt-core": "^3.4", + "web-token/jwt-signature-algorithm-rsa": "^3.4", + "web-token/jwt-encryption": "^3.4", + "web-token/jwt-encryption-algorithm-rsa": "^3.4", + "web-token/jwt-encryption-algorithm-aescbc": "^3.4" }, "autoload": { "psr-4": { "Hyperwallet\\": "src/Hyperwallet" } From 8585e886192e90e4cde58051e5ebed345a98943c Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:47:19 -0400 Subject: [PATCH 03/11] =?UTF-8?q?Added=20native=20JWK/JWS/JWE=20handling.?= =?UTF-8?q?=20Preserved=20RS256,=20RSA-OAEP-256,=20and=20A256CBC-HS512=20s?= =?UTF-8?q?upport.=20Removed=20the=20Composer-time=20JOSE=20patch=20and=20?= =?UTF-8?q?obsolete=20source=20files.=20Raised=20the=20minimum=20PHP=20ver?= =?UTF-8?q?sion=20to=208.1.=20Updated=20CI=20to=20test=20PHP=208.1?= =?UTF-8?q?=E2=80=938.4.=20Updated=20documentation=20generation=20to=20PHP?= =?UTF-8?q?=208.4.=20Updated=20README=20prerequisites.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Hyperwallet/Model/HyperwalletVerificationDocument.php | 3 +++ .../Model/HyperwalletVerificationDocumentReason.php | 3 +++ src/Hyperwallet/Util/HyperwalletEncryption.php | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Hyperwallet/Model/HyperwalletVerificationDocument.php b/src/Hyperwallet/Model/HyperwalletVerificationDocument.php index 1deaab61..ea2c1d69 100644 --- a/src/Hyperwallet/Model/HyperwalletVerificationDocument.php +++ b/src/Hyperwallet/Model/HyperwalletVerificationDocument.php @@ -162,6 +162,9 @@ public function getUploadFiles($uploadFiles) { */ class HyperwalletVerificationDocumentCollection { + /** @var HyperwalletVerificationDocument[] */ + private $documents; + public function __construct(HyperwalletVerificationDocument ...$documents) { $this->documents = $documents; } diff --git a/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php b/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php index f86a1a31..7eb3aa6a 100644 --- a/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php +++ b/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php @@ -69,6 +69,9 @@ public function getDescription() { */ class HyperwalletVerificationDocumentReasonCollection { + /** @var HyperwalletVerificationDocumentReason[] */ + private $reasons; + public function __construct(HyperwalletVerificationDocumentReason ...$reasons) { $this->reasons = $reasons; } diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index 43b7eb4b..3530f010 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -141,7 +141,7 @@ public function decrypt($body) { $serializer = new JWECompactSerializer(); $jwe = $serializer->unserialize($body); $this->checkJweHeaderAlgorithm($jwe->getSharedProtectedHeader()); - (new JWEDecrypter(new AlgorithmManager([new RSAOAEP256(), new A256CBCHS512()])))->decryptUsingKey($jwe, $privateJweKey, 0); + (new JWEDecrypter(new AlgorithmManager([new RSAOAEP256(), new A256CBCHS512()]), null))->decryptUsingKey($jwe, $privateJweKey, 0); $publicJwsKey = $this->getPublicJwsKey(); $jwsToVerify = (new JWSCompactSerializer())->unserialize($jwe->getPayload()); From 7cdc4de10035bfcecc21387cd254a8c23446bfc2 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:49:27 -0400 Subject: [PATCH 04/11] Support PHP 8.4 --- src/Hyperwallet/Exception/HyperwalletArgumentException.php | 2 +- src/Hyperwallet/Exception/HyperwalletException.php | 2 +- src/Hyperwallet/Hyperwallet.php | 2 +- src/Hyperwallet/Model/BankAccount.php | 2 +- src/Hyperwallet/Model/BankCard.php | 2 +- src/Hyperwallet/Model/BusinessStakeholder.php | 2 +- src/Hyperwallet/Model/Payment.php | 4 ++-- src/Hyperwallet/Model/TransferMethod.php | 2 +- src/Hyperwallet/Model/User.php | 2 +- src/Hyperwallet/Util/ApiClient.php | 2 +- 10 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Hyperwallet/Exception/HyperwalletArgumentException.php b/src/Hyperwallet/Exception/HyperwalletArgumentException.php index dc22881b..0394fa6b 100644 --- a/src/Hyperwallet/Exception/HyperwalletArgumentException.php +++ b/src/Hyperwallet/Exception/HyperwalletArgumentException.php @@ -15,7 +15,7 @@ class HyperwalletArgumentException extends HyperwalletException { * @param int $code The error code * @param \Exception|null $previous The original exception */ - public function __construct($message, $code = 0, \Exception $previous = null) { + public function __construct($message, $code = 0, ?\Exception $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Hyperwallet/Exception/HyperwalletException.php b/src/Hyperwallet/Exception/HyperwalletException.php index 45085ca1..9b95c153 100644 --- a/src/Hyperwallet/Exception/HyperwalletException.php +++ b/src/Hyperwallet/Exception/HyperwalletException.php @@ -15,7 +15,7 @@ class HyperwalletException extends \Exception { * @param int $code The error code * @param \Exception|null $previous The original exception */ - public function __construct($message = "", $code = 0, \Exception $previous = null) { + public function __construct($message = "", $code = 0, ?\Exception $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Hyperwallet/Hyperwallet.php b/src/Hyperwallet/Hyperwallet.php index f824a2b3..29bd804e 100644 --- a/src/Hyperwallet/Hyperwallet.php +++ b/src/Hyperwallet/Hyperwallet.php @@ -1543,7 +1543,7 @@ public function listBankCardStatusTransitions($userToken, $bankCardToken, array * @throws HyperwalletArgumentException * @throws HyperwalletApiException */ - public function createTransferMethod($userToken, $jsonCacheToken, TransferMethod $transferMethod = null) { + public function createTransferMethod($userToken, $jsonCacheToken, ?TransferMethod $transferMethod = null) { if (empty($userToken)) { throw new HyperwalletArgumentException('userToken is required!'); } diff --git a/src/Hyperwallet/Model/BankAccount.php b/src/Hyperwallet/Model/BankAccount.php index 5bc8de0b..89bb4b45 100644 --- a/src/Hyperwallet/Model/BankAccount.php +++ b/src/Hyperwallet/Model/BankAccount.php @@ -816,7 +816,7 @@ public function getDateOfBirth() { * @param \DateTime|null $dateOfBirth * @return BankAccount */ - public function setDateOfBirth(\DateTime $dateOfBirth = null) { + public function setDateOfBirth(?\DateTime $dateOfBirth = null) { $this->dateOfBirth = $dateOfBirth == null ? null : $dateOfBirth->format('Y-m-d'); return $this; } diff --git a/src/Hyperwallet/Model/BankCard.php b/src/Hyperwallet/Model/BankCard.php index 8b09b721..66a1b1d4 100644 --- a/src/Hyperwallet/Model/BankCard.php +++ b/src/Hyperwallet/Model/BankCard.php @@ -234,7 +234,7 @@ public function getDateOfExpiry() { * @param \DateTime $dateOfExpiry * @return BankCard */ - public function setDateOfExpiry(\DateTime $dateOfExpiry = null) { + public function setDateOfExpiry(?\DateTime $dateOfExpiry = null) { $this->dateOfExpiry = $dateOfExpiry == null ? null : $dateOfExpiry->format('Y-m-d'); return $this; } diff --git a/src/Hyperwallet/Model/BusinessStakeholder.php b/src/Hyperwallet/Model/BusinessStakeholder.php index 83c2fb2b..770b08e2 100644 --- a/src/Hyperwallet/Model/BusinessStakeholder.php +++ b/src/Hyperwallet/Model/BusinessStakeholder.php @@ -329,7 +329,7 @@ public function getDateOfBirth() { * @param \DateTime|null $dateOfBirth * @return BusinessStakeholder */ - public function setDateOfBirth(\DateTime $dateOfBirth = null) { + public function setDateOfBirth(?\DateTime $dateOfBirth = null) { $this->dateOfBirth = $dateOfBirth == null ? null : $dateOfBirth->format('Y-m-d'); return $this; } diff --git a/src/Hyperwallet/Model/Payment.php b/src/Hyperwallet/Model/Payment.php index 0396c8dc..d55a2215 100644 --- a/src/Hyperwallet/Model/Payment.php +++ b/src/Hyperwallet/Model/Payment.php @@ -253,7 +253,7 @@ public function getReleaseOn() { * @param \DateTime $releaseOn * @return Payment */ - public function setReleaseOn(\DateTime $releaseOn = null) { + public function setReleaseOn(?\DateTime $releaseOn = null) { $this->releaseOn = $releaseOn == null ? null : $releaseOn->format('Y-m-d\TH:i:s'); return $this; } @@ -272,7 +272,7 @@ public function getExpiresOn() { * @param \DateTime $expiresOn * @return Payment */ - public function setExpiresOn(\DateTime $expiresOn = null) { + public function setExpiresOn(?\DateTime $expiresOn = null) { $this->expiresOn = $expiresOn == null ? null : $expiresOn->format('Y-m-d\TH:i:s'); return $this; } diff --git a/src/Hyperwallet/Model/TransferMethod.php b/src/Hyperwallet/Model/TransferMethod.php index 85b39d39..14741c50 100644 --- a/src/Hyperwallet/Model/TransferMethod.php +++ b/src/Hyperwallet/Model/TransferMethod.php @@ -892,7 +892,7 @@ public function getDateOfBirth() { * @param \DateTime|null $dateOfBirth * @return TransferMethod */ - public function setDateOfBirth(\DateTime $dateOfBirth = null) { + public function setDateOfBirth(?\DateTime $dateOfBirth = null) { $this->dateOfBirth = $dateOfBirth == null ? null : $dateOfBirth->format('Y-m-d'); return $this; } diff --git a/src/Hyperwallet/Model/User.php b/src/Hyperwallet/Model/User.php index c0d59488..c7a75f23 100644 --- a/src/Hyperwallet/Model/User.php +++ b/src/Hyperwallet/Model/User.php @@ -439,7 +439,7 @@ public function getDateOfBirth() { * @param \DateTime|null $dateOfBirth * @return User */ - public function setDateOfBirth(\DateTime $dateOfBirth = null) { + public function setDateOfBirth(?\DateTime $dateOfBirth = null) { $this->dateOfBirth = $dateOfBirth == null ? null : $dateOfBirth->format('Y-m-d'); return $this; } diff --git a/src/Hyperwallet/Util/ApiClient.php b/src/Hyperwallet/Util/ApiClient.php index 286b3f7e..06db55f4 100644 --- a/src/Hyperwallet/Util/ApiClient.php +++ b/src/Hyperwallet/Util/ApiClient.php @@ -92,7 +92,7 @@ public function __construct($username, $password, $server, $clientOptions = arra * * @throws HyperwalletApiException */ - public function doPost($partialUrl, array $uriParams, BaseModel $data = null, array $query = array(), array $headers = array()) { + public function doPost($partialUrl, array $uriParams, ?BaseModel $data = null, array $query = array(), array $headers = array()) { return $this->doRequest('POST', $partialUrl, $uriParams, array( 'query' => $query, 'body' => $data ? \GuzzleHttp\json_encode($data->getPropertiesForCreate(), JSON_FORCE_OBJECT) : '{}', From 56b5055f76797380b4b342aca21ae2e9fd781b01 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:51:20 -0400 Subject: [PATCH 05/11] Support PHP 8.4 --- src/Hyperwallet/Model/HyperwalletVerificationDocument.php | 2 +- .../Model/HyperwalletVerificationDocumentReason.php | 2 +- src/Hyperwallet/Util/HyperwalletEncryption.php | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Hyperwallet/Model/HyperwalletVerificationDocument.php b/src/Hyperwallet/Model/HyperwalletVerificationDocument.php index ea2c1d69..fdff71a2 100644 --- a/src/Hyperwallet/Model/HyperwalletVerificationDocument.php +++ b/src/Hyperwallet/Model/HyperwalletVerificationDocument.php @@ -163,7 +163,7 @@ public function getUploadFiles($uploadFiles) { class HyperwalletVerificationDocumentCollection { /** @var HyperwalletVerificationDocument[] */ - private $documents; + public $documents; public function __construct(HyperwalletVerificationDocument ...$documents) { $this->documents = $documents; diff --git a/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php b/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php index 7eb3aa6a..3632df05 100644 --- a/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php +++ b/src/Hyperwallet/Model/HyperwalletVerificationDocumentReason.php @@ -70,7 +70,7 @@ public function getDescription() { class HyperwalletVerificationDocumentReasonCollection { /** @var HyperwalletVerificationDocumentReason[] */ - private $reasons; + public $reasons; public function __construct(HyperwalletVerificationDocumentReason ...$reasons) { $this->reasons = $reasons; diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index 3530f010..0096b273 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -114,8 +114,9 @@ public function __construct($clientPrivateKeySetLocation, $hyperwalletKeySetLoca */ public function encrypt($body) { $privateJwsKey = $this->getPrivateJwsKey(); + $payload = is_string($body) ? $body : json_encode($body); $jws = (new JWSBuilder(new AlgorithmManager([new RS256()])))->create() - ->withPayload($body) + ->withPayload($payload) ->addSignature($privateJwsKey, ['alg' => $this->signAlgorithm, 'kid' => $this->jwsKid, 'exp' => $this->getSignatureExpirationTime()]) ->build(); $jwsToken = (new JWSCompactSerializer())->serialize($jws); @@ -150,7 +151,8 @@ public function decrypt($body) { if (!(new JWSVerifier(new AlgorithmManager([new RS256()])))->verifyWithKey($jwsToVerify, $publicJwsKey, 0)) { throw new HyperwalletException('Signature verification failed'); } - return json_decode($jwsToVerify->getPayload(), true); + $claims = json_decode($jwsToVerify->getPayload(), true); + return is_array($claims) ? $claims : array('scalar' => $claims); } /** From 365fec75e615932d93373e3eb8bf094de4e179ec Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:52:58 -0400 Subject: [PATCH 06/11] Support PHP 8.4 --- src/Hyperwallet/Util/HyperwalletEncryption.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index 0096b273..03c7912b 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -142,7 +142,10 @@ public function decrypt($body) { $serializer = new JWECompactSerializer(); $jwe = $serializer->unserialize($body); $this->checkJweHeaderAlgorithm($jwe->getSharedProtectedHeader()); - (new JWEDecrypter(new AlgorithmManager([new RSAOAEP256(), new A256CBCHS512()]), null))->decryptUsingKey($jwe, $privateJweKey, 0); + (new JWEDecrypter( + new AlgorithmManager([new RSAOAEP256()]), + new AlgorithmManager([new A256CBCHS512()]) + ))->decryptUsingKey($jwe, $privateJweKey, 0); $publicJwsKey = $this->getPublicJwsKey(); $jwsToVerify = (new JWSCompactSerializer())->unserialize($jwe->getPayload()); From 09c12f2543315ea468ea81eb6fe28f9df1259b23 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Thu, 1 Oct 2026 23:55:02 -0400 Subject: [PATCH 07/11] Support PHP 8.4 --- src/Hyperwallet/Util/HyperwalletEncryption.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index 03c7912b..ad1f87cc 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -122,7 +122,10 @@ public function encrypt($body) { $jwsToken = (new JWSCompactSerializer())->serialize($jws); $publicJweKey = $this->getPublicJweKey(); - $jwe = (new JWEBuilder(new AlgorithmManager([new RSAOAEP256(), new A256CBCHS512()]))) + $jwe = (new JWEBuilder( + new AlgorithmManager([new RSAOAEP256()]), + new AlgorithmManager([new A256CBCHS512()]) + )) ->create()->withPayload($jwsToken) ->withSharedProtectedHeader(['alg' => $this->encryptionAlgorithm, 'enc' => $this->encryptionMethod, 'kid' => $this->jweKid]) ->addRecipient($publicJweKey)->build(); From ff21e355405fbe3f8ca93b9b13d669978844f5d9 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Fri, 2 Oct 2026 00:03:59 -0400 Subject: [PATCH 08/11] Support PHP 8.4 --- src/Hyperwallet/Util/HyperwalletEncryption.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index ad1f87cc..6898085d 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -145,10 +145,16 @@ public function decrypt($body) { $serializer = new JWECompactSerializer(); $jwe = $serializer->unserialize($body); $this->checkJweHeaderAlgorithm($jwe->getSharedProtectedHeader()); - (new JWEDecrypter( + $decrypted = (new JWEDecrypter( new AlgorithmManager([new RSAOAEP256()]), new AlgorithmManager([new A256CBCHS512()]) ))->decryptUsingKey($jwe, $privateJweKey, 0); + if ($decrypted instanceof \Jose\Component\Encryption\JWE) { + $jwe = $decrypted; + } + if (!$jwe->getPayload()) { + throw new HyperwalletException('Payload decryption failed'); + } $publicJwsKey = $this->getPublicJwsKey(); $jwsToVerify = (new JWSCompactSerializer())->unserialize($jwe->getPayload()); From 48a75c849d85a6853d0319776430d5eb30aa3863 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Fri, 2 Oct 2026 00:06:16 -0400 Subject: [PATCH 09/11] Support PHP 8.4 --- src/Hyperwallet/Util/HyperwalletEncryption.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index 6898085d..c5ae2342 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -114,7 +114,7 @@ public function __construct($clientPrivateKeySetLocation, $hyperwalletKeySetLoca */ public function encrypt($body) { $privateJwsKey = $this->getPrivateJwsKey(); - $payload = is_string($body) ? $body : json_encode($body); + $payload = json_encode($body); $jws = (new JWSBuilder(new AlgorithmManager([new RS256()])))->create() ->withPayload($payload) ->addSignature($privateJwsKey, ['alg' => $this->signAlgorithm, 'kid' => $this->jwsKid, 'exp' => $this->getSignatureExpirationTime()]) From 591bbdee8d347fb465e029b2a027d092ca60a279 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Fri, 2 Oct 2026 09:20:42 -0400 Subject: [PATCH 10/11] Update ci.yml --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index da5ff49c..9364a801 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,8 +36,6 @@ jobs: #get dependencies - name: Install dependencies - env: - COMPOSER_NO_BLOCKING: 1 run: composer install --prefer-dist --no-progress #get static analysis tool @@ -74,8 +72,6 @@ jobs: run: composer validate - name: Install dependencies - env: - COMPOSER_NO_BLOCKING: 1 run: composer install --prefer-dist --no-progress - name: Run test suite @@ -106,8 +102,6 @@ jobs: run: composer validate - name: Install dependencies - env: - COMPOSER_NO_BLOCKING: 1 run: composer install --prefer-dist --no-progress - name: Run test suite From 14c3b8c72aa06d3c73b1f4915094f9c984b4ea35 Mon Sep 17 00:00:00 2001 From: Gustavo Meyer Date: Fri, 2 Oct 2026 09:56:01 -0400 Subject: [PATCH 11/11] Update documentation.yml --- .github/workflows/documentation.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 9d4afa66..824dd4b5 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -26,13 +26,9 @@ jobs: coverage: xdebug - name: Install dependencies - env: - COMPOSER_NO_BLOCKING: 1 run: composer install --prefer-dist --no-progress - name: Install API doc generator tool - env: - COMPOSER_NO_BLOCKING: 1 run: composer create-project --no-dev apigen/apigen:^7.0 tools/apigen - name: Generate Documentation