diff --git a/Bootstrap.php b/Bootstrap.php index 64c96da..74a198f 100644 --- a/Bootstrap.php +++ b/Bootstrap.php @@ -177,6 +177,8 @@ public function boot(Dispatcher $dispatcher): void // Backend Hooks if (!Shop::isFrontend()) { + $this->deactivateDeprecatedPaymentMethods(); + /** * !FIX ISSUES WITH getHelpDesc: * - Description not being translated @@ -242,21 +244,7 @@ public function installed() $seeder->run(); } - // Deactivate Invoice Factoring Payment Method by setting nNutzbar to 0 - foreach ($this->getPlugin()->getPaymentMethods()->getMethods() as $method) { - if ( - ($method->getActive() || $method->getUsable()) && - in_array($method->getClassName(), self::getDeprecatedPaymentMethods()) - ) { - $this->getDB()->update( - 'tzahlungsart', - 'kZahlungsart', - $method->getMethodID(), - (object) ['nNutzbar' => 0, 'nActive' => 0] - ); - } - } - + $this->deactivateDeprecatedPaymentMethods(); $this->addApplePayVerification(); Shop::Container()->getCache()->flushTags([ @@ -273,22 +261,7 @@ public function installed() */ public function updated($oldVersion, $newVersion) { - // Deactivate Invoice Factoring Payment Method by setting nNutzbar to 0 - foreach ($this->getPlugin()->getPaymentMethods()->getMethods() as $method) { - if ( - ($method->getActive() || $method->getUsable()) && - in_array($method->getClassName(), self::getDeprecatedPaymentMethods()) - ) { - $this->getDB()->update( - 'tzahlungsart', - 'kZahlungsart', - $method->getMethodID(), - (object) ['nNutzbar' => 0, 'nActive' => 0] - ); - $this->getDB()->delete('tversandartzahlungsart', 'kZahlungsart', $method->getMethodID()); - } - } - + $this->deactivateDeprecatedPaymentMethods(); $this->addApplePayVerification(); Shop::Container()->getCache()->flushTags([ @@ -404,6 +377,24 @@ private function addApplePayVerification() } } + private function deactivateDeprecatedPaymentMethods(): void + { + foreach ($this->getPlugin()->getPaymentMethods()->getMethods() as $method) { + if ( + ($method->getActive() || $method->getUsable()) && + in_array($method->getClassName(), self::getDeprecatedPaymentMethods(), true) + ) { + $this->getDB()->update( + 'tzahlungsart', + 'kZahlungsart', + $method->getMethodID(), + (object) ['nNutzbar' => 0, 'nActive' => 0] + ); + + $this->getDB()->delete('tversandartzahlungsart', 'kZahlungsart', $method->getMethodID()); + } + } + } private function registerSmartyPhpFunctions(JTLSmarty $smarty): void { diff --git a/CHANGELOG.md b/CHANGELOG.md index c32ed6f..888e67d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [2.0.4] (June 2026) +### Added +- support for **JTL 5.7** and **PHP 8.5** +- added support for 2FA redirects for *Invoice*, *Installments*, and *Direct Debit* + +### Changed +- updated plugin documentation requirements +- remove *Merchant ID for Insight Portal* from settings as it is not needed anymore + +### Fixed +- updated order status logic for *Direct Bank Transfer* due to updated flow where payment status AND transaction status must be considered +- added missing error message after canceling card payments on 3DS redirect page +- added missing "language" to customer object for B2B customers for *Google Pay* +- handle error after canceling *Wero* payment +- issue with customer name being taken from the shipping address instead of the billing address +- issue with B2B customer object for non-UPL payment methods (missing *company* field in address, missing *companyInfo* field) + ## [2.0.3] (April 2026) ### Changed - basket metadata is now set for all payment methods diff --git a/README.md b/README.md index 4dbaf6e..defaf70 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Dieses Plugin integriert die folgenden Unzer-Zahlungsarten im JTL Shop: ## Installation / Update ### Systemvoraussetzungen - JTL-Shop 5.0.0+ und dessen Vorraussetzungen -- PHP Version: 7.4 - 8.4 +- PHP Version: 7.4 - 8.5 - Die folgenden PHP Erweiterungen - ext-json - ext-curl @@ -80,7 +80,7 @@ This plugin integrates the following Unzer payment methods into the JTL Shop: ## Installation/update ### System requirements - JTL-Shop 5.0.0+ and its requirements -- PHP version: 7.4 - 8.4 +- PHP version: 7.4 - 8.5 - The following PHP extensions - ext-json - ext-curl diff --git a/adminmenu/template/partials/_order_detail.tpl b/adminmenu/template/partials/_order_detail.tpl index cc366ae..0ccb312 100644 --- a/adminmenu/template/partials/_order_detail.tpl +++ b/adminmenu/template/partials/_order_detail.tpl @@ -1,25 +1,5 @@ {strip}
- {*
-
-
-
- {if $hpPortalUrl} - {if $hpPayment->getPaymentType()->getResourceName() === 'paylater-invoice'} - - {__('hpOpenInPaylaterPortal')} - - {else} - - {__('hpOpenInPortal')} - - {/if} - {/if} -
-
-
-
*} -
diff --git a/adminmenu/template/partials/_order_item.tpl b/adminmenu/template/partials/_order_item.tpl index 6e16e3b..4045284 100644 --- a/adminmenu/template/partials/_order_item.tpl +++ b/adminmenu/template/partials/_order_item.tpl @@ -99,9 +99,6 @@
- {* {if $hpPortalUrl} - - {/if} *}
diff --git a/adminmenu/template/settings.tpl b/adminmenu/template/settings.tpl index 1e3a6f7..404d47a 100644 --- a/adminmenu/template/settings.tpl +++ b/adminmenu/template/settings.tpl @@ -40,17 +40,6 @@ {__('hpSettingsPublicKeyHelp')}
- - {* hIP / Insight Merchant ID *} -
-
- -
-
- - {__('hpSettingsMerchantIdHelp')} -
-
diff --git a/checksums.csv b/checksums.csv index 1e7396e..2e4c2ab 100644 --- a/checksums.csv +++ b/checksums.csv @@ -1,12 +1,12 @@ 145536c4c9441cf9505709d27d9ace95;vendor/autoload.php 42215678dd84b72ae4592d6ff273a5a4;vendor/unzerdev/php-sdk/.gitignore -5b1d4c545c4730184ee6d31e1b62d6d9;vendor/unzerdev/php-sdk/composer.json +91f38bd3958dc339911e610cab558dc1;vendor/unzerdev/php-sdk/composer.json d045397c5fda276eb286c147ceb74ee4;vendor/unzerdev/php-sdk/.php-cs-fixer.php 2a835730131c1caf9963f59289b389bb;vendor/unzerdev/php-sdk/unzer_logo.svg 82e474803328bb1afbfaf2b535683353;vendor/unzerdev/php-sdk/README.md -a4af7012fda92d785800fc2b39554efa;vendor/unzerdev/php-sdk/src/Adapter/ApplepayAdapter.php -b3cc767aacbb53771524c28679417389;vendor/unzerdev/php-sdk/src/Adapter/CurlAdapter.php -88f296c8dfdf09a9458bb75157cc5c3d;vendor/unzerdev/php-sdk/src/Adapter/HttpAdapterInterface.php +9f49625409c8562dc5da83096fd8a2e9;vendor/unzerdev/php-sdk/src/Adapter/ApplepayAdapter.php +552058cd99a7a6fd1834483e38f98858;vendor/unzerdev/php-sdk/src/Adapter/CurlAdapter.php +eb44b2c3c837196f74cc8faea5bb31a0;vendor/unzerdev/php-sdk/src/Adapter/HttpAdapterInterface.php aa58f837939ad64accce276415d6f06e;vendor/unzerdev/php-sdk/src/Apis/PaymentApiConfigBearerAuth.php 2cc971984b5e289b35fd1d0cf521d3ec;vendor/unzerdev/php-sdk/src/Apis/ApiRequest.php 30626969f60f4698d5f563f170049344;vendor/unzerdev/php-sdk/src/Apis/PaymentApiConfig.php @@ -16,11 +16,11 @@ a9e0cee672d89f960dd976da3c6ad9ee;vendor/unzerdev/php-sdk/src/Apis/PaypageAPIConf 75c5a444fb0c4ab0a80aed8d2e2967bc;vendor/unzerdev/php-sdk/src/Apis/TokenApiConfig.php a4d2fcde4cc90b1e230d3a3297b5d6f8;vendor/unzerdev/php-sdk/src/Exceptions/ApplepayMerchantValidationException.php 5f5e379cbf764b6e85a55d4894b17741;vendor/unzerdev/php-sdk/src/Exceptions/UnzerApiException.php -4c2df74677faf75d3a102b4a29114152;vendor/unzerdev/php-sdk/src/Services/PaymentService.php +686a2beca8f8aa446327477d76db9b21;vendor/unzerdev/php-sdk/src/Services/PaymentService.php 71d63712f7831a18ceb6285a4668c11a;vendor/unzerdev/php-sdk/src/Services/JwtService.php ce9878fd925c1e5e1569c27f121cf994;vendor/unzerdev/php-sdk/src/Services/ResourceNameService.php -852732451b4c657778f8b3a36b2106ce;vendor/unzerdev/php-sdk/src/Services/ResourceService.php -3125b48394c6d38da644ac8d39c95c13;vendor/unzerdev/php-sdk/src/Services/HttpService.php +caff8c617fe1670be57c779068a4e74f;vendor/unzerdev/php-sdk/src/Services/ResourceService.php +770fc43a506087f04287c82f786ca213;vendor/unzerdev/php-sdk/src/Services/HttpService.php ae5f057b154780300a9d422e51267c47;vendor/unzerdev/php-sdk/src/Services/ValueService.php 4dc8957cf26214316b9dbf19e9624570;vendor/unzerdev/php-sdk/src/Services/EnvironmentService.php f49941ac10f5c4493af0711ad48ce056;vendor/unzerdev/php-sdk/src/Services/WebhookService.php @@ -30,14 +30,15 @@ ef551bd65236c93d95854665fe9671f2;vendor/unzerdev/php-sdk/src/Services/IdService. a7ca6bddd5964f87f73beaa4c48cb9e1;vendor/unzerdev/php-sdk/src/Resources/Webhooks.php e8072c55c5894fe4cb8df5773da221be;vendor/unzerdev/php-sdk/src/Resources/PaylaterInstallmentPlans.php 595c41677b4b4e225d2af3e87fc5abe2;vendor/unzerdev/php-sdk/src/Resources/Config.php -e0a74d283a2169dbfeeb1143a44259d5;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Authorization.php -b906ccbb36133becfb879319a254d1a9;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Cancellation.php -7930009039dd07900eff065e29c246ee;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/AbstractTransactionType.php -a152d436db1db5a5c73f8e6a056b5ef0;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Chargeback.php -0aae277cba417d984000ed45a632ec2d;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Payout.php -c980f0dd8167b419e3b16f6a5f065de9;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Shipment.php +222875e3341c7255dcb12146c6c13eee;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Authorization.php +734cdc8b48aa8ebd6d52a465f01136a6;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Sca.php +2b1de8d68da8fa5a9296e16940325c01;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Cancellation.php +1ca23a6063572f7131f0ba4f75c4ce2c;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/AbstractTransactionType.php +3af79cec09dcc1d19d176019ba93673e;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Chargeback.php +d41239bda7030d30f68a4a5e396ea6d6;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Payout.php +3d5871fbf83878e82786067d8bf94321;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Shipment.php 838230dff07bf7f53ce1d1624e181ba4;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/PreAuthorization.php -b85f24ac5ffd4d18d3e7402c9b137ad4;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Charge.php +67df9a096e11bd79af51ce8f8ea53548;vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Charge.php 80aba343a244782d1083deecceb47716;vendor/unzerdev/php-sdk/src/Resources/Keypair.php c2d7dea4481042090695eb953609149b;vendor/unzerdev/php-sdk/src/Resources/CustomerFactory.php a7d177281187488e329194e8a03f3648;vendor/unzerdev/php-sdk/src/Resources/Recurring.php @@ -62,16 +63,16 @@ a6707cb0803758888a636a27bda62484;vendor/unzerdev/php-sdk/src/Resources/EmbeddedR 817f0f9895c40818f33d68450acfb8dd;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Payment.php 6f87064d204f19090cea2a076047fc9c;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/PaymentMethodConfig.php f6fd7cc64eb7683f8c744d48c3624d2d;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Resources.php -e640841cde29c0d4f41b39e0f49cdd9b;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Urls.php +06b1081477352a826b00b46ccd5d4090;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Urls.php abb9026bf13603593ef7ed6b36a20b6e;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/WeroEventDependentPayment.php 991b1745a5e85730edd024799da8e016;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Amount.php -4c5ae19b086aa7ba6487d9538b3d034e;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Address.php +a3d6bdf35f37070274e485a9c1a13952;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Address.php d078edc8bc6f4252e14bb3ee1beeb7b7;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/WeroTransactionData.php 49dbf6c8a912cc4f2038282435e4e953;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/CardTransactionData.php cbf16109faff0b644e54275047af86a9;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/RiskData.php 8a44e7b39b46559b0a6a665ca64c50e0;vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/CardDetails.php 89e657fa872ca0c6a816fe7b78cf7947;vendor/unzerdev/php-sdk/src/Resources/InstalmentPlans.php -c39894f511400c81c0eab4137fdd9495;vendor/unzerdev/php-sdk/src/Resources/Payment.php +f6e11fded1b16b2730fc0ab8eae719ef;vendor/unzerdev/php-sdk/src/Resources/Payment.php 9882f597bd321facccdf64f059f3f00d;vendor/unzerdev/php-sdk/src/Resources/Authentication/Token.php ddfd5bb7fd8a51627555ea5848042df9;vendor/unzerdev/php-sdk/src/Resources/Basket.php dd622d8ec6f7c8e4dd46e9d546907d47;vendor/unzerdev/php-sdk/src/Resources/ExternalResources/ApplepaySession.php @@ -95,7 +96,7 @@ caeb3b948944a85c95b0484d8218c175;vendor/unzerdev/php-sdk/src/Resources/PaymentTy 04aa677940d068649579dc0d64e4e197;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Wero.php 202e427f0c83e6e1c07c2b88a63b9ffd;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Prepayment.php aeef0a128d084d193928963672d3c8c1;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/PayU.php -ef86892e52f66de6cee3d0f30fa9128a;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Giropay.php +e853c117069976d374373ff92d4de8cf;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Giropay.php fc44edd342dfa869073c5046d0ad57ef;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/PaylaterInstallment.php c24930d176f6feb44ebdd8667b78d2a9;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Paypage.php 3969c1660e11ad35f9725e6c0dd12ff1;vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Paypal.php @@ -124,11 +125,11 @@ f8404409d255be6044ca17101d30c3f1;vendor/unzerdev/php-sdk/src/Constants/WeroCaptu d6ce87c1b1074bd214c33a699dda1ba4;vendor/unzerdev/php-sdk/src/Constants/PaypageCheckoutTypes.php 0e200a50be01534d35527c06939d1721;vendor/unzerdev/php-sdk/src/Constants/RecurrenceTypes.php c8cd2db011dac68e7b0b34fbc2834cd3;vendor/unzerdev/php-sdk/src/Constants/CompanyCommercialSectorItems.php -e3d540435791c183ea9b85c4dfe068aa;vendor/unzerdev/php-sdk/src/Constants/ApiResponseCodes.php +2adaf19318b19c5894ac92ebe422d6f3;vendor/unzerdev/php-sdk/src/Constants/ApiResponseCodes.php 48c8611e7a204fbcdc8305f7bd77fd94;vendor/unzerdev/php-sdk/src/Constants/ApiVersions.php 98b1a747a7cf8967723484dc357435f3;vendor/unzerdev/php-sdk/src/Constants/BasketItemTypes.php 24fd3dfe4fb5793d8e18d49146c1aba2;vendor/unzerdev/php-sdk/src/Constants/CompanyRegistrationTypes.php -2f146fe88f6e1fc021fd221e0520dbfc;vendor/unzerdev/php-sdk/src/Constants/TransactionTypes.php +dd77648e7995d9b66e179747f30b6163;vendor/unzerdev/php-sdk/src/Constants/TransactionTypes.php 1c9d020ce65ee798772ca615b738ef11;vendor/unzerdev/php-sdk/src/Constants/WeroAmountPaymentTypes.php 3566859c7e75857511595a9f0525bd45;vendor/unzerdev/php-sdk/src/Constants/TransactionStatus.php 86812143071f5cf885cef4d0bb79309a;vendor/unzerdev/php-sdk/src/Constants/ExemptionType.php @@ -138,13 +139,13 @@ afcfc9d1619fec0c54b2c3a208cdaa39;vendor/unzerdev/php-sdk/src/Constants/ApplepayV dc551df19569c288082c989c2bbf3e85;vendor/unzerdev/php-sdk/src/Constants/ShippingTypes.php e9f968341351755f055d926c21f05adc;vendor/unzerdev/php-sdk/src/Constants/Salutations.php 5984d0444c09208017ef39cf46347aea;vendor/unzerdev/php-sdk/src/Constants/CustomerGroups.php -2d47ffdbaeeea41d28d88aa3695c5067;vendor/unzerdev/php-sdk/src/Constants/IdStrings.php +a87e48ce2925af0df9e27be25dfc7c0d;vendor/unzerdev/php-sdk/src/Constants/IdStrings.php a67c8a544a6760a9f5e8a490dae004ca;vendor/unzerdev/php-sdk/src/Constants/AdditionalAttributes.php 36d1a80f7177ac150fc5762078ddb55e;vendor/unzerdev/php-sdk/src/Constants/PaymentState.php e648bfec127404941a0a104ac0320272;vendor/unzerdev/php-sdk/src/Validators/PrivateKeyValidator.php c62a9f0b3664502a49fd27f6cd6919b3;vendor/unzerdev/php-sdk/src/Validators/PublicKeyValidator.php aaf5ac4b651d570ea067cd78ab596e96;vendor/unzerdev/php-sdk/src/Validators/ExpiryDateValidator.php -77fe01270009288a8ac9f84d89a503ad;vendor/unzerdev/php-sdk/src/Unzer.php +ea43bc5e8e2842df517ac7ad2a975943;vendor/unzerdev/php-sdk/src/Unzer.php 58dccf5766f3619b338dd4f8803fae4c;vendor/unzerdev/php-sdk/src/Traits/HasUniqueAndShortId.php e032a9a2cc661550726c2f898f983682;vendor/unzerdev/php-sdk/src/Traits/HasAdditionalTransactionData.php 84e1de89b2385e79556c2ec21ba086f3;vendor/unzerdev/php-sdk/src/Traits/HasCustomerMessage.php @@ -172,8 +173,8 @@ f0a492f8bfbdff8718ae4c0c5571790b;vendor/unzerdev/php-sdk/src/Traits/HasAccountIn 454557a6a894225ddf5912e990e8f19e;vendor/unzerdev/php-sdk/src/Interfaces/DebugHandlerInterface.php 90d968a7c087f103a1b627f1346622ed;vendor/unzerdev/php-sdk/src/Interfaces/WebhookServiceInterface.php 89d011fdc511aeb3f0b3dd3936f28d75;vendor/unzerdev/php-sdk/src/Interfaces/CancelServiceInterface.php -6c31c5fde8540d9e40a29590a4ea737f;vendor/unzerdev/php-sdk/src/Interfaces/PaymentServiceInterface.php -c05113458aca974c27fc8b748d7b7ef8;vendor/unzerdev/php-sdk/src/Interfaces/ResourceServiceInterface.php +db3d2e1b5409735acf0fed6c07fb3c81;vendor/unzerdev/php-sdk/src/Interfaces/PaymentServiceInterface.php +e9c317d65ba22f6f7c59ee6fd6e329d4;vendor/unzerdev/php-sdk/src/Interfaces/ResourceServiceInterface.php 86d3f3a95c324c9479bd8986968f4327;vendor/unzerdev/php-sdk/LICENSE 9e9f49ec809ad456b453410ef1785548;vendor/unzerdev/php-sdk/.codacy.yml 3acde2e3165b3bc005591d39f205b73d;vendor/unzerdev/php-sdk/examples/ExampleDebugHandler.php @@ -292,10 +293,10 @@ c1c5a14b36b9d911f5a0e978556dc71c;vendor/unzerdev/php-sdk/examples/Card/index.php 91c640a180c6a402db48711a0c99aed4;vendor/unzerdev/php-sdk/examples/EPSCharge/Controller.php 29a32449df2a240cad460522a386570b;vendor/unzerdev/php-sdk/examples/EPSCharge/Constants.php 4a03f03080b4c42e66111dd0d47e590f;vendor/unzerdev/php-sdk/examples/EPSCharge/index.php -89ebe697baeeb27174bdca3648ef1f3f;vendor/unzerdev/php-sdk/phpunit.xml +9188d01a5a66261215c8dbc4ebddc2e4;vendor/unzerdev/php-sdk/phpunit.xml 417e6e42dee83ba2011090b70c0cd90c;vendor/unzerdev/php-sdk/.travis.yml cdbe7e4fb996b050423c7232a71bff67;vendor/unzerdev/php-sdk/NOTICE -6758028fe0caf5928bd44c405aa08596;vendor/unzerdev/php-sdk/CHANGELOG.md +017585f45b04774ea8e4cb0c1ebd96cc;vendor/unzerdev/php-sdk/CHANGELOG.md 4d30b8fd445b436492aa726177b2f3be;vendor/unzerdev/php-sdk/test/BaseIntegrationTest.php 500708d41b270db56199238ec7a678ff;vendor/unzerdev/php-sdk/test/unit/DummyResource.php 2326f4bd5d26ead1710d780114fe9ffb;vendor/unzerdev/php-sdk/test/unit/Adapter/ApplepaySessionTest.php @@ -304,18 +305,18 @@ ac839c86ae72500cc78d6b746c841d27;vendor/unzerdev/php-sdk/test/unit/Exceptions/Un 9b86dd7a5798109211e4bba3eb70c5e7;vendor/unzerdev/php-sdk/test/unit/Services/DummyDebugHandler.php 828450cf3e68bc204d592b1b41dd2246;vendor/unzerdev/php-sdk/test/unit/Services/PaymentServiceTest.php 3c6fab6f8e2b1ba3e056779a8e8278a5;vendor/unzerdev/php-sdk/test/unit/Services/JwtServiceTest.php -19faed6f4d6d88ab787808229a7a0d7e;vendor/unzerdev/php-sdk/test/unit/Services/WebhooksServiceTest.php -1eff3cfce97848172d9e7666ce75aba5;vendor/unzerdev/php-sdk/test/unit/Services/DummyAdapter.php -4d8a94a1783075d3193ef964874711dd;vendor/unzerdev/php-sdk/test/unit/Services/CancelServiceTest.php -dc0ccf9224c7cbfd6256cd902e8a7014;vendor/unzerdev/php-sdk/test/unit/Services/ResourceServiceTest.php +3606ddd2612a90895b9dc2378eccadb1;vendor/unzerdev/php-sdk/test/unit/Services/WebhooksServiceTest.php +949702b3d491fa8920936fad49487928;vendor/unzerdev/php-sdk/test/unit/Services/DummyAdapter.php +4d019ea5ac8ff292b44b8972b89a3944;vendor/unzerdev/php-sdk/test/unit/Services/CancelServiceTest.php +c07aa855ebeba0a69bbe0d707a0f9eae;vendor/unzerdev/php-sdk/test/unit/Services/ResourceServiceTest.php 66acfe236eb7dcb1b2fa73c70b3d7ca5;vendor/unzerdev/php-sdk/test/unit/Services/ResourceNameServiceTest.php -5fb399f6993314066a7fb99bd6158b03;vendor/unzerdev/php-sdk/test/unit/Services/HttpServiceTest.php +dfba206be238951a73882d433fe9deb8;vendor/unzerdev/php-sdk/test/unit/Services/HttpServiceTest.php 04033672568687db6ff4937d891caa9f;vendor/unzerdev/php-sdk/test/unit/Services/IdServiceTest.php -3506ff4007bb51bf218ac7fd08160564;vendor/unzerdev/php-sdk/test/unit/UnzerTest.php +011ec356390f2c13158ef3d03fad5be7;vendor/unzerdev/php-sdk/test/unit/UnzerTest.php 9305a2c9ec330ae8e730116239710828;vendor/unzerdev/php-sdk/test/unit/Resources/KeypairTest.php 55c8f63568b8a95322e9f8c62c2c80d9;vendor/unzerdev/php-sdk/test/unit/Resources/InstalmentPlanTest.php db440982ec14bd99d4ba4a746fd7e554;vendor/unzerdev/php-sdk/test/unit/Resources/PaymentTest.php -8e1b69587751e684d738b537f3b9f4c7;vendor/unzerdev/php-sdk/test/unit/Resources/CustomerTest.php +6abd3bb4eb734944729720941db5aeb5;vendor/unzerdev/php-sdk/test/unit/Resources/CustomerTest.php fac208735ce2184117af0cbf4c677215;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/ShipmentTest.php 036e99aad2e09e82c96c9d2de1183535;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/PayoutTest.php 5f9b74b9a50978fc421f62ed6177e98d;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/AbstractTransactionTypeTest.php @@ -323,6 +324,7 @@ c95c7d800a8d15fb66277cbfeb21b220;vendor/unzerdev/php-sdk/test/unit/Resources/Tra 0d6708b71d9c8575ba182a054d76f2d7;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/ChargeTest.php 45cd24b6560bc2f4e403c2cc5dbd9473;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/DummyTransactionType.php fcaa8b37f1a82ceb6dba3d6b58b01a41;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/AuthorizationTest.php +eba02cd6f41fbb67869425352abe824c;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/ScaTest.php 855505d7d60059ccae8ce92062bcd9a5;vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/CancellationTest.php 8e49881a9046c585465771123c43de0f;vendor/unzerdev/php-sdk/test/unit/Resources/PaylaterInstallmentPlansTest.php 64764b6899b8aa3780df619a670f3a42;vendor/unzerdev/php-sdk/test/unit/Resources/WebhookTest.php @@ -401,15 +403,16 @@ a95799f26594e269182ddea7e3c084b5;vendor/unzerdev/php-sdk/test/integration/Transa 40893d16f3c3cda0d1d4dc10ecce933b;vendor/unzerdev/php-sdk/test/integration/TransactionTypes/CancelTest.php 2f64cf368a9b25f7a40300359aa69087;vendor/unzerdev/php-sdk/test/integration/TransactionTypes/ChargeTest.php a82ed165d0b3ee08c60f73be0a3cdea2;vendor/unzerdev/php-sdk/test/integration/TransactionTypes/AuthorizationTest.php +ba60f31732a6a69c1a96199d51f07345;vendor/unzerdev/php-sdk/test/integration/TransactionTypes/ScaTest.php d7a1322927ca7755d0f5e49540540e13;vendor/unzerdev/php-sdk/test/integration/TransactionTypes/PreAuthorizationTest.php -ec49c19bbe0ac1c76444f14a39ce91f3;vendor/unzerdev/php-sdk/test/integration/WebhookTest.php +a2945a7614063d49bbb39eda237e6138;vendor/unzerdev/php-sdk/test/integration/WebhookTest.php c05be2f170488399917d1163f7b320e2;vendor/unzerdev/php-sdk/test/integration/Resources/BasketV2Test.php 85c232a1b8a7ef9ddb25ff8486d58f97;vendor/unzerdev/php-sdk/test/integration/Resources/KeypairTest.php ee8dd89cf6b958dfb375a12de69d585a;vendor/unzerdev/php-sdk/test/integration/Resources/BasketV3Test.php 281b8567daa5fb185052501ea191bdac;vendor/unzerdev/php-sdk/test/integration/Resources/AuthTokenTest.php c316f310519ecb2042832a8c9b1ceb45;vendor/unzerdev/php-sdk/test/integration/Resources/CustomerTest.php a66a6f07314de8a6963cf0dc6546d49a;vendor/unzerdev/php-sdk/test/integration/Resources/LinkpayV2Test.php -944338aacaf487be6f86c66e720ffc3d;vendor/unzerdev/php-sdk/test/integration/Resources/PaypageV2Test.php +92c9f9a30dbe08e4534de30543c2a162;vendor/unzerdev/php-sdk/test/integration/Resources/PaypageV2Test.php 939f400632308f5bc47403c704c74dfb;vendor/unzerdev/php-sdk/test/integration/Resources/CustomerV2Test.php 1d3f9ae6c57d57fff67ad8e665a48fe6;vendor/unzerdev/php-sdk/test/integration/Resources/ConfigTest.php 2f61e94cd276a0e8134f180240b394c5;vendor/unzerdev/php-sdk/test/integration/Resources/BasketTest.php @@ -431,7 +434,6 @@ c7b76e5bb76f092d28414526cff6296f;vendor/unzerdev/php-sdk/test/integration/Paymen 68e14fbe9ec515539fc605fe7f0301c5;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/HirePurchaseTest.php c313889561db37bb58b1e12f8e5a2d5c;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/PostFinanceEfinanceTest.php e05854b48b714df0bdc0cf23f4933e39;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/Przelewy24Test.php -c579a34b18cb399d3dc245510033ae4f;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/GiropayTest.php 3e33484f5d4a6ceeee0e9e2fdcf33f6e;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/OpenBankingTest.php 32f07cd5dd649448e750cfeb87b3a115;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/SepaDirectDebitTest.php c56b45988630951dcfc0c8a69fe46983;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/SepaDirectDebitSecuredTest.php @@ -449,9 +451,9 @@ be8d81d889f66425c9b3df8aaa308aab;vendor/unzerdev/php-sdk/test/integration/Paymen 4d0568fc244daf8c175c51843823a24d;vendor/unzerdev/php-sdk/test/integration/PaymentTypes/WechatpayTest.php b5cd4812669a03576f47293ff8c93208;vendor/unzerdev/php-sdk/test/integration/ExceptionTest.php 30f2e8cb9ff544ae1b23029783424b16;vendor/unzerdev/php-sdk/test/TestDebugHandler.php -f8f15b6e3f16a292aec754dd2f758ae7;vendor/unzerdev/php-sdk/test/Helper/TestEnvironmentService.php +81ba407b450b7dd51dc1d81897b5179a;vendor/unzerdev/php-sdk/test/Helper/TestEnvironmentService.php 7e38b5a3118a4d3c48875bdd5951e9f1;vendor/unzerdev/php-sdk/test/Fixtures/DummyPaypageResource.php -f3f5137c2d3e4e8e67a64cd049628d4f;vendor/unzerdev/php-sdk/test/Fixtures/CustomerFixtureTrait.php +1d777fcf089b0f25e2003643723f817a;vendor/unzerdev/php-sdk/test/Fixtures/CustomerFixtureTrait.php a345f9cd02ebbed4a0389b6e7f0e3423;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/paymentWithMultipleChargebacks.json a8441a121efba5227555da6e57398674;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/sofortResponseWithIban.json bc03ca4a157c1385fbb2beb0479866db;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/googlePay/fetchResponse.json @@ -460,6 +462,8 @@ dd56c7e88804f2352c1dcdd889e024e3;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/ 0b13de4b63f5cbcc258f65201874860d;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/paymentWithDirectChargeback.json 76a1641ff2bef335125ca6d8e38e4565;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/openBanking/fetchResponse.json ac2e9e419384b726bad7428cc133ef96;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/openBanking/createRequest.json +fa8d2dcb99e3573025c4adf2621626f3;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaResponse.json +fa8d2dcb99e3573025c4adf2621626f3;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaPaymentResponse.json b0833d74dd2e9cf65ef75fb25be5d638;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/chargeback.json 479257fe263661437ba83428b5eacea4;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/paylaterPlansResponse.json 5d8230cbfdfba058282fb1dbfbb1671c;vendor/unzerdev/php-sdk/test/Fixtures/jsonData/clicktopay/fetchResponse.json @@ -472,13 +476,13 @@ e774a6ac03dc87705a34dd6d7f3c12a5;vendor/unzerdev/php-sdk/.github/workflows/relea fcaa877ac215df25e0d42b84944bebfb;vendor/unzerdev/php-sdk/.github/workflows/test-group.yml d51675285e38b187ec6501184c62e639;vendor/unzerdev/php-sdk/.github/workflows/validate-pull-request.yaml 46d029825edf473241d92ecac3c3c99f;vendor/unzerdev/php-sdk/.github/workflows/pre-release.yml -334bdebaaac275bb9e6d71b7fec6ffd6;vendor/unzerdev/php-sdk/.github/workflows/integration-tests.yml -fa04e71dfaaf414b6cfb5346dfa90dbe;vendor/unzerdev/php-sdk/.github/workflows/unit-tests.yml +75838ebe2f7d3bf2f532b52d5ffdd0da;vendor/unzerdev/php-sdk/.github/workflows/integration-tests.yml +0fe235db894f6e6f84da29f5c75bf13c;vendor/unzerdev/php-sdk/.github/workflows/unit-tests.yml 285a85e6e41f2280105391b2c2eb419a;vendor/unzerdev/php-sdk/.github/CODEOWNERS dd08d7ce34d93812b90e0c83b0830e8e;vendor/phpseclib/phpseclib/composer.json -7c4783c1028e43311e7cf8b23c24e04d;vendor/phpseclib/phpseclib/README.md +e2a1eb9143daf9f081f5084edcb058e1;vendor/phpseclib/phpseclib/README.md af7368297e479652e6ef808a77702c02;vendor/phpseclib/phpseclib/LICENSE -280193e7acc99cbd28d43ebacd2fd641;vendor/phpseclib/phpseclib/BACKERS.md +c0ee803794670f39215eed46917d433e;vendor/phpseclib/phpseclib/BACKERS.md 1fb9bc73e302ba9f215d86d67b3b5d73;vendor/phpseclib/phpseclib/phpseclib/Math/Common/FiniteField/Integer.php 8e0f3772662114a3962313d5db474e6e;vendor/phpseclib/phpseclib/phpseclib/Math/Common/FiniteField.php 042e8e610407b41b8a04e2872dedccbb;vendor/phpseclib/phpseclib/phpseclib/Math/BinaryField/Integer.php @@ -495,29 +499,30 @@ d8f32f01017420777ca33c5ab42d198d;vendor/phpseclib/phpseclib/phpseclib/Math/BigIn b0bdb15defb90d6831c4fe93304b77f2;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/DefaultEngine.php d47eb0d3141be93cd6922acb835490cd;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Base.php 4cbcdafb51c872cba4056acc5f6eac8b;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP/Montgomery.php -6332016312d1d3953c80fb455f58f408;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php +0cfc7293113928a788661fd5f9af7c93;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php 49b1796260911082f7161693e98f85dd;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/BuiltIn.php 1c15632b86b84f479562355f5bd64508;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/EvalBarrett.php c9d1fa5d368cb1c02419385af1f53682;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Reductions/Barrett.php ff90ba3a9f0c50437fb28123c299f54b;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/OpenSSL.php 015ff4bbf9f1f1a7ff93ce629d26e526;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/DefaultEngine.php 069ab262e56cb04c8e98f984990c0c33;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath/Base.php -e631a19bb6a96bdc18adf2403a2d56eb;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php +980b079f85d93d1b4b2e6975b9e86c30;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php cbd9ba4467f0da947945995a321edd21;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/OpenSSL.php 0aa26e7824ba2a16a70c86b75c841457;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/GMP.php f7b341f7c554b4e54f171e2422fa8b5e;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP64.php cd487f310c02e392196943e546884f8e;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP32.php 4c97fb94f7ece153860c64e23ab23a4c;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/PHP.php -62f752aa06fad549c4d1cb42f867615e;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php +5ca3190b44646deae3acd42118e1a6cf;vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php 36512abd6cdfe352f637cb76498735b8;vendor/phpseclib/phpseclib/phpseclib/Math/PrimeField.php -198e01f56568a15f8974b3a6b6f0ccd9;vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php +ba1d4ac9deaeab29eb0ecb68b253f7b5;vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php +729ff7444a2fd7e4b9f97e8764aaf98e;vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php c539ce0c2ace26e54f815dc528ad2d11;vendor/phpseclib/phpseclib/phpseclib/Net/SFTP/Stream.php -94ee2a235b1662100d5a2304d8996ebf;vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php -e210be3ac52737cd128b7b3a06b01eb5;vendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php +f869da816440163ccd245c3f1697f200;vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php +0883155c763939fd885c577e110e2c83;vendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php 0c054287acdbdda2d6244fc5ade26b95;vendor/phpseclib/phpseclib/phpseclib/System/SSH/Common/Traits/ReadBytes.php 36cc261390c51c0fa66f632955b0dab9;vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent.php 41b9b94bdfd534ab6ebfb7d0bf8a549a;vendor/phpseclib/phpseclib/phpseclib/System/SSH/Agent/Identity.php -61bbb04b8162a956e98bb7ccc1fe0586;vendor/phpseclib/phpseclib/phpseclib/File/X509.php +25600dbef9f25b058af6b58c2de0c320;vendor/phpseclib/phpseclib/phpseclib/File/X509.php 018bd58600c2545f967ada149fdc68ca;vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PolicyMappings.php 166dfc573923b7344b378c9206e740e3;vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/EncryptedPrivateKeyInfo.php 13d1f23144be3bc417b9bd3be4fc2e49;vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/PublicKeyAndChallenge.php @@ -644,7 +649,7 @@ e903157db0864e0e9d0eb218fe7cee40;vendor/phpseclib/phpseclib/phpseclib/File/ASN1/ 3f7317e790640697bfb4bf94a90ab5af;vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Maps/ORAddress.php 64c983e5d1708fe24f8846e2ebbec7ed;vendor/phpseclib/phpseclib/phpseclib/File/ASN1/Element.php be01c1e368e54acfcae749bb5adbec11;vendor/phpseclib/phpseclib/phpseclib/File/ANSI.php -bb23f25797936751ad5a0bafbca14e72;vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php +f6b9807b84219280f9ad3f0ffa014f8f;vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php f4c5e01e7cb2909f26413f789ed81397;vendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedAlgorithmException.php e1e2e5e0b7e8cc03abe3ff1acabd24a3;vendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedCurveException.php fb3bcd58ba318d74117a7c3e05edc63b;vendor/phpseclib/phpseclib/phpseclib/Exception/ConnectionClosedException.php @@ -661,23 +666,23 @@ cf8e7671e5079a6774c35202ae5ff4b4;vendor/phpseclib/phpseclib/phpseclib/Exception/ 0b7d8e736a24ddedf5ed00d3484c8975;vendor/phpseclib/phpseclib/phpseclib/Exception/UnsupportedOperationException.php 6601a8131d3fa88b4f1ecf2ae6f9a08b;vendor/phpseclib/phpseclib/phpseclib/Exception/InsufficientSetupException.php 87189e47473849d93fabe1d4fd321afb;vendor/phpseclib/phpseclib/phpseclib/Exception/BadConfigurationException.php -08f1c224f83cb895ccfcbf19fb533d77;vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php -83ca72d0fc0877c6b83d4ef9012c081b;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH.php +6b921084db11ad69e05e2bd4511e5e13;vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php +50a9970abe5d79864ed0c2a07a9e3d2a;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH.php 63ad81d212055e6f7cb2a7b4fd3dec45;vendor/phpseclib/phpseclib/phpseclib/Crypt/TripleDES.php -94de83bbcb9b5dc37a31dc88601f2a61;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php -a8f255a935d49125b9b5fd2203acadef;vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php +a2927cb3a950e3134205973d39e7ff60;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php +c240cb99074591033cb4b315adeaf14b;vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php bf244e3a321ca4b5ff3a7fd6124d890f;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH/Parameters.php 543a0fad2f9537141cf01ea1e20bea7f;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php a65e06350f5c66ead4851267d6fe8691;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH/Formats/Keys/PKCS1.php 9088f575e0a162a7ea204b0096ba203d;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH/PrivateKey.php 69f80949b9a90d0cc5e0cf85a3cc6410;vendor/phpseclib/phpseclib/phpseclib/Crypt/DH/PublicKey.php -9413e5062c393230ba5864b0e0c8c846;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php +e95a3979cdf515ccab79d1a7187b7e09;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php fd01c80ae620ff944ad224694f7929a1;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Signature/Raw.php e2a29c354145d8d4a02f7fd90a9a51ec;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS.php 28c57580625b4396514c8b6fd6afda6a;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PuTTY.php 1cd0dcbf16bd2e409de781bada186d38;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/JWK.php -dec9bf7e379ae4691a569535e30d2a2a;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php -00a43339931458efdcf9b0f35aca57b8;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php +46ef6859c4e069274e8f543c6d8848ac;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php +22b1cf15eacbaade6e7f9802796a9ace;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php fec521301d5d0c69fc1e507c13443437;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS1.php 8e36169ff0be06f0fde8dcdaec6631ec;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/PrivateKey.php 0ce1b5e4f8296fd1de88185604288aee;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/BlockCipher.php @@ -685,20 +690,20 @@ be5ec9615271e674d660a46dab540f31;vendor/phpseclib/phpseclib/phpseclib/Crypt/Comm 448c1f9a32d7d769cc24abf4b906888f;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Traits/Fingerprint.php 13e51444d2a368f6f325cd1bc9daa75c;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Traits/PasswordProtected.php cdf03f8e50e4baf4dde4d86f80b8cf08;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/StreamCipher.php -365e89f10135eb4e3f448e37418a7778;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php +241ba2de0c2de36b0781d7b949b1ba7c;vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php 3fdd8c95b7cffb0e9985d338090b2ba0;vendor/phpseclib/phpseclib/phpseclib/Crypt/AES.php 2523c7f8b512e8cbf08806f4afcd33be;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PuTTY.php 300c092291bcb0f9810bdfcb03bca8ac;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/JWK.php bd1be69d327c3385d54fbb4be12a8c49;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/OpenSSH.php -35dd7d5ab9f357186aab27fa4b5adaec;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php +b52a5943e684cf304ce1967831867225;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php 5aee20c33f0c4e3152db822c0ff3ad19;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/XML.php 4ceeb99d0ec6988cf1e38b5677190eb0;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php 83aeef91fc41a7d310184a2f6f3dc00a;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/MSBLOB.php dce1fa9b37bace1cfea1e59fff413c07;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/Raw.php e6b34e419e1f9c283afed8e127186177;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PKCS1.php -573ebd3d7592f942607f0f863047a8ec;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php -cc9c52e18a5bdd5accd3b0342688316a;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php -faae4fd5334a06dd045f5ea9f24c4a82;vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php +79ecf54c314660b58d5d6883dcf1ff6f;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php +95a09d38570dbbf9f8e632966f8925b4;vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php +640faa0a1e72f908c93b6f5c2622e534;vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php be41f929cc2e3f28ab1ced739e90dd83;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Parameters.php 9d94fcf7c2c31ac144ecdcf399122454;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Signature/Raw.php d99fdeeb603fdfdaf88ac1ff319ee8bd;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Signature/SSH2.php @@ -708,13 +713,13 @@ cef2fcfeacae8f8b58037115d3596960;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/ 3f7cc67bf4baee83664bb5067d309790;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/XML.php 3cb89b48d5d9cee6514ff83cfbec5c1d;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php 544d3076a0df77855ea438bd94495b05;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/Raw.php -344f0386bf46c3a802d3c9dc77c7b71a;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php -62858ce67a39c0f860f65e1745ea7945;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php -4d357430f1fbfa1a94da864bf86e7c7b;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php -20841644093a890e427d544bce7f0085;vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php -6700600289fca3163991c7c720be22f0;vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php -aadf4bea69438b0df5df383db2bf7edd;vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php -85da87aa04d087e7fd547519ce46719b;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC.php +c5371cebe32400e7d65b7a40f0ef5b57;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php +6817ebec3db96a793044009dcedbf75c;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php +35ca39bc46aef2a3928a7f6861434309;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php +5c456d0cee3ba0e790973f05c78c0f50;vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php +c1382fc196af5bacbbc85c45addb0e2c;vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php +5a9c3a3562a2bfff76fb9fb180b7c201;vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php +c6917bd420a67b6288203cc69f359bd7;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC.php 8c0d2120d75748c1877e858264ed2eed;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Parameters.php c15814b88489f84bc7eeafdea9559978;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/IEEE.php 243a88eea5b939ace6db9da70b3ebd6f;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Signature/Raw.php @@ -724,13 +729,13 @@ c3d6cdb76651ffbc8162f66e0efb393b;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/F 6e0f3ae71aa2f4211949e8396c4378b8;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PuTTY.php 9c43bd7d84ea054a996736bf1e06439c;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/JWK.php e627a2980cb53542b64b6d9a234ae083;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPublic.php -4cc7ff2b22efc1d251b589c270f31d82;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php -80c8c62adea3c913d884a75a74d3c42b;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.php +671756f559702c1b58b99df92d24d239;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php +c2368b4f6953a813b53fb06ac8b69dc3;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.php 3f209c71eca69afcf9f2eef5bc13eaf8;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/XML.php -68746f75dd0f9511fed627f2f63c54f3;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php +ca8b73f15338fc565d374f41c71d4efd;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php 323faab72989033c47475e558f680dc7;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS1.php -0e4c5a8eaf9cc097a7c6ddf571d7eed3;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php -6697227426fca966edc9500319899eac;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php +fca70c4e6ad0b092f8dfbe10bbdab41b;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php +fc7577ccecb0411ed3262f8c399a6bb0;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php 1fcd67e0de877b8e8f004478eb00eda3;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect283r1.php 9a15efda0ba337785d71f9969f835474;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime192v1.php e948f4a79170fb2d8fb3d3d1f2349cb9;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp160r2.php @@ -759,7 +764,7 @@ f7c40494abfbc18d7918089bb492a3f8;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/C 24284308da3c26af6d6fd576feddfeea;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect193r1.php f79737664973102e8272ef2c11b7e974;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect131r1.php 706c4f2d8efdbc0f83676ee608e56d96;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP384t1.php -2e808c3ad853412ea67d11dc495ba179;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php +8b9d1c1f83aab1e6ae7a83859eb6b708;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php f99b47e07072dbec9de6e1b9d612c129;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/nistp384.php 44b9ff1e875f430237714e3a11fa21fc;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP256t1.php 2982b9b3a7534834c313f10ff71e5b22;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect409k1.php @@ -773,7 +778,7 @@ f6fb7890cc2d544e5d438c9e34912a16;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/C 3e9a642ffccc5aba7e3b139ee02c1fa4;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp256k1.php dbece4a6c174eca6fa98c08855c8a9b3;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/brainpoolP160t1.php e99d7c70670820a38b271d734c961341;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect163r2.php -617693d0796bcdc00a0687b6e9a266a8;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.php +a4a24cd2880e8af5d32f5df0caa764a9;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.php 203955d4495b242e33d26ef526627424;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/sect571r1.php 8519adac393dd5ac2c0654ac581c86cf;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/prime239v1.php 351072838aa7a4696e8e27d517773060;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/secp256r1.php @@ -807,28 +812,29 @@ af1aafd7e929c39c243eab4db3f764a8;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/C 857030d72a730339bee1d71f16e0a840;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Binary.php 3a98aff9b0e7c041d9f50a957d3d2620;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/TwistedEdwards.php d359cd5abfdd829af67316589817ec49;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/BaseCurves/Montgomery.php -fafe0bc6b12ba296e5d5fe11a4f0183c;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php +e86354e3df7fea997ecb6c46654cfe05;vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php af21a780fc59992b916b419d9e40b2db;vendor/phpseclib/phpseclib/phpseclib/Crypt/Random.php -2a53b02f538e9b20e8cfe9255a1e6db7;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php -8edfbdc34195bbc3645b0ec19f828646;vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php +79d7650ddcc9ef3482c4572abac1affe;vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php +f1d053c03b8f535d41d7281e3c6a742b;vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php daaf4a58012b688e8550ffa25ba9c8b0;vendor/phpseclib/phpseclib/phpseclib/Crypt/RC2.php 8150e3db849c87d46626a8ba78de6076;vendor/phpseclib/phpseclib/phpseclib/Crypt/RC4.php 242ed95eb90447e56daaa42c7d23ff9b;vendor/phpseclib/phpseclib/phpseclib/Crypt/PublicKeyLoader.php -b4409823562c617107907cd04d67c8fa;vendor/phpseclib/phpseclib/phpseclib/openssl.cnf +f064875346b0ec5f714384018db4199f;vendor/phpseclib/phpseclib/phpseclib/openssl.cnf fa4bab04703bfcb560be4489526b0991;vendor/phpseclib/phpseclib/phpseclib/bootstrap.php +77b63f58b245c8e6e90643e727d04fb0;vendor/phpseclib/phpseclib/SECURITY.md 3012f773b400715a955cffa18c8016e0;vendor/phpseclib/phpseclib/AUTHORS 182d5924ff0b528f008a83d1f5809d02;vendor/composer/InstalledVersions.php -8dd932a7a65010dd3e49368bb2dea609;vendor/composer/platform_check.php +77536de43a8cfa1daaca6a8542f5f27f;vendor/composer/platform_check.php ab90ab9876b52e0fe15a5e5ec32e25b7;vendor/composer/autoload_files.php 955d5fe58c231244f6b49000f383b5e2;vendor/composer/LICENSE -c8b92c5114ddd48a1451674cbf3c2081;vendor/composer/installed.php +f27965fa157808b53d5c03969a3948b9;vendor/composer/installed.php 631b00271668b14aee0447e8e8947507;vendor/composer/autoload_static.php 5615b29a1f5688414d56a1515d954a91;vendor/composer/autoload_classmap.php 79512e55245b2a8b64e60c3c1d05ab0e;vendor/composer/autoload_psr4.php 224007c97efb82c7b45b0e92f240af41;vendor/composer/autoload_namespaces.php 824e49753cf879aa756c9d6fbfe0c863;vendor/composer/autoload_real.php c02be6d96671f88d28aad3ffa134c8ae;vendor/composer/ClassLoader.php -778f43e9d652a98ae4dbbce0f4d4c81c;vendor/composer/installed.json +7915cbe05ec329969d43acfa054b12d6;vendor/composer/installed.json 784efccde8a58c8491c20ef0eca6bf87;vendor/paragonie/random_compat/composer.json 4b54cbf6ccb77afb7ade42183affc554;vendor/paragonie/random_compat/lib/random.php 8eb7e9dc637fb48d8bddfb470e370f42;vendor/paragonie/random_compat/build-phar.sh @@ -852,9 +858,9 @@ c979337b7229f44f958eeb7ecdc43f52;vendor/paragonie/constant_time_encoding/src/RFC 70ca37cf7170c539a0d65bd2e4591b91;vendor/paragonie/constant_time_encoding/src/Base64UrlSafe.php d74ee339a9008b6c184705dcf20536ee;vendor/paragonie/constant_time_encoding/src/Hex.php 71cf58b32ec1818382729a499503af82;vendor/paragonie/constant_time_encoding/src/Base32.php -a761dc4a6a7338866116567ae11c4368;composer.lock +97657ac60f240bd9b6180524914c1c02;composer.lock 0a7ea3bc84eaecb910b6cb1b6f474db5;apple-developer-merchantid-domain-association -c466bfceae7a1c850f00a4bd2c8400db;composer.json +56f3882df96a1eb54693b8e937c58c45;composer.json 23ada647e7af4c86e7388b6b74efca32;frontend/js/unzer-ui-components.js 35aa90abd4f87d672b078fe554d61349;frontend/js/unzer-ui-components.min.js.map 86efdfbb532c2954668d7cfa59d645f2;frontend/js/unzer-ui-components.js.map @@ -866,8 +872,8 @@ d5de3c2637eb45440c212d9a0824ee18;frontend/src/js/components/index.js 2292f0faa91e69e2fbcfcb332e7e9bce;frontend/src/js/components/base.js 15112aab51c1133c80096c05759e4008;frontend/src/js/utils/errors.js cf44e5fa2ae44e1a9756651963bfe755;frontend/src/js/utils/debugging.js -280b9703c8fd488aebf961bd9a721cd0;frontend/sync-workflow.php -780b2b8990e8dba5534b2d1fa468c6f3;frontend/webhook.php +2204ebc7811216c1eb4536b186659f24;frontend/sync-workflow.php +def2542a414de4f29475714497739318;frontend/webhook.php 824c7c0e6cf814a4e52b7a45d26a657e;frontend/template/google_pay_button.tpl 3e34c443a1d94d22322bdd82673d0dd6;frontend/template/hire_purchase_direct_debit.tpl ca79740c158847ad33410b9f2d9746c0;frontend/template/partials/_threatMetrix.tpl @@ -887,9 +893,9 @@ c2405627e35992f208ba7281a6490256;adminmenu/scss/admin.scss 746bd73bf157393d5d55f4b559a8c6e5;adminmenu/css/admin.css.map ea5a5b2dc793ab305fe96a7822ba667d;adminmenu/template/applepay.tpl bd1dee2d300e99d194c69dfb1693075e;adminmenu/template/keypairs.tpl -910a55e93d804f4f24251c5b197893e9;adminmenu/template/settings.tpl -34e0beaa04e4bef9d55c15dc6b4a1f0d;adminmenu/template/partials/_order_item.tpl -c973e777d822dfcc69c48771aee4ab72;adminmenu/template/partials/_order_detail.tpl +95efa85cfe5a32efc50029500c50c4dc;adminmenu/template/settings.tpl +a5e7815bcaa04b15bd90e93f6967f223;adminmenu/template/partials/_order_item.tpl +9a66253251d74318da9f8208d577f9be;adminmenu/template/partials/_order_detail.tpl 94692a0334d6eeefe4b4806fc5832914;adminmenu/template/partials/_includes.tpl 50329cc04d18170a2e8f086579a67366;adminmenu/template/partials/_keypair_list.tpl e68888b6874c60a42db48e2ead9dba40;adminmenu/template/partials/_keypair_item.tpl @@ -897,7 +903,7 @@ e0b9e6894421345360862d2571283a23;adminmenu/template/partials/_header.tpl dad4062692dbd99b16ae3233b36ec1ec;adminmenu/template/orders.tpl 30e621c301583a4e13928bd8b9a09a9d;.jshintrc 2c62fe5947e6614a783d78e29f531d00;phpmd-ruleset.xml -6a4b7de12703b622853d4aa40dac6a7a;README.md +528204be7bd0de771948370416c804dc;README.md 767ba442de91503e5b6245c2d114a5c7;src/ApplePay/CertificatesResource.php 6703c52f0190cd22bfa1f72d7930fce1;src/ApplePay/CertificationService.php 4ad80bac1bc3c0c244426c6dd6279a96;src/ApplePay/CertificateException.php @@ -905,7 +911,7 @@ dad4062692dbd99b16ae3233b36ec1ec;adminmenu/template/orders.tpl a3255fc904b7509e171553ea009c9c82;src/ApplePay/ActivateCertificateResource.php 4ba10c90d08b3f639e188c332647e1c5;src/Payments/PaymentMethodModuleFactory.php b7d6a5dab057b0bb5bb42c02456aedf7;src/Payments/HeidelpayApiAdapter.php -d7d9c9455ae5943a40596d3d170c3c39;src/Payments/HeidelpayPaymentMethod.php +621352b49a860be17d65273dab104dde;src/Payments/HeidelpayPaymentMethod.php 85dadc4e055384cf11546247308921f5;src/Payments/Traits/PriceCurrencyConverter.php 54f0fff5386a4145ce981a2c4e24d576;src/Payments/Traits/SupportsB2B.php ad359a50ddb9c76117d5941d75617fc8;src/Payments/Traits/HasSavedPaymentData.php @@ -914,7 +920,7 @@ d78c74c0918be9b079a8cf4655446589;src/Payments/Traits/HasState.php 3324fa5c40887fa065d5357432fd1e52;src/Payments/Traits/HasBasket.php aa1212a34a1c3b4f1475e6b439603404;src/Payments/Traits/HasMetadata.php 9f5c6070edc5f2c82560e28fd47a66ac;src/Payments/Traits/CancelPaymentTransaction.php -c2632abd856021c7b0cdef9f8f6f0fca;src/Payments/Traits/HasCustomer.php +9028032cf7c16f02894e42d0494b158c;src/Payments/Traits/HasCustomer.php eafbb3fd550ede774e80f963759e71ea;src/Payments/Traits/HasPayStatus.php 8922f3e4843d3879c6c01d6da80166d1;src/Payments/Traits/HasDirectCharge.php f64f8fbc30450ccafaa26deee7e4fb9e;src/Payments/PaymentHandler.php @@ -926,7 +932,7 @@ d98195f0c1485f6412b599b3f1581902;src/Payments/Interfaces/HasPayButton.php 04525b7293527904b5c527dd5aecbd9b;src/Payments/Interfaces/HandleStepReviewOrderInterface.php ab1b1e5c0f257e793786fd8f49b3a9b7;src/Payments/Interfaces/NotificationInterface.php 24bea0a602bf575ea6c7d432587c4fba;src/Charges/ChargeMappingModel.php -9e1567a3d74129750aa8bd161d51f8fc;src/Charges/ChargeHandler.php +4f9b1f1b1decd27496236d9634b77012;src/Charges/ChargeHandler.php 20db0d8770933362b0b8b7fa32c18494;src/Charges/ChargeMappingEntity.php cc1c780662e1a85826bafc4dbfef25fc;src/Controllers/Controller.php 6b557d2f5af216698fad3cbb233f211e;src/Controllers/AjaxResponse.php @@ -940,8 +946,8 @@ ac4c5cefb686188aaf1b69f99f3ba4ae;src/Controllers/PaymentController.php e990705d5e8da7895d4460e98f516ec3;src/Controllers/Admin/AdminController.php 1902987773d5d5f5582f0c90198628fd;src/Controllers/Admin/AdminApplePayController.php 47d5c9582887c2d15265d9ef572b9b8d;src/Controllers/Admin/AdminKeyPairsController.php -5827d6899028ef0919847b0fdaafcee0;src/Controllers/Admin/AdminOrdersController.php -8a9dc40409220ffb905b588d056d2427;src/Controllers/Admin/AdminSettingsController.php +283b307a5a04db56ba03fe1bd73f89cc;src/Controllers/Admin/AdminOrdersController.php +bdcf3b5e6d2e5d639454d5921b557a07;src/Controllers/Admin/AdminSettingsController.php 8296f8b464c72e7441c7dedec8159728;src/Orders/OrderMappingModel.php 3da45aa29a08f869b95627a6e46e5f9a;src/Orders/OrderViewStruct.php c1f8da0ce57d62d455c5e259c24685d0;src/Orders/OrderMappingEntity.php @@ -949,16 +955,16 @@ f8bcecf005718c0af3412829d40aa63b;src/Services/SavedPaymentDataService.php 521e61755ca1485bfe834b40a50ac426;src/Utils/Logger.php ff2e8ea1952f33020fe432ab359624d6;src/Utils/JtlLinkHelper.php 3f168e1ffb14560bed4eb5d301c8f748;src/Utils/SessionHelper.php -d8659e8d6c1850a787285eb36967e3f1;src/Utils/Config.php +d6d21974f88ddeca3f6798d2b5ff53f8;src/Utils/Config.php d5d5d79ab6d86b5a965cf17240ff601e;src/Utils/JtlLoggerTrait.php 45d77592d5be177698832b19d2f84b78;src/Utils/Compatibility.php 48830baed39f5710178337ad6d6f8444;src/Utils/TranslatorTrait.php -82c185d48308e87dd3f586a6b4e3261e;src/Webhooks/PaymentEventSubscriber.php +3419a6978403bd64af2e33b5bd2fee77;src/Webhooks/PaymentEventSubscriber.php 4a6bd5f25d0487b44b664403d6b0315c;src/KeyPairs/KeyPairModel.php 8e0682ac5c506aa7ed6bc23a06970633;src/KeyPairs/KeyPairService.php 02ead16397ed114e97dc4a017cf2b30e;src/KeyPairs/KeyPairEntity.php 07e542740aeb10d40b387b86ff17ca15;src/Foundation/Struct.php -b93684508161f05d1e5ab245170921cf;src/Foundation/EventSubscriber.php +0b060144734e56201d155a5033a6aa8c;src/Foundation/EventSubscriber.php a78e5bba0c2635642ab607fbf73b0cea;src/Foundation/EventPayload.php 666e75baf5eddfcf0c50e83a5386bb5d;src/Foundation/ServiceProvider.php fda45f203428056c6676cf83a15b4387;src/Foundation/Seeder.php @@ -966,28 +972,28 @@ fda45f203428056c6676cf83a15b4387;src/Foundation/Seeder.php a09b4b6da00f1cd498ddbac5b8c4d051;src/Foundation/Entity.php 97287cd9117f7b341aefb53cfe00ac64;src/Foundation/Model.php ea7aa4025fd765d650d31bf1c60e768f;LICENSE -38a3fc22572cdee9a3885683bf3b007c;paymentmethod/UnzerPaylaterDirectDebit.php -3ca7967b1966f2fda5a4732d0779aeb8;paymentmethod/HeidelpayPrepayment.php -ec0675d513fe14aa3766347ab3fe45ba;paymentmethod/UnzerDirectBankTransfer.php +64661598b36332415395dff9b8f74e61;paymentmethod/UnzerPaylaterDirectDebit.php +a0fc97ff7e8358583001981b629fa534;paymentmethod/HeidelpayPrepayment.php +07c86fb1d16b73504525fac000fc49a0;paymentmethod/UnzerDirectBankTransfer.php cdf083b85ad47dd962fb7223301609c3;paymentmethod/UnzerWero.php 4704fb5d3c5b2581977682c705979bf0;paymentmethod/HeidelpayInvoiceGuaranteed.php 9e34f11f989a7ec68c9e4cc9c8a380d2;paymentmethod/UnzerKlarna.php -7101d4748dff19c48223d84a112339db;paymentmethod/UnzerBancontact.php -936e2ea3fec93fc4498132b81ec8f4f1;paymentmethod/HeidelpayPayPal.php -c33ab12c2ff6b0a4be832b1fd5ccc258;paymentmethod/UnzerTwint.php +9682bc83999be093f4420cbbcd23563d;paymentmethod/UnzerBancontact.php +8d1312e7a3c4e06ae02e31324ddc5b77;paymentmethod/HeidelpayPayPal.php +b32231d6b79eb98c9eeb6848e8a97d8d;paymentmethod/UnzerTwint.php bc6a8299df4b8de3e0b2743ed860d61f;paymentmethod/UnzerApplePay.php -75d281c904425534046164df12e3d1f5;paymentmethod/HeidelpayWeChatPay.php -2cde4fb87f7ba1ccd21abbac226d75eb;paymentmethod/UnzerApplePayV2.php -d6e6fa5c751565b83ebc6c2c3676cc94;paymentmethod/HeidelpayEPS.php -321b61e4a93e0d0860f9dd8404ebf377;paymentmethod/HeidelpaySEPADirectDebit.php +214d39a989b4d2c6e6837a66278d0d7e;paymentmethod/HeidelpayWeChatPay.php +95768e6ccbdefc78512188cb14009e26;paymentmethod/UnzerApplePayV2.php +17e7f2366570a8c2e881a2a02b652cbf;paymentmethod/HeidelpayEPS.php +c1de49d54966ebd793ca4e1d9e7acea7;paymentmethod/HeidelpaySEPADirectDebit.php 04f239d9194556e5a43ef6c6b6168f43;paymentmethod/HeidelpayGiropay.php 3aea69ee54494a9981058e8f84be502e;paymentmethod/HeidelpayFlexiPayDirect.php b80ab88d008319b39cba524bf2bd1b11;paymentmethod/HeidelpayInvoiceFactoring.php 58dae7c0526e2464e276aba8f326a7e0;paymentmethod/HeidelpaySEPADirectDebitGuaranteed.php -524d91a283d4adcd7b18466d25fe9ae1;paymentmethod/HeidelpayiDEAL.php -91aff68f9cc80451feb3b05f9f435d20;paymentmethod/UnzerPaylaterInstallment.php +8edb53e2702f483105dcc644374562bf;paymentmethod/HeidelpayiDEAL.php +abab7196c5cf41e5889ea8fdf2aba7ca;paymentmethod/UnzerPaylaterInstallment.php 76aac63ba26683b03f88e06311db677e;paymentmethod/HeidelpayInvoice.php -4bc389fe7847acb688edcd86bf0b9b81;paymentmethod/UnzerPaylaterInvoice.php +8d3c93ba2fca9823da97f7276406e609;paymentmethod/UnzerPaylaterInvoice.php b2b5981cdb3060854934a7a4ddd86352;paymentmethod/HeidelpaySofort.php 405ab8956305746a8bfe2f10955d367a;paymentmethod/images/Default.svg e9b9822db699305c6f9210f7a3296d99;paymentmethod/images/Bancontact.svg @@ -1028,10 +1034,10 @@ d2198616c50a0ffd907e94a2f42c5f8b;paymentmethod/images/iDeal_WERO.svg a25d1f684f60c0372468352a886400d5;paymentmethod/images/DirectDebitSecuredWL.svg 36dc54e9a212afc559462b482399025c;paymentmethod/images/Ideal.svg 97301dfb7f296851b5c3d01f5f1459ce;paymentmethod/images/Discover.svg -96277ca6f92c342d9667542213dd903f;paymentmethod/HeidelpayPrzelewy24.php +860263e3116bce01d76f07ee11fad24c;paymentmethod/HeidelpayPrzelewy24.php 4c63e15cb4148ac8d76fead03e93f5e1;paymentmethod/HeidelpayHirePurchaseDirectDebit.php -4c97bb9c40d73235c899b707e60c4a0c;paymentmethod/HeidelpayAlipay.php -608e304f236b8f85fca13d8cf4069077;paymentmethod/UnzerGooglePay.php +ab8cff88f42842b133ba3428f7798641;paymentmethod/HeidelpayAlipay.php +a8dbcbd62cd37fbe7861c946552acee9;paymentmethod/UnzerGooglePay.php 43aa1ac4c28b351cdb5c54656b0586b5;paymentmethod/template/hire_purchase_direct_debit_form.tpl e8405d784f1b577d8332cfd9f2702587;paymentmethod/template/sepa_form.tpl 43aa1ac4c28b351cdb5c54656b0586b5;paymentmethod/template/sepa_guaranteed_form.tpl @@ -1063,15 +1069,15 @@ a60e1531064c14507ae0429e123a1112;paymentmethod/template/ideal_form.tpl ddaaceadd4366b7aa7aaa82ae405c821;paymentmethod/template/alipay_form.tpl 43aa1ac4c28b351cdb5c54656b0586b5;paymentmethod/template/invoice_guaranteed_form.tpl 54fd30a2872c9c7223da7c93d746029b;paymentmethod/template/prepayment_form.tpl -c6212be984396ea5ae48880b371e2c61;paymentmethod/HeidelpayCreditCard.php -ee72586bef75c15d1d06a437e4354ec8;info.xml +85235d75531f240854aa4dc572d22c71;paymentmethod/HeidelpayCreditCard.php +fd2b479e304868f66a918983ec309b79;info.xml c237fcf06c9da2f07028932e8eb8aa36;Migrations/Migration20230925100000.php 686b3eec05aa867a757aa916dd50b50a;Migrations/Migration20260303100000.php 55ccfd103771065e96f3e482ee49499e;Migrations/Migration20220511114913.php cd6d409b4fbd95d76bfe82ab4805a17b;Migrations/Migration20230919100000.php 166d9346b496a3a2a2332586e8dcfa44;Migrations/Migration20221006103000.php 3faed6c0507c6f399d352282db7c777b;Migrations/Migration20201027083900.php -3457b9fdf3d1762d3fdc8a2d2a10cacf;Bootstrap.php +ffbf0093371c992e85e607cf44fbcc18;Bootstrap.php c9f6e33220cf462393c7070cffcfff1a;NOTICE 4db0ef5803b943bc62cf9a6e0f7b40b5;Seeders/Shop4PluginMigrationSeeder.php 24c7b7d22435a4e5efc810d505d146cb;locale/de-DE/base.po @@ -1079,4 +1085,4 @@ c9f6e33220cf462393c7070cffcfff1a;NOTICE 778e8c29f694bc2c9902c04ed686ac0b;locale/en-GB/base.po a1f17490d317c9c3c41322d96a75daa4;locale/en-GB/base.mo e73740baa8bcab9ac6d47b2a95daa826;jsconfig.json -835d1c9f49afcc380506604e594054fb;CHANGELOG.md +fde39680b5cf2c49ad1ba41f97ecbe58;CHANGELOG.md diff --git a/composer.json b/composer.json index 2241463..ce1301e 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ } ], "require": { - "unzerdev/php-sdk": "^3.7.0", + "unzerdev/php-sdk": "^4.0.0", "phpseclib/phpseclib": "~3.0" } } diff --git a/composer.lock b/composer.lock index 71c9713..78e35f7 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c6d741e7e3704870a751bd9c4903681d", + "content-hash": "4396889dd3a0348ff4a2b3eb3cec8fd6", "packages": [ { "name": "paragonie/constant_time_encoding", @@ -127,16 +127,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.46", + "version": "3.0.53", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" + "reference": "511ddc8e352d5d1f1e33bea468b6f4ef48438cf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", - "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/511ddc8e352d5d1f1e33bea468b6f4ef48438cf9", + "reference": "511ddc8e352d5d1f1e33bea468b6f4ef48438cf9", "shasum": "" }, "require": { @@ -217,7 +217,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.53" }, "funding": [ { @@ -233,29 +233,29 @@ "type": "tidelift" } ], - "time": "2025-06-26T16:29:55+00:00" + "time": "2026-06-09T18:08:26+00:00" }, { "name": "unzerdev/php-sdk", - "version": "3.13.1", + "version": "4.0.1", "source": { "type": "git", "url": "https://github.com/unzerdev/php-sdk.git", - "reference": "0a26d70b33185d52e49b06cb500a6e01bb6f1087" + "reference": "a9344b823fbf5374cd49e07ab6352d385578299e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/unzerdev/php-sdk/zipball/0a26d70b33185d52e49b06cb500a6e01bb6f1087", - "reference": "0a26d70b33185d52e49b06cb500a6e01bb6f1087", + "url": "https://api.github.com/repos/unzerdev/php-sdk/zipball/a9344b823fbf5374cd49e07ab6352d385578299e", + "reference": "a9344b823fbf5374cd49e07ab6352d385578299e", "shasum": "" }, "require": { "ext-json": "*", - "php": "~7.4.0|~8.0.0|~8.1.0|~8.2.0|~8.3.0|~8.4.0" + "php": "~8.1.0|~8.2.0|~8.3.0|~8.4.0|~8.5.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", - "phpunit/phpunit": ">6.5 <10.0" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-curl": "*" @@ -274,9 +274,9 @@ "description": "This is the php sdk to connect to the Unzer rest API.", "support": { "email": "support@unzer.com", - "source": "https://github.com/unzerdev/php-sdk/tree/3.13.1" + "source": "https://github.com/unzerdev/php-sdk/tree/4.0.1" }, - "time": "2025-09-23T14:21:50+00:00" + "time": "2026-05-15T13:48:06+00:00" } ], "packages-dev": [], diff --git a/frontend/sync-workflow.php b/frontend/sync-workflow.php index 3758e66..587ea5d 100644 --- a/frontend/sync-workflow.php +++ b/frontend/sync-workflow.php @@ -8,7 +8,7 @@ try { $controller = new SyncWorkflowController(Shop::Container()->get(Config::PLUGIN_ID)); $controller->handle(); -} catch (Exception $exc) { +} catch (Throwable $exc) { Logger::error( $exc->getCode() . ':' . $exc->getMessage() . ', Exception in FRONTEND_LINK sync-workflow.php' ); diff --git a/frontend/webhook.php b/frontend/webhook.php index 149c97a..850824c 100644 --- a/frontend/webhook.php +++ b/frontend/webhook.php @@ -8,9 +8,9 @@ try { $controller = new WebhookController(Shop::Container()->get(Config::PLUGIN_ID)); $controller->handle(); -} catch (Exception $exc) { +} catch (Throwable $exc) { Logger::error( - $exc->getCode() . ':' . $exc->getMessage() . ', Exception in FRONTEND_LINK webhook.php' + 'Exception in FRONTEND_LINK webhook.php: ' . $exc->getMessage() . PHP_EOL . $exc->getTraceAsString() ); http_response_code(403); } diff --git a/info.xml b/info.xml index ef98a98..7bbda96 100644 --- a/info.xml +++ b/info.xml @@ -6,7 +6,7 @@ http://www.solution360.de 100 5.0.0 - 2.0.3 + 2.0.4 s360_unzer_shop5 2020-10-27 @@ -116,6 +116,18 @@ + + s360_hp_cancel_by_user + + + + + + + + + + s360_hp_error_validating_merchant diff --git a/paymentmethod/HeidelpayAlipay.php b/paymentmethod/HeidelpayAlipay.php index 1ca94ee..f3d64bf 100644 --- a/paymentmethod/HeidelpayAlipay.php +++ b/paymentmethod/HeidelpayAlipay.php @@ -5,6 +5,7 @@ namespace Plugin\s360_unzer_shop5\paymentmethod; use JTL\Checkout\Bestellung; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -29,6 +30,7 @@ */ class HeidelpayAlipay extends HeidelpayPaymentMethod implements RedirectPaymentInterface { + use SupportsB2B; use HasBasket; use HasMetadata; use HasCustomer; @@ -45,10 +47,10 @@ protected function getAllowedCurrencies(): array protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType { // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/HeidelpayCreditCard.php b/paymentmethod/HeidelpayCreditCard.php index e90c15a..1171654 100644 --- a/paymentmethod/HeidelpayCreditCard.php +++ b/paymentmethod/HeidelpayCreditCard.php @@ -7,6 +7,7 @@ use Exception; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasSavedPaymentData; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\PaymentTypes\Card; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; @@ -52,6 +53,7 @@ class HeidelpayCreditCard extends HeidelpayPaymentMethod implements HandleStepAdditionalInterface { use CancelPaymentTransaction; + use SupportsB2B; use HasBasket; use HasMetadata; use HasAuthorization; @@ -155,12 +157,11 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde $customer = $this->createOrFetchHeidelpayCustomer( $this->adapter, $this->sessionHelper, - false + $this->isB2BCustomer($shopCustomer) ); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); // Update existing customer resource if needed diff --git a/paymentmethod/HeidelpayEPS.php b/paymentmethod/HeidelpayEPS.php index ddcfebb..2ab919f 100644 --- a/paymentmethod/HeidelpayEPS.php +++ b/paymentmethod/HeidelpayEPS.php @@ -6,6 +6,7 @@ use JTL\Checkout\Bestellung; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -32,6 +33,7 @@ class HeidelpayEPS extends HeidelpayPaymentMethod implements RedirectPaymentInte use HasBasket; use HasMetadata; use HasCustomer; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -50,10 +52,10 @@ protected function getAllowedCurrencies(): array protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType { // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/HeidelpayPayPal.php b/paymentmethod/HeidelpayPayPal.php index 998c5af..c2a8761 100644 --- a/paymentmethod/HeidelpayPayPal.php +++ b/paymentmethod/HeidelpayPayPal.php @@ -7,6 +7,7 @@ use JTL\Checkout\Bestellung; use JTL\Shop; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasSavedPaymentData; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -44,6 +45,7 @@ class HeidelpayPayPal extends HeidelpayPaymentMethod implements RedirectPaymentI use HasDirectCharge; use HasMetadata; use HasSavedPaymentData; + use SupportsB2B; /** * Although Paypal support both auth as well as charge calls, we only support Direct Charge. @@ -63,7 +65,7 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde // Create a customer with shipping address for Paypal's Buyer Protection $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); diff --git a/paymentmethod/HeidelpayPrepayment.php b/paymentmethod/HeidelpayPrepayment.php index e8a696a..814e163 100644 --- a/paymentmethod/HeidelpayPrepayment.php +++ b/paymentmethod/HeidelpayPrepayment.php @@ -4,7 +4,9 @@ namespace Plugin\s360_unzer_shop5\paymentmethod; +use Plugin\s360_unzer_shop5\src\Payments\Interfaces\RedirectPaymentInterface; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -29,11 +31,12 @@ * * @see https://docs.heidelpay.com/docs/prepayment-payment */ -class HeidelpayPrepayment extends HeidelpayPaymentMethod +class HeidelpayPrepayment extends HeidelpayPaymentMethod implements RedirectPaymentInterface { use HasBasket; use HasMetadata; use HasCustomer; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -91,10 +94,10 @@ public function getOrderAttributes(Bestellung $order, AbstractTransactionType $t protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType { // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/HeidelpayPrzelewy24.php b/paymentmethod/HeidelpayPrzelewy24.php index 7fa9d1a..9505de4 100644 --- a/paymentmethod/HeidelpayPrzelewy24.php +++ b/paymentmethod/HeidelpayPrzelewy24.php @@ -6,6 +6,7 @@ use JTL\Checkout\Bestellung; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -30,6 +31,7 @@ class HeidelpayPrzelewy24 extends HeidelpayPaymentMethod implements RedirectPaym use HasBasket; use HasMetadata; use HasCustomer; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -48,10 +50,10 @@ protected function getAllowedCurrencies(): array protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType { // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/HeidelpaySEPADirectDebit.php b/paymentmethod/HeidelpaySEPADirectDebit.php index abdcf80..b503bc7 100644 --- a/paymentmethod/HeidelpaySEPADirectDebit.php +++ b/paymentmethod/HeidelpaySEPADirectDebit.php @@ -7,6 +7,7 @@ use JTL\Checkout\Bestellung; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasSavedPaymentData; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -43,6 +44,7 @@ class HeidelpaySEPADirectDebit extends HeidelpayPaymentMethod implements use HasMetadata; use HasCustomer; use TranslatorTrait; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -85,10 +87,10 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde } // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/HeidelpayWeChatPay.php b/paymentmethod/HeidelpayWeChatPay.php index 94acb62..d9b447c 100644 --- a/paymentmethod/HeidelpayWeChatPay.php +++ b/paymentmethod/HeidelpayWeChatPay.php @@ -6,6 +6,7 @@ use JTL\Checkout\Bestellung; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -29,6 +30,7 @@ class HeidelpayWeChatPay extends HeidelpayPaymentMethod implements RedirectPayme use HasBasket; use HasMetadata; use HasCustomer; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -47,10 +49,10 @@ protected function getAllowedCurrencies(): array protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType { // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/HeidelpayiDEAL.php b/paymentmethod/HeidelpayiDEAL.php index ae74e55..7499583 100644 --- a/paymentmethod/HeidelpayiDEAL.php +++ b/paymentmethod/HeidelpayiDEAL.php @@ -6,6 +6,7 @@ use JTL\Checkout\Bestellung; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -35,6 +36,7 @@ class HeidelpayiDEAL extends HeidelpayPaymentMethod implements RedirectPaymentIn use HasBasket; use HasMetadata; use HasCustomer; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -53,10 +55,10 @@ protected function getAllowedCurrencies(): array protected function performTransaction(BasePaymentType $payment, Bestellung $order): AbstractTransactionType { // Create / Update existing customer resource if needed - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); if ($customer->getId()) { diff --git a/paymentmethod/UnzerApplePayV2.php b/paymentmethod/UnzerApplePayV2.php index cec60bd..98ade68 100644 --- a/paymentmethod/UnzerApplePayV2.php +++ b/paymentmethod/UnzerApplePayV2.php @@ -11,23 +11,26 @@ use Plugin\s360_unzer_shop5\src\Payments\Interfaces\CancelableInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HasPayButton; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\NotificationInterface; +use Plugin\s360_unzer_shop5\src\Payments\Interfaces\RedirectPaymentInterface; use Plugin\s360_unzer_shop5\src\Payments\Traits\CancelPaymentTransaction; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasAuthorization; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasCustomer; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasMetadata; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use Plugin\s360_unzer_shop5\src\Utils\Config; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; -class UnzerApplePayV2 extends HeidelpayPaymentMethod implements HasPayButton, NotificationInterface, CancelableInterface +class UnzerApplePayV2 extends HeidelpayPaymentMethod implements HasPayButton, NotificationInterface, CancelableInterface, RedirectPaymentInterface { use HasAuthorization; use HasCustomer; use HasMetadata; use HasBasket; use CancelPaymentTransaction; + use SupportsB2B; public function addPayButton(JTLSmarty $view): ?string { @@ -86,14 +89,10 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde $config = Shop::Container()->get(Config::class); // Create or fetch customer resource - $customer = $this->createOrFetchHeidelpayCustomer( - $this->adapter, - $this->sessionHelper, - false - ); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); // Update existing customer resource if needed diff --git a/paymentmethod/UnzerBancontact.php b/paymentmethod/UnzerBancontact.php index 547a426..6d4f52a 100644 --- a/paymentmethod/UnzerBancontact.php +++ b/paymentmethod/UnzerBancontact.php @@ -7,6 +7,7 @@ use JTL\Shop; use JTL\Smarty\JTLSmarty; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; +use Plugin\s360_unzer_shop5\src\Payments\Traits\SupportsB2B; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; use UnzerSDK\Resources\TransactionTypes\Charge; @@ -27,6 +28,7 @@ class UnzerBancontact extends HeidelpayPaymentMethod implements RedirectPaymentI use HasBasket; use HasCustomer; use HasMetadata; + use SupportsB2B; protected function getAllowedCountries(): array { @@ -66,7 +68,8 @@ public function handleStepAdditional(JTLSmarty $view): void protected function performTransaction(BasePaymentType $payment, $order): AbstractTransactionType { // Create a customer with shipping address for Paypal's Buyer Protection - $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, false); + $shopCustomer = $this->sessionHelper->getFrontendSession()->getCustomer(); + $customer = $this->createOrFetchHeidelpayCustomer($this->adapter, $this->sessionHelper, $this->isB2BCustomer($shopCustomer)); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); diff --git a/paymentmethod/UnzerDirectBankTransfer.php b/paymentmethod/UnzerDirectBankTransfer.php index 5b81c58..fa56b4d 100644 --- a/paymentmethod/UnzerDirectBankTransfer.php +++ b/paymentmethod/UnzerDirectBankTransfer.php @@ -47,7 +47,6 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde ); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); // Update existing customer resource if needed diff --git a/paymentmethod/UnzerGooglePay.php b/paymentmethod/UnzerGooglePay.php index 71af85e..3c79eca 100644 --- a/paymentmethod/UnzerGooglePay.php +++ b/paymentmethod/UnzerGooglePay.php @@ -194,7 +194,6 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde ); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); // Update existing customer resource if needed diff --git a/paymentmethod/UnzerPaylaterDirectDebit.php b/paymentmethod/UnzerPaylaterDirectDebit.php index 018e711..5508e5b 100644 --- a/paymentmethod/UnzerPaylaterDirectDebit.php +++ b/paymentmethod/UnzerPaylaterDirectDebit.php @@ -10,6 +10,7 @@ use Plugin\s360_unzer_shop5\src\Payments\Interfaces\CancelableInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HandleStepAdditionalInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HandleStepReviewOrderInterface; +use Plugin\s360_unzer_shop5\src\Payments\Interfaces\RedirectPaymentInterface; use Plugin\s360_unzer_shop5\src\Payments\Traits\CancelPaymentTransaction; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasAuthorization; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; @@ -22,6 +23,7 @@ use UnzerSDK\Resources\TransactionTypes\Authorization; class UnzerPaylaterDirectDebit extends HeidelpayPaymentMethod implements + RedirectPaymentInterface, HandleStepAdditionalInterface, HandleStepReviewOrderInterface, CancelableInterface diff --git a/paymentmethod/UnzerPaylaterInstallment.php b/paymentmethod/UnzerPaylaterInstallment.php index cef2a89..1ef2a5a 100644 --- a/paymentmethod/UnzerPaylaterInstallment.php +++ b/paymentmethod/UnzerPaylaterInstallment.php @@ -15,6 +15,7 @@ use Plugin\s360_unzer_shop5\src\Payments\Interfaces\CancelableInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HandleStepAdditionalInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HandleStepReviewOrderInterface; +use Plugin\s360_unzer_shop5\src\Payments\Interfaces\RedirectPaymentInterface; use Plugin\s360_unzer_shop5\src\Payments\PaymentHandler; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasAuthorization; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; @@ -30,6 +31,7 @@ use UnzerSDK\Resources\TransactionTypes\Cancellation; class UnzerPaylaterInstallment extends HeidelpayPaymentMethod implements + RedirectPaymentInterface, HandleStepAdditionalInterface, HandleStepReviewOrderInterface, CancelableInterface diff --git a/paymentmethod/UnzerPaylaterInvoice.php b/paymentmethod/UnzerPaylaterInvoice.php index d054654..b3dc7ab 100644 --- a/paymentmethod/UnzerPaylaterInvoice.php +++ b/paymentmethod/UnzerPaylaterInvoice.php @@ -13,6 +13,7 @@ use Plugin\s360_unzer_shop5\src\Payments\Interfaces\CancelableInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HandleStepAdditionalInterface; use Plugin\s360_unzer_shop5\src\Payments\Interfaces\HandleStepReviewOrderInterface; +use Plugin\s360_unzer_shop5\src\Payments\Interfaces\RedirectPaymentInterface; use Plugin\s360_unzer_shop5\src\Payments\Traits\CancelPaymentTransaction; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasAuthorization; use Plugin\s360_unzer_shop5\src\Payments\Traits\HasBasket; @@ -31,6 +32,7 @@ use UnzerSDK\Resources\TransactionTypes\Authorization; class UnzerPaylaterInvoice extends HeidelpayPaymentMethod implements + RedirectPaymentInterface, HandleStepAdditionalInterface, HandleStepReviewOrderInterface, CancelableInterface diff --git a/paymentmethod/UnzerTwint.php b/paymentmethod/UnzerTwint.php index 145881e..d292eba 100644 --- a/paymentmethod/UnzerTwint.php +++ b/paymentmethod/UnzerTwint.php @@ -47,7 +47,6 @@ protected function performTransaction(BasePaymentType $payment, Bestellung $orde ); $customer->setShippingAddress($this->createHeidelpayAddress($order->Lieferadresse)); $customer->setBillingAddress($this->createHeidelpayAddress($order->oRechnungsadresse)); - $customer->setCompanyInfo(null); $this->debugLog('Customer Resource: ' . $customer->jsonSerialize(), static::class); // Update existing customer resource if needed diff --git a/src/Charges/ChargeHandler.php b/src/Charges/ChargeHandler.php index 7c14bfc..88bff5d 100644 --- a/src/Charges/ChargeHandler.php +++ b/src/Charges/ChargeHandler.php @@ -179,6 +179,8 @@ public function addCharge( Bestellung $order, ?int $deliveryId = null ): void { + $this->debugLog("Trying to add charge " . print_r($charge->jsonSerialize(), true) . " for order {$order->cBestellNr}", self::class); + // Charge is already marked as incoming payment -> skip! if ($this->model->getChargeForOrder((int) $order->kBestellung, $charge->getId())) { $paymentMethod->doLog( @@ -191,7 +193,7 @@ public function addCharge( if ($charge->isSuccess()) { // Add Incoming Payment - if ($this->config->get(Config::ADD_INCOMING_PAYMENTS, true)) { + if ($this->config->get(Config::ADD_INCOMING_PAYMENTS, 'on') === 'on') { $paymentMethod->addIncomingPayment($order, (object) [ 'fBetrag' => $charge->getAmount(), 'cISO' => $charge->getCurrency(), @@ -245,7 +247,7 @@ public function markAsPaid(Payment $payment, HeidelpayPaymentMethod $paymentMeth { $this->debugLog( "Check if order {$order->cBestellNr} should be marked as paid." . - "Status: {$order->cStatus} | Add Incoming Payment: {$this->config->get(Config::ADD_INCOMING_PAYMENTS, true)}", + "Status: {$order->cStatus} | Add Incoming Payment: {$this->config->get(Config::ADD_INCOMING_PAYMENTS, true)} | Payment {$payment->jsonSerialize()}", static::class ); diff --git a/src/Controllers/Admin/AdminOrdersController.php b/src/Controllers/Admin/AdminOrdersController.php index df63d4c..38ec58b 100644 --- a/src/Controllers/Admin/AdminOrdersController.php +++ b/src/Controllers/Admin/AdminOrdersController.php @@ -233,7 +233,6 @@ private function handleGetOrderDetails(): void $this->model->save($orderMapping); // Load View - $url = $this->config->getInsightPortalUrl($orderMapping); $orderMapping->setOrder(null); $this->jsonResponse([ @@ -244,7 +243,6 @@ private function handleGetOrderDetails(): void 'hpOrderMapping' => $orderMapping, 'hpOrder' => $order, 'hpPayment' => $payment, - 'hpPortalUrl' => $url, 'hpCancellations' => $cancellations ]) ) @@ -271,12 +269,10 @@ private function handleLoadOrders(): void $order->getOrder()->Waehrung = new Currency((int)$order->getOrder()->kWaehrung); } - $url = $this->config->getInsightPortalUrl($order); $data[] = new OrderViewStruct( $order, $this->view(self::TEMPLATE_ID_ORDER_ITEM, [ 'hpOrder' => $order, - 'hpPortalUrl' => $url ]) ); } diff --git a/src/Controllers/Admin/AdminSettingsController.php b/src/Controllers/Admin/AdminSettingsController.php index 4a5c744..967250d 100644 --- a/src/Controllers/Admin/AdminSettingsController.php +++ b/src/Controllers/Admin/AdminSettingsController.php @@ -97,7 +97,6 @@ protected function handleSaveRequest(): void } // Set Config - $this->config->set(Config::MERCHANT_ID, Request::postVar('merchantId')); $this->config->set(Config::FONT_SIZE, Request::postVar('fontSize')); $this->config->set(Config::FONT_COLOR, Request::postVar('fontColor')); $this->config->set(Config::FONT_FAMILY, Request::postVar('fontFamily')); @@ -157,7 +156,7 @@ protected function handleSaveRequest(): void if (empty($publicKey)) { $this->addError(__('Ungültiger Public Key - eine leere Zeichenfolge ist nicht zulässig.')); $valid = false; - } elseif(!PublicKeyValidator::validate($publicKey)) { + } elseif (!PublicKeyValidator::validate($publicKey)) { $this->addError( __('Ungültiger Public Key. Bitte stellen Sie sicher, dass sie hier Ihren Public Key und nicht Ihren Private Key angeben!') ); @@ -207,19 +206,15 @@ protected function saveChannelId(?string $channelId = null): void */ protected function registerWebhooks(HeidelpayApiAdapter $adapter): void { - $newEvents = array_keys(PaymentEventSubscriber::getSubscribedEvents()); - - if (empty($newEvents)) { - return; - } + $newEvents = ['payment', 'charge']; // Register for all keyparis + default - try { - $linkHelper = new JtlLinkHelper(); - $model = new KeyPairModel(Shop::Container()->getDB()); - $keypairs = $model->all(); + $linkHelper = new JtlLinkHelper(); + $model = new KeyPairModel(Shop::Container()->getDB()); + $keypairs = $model->all(); - foreach ($keypairs as $keypair) { + foreach ($keypairs as $keypair) { + try { $adapter->setCurrentConnection( $keypair->isB2B(), $keypair->getCurrencyId(), @@ -228,8 +223,12 @@ protected function registerWebhooks(HeidelpayApiAdapter $adapter): void $linkHelper->getFullFrontendFileUrl(JtlLinkHelper::FRONTEND_FILE_WEBHOOKS), $newEvents ); + } catch (Exception $exc) { + $this->errorLog('Could not register webhook: ' . $exc->getMessage(), static::class); } + } + try { $adapter->getDefaultConnection()->registerMultipleWebhooks( $linkHelper->getFullFrontendFileUrl(JtlLinkHelper::FRONTEND_FILE_WEBHOOKS), $newEvents diff --git a/src/Foundation/EventSubscriber.php b/src/Foundation/EventSubscriber.php index d79cb9f..153ca88 100644 --- a/src/Foundation/EventSubscriber.php +++ b/src/Foundation/EventSubscriber.php @@ -37,14 +37,8 @@ public function handleEvent(EventPayload $payload): void $events = static::getSubscribedEvents(); $event = $payload->getEvent(); - if (!array_key_exists($event, $events)) { - throw new InvalidArgumentException('There is no event listener subscribed for event: ' . $event); - } - - if (!method_exists($this, $events[$event])) { - throw new InvalidArgumentException( - 'The registered event listener ' . $events[$event] . ' for the event ' . $event . ' does not exist!' - ); + if (!array_key_exists($event, $events) || !method_exists($this, $events[$event])) { + return; } call_user_func([$this, $events[$event]], $payload); diff --git a/src/Payments/HeidelpayPaymentMethod.php b/src/Payments/HeidelpayPaymentMethod.php index fd78248..aba5b9b 100644 --- a/src/Payments/HeidelpayPaymentMethod.php +++ b/src/Payments/HeidelpayPaymentMethod.php @@ -6,6 +6,7 @@ use Exception; use JTL\Alert\Alert; use Plugin\s360_unzer_shop5\src\Foundation\ServiceProvider; +use Plugin\s360_unzer_shop5\src\Utils\Logger; use UnzerSDK\Exceptions\UnzerApiException; use UnzerSDK\Resources\PaymentTypes\BasePaymentType; use UnzerSDK\Resources\TransactionTypes\AbstractTransactionType; @@ -386,8 +387,22 @@ public function finalizeOrder(Bestellung $order, string $hash, array $args): boo { // Validate Payment Request (check: currency changed, order amount, cart checksum) if (isset($args['state']) && $args['state'] == self::STATE_DURING_CHECKOUT) { - $this->adapter->getConnectionForOrder($order); - $payment = $this->adapter->fetchPayment(); + try { + $this->adapter->getConnectionForOrder($order); + $payment = $this->adapter->fetchPayment(); + } catch(Throwable $err) { + // For some reason we could not fetch the payment -> abort + Shop::Container()->getAlertService()->addError( + $this->plugin->getLocalization()->getTranslation(Config::LANG_CANCEL_BY_USER) ?? Config::LANG_CANCEL_BY_USER, + 'transactionError', + ['saveInSession' => true] + ); + + $this->setPayStatus(self::PAYSTATUS_FAILED); + $this->deletePaymentHash($hash); + + return false; + } // Invalid Request (basket, currency mismatch) if (!$this->handler->validatePaymentRequest($payment)) { @@ -403,13 +418,8 @@ public function finalizeOrder(Bestellung $order, string $hash, array $args): boo $this->deletePaymentHash($hash); $transaction = $this->adapter->getPaymentTransaction($payment); - $this->sessionHelper->addErrorAlert( - Text::convertUTF8($transaction->getMessage()->getMerchant()), - Text::convertUTF8($transaction->getMessage()->getCustomer()), - 'transactionError', - null, - static::class - ); + Shop::Container()->getAlertService()->addError(Text::convertUTF8($transaction->getMessage()->getCustomer()), 'transactionError', ['saveInSession' => true]); + Logger::error($transaction->getMessage()->getMerchant()); return false; } diff --git a/src/Payments/Traits/HasCustomer.php b/src/Payments/Traits/HasCustomer.php index 07bbfb0..7602674 100644 --- a/src/Payments/Traits/HasCustomer.php +++ b/src/Payments/Traits/HasCustomer.php @@ -4,6 +4,10 @@ namespace Plugin\s360_unzer_shop5\src\Payments\Traits; +use JTL\Shop; +use UnzerSDK\Constants\CompanyCommercialSectorItems; +use UnzerSDK\Constants\CompanyRegistrationTypes; +use UnzerSDK\Constants\CompanyTypes; use UnzerSDK\Resources\Customer; use UnzerSDK\Resources\CustomerFactory; use UnzerSDK\Resources\EmbeddedResources\Address; @@ -18,6 +22,8 @@ use UnzerSDK\Constants\ShippingTypes; use UnzerSDK\Exceptions\UnzerApiException; +use UnzerSDK\Resources\EmbeddedResources\CompanyInfo; +use UnzerSDK\Resources\EmbeddedResources\CompanyOwner; use function Functional\first; /** @@ -61,32 +67,29 @@ protected function createOrFetchHeidelpayCustomer( $customer->setCompany(Text::convertUTF8(html_entity_decode($frontSession->getCustomer()->cFirma))); } - $language = first( - $this->sessionHelper->getFrontendSession()->getLanguages(), - fn (LanguageModel $lang) => $lang->id === $this->sessionHelper->getFrontendSession()->getCustomer()->kSprache - )?->getIso639(); - - $customer->setLanguage(strtolower($language ?? $customer->getLanguage() ?? 'en')); + $this->setCustomerLanguage($customer); // Update names as they might have changed (but not on B2B so that we do not overwrite the B2B Form changes) if (!$isB2B) { $customer->setFirstname(Text::convertUTF8(html_entity_decode($frontSession->getCustomer()->cVorname))); $customer->setLastname(Text::convertUTF8(html_entity_decode($frontSession->getCustomer()->cNachname))); - if ($customer->getShippingAddress()->getShippingType() === ShippingTypes::DIFFERENT_ADDRESS) { - $customer->setFirstname( - Text::convertUTF8(html_entity_decode($frontSession->getDeliveryAddress()->cVorname)) - ); - $customer->setLastname( - Text::convertUTF8(html_entity_decode($frontSession->getDeliveryAddress()->cNachname)) - ); - } - // Remove Company Infomartion as we do not want to be treated as a B2B User $customer->setCompany(null); // $customer->setCompanyInfo(new CompanyInfo()); } + // UOPP-91: Set company info for b2b customers + if ($isB2B && $customer->getCompanyInfo() === null) { + $customer->setCompanyInfo(new CompanyInfo()); + $customer->getCompanyInfo() + ->setRegistrationType(CompanyRegistrationTypes::REGISTRATION_TYPE_NOT_REGISTERED) + ->setFunction('OWNER') + ->setCommercialSector(CompanyCommercialSectorItems::OTHER) + ->setOwner((new CompanyOwner())->setFirstname($customer->getFirstname())->setLastname($customer->getLastname())) + ->setCompanyType(CompanyTypes::OTHER); + } + return $customer; } @@ -133,12 +136,7 @@ protected function createHeidelpayCustomer(ShopCustomer $customer): Customer } // Set user language - $language = first( - $this->sessionHelper->getFrontendSession()->getLanguages(), - fn (LanguageModel $lang) => $lang->id === $this->sessionHelper->getFrontendSession()->getCustomer()->kSprache - )?->getIso639(); - - $customerObj->setLanguage(strtolower($language ?? 'en')); + $this->setCustomerLanguage($customerObj); // Set external customer so we do not have to map it ourself. if (!empty($customer->kKunde)) { @@ -165,7 +163,8 @@ protected function createHeidelpayAddress($address): Address ->setStreet(Text::convertUTF8(html_entity_decode($address->cStrasse . ' ' . $address->cHausnummer))) ->setZip(Text::convertUTF8(html_entity_decode($address->cPLZ))) ->setCity(Text::convertUTF8(html_entity_decode($address->cOrt))) - ->setCountry(Text::convertUTF8(html_entity_decode($address->cLand))); + ->setCountry(Text::convertUTF8(html_entity_decode($address->cLand))) + ->setCompany(!empty($address->cFirma) ? Text::convertUTF8(html_entity_decode($address->cFirma)) : null); if (! $address instanceof \JTL\Customer\Customer) { $address->setShippingType($type); @@ -182,12 +181,18 @@ protected function createHeidelpayAddress($address): Address */ protected function createHeidelpayB2BCustomer(ShopCustomer $customer): Customer { + // UOPP-91 + $companyOwner = (new CompanyOwner()) + ->setFirstname(Text::convertUTF8(html_entity_decode($customer->cVorname))) + ->setLastname(Text::convertUTF8(html_entity_decode($customer->cNachname))); + $address = (new Address()) ->setName(Text::convertUTF8(html_entity_decode($customer->cVorname . ' ' . $customer->cNachname))) ->setStreet(Text::convertUTF8(html_entity_decode($customer->cStrasse . ' ' . $customer->cHausnummer))) ->setZip(Text::convertUTF8(html_entity_decode($customer->cPLZ))) ->setCity(Text::convertUTF8(html_entity_decode($customer->cOrt))) - ->setCountry(Text::convertUTF8(html_entity_decode($customer->cLand))); + ->setCountry(Text::convertUTF8(html_entity_decode($customer->cLand))) + ->setCompany(!empty($customer->cFirma) ? Text::convertUTF8(html_entity_decode($customer->cFirma)) : null); // Registered = registered in the commercial register with a commercial register number if ($customer->cUSTID) { @@ -201,11 +206,15 @@ protected function createHeidelpayB2BCustomer(ShopCustomer $customer): Customer $obj->setLastname(Text::convertUTF8(html_entity_decode($customer->cNachname))); $obj->setEmail($customer->cMail); $obj->setCustomerId((string) $customer->kKunde); + $obj->getCompanyInfo()?->setOwner($companyOwner); + $obj->getCompanyInfo()?->setCompanyType(CompanyTypes::OTHER); if (!empty($customer->cAnrede)) { $obj->setSalutation($customer->cAnrede == 'm' ? 'mr' : ($customer->cAnrede == 'w' ? 'mrs' : null)); } + $this->setCustomerLanguage($obj); + return $obj; } @@ -224,6 +233,9 @@ protected function createHeidelpayB2BCustomer(ShopCustomer $customer): Customer Text::convertUTF8(html_entity_decode($customer->cFirma)) ); $obj->setCustomerId((string) $customer->kKunde); + $obj->getCompanyInfo()?->setOwner($companyOwner); + $obj->getCompanyInfo()?->setCompanyType(CompanyTypes::OTHER); + $this->setCustomerLanguage($obj); if (!empty($customer->cAnrede)) { $obj->setSalutation($customer->cAnrede == 'm' ? 'mr' : ($customer->cAnrede == 'w' ? 'mrs' : null)); @@ -272,4 +284,14 @@ protected function getStreetFromAddress(Address $address): array return $data; } + + private function setCustomerLanguage(Customer $customer): void + { + $language = first( + $this->sessionHelper->getFrontendSession()->getLanguages(), + fn (LanguageModel $lang) => $lang->id === ($this->sessionHelper->getFrontendSession()->getCustomer()->kSprache ?? Shop::getLanguageID()) + )?->getIso639(); + + $customer->setLanguage(strtolower($language ?? 'en')); + } } diff --git a/src/Utils/Config.php b/src/Utils/Config.php index 04ffdcc..cec9364 100644 --- a/src/Utils/Config.php +++ b/src/Utils/Config.php @@ -22,10 +22,6 @@ class Config public const TABLE = 'xplugin_s360_unzer_shop5_config'; public const PLUGIN_ID = 's360_unzer_shop5'; public const PLUGIN_SESSION = 's360_heidelpay'; - public const HIP_URL = 'https://insights.unzer.com/merchant/{merchantId}/order/{id}'; - public const HIP_URL_SANDBOX = 'https://sbx-insights.unzer.com/merchant/{merchantId}/order/{id}'; - public const PAYLATER_PORTAL_URL = 'https://merchant.payolution.com/'; - public const PAYLATER_PORTAL_URL_SANDBOX = 'https://test-merchant.paylater.unzer.com/'; // Lang Var Keys public const LANG_INVALID_TOKEN = 's360_hp_invalid_form_token'; @@ -44,6 +40,7 @@ class Config public const LANG_ERROR_VALIDATING_MERCHANT = 's360_hp_error_validating_merchant'; public const LANG_APPLE_PAY_NOT_SUPPORTED = 's360_hp_apple_pay_not_supported'; public const LANG_APPLE_PAY_CANCEL_BY_USER = 's360_hp_apple_pay_cancel_by_user'; + public const LANG_CANCEL_BY_USER = 's360_hp_cancel_by_user'; public const LANG_CANCEL_PAYMENT_REFERENCE = 's360_hp_cancel_payment_reference'; public const LANG_INSTLAMENT_INFO = 's360_hp_instalment_info'; public const LANG_COMPANY_TYPE_MISSING = 's360_hp_company_type_missing'; @@ -52,7 +49,6 @@ class Config // Config Keys public const PRIVATE_KEY = 'privateKey'; public const PUBLIC_KEY = 'publicKey'; - public const MERCHANT_ID = 'merchantId'; public const FONT_SIZE = 'fontSize'; public const FONT_COLOR = 'fontColor'; public const FONT_FAMILY = 'fontFamily'; @@ -259,31 +255,6 @@ public function getPaymentSetting(string $key, string $moduleId, ?PluginInterfac return $plugin->getConfig()->getValue($moduleId . '_' . $key); } - /** - * Get Insight Portal URL if merchant id is configured - * - * @param OrderMappingEntity|null $orderMapping - * @return string|null - */ - public function getInsightPortalUrl(?OrderMappingEntity $orderMapping): ?string - { - $merchantId = $this->get(self::MERCHANT_ID); - - if ($orderMapping->getPaymentTypeName() === 'paylater-invoice') { - return $this->isSandbox() ? self::PAYLATER_PORTAL_URL_SANDBOX : self::PAYLATER_PORTAL_URL; - } - - if (!empty($merchantId) && !empty($orderMapping->getTransactionUniqueId())) { - return str_replace( - ['{merchantId}', '{id}'], - [$merchantId, $orderMapping->getTransactionUniqueId()], - $this->isSandbox() ? self::HIP_URL_SANDBOX : self::HIP_URL - ); - } - - return null; - } - /** * Check if api is in sandbox mode based on api keys * diff --git a/src/Webhooks/PaymentEventSubscriber.php b/src/Webhooks/PaymentEventSubscriber.php index 876e944..3958844 100644 --- a/src/Webhooks/PaymentEventSubscriber.php +++ b/src/Webhooks/PaymentEventSubscriber.php @@ -4,6 +4,7 @@ namespace Plugin\s360_unzer_shop5\src\Webhooks; +use Throwable; use UnzerSDK\Constants\WebhookEvents; use UnzerSDK\Resources\Payment; use JTL\Shop; @@ -15,6 +16,7 @@ use Plugin\s360_unzer_shop5\src\Payments\PaymentMethodModuleFactory; use Plugin\s360_unzer_shop5\src\Utils\JtlLoggerTrait; use RuntimeException; +use UnzerSDK\Resources\TransactionTypes\Charge; /** * Heidelpay Payment Webhooks Event Subscriber @@ -42,7 +44,8 @@ public static function getSubscribedEvents(): array { return [ WebhookEvents::PAYMENT_COMPLETED => 'onHandleIncomingPayment', - WebhookEvents::PAYMENT_PARTLY => 'onHandleIncomingPayment' + WebhookEvents::PAYMENT_PARTLY => 'onHandleIncomingPayment', + WebhookEvents::CHARGE_SUCCEEDED => 'onHandleIncomingPayment', ]; } @@ -66,20 +69,28 @@ public static function getSubscribedEvents(): array */ public function onHandleIncomingPayment(EventPayload $payload) { - /** @var Payment $payment */ - $payment = $payload->getResource(); - $this->debugLog('Handling incoming event ' . $payload->getEvent() . ' with: ' . $payment->jsonSerialize()); + /** @var Payment|Charge $resource */ + $payment = null; + $resource = $payload->getResource(); + $this->debugLog('Handling incoming event ' . $payload->getEvent() . ' with: ' . $resource->jsonSerialize()); - $orderMapping = $this->model->findByPayment($payment->getId()); - $paymentMethod = $this->paymentMethodFactory->createForType( - $payment->getPaymentType(), - ['id-string' => $orderMapping->getPaymentTypeId()] - ); + if ($resource instanceof Charge) { + $payment = $resource->getPayment(); + } elseif ($resource instanceof Payment) { + $payment = $resource; + } + + if ($payment === null) { + $this->debugLog('Handling incoming event ' . $payload->getEvent() . ' without payment'); + return; + } - if (empty($orderMapping)) { - throw new RuntimeException( + $orderMapping = $this->model->findByPayment($payment->getId()); + if ($orderMapping === null) { + $this->debugLog( 'Cannot find order for payment ' . $payment->getId() . '. Maybe it is not mapped yet.' ); + return; } // The payment is completed, which means that a pending order can now be released. @@ -96,11 +107,20 @@ public function onHandleIncomingPayment(EventPayload $payload) $adapter = Shop::Container()->get(HeidelpayApiAdapter::class); $api = $adapter->getConnectionForPublicKey($payload->getPublicKey()); + $paymentMethod = $this->paymentMethodFactory->createForType( + $payment->getPaymentType(), + ['id-string' => $orderMapping->getPaymentTypeId()] + ); + foreach ($payment->getCharges() as $charge) { // we need to fetch the charge because the charge in the payment object might not contain all information. // Especially the isError, isPending, isSuccess flags - $charge = $api->fetchCharge($charge); - $this->charges->addCharge($charge, $paymentMethod, $orderMapping->getOrder()); + try { + $charge = $api->fetchCharge($charge); + $this->charges->addCharge($charge, $paymentMethod, $orderMapping->getOrder()); + } catch (Throwable $exc) { + $this->errorLog("Could not handle charge {$charge->getId()} for order {$orderMapping->getJtlOrderNumber()}: " . $exc->getMessage()); + } } // Mark order as paid if there is no remaining amount on the payment. diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 294ea2b..b1e497a 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -127,17 +127,17 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.46", - "version_normalized": "3.0.46.0", + "version": "3.0.53", + "version_normalized": "3.0.53.0", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6" + "reference": "511ddc8e352d5d1f1e33bea468b6f4ef48438cf9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", - "reference": "56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/511ddc8e352d5d1f1e33bea468b6f4ef48438cf9", + "reference": "511ddc8e352d5d1f1e33bea468b6f4ef48438cf9", "shasum": "" }, "require": { @@ -155,7 +155,7 @@ "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations." }, - "time": "2025-06-26T16:29:55+00:00", + "time": "2026-06-09T18:08:26+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -220,7 +220,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.46" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.53" }, "funding": [ { @@ -240,31 +240,31 @@ }, { "name": "unzerdev/php-sdk", - "version": "3.13.1", - "version_normalized": "3.13.1.0", + "version": "4.0.1", + "version_normalized": "4.0.1.0", "source": { "type": "git", "url": "https://github.com/unzerdev/php-sdk.git", - "reference": "0a26d70b33185d52e49b06cb500a6e01bb6f1087" + "reference": "a9344b823fbf5374cd49e07ab6352d385578299e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/unzerdev/php-sdk/zipball/0a26d70b33185d52e49b06cb500a6e01bb6f1087", - "reference": "0a26d70b33185d52e49b06cb500a6e01bb6f1087", + "url": "https://api.github.com/repos/unzerdev/php-sdk/zipball/a9344b823fbf5374cd49e07ab6352d385578299e", + "reference": "a9344b823fbf5374cd49e07ab6352d385578299e", "shasum": "" }, "require": { "ext-json": "*", - "php": "~7.4.0|~8.0.0|~8.1.0|~8.2.0|~8.3.0|~8.4.0" + "php": "~8.1.0|~8.2.0|~8.3.0|~8.4.0|~8.5.0" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.0", - "phpunit/phpunit": ">6.5 <10.0" + "phpunit/phpunit": "^9.6" }, "suggest": { "ext-curl": "*" }, - "time": "2025-09-23T14:21:50+00:00", + "time": "2026-05-15T13:48:06+00:00", "type": "library", "installation-source": "dist", "autoload": { @@ -280,7 +280,7 @@ "description": "This is the php sdk to connect to the Unzer rest API.", "support": { "email": "support@unzer.com", - "source": "https://github.com/unzerdev/php-sdk/tree/3.13.1" + "source": "https://github.com/unzerdev/php-sdk/tree/4.0.1" }, "install-path": "../unzerdev/php-sdk" } diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 07f5e42..dca2f4d 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 's360/s360_unzer_shop5', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '7003c4acea1ff6298834f293122048fcffe8814b', + 'reference' => 'ccda2fb95972aba588f2547b863c10d710c83457', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -29,9 +29,9 @@ 'dev_requirement' => false, ), 'phpseclib/phpseclib' => array( - 'pretty_version' => '3.0.46', - 'version' => '3.0.46.0', - 'reference' => '56483a7de62a6c2a6635e42e93b8a9e25d4f0ec6', + 'pretty_version' => '3.0.53', + 'version' => '3.0.53.0', + 'reference' => '511ddc8e352d5d1f1e33bea468b6f4ef48438cf9', 'type' => 'library', 'install_path' => __DIR__ . '/../phpseclib/phpseclib', 'aliases' => array(), @@ -40,16 +40,16 @@ 's360/s360_unzer_shop5' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '7003c4acea1ff6298834f293122048fcffe8814b', + 'reference' => 'ccda2fb95972aba588f2547b863c10d710c83457', 'type' => 'library', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), 'dev_requirement' => false, ), 'unzerdev/php-sdk' => array( - 'pretty_version' => '3.13.1', - 'version' => '3.13.1.0', - 'reference' => '0a26d70b33185d52e49b06cb500a6e01bb6f1087', + 'pretty_version' => '4.0.1', + 'version' => '4.0.1.0', + 'reference' => 'a9344b823fbf5374cd49e07ab6352d385578299e', 'type' => 'library', 'install_path' => __DIR__ . '/../unzerdev/php-sdk', 'aliases' => array(), diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php index adfb472..4c3a5d6 100644 --- a/vendor/composer/platform_check.php +++ b/vendor/composer/platform_check.php @@ -4,8 +4,8 @@ $issues = array(); -if (!(PHP_VERSION_ID >= 80000)) { - $issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.'; +if (!(PHP_VERSION_ID >= 80100)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.'; } if ($issues) { diff --git a/vendor/phpseclib/phpseclib/BACKERS.md b/vendor/phpseclib/phpseclib/BACKERS.md index cafcf60..d9406b2 100644 --- a/vendor/phpseclib/phpseclib/BACKERS.md +++ b/vendor/phpseclib/phpseclib/BACKERS.md @@ -16,4 +16,5 @@ phpseclib ongoing development is made possible by [Tidelift](https://tidelift.co - [istiak-tridip](https://github.com/istiak-tridip) - [Anna Filina](https://github.com/afilina) - [blakemckeeby](https://github.com/blakemckeeby) -- [ssddanbrown](https://github.com/ssddanbrown) \ No newline at end of file +- [ssddanbrown](https://github.com/ssddanbrown) +- Stefan Beck \ No newline at end of file diff --git a/vendor/phpseclib/phpseclib/README.md b/vendor/phpseclib/phpseclib/README.md index 37cbcb9..1a7e3c7 100644 --- a/vendor/phpseclib/phpseclib/README.md +++ b/vendor/phpseclib/phpseclib/README.md @@ -29,6 +29,17 @@ SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 / * Unstable API * Do not use in production +### 4.0 + +* Expected Release Date: September 2026 +* Long term support (LTS) release +* X509 split into separate X509, CRL, CSR and SPKAC classes +* PFX and CMS classes added +* All ASN1 classes are lazy loaded by default +* Minimum PHP version: 8.1.0 +* PSR-4 autoloading with namespace rooted at `\phpseclib4` +* Install via Composer: `composer require phpseclib/phpseclib:4.0.x-dev` + ### 3.0 * Long term support (LTS) release @@ -51,7 +62,7 @@ SSH-2, SFTP, X.509, an arbitrary-precision integer arithmetic library, Ed25519 / * PHP4 compatible * Composer compatible (PSR-0 autoloading) * Install using Composer: `composer require phpseclib/phpseclib:~1.0` -* [Download 1.0.23 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.23.zip/download) +* [Download 1.0.25 as ZIP](http://sourceforge.net/projects/phpseclib/files/phpseclib1.0.25.zip/download) ## Security contact information @@ -63,14 +74,22 @@ Need Support? * [Checkout Questions and Answers on Stack Overflow](http://stackoverflow.com/questions/tagged/phpseclib) * [Create a Support Ticket on GitHub](https://github.com/phpseclib/phpseclib/issues/new) -* [Browse the Support Forum](http://www.frostjedi.com/phpbb/viewforum.php?f=46) (no longer in use) ## Special Thanks -Special Thanks to our $50+ sponsors!: +

+ + Sovereign Tech Agency + +

+ +## Additional Thanks - Allan Simon +- [Anna Filina](https://afilina.com/) +- delovelady - [ChargeOver](https://chargeover.com/) +- ## Contributing diff --git a/vendor/phpseclib/phpseclib/SECURITY.md b/vendor/phpseclib/phpseclib/SECURITY.md new file mode 100644 index 0000000..f8368b6 --- /dev/null +++ b/vendor/phpseclib/phpseclib/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 1.0.x | :white_check_mark: | +| 2.0.x | :white_check_mark: | +| 3.0.x | :white_check_mark: | + +## Reporting a Vulnerability + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. \ No newline at end of file diff --git a/vendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php b/vendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php index ad8f63b..7a56f7c 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Common/Functions/Strings.php @@ -356,9 +356,11 @@ public static function switchEndianness($x) // from http://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith32Bits $p1 = ($b * 0x0802) & 0x22110; $p2 = ($b * 0x8020) & 0x88440; - $r .= chr( - (($p1 | $p2) * 0x10101) >> 16 - ); + $temp = ($p1 | $p2) * 0x10101; + if (is_float($temp)) { + $temp = (int) fmod($temp, 0x7FFFFFFF); + } + $r .= chr(($temp >> 16) & 0xFF); } } return $r; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php index 998cf8b..38df513 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Blowfish.php @@ -448,8 +448,8 @@ protected function setupKey() protected static function initialize_static_variables() { if (is_float(self::$sbox[0x200])) { - self::$sbox = array_map('intval', self::$sbox); - self::$parray = array_map('intval', self::$parray); + self::$sbox = array_map([self::class, 'safe_intval'], self::$sbox); + self::$parray = array_map([self::class, 'safe_intval'], self::$parray); } parent::initialize_static_variables(); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php index b2691b5..dc365aa 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/ChaCha20.php @@ -279,10 +279,10 @@ protected static function quarterRound(&$a, &$b, &$c, &$d) // xor'ing and rotation are all on the same line so i'm keeping it on the same // line here as well // @codingStandardsIgnoreStart - $a+= $b; $d = self::leftRotate(intval($d) ^ intval($a), 16); - $c+= $d; $b = self::leftRotate(intval($b) ^ intval($c), 12); - $a+= $b; $d = self::leftRotate(intval($d) ^ intval($a), 8); - $c+= $d; $b = self::leftRotate(intval($b) ^ intval($c), 7); + $a+= $b; $d = self::leftRotate(self::safe_intval($d) ^ self::safe_intval($a), 16); + $c+= $d; $b = self::leftRotate(self::safe_intval($b) ^ self::safe_intval($c), 12); + $a+= $b; $d = self::leftRotate(self::safe_intval($d) ^ self::safe_intval($a), 8); + $c+= $d; $b = self::leftRotate(self::safe_intval($b) ^ self::safe_intval($c), 7); // @codingStandardsIgnoreEnd } @@ -357,424 +357,424 @@ protected static function salsa20($x) // @codingStandardsIgnoreStart // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // columnRound - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 16); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 12); - $x0+= $x4; $x12 = self::leftRotate(intval($x12) ^ intval($x0), 8); - $x8+= $x12; $x4 = self::leftRotate(intval($x4) ^ intval($x8), 7); - - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 16); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 12); - $x1+= $x5; $x13 = self::leftRotate(intval($x13) ^ intval($x1), 8); - $x9+= $x13; $x5 = self::leftRotate(intval($x5) ^ intval($x9), 7); - - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 16); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 12); - $x2+= $x6; $x14 = self::leftRotate(intval($x14) ^ intval($x2), 8); - $x10+= $x14; $x6 = self::leftRotate(intval($x6) ^ intval($x10), 7); - - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 16); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 12); - $x3+= $x7; $x15 = self::leftRotate(intval($x15) ^ intval($x3), 8); - $x11+= $x15; $x7 = self::leftRotate(intval($x7) ^ intval($x11), 7); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 16); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 12); + $x0+= $x4; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x0), 8); + $x8+= $x12; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x8), 7); + + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 16); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 12); + $x1+= $x5; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x1), 8); + $x9+= $x13; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x9), 7); + + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 16); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 12); + $x2+= $x6; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x2), 8); + $x10+= $x14; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x10), 7); + + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 16); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 12); + $x3+= $x7; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x3), 8); + $x11+= $x15; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x11), 7); // rowRound - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 16); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 12); - $x0+= $x5; $x15 = self::leftRotate(intval($x15) ^ intval($x0), 8); - $x10+= $x15; $x5 = self::leftRotate(intval($x5) ^ intval($x10), 7); - - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 16); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 12); - $x1+= $x6; $x12 = self::leftRotate(intval($x12) ^ intval($x1), 8); - $x11+= $x12; $x6 = self::leftRotate(intval($x6) ^ intval($x11), 7); - - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 16); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 12); - $x2+= $x7; $x13 = self::leftRotate(intval($x13) ^ intval($x2), 8); - $x8+= $x13; $x7 = self::leftRotate(intval($x7) ^ intval($x8), 7); - - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 16); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 12); - $x3+= $x4; $x14 = self::leftRotate(intval($x14) ^ intval($x3), 8); - $x9+= $x14; $x4 = self::leftRotate(intval($x4) ^ intval($x9), 7); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 16); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 12); + $x0+= $x5; $x15 = self::leftRotate(self::safe_intval($x15) ^ self::safe_intval($x0), 8); + $x10+= $x15; $x5 = self::leftRotate(self::safe_intval($x5) ^ self::safe_intval($x10), 7); + + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 16); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 12); + $x1+= $x6; $x12 = self::leftRotate(self::safe_intval($x12) ^ self::safe_intval($x1), 8); + $x11+= $x12; $x6 = self::leftRotate(self::safe_intval($x6) ^ self::safe_intval($x11), 7); + + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 16); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 12); + $x2+= $x7; $x13 = self::leftRotate(self::safe_intval($x13) ^ self::safe_intval($x2), 8); + $x8+= $x13; $x7 = self::leftRotate(self::safe_intval($x7) ^ self::safe_intval($x8), 7); + + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 16); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 12); + $x3+= $x4; $x14 = self::leftRotate(self::safe_intval($x14) ^ self::safe_intval($x3), 8); + $x9+= $x14; $x4 = self::leftRotate(self::safe_intval($x4) ^ self::safe_intval($x9), 7); // @codingStandardsIgnoreEnd $x0 += $z0; @@ -794,6 +794,6 @@ protected static function salsa20($x) $x14 += $z14; $x15 += $z15; - return pack('V*', $x0, $x1, $x2, $x3, $x4, $x5, $x6, $x7, $x8, $x9, $x10, $x11, $x12, $x13, $x14, $x15); + return pack('V*', self::safe_intval($x0), self::safe_intval($x1), self::safe_intval($x2), self::safe_intval($x3), self::safe_intval($x4), self::safe_intval($x5), self::safe_intval($x6), self::safe_intval($x7), self::safe_intval($x8), self::safe_intval($x9), self::safe_intval($x10), self::safe_intval($x11), self::safe_intval($x12), self::safe_intval($x13), self::safe_intval($x14), self::safe_intval($x15)); } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php index a380e43..a8074cb 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/AsymmetricKey.php @@ -79,18 +79,19 @@ abstract class AsymmetricKey private static $invisiblePlugins = []; /** - * Available Engines + * Key Comment * - * @var boolean[] + * @var null|string */ - protected static $engines = []; + private $comment; /** - * Key Comment + * OpenSSL configuration file name. * - * @var null|string + * @see self::createKey() + * @var ?string */ - private $comment; + protected static $configFile; /** * @param string $type @@ -119,6 +120,10 @@ protected static function initialize_static_variables() self::$one = new BigInteger(1); } + if (!isset(self::$configFile)) { + self::$configFile = dirname(__FILE__) . '/../../openssl.cnf'; + } + self::loadPlugins('Keys'); if (static::ALGORITHM != 'RSA' && static::ALGORITHM != 'DH') { self::loadPlugins('Signature'); @@ -363,6 +368,18 @@ public static function getSupportedKeyFormats() return self::$plugins[static::ALGORITHM]['Keys']; } + /** + * Sets the OpenSSL config file path + * + * Set to the empty string to use the default config file + * + * @param string $val + */ + public static function setOpenSSLConfigPath($val) + { + self::$configFile = $val; + } + /** * Add a fileformat plugin * @@ -419,34 +436,28 @@ public function getComment() } /** - * Tests engine validity - * + * Force engine (useful for unit testing) */ - public static function useBestEngine() + public static function forceEngine($engine = null) { - static::$engines = [ - 'PHP' => true, - 'OpenSSL' => extension_loaded('openssl'), - // this test can be satisfied by either of the following: - // http://php.net/manual/en/book.sodium.php - // https://github.com/paragonie/sodium_compat - 'libsodium' => function_exists('sodium_crypto_sign_keypair') - ]; - - return static::$engines; + if (!isset($engine)) { + static::$forcedEngine = null; + return; + } + switch ($engine) { + case 'PHP': + case 'OpenSSL': + case 'libsodium': + static::$forcedEngine = $engine; + break; + default: + throw new \InvalidArgumentException('Valid engines are null, PHP, OpenSSL or libsodium'); + } } - /** - * Flag to use internal engine only (useful for unit testing) - * - */ - public static function useInternalEngine() + public static function getForcedEngine() { - static::$engines = [ - 'PHP' => true, - 'OpenSSL' => false, - 'libsodium' => false - ]; + return static::$forcedEngine; } /** diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php index ab7f050..6673ac5 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/OpenSSH.php @@ -118,7 +118,7 @@ public static function load($key, $password = '') return compact('type', 'publicKey', 'paddedKey'); } - $parts = explode(' ', $key, 3); + $parts = preg_split("#[\t ]+#", $key, 3); if (!isset($parts[1])) { $key = base64_decode($parts[0]); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php index 2211a87..8971a80 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php @@ -565,7 +565,7 @@ protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = ], 'privateKey' => $key ]; - if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') { + if ($oid != 'id-Ed25519' && $oid != 'id-Ed448' && $oid != 'id-X25519' && $oid != 'id-X448') { $key['privateKeyAlgorithm']['parameters'] = $params; } if (!empty($attr)) { @@ -682,7 +682,7 @@ protected static function wrapPublicKey($key, $params, $oid = null, array $optio 'publicKey' => "\0" . $key ]; - if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') { + if ($oid != 'id-Ed25519' && $oid != 'id-Ed448' && $oid != 'id-X25519' && $oid != 'id-X448') { $key['publicKeyAlgorithm']['parameters'] = $params; } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php index 35d7a7d..6e70be4 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/SymmetricKey.php @@ -666,6 +666,11 @@ protected static function initialize_static_variables() { if (!isset(self::$use_reg_intval)) { switch (true) { + // PHP 8.5, per https://www.php.net/manual/en/migration85.incompatible.php, now emits a warning + // "when casting floats (or strings that look like floats) to int if they cannot be represented as one" + case PHP_VERSION_ID >= 80500 && PHP_INT_SIZE == 4: + self::$use_reg_intval = false; + break; // PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster case (PHP_OS & "\xDF\xDF\xDF") === 'WIN': case !function_exists('php_uname'): @@ -2591,7 +2596,7 @@ protected function unpad($text) $length = ord($text[strlen($text) - 1]); - if (!$length || $length > $this->block_size) { + if (!$length | ($length > $this->block_size)) { throw new BadDecryptionException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})"); } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php index 93d7ad2..d02d29e 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DES.php @@ -673,14 +673,14 @@ private function processBlock($block, $mode) { static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; if (!$sbox1) { - $sbox1 = array_map('intval', self::$sbox1); - $sbox2 = array_map('intval', self::$sbox2); - $sbox3 = array_map('intval', self::$sbox3); - $sbox4 = array_map('intval', self::$sbox4); - $sbox5 = array_map('intval', self::$sbox5); - $sbox6 = array_map('intval', self::$sbox6); - $sbox7 = array_map('intval', self::$sbox7); - $sbox8 = array_map('intval', self::$sbox8); + $sbox1 = array_map([self::class, 'safe_intval'], self::$sbox1); + $sbox2 = array_map([self::class, 'safe_intval'], self::$sbox2); + $sbox3 = array_map([self::class, 'safe_intval'], self::$sbox3); + $sbox4 = array_map([self::class, 'safe_intval'], self::$sbox4); + $sbox5 = array_map([self::class, 'safe_intval'], self::$sbox5); + $sbox6 = array_map([self::class, 'safe_intval'], self::$sbox6); + $sbox7 = array_map([self::class, 'safe_intval'], self::$sbox7); + $sbox8 = array_map([self::class, 'safe_intval'], self::$sbox8); /* Merge $shuffle with $[inv]ipmap */ for ($i = 0; $i < 256; ++$i) { $shuffleip[] = self::$shuffle[self::$ipmap[$i]]; @@ -1243,9 +1243,9 @@ protected function setupKey() $pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF]; // Reorder: odd bytes/even bytes. Push the result in key schedule. - $val1 = ( $cp & intval(0xFF000000)) | (($cp << 8) & 0x00FF0000) | + $val1 = ( $cp & self::safe_intval(0xFF000000)) | (($cp << 8) & 0x00FF0000) | (($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF); - $val2 = (($cp << 8) & intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) | + $val2 = (($cp << 8) & self::safe_intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) | (($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF); $keys[$des_round][self::ENCRYPT][ ] = $val1; $keys[$des_round][self::DECRYPT][$ki - 1] = $val1; @@ -1292,14 +1292,14 @@ protected function setupInlineCrypt() $init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip; if (!$sbox1) { - $sbox1 = array_map("intval", self::$sbox1); - $sbox2 = array_map("intval", self::$sbox2); - $sbox3 = array_map("intval", self::$sbox3); - $sbox4 = array_map("intval", self::$sbox4); - $sbox5 = array_map("intval", self::$sbox5); - $sbox6 = array_map("intval", self::$sbox6); - $sbox7 = array_map("intval", self::$sbox7); - $sbox8 = array_map("intval", self::$sbox8);' + $sbox1 = array_map(["' . self::class . '", "safe_intval"], self::$sbox1); + $sbox2 = array_map(["' . self::class . '", "safe_intval"], self::$sbox2); + $sbox3 = array_map(["' . self::class . '", "safe_intval"], self::$sbox3); + $sbox4 = array_map(["' . self::class .'", "safe_intval"], self::$sbox4); + $sbox5 = array_map(["' . self::class . '", "safe_intval"], self::$sbox5); + $sbox6 = array_map(["' . self::class . '", "safe_intval"], self::$sbox6); + $sbox7 = array_map(["' . self::class . '", "safe_intval"], self::$sbox7); + $sbox8 = array_map(["' . self::class . '", "safe_intval"], self::$sbox8);' /* Merge $shuffle with $[inv]ipmap */ . ' for ($i = 0; $i < 256; ++$i) { $shuffleip[] = self::$shuffle[self::$ipmap[$i]]; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DH.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DH.php index b230198..bab2e9a 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DH.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DH.php @@ -28,8 +28,14 @@ use phpseclib3\Crypt\DH\Parameters; use phpseclib3\Crypt\DH\PrivateKey; use phpseclib3\Crypt\DH\PublicKey; +use phpseclib3\Crypt\EC\Curves\Curve25519; +use phpseclib3\Crypt\EC\Curves\Curve448; +use phpseclib3\Crypt\EC\Formats\Keys\PKCS1; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\NoKeyLoadedException; use phpseclib3\Exception\UnsupportedOperationException; +use phpseclib3\File\ASN1; +use phpseclib3\File\ASN1\Maps; use phpseclib3\Math\BigInteger; /** @@ -295,21 +301,51 @@ public static function computeSecret($private, $public) } if ($private instanceof EC\PrivateKey) { + $privateCurve = $private->getCurve(); switch (true) { case $public instanceof EC\PublicKey: + if ($privateCurve !== $public->getCurve()) { + throw new \InvalidArgumentException("The public key curve (" . $public->getCurve() . ") and private key curve ($privateCurve) need to match"); + } + $orig = $public; $public = $public->getEncodedCoordinates(); // fall-through case is_string($public): - $point = $private->multiply($public); - switch ($private->getCurve()) { - case 'Curve25519': - case 'Curve448': - $secret = $point; - break; - default: - // according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned - $secret = substr($point, 1, (strlen($point) - 1) >> 1); + $forcedEngine = EC::getForcedEngine(); + if ($forcedEngine === 'libsodium' && $privateCurve !== 'Curve25519') { + throw new BadConfigurationException('Engine libsodium is forced but can only used with Curve25519 for ECDH'); + } + if (!isset($forcedEngine) || $forcedEngine === 'OpenSSL') { + // PHP 7.3.0 introduced the openssl_pkey_derive() function + // openssl_dh_computee_key() has been around since PHP 5.3.0+ BUT it did not support ECDH + // until PHP 8.1.0 / OpenSSL 3.0.0 + if ($forcedEngine === 'OpenSSL' && !function_exists('openssl_pkey_derive')) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDH'); + } + if (function_exists('openssl_pkey_derive')) { + $privateStr = (string) $private->withPassword(); + $publicStr = (string) (isset($orig) ? $orig : EC::convertPointToPublicKey($private->getCurve(), $public)); + $result = openssl_pkey_derive($publicStr, $privateStr); + if ($result) { + return $result; + } + if ($forcedEngine === 'OpenSSL') { + // i suppose we _could_ try openssl_dh_compute_key() at this point + // quoting https://www.php.net/openssl-dh-compute-key "ECDH is only supported as of PHP 8.1.0 and OpenSSL 3.0.0". ie. + // PHP_VERSION_ID >= 80100 && OPENSSL_VERSION_NUMBER >= 0x3000000f + // but i think that's overkill. if openssl_pkey_derive() doesn't work it seems doubtful to me that openssl_dh_compute_key() would + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to perform ECDH because of ' . openssl_error_string()); + } + } } + $curveName = $private->getCurve(); + $isMontgomeryCurve = $curveName == 'Curve25519' || $curveName == 'Curve448'; + if (!$isMontgomeryCurve) { + $public = EC::convertPointToPublicKey($curveName, $public, false); + } + $point = $private->multiply($public); + // according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned + $secret = $isMontgomeryCurve ? $point : substr($point, 1, (strlen($point) - 1) >> 1); /* if (($secret[0] & "\x80") === "\x80") { $secret = "\0$secret"; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php index 92c777d..23c54df 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA.php @@ -33,6 +33,7 @@ use phpseclib3\Crypt\DSA\Parameters; use phpseclib3\Crypt\DSA\PrivateKey; use phpseclib3\Crypt\DSA\PublicKey; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\InsufficientSetupException; use phpseclib3\Math\BigInteger; @@ -87,6 +88,14 @@ abstract class DSA extends AsymmetricKey */ protected $sigFormat; + /** + * Forced Engine + * + * @var ?string + * @see parent::forceEngine() + */ + protected static $forcedEngine = null; + /** * Signature Format (Short) * @@ -110,10 +119,6 @@ public static function createParameters($L = 2048, $N = 224) throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')'); } - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - switch (true) { case $N == 160: /* @@ -185,15 +190,19 @@ public static function createKey(...$args) { self::initialize_static_variables(); + if (self::$forcedEngine == 'libsodium') { + throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for DSA'); + } + + if (self::$forcedEngine == 'OpenSSL' && !defined('OPENSSL_KEYTYPE_DSA')) { + throw new BadConfigurationException("Engine OpenSSL is forced but unsupported for DSA"); + } + $class = new \ReflectionClass(static::class); if ($class->isFinal()) { throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); } - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) { $params = self::createParameters($args[0], $args[1]); } elseif (count($args) == 1 && $args[0] instanceof Parameters) { @@ -204,6 +213,33 @@ public static function createKey(...$args) throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.'); } + // at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null + // if it's either OpenSSL or null we'll use OpenSSL (if it's available) + if (self::$forcedEngine !== 'PHP' && defined('OPENSSL_KEYTYPE_DSA')) { + $config = []; + if (self::$configFile) { + $config['config'] = self::$configFile; + } + $dsa = openssl_pkey_new($config + [ + 'private_key_type' => OPENSSL_KEYTYPE_DSA, + 'p' => $params->p, + 'q' => $params->q, + 'g' => $params->g, + ]); + if ($dsa && openssl_pkey_export($dsa, $privatekeystr, null, $config)) { + // clear the buffer of error strings stemming from a minimalistic openssl.cnf + // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up + while (openssl_error_string() !== false) { + } + + return DSA::load($privatekeystr) + ->withHash($params->hash->getHash()) + ->withSignatureFormat($params->shortFormat); + } elseif (isset(self::$forcedEngine)) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA'); + } + } + $private = new PrivateKey(); $private->p = $params->p; $private->q = $params->q; @@ -227,10 +263,6 @@ public static function createKey(...$args) */ protected static function onLoad(array $components) { - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - if (!isset($components['x']) && !isset($components['y'])) { $new = new Parameters(); } elseif (isset($components['x'])) { @@ -276,22 +308,6 @@ public function getLength() return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()]; } - /** - * Returns the current engine being used - * - * @see self::useInternalEngine() - * @see self::useBestEngine() - * @return string - */ - public function getEngine() - { - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ? - 'OpenSSL' : 'PHP'; - } - /** * Returns the parameters * diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php index 800cfb3..77faff9 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/Formats/Keys/PKCS1.php @@ -66,10 +66,22 @@ public static function load($key, $password = '') return $key; } - $key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP); - if (is_array($key)) { - return $key; - } + // PKCS1 DSA public keys are not supported by phpseclib since they can't be used to do + // anything on their own. in order to verify a signature with DSA you need p, q, g and y. + // a PKCS1 DSA public key only has y. to verify a signature with a PKCS1 DSA public key + // you'd also need to load a PKCS1 DSA parameters file separately. like you'd need to + // load two files instead of just one. there's no other key format that phpseclib supports + // that has that requirement so building it in for PKCS1 DSA public keys seems excessive. + // + // the whole thing would be rather like an RSA public key having the modulo live in + // a separate file than the exponent. + // + // this isn't an issue for PKCS8 DSA public keys because those keys have the parameters + // included. eg. \phpseclib3\File\ASN1\Maps\SubjectPublicKeyInfo has "algorithm" and + // "subjectPublicKey" and "algorithm", in turn, has "algorithm" and "parameters". y + // is saved as "subjectPublicKey" and p, q and g are saved as "parameters". + + //$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP); throw new \RuntimeException('Unable to perform ASN1 mapping'); } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php index 9025213..b30d913 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PrivateKey.php @@ -15,6 +15,7 @@ use phpseclib3\Crypt\DSA; use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature; use phpseclib3\Math\BigInteger; +use phpseclib3\Exception\BadConfigurationException; /** * DSA Private Key @@ -79,20 +80,34 @@ public function sign($message) { $format = $this->sigFormat; - if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { - $signature = ''; - $result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash()); + if (self::$forcedEngine === 'libsodium') { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for DSA'); + } - if ($result) { - if ($this->shortFormat == 'ASN1') { - return $signature; - } + if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA'); + } - $loaded = ASN1Signature::load($signature); - $r = $loaded['r']; - $s = $loaded['s']; + if (function_exists('openssl_get_md_methods') && self::$forcedEngine !== 'PHP') { + if (in_array($this->hash->getHash(), openssl_get_md_methods())) { + $signature = ''; + $result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8'), $this->hash->getHash()); - return $format::save($r, $s); + if ($result) { + if ($this->shortFormat == 'ASN1') { + return $signature; + } + + $loaded = ASN1Signature::load($signature); + $r = $loaded['r']; + $s = $loaded['s']; + + return $format::save($r, $s); + } elseif (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string()); + } + } elseif (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA / ' . $this->hash->getHash()); } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php index 3e16762..e7e7d7e 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/DSA/PublicKey.php @@ -14,6 +14,7 @@ use phpseclib3\Crypt\Common; use phpseclib3\Crypt\DSA; use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature; +use phpseclib3\Exception\BadConfigurationException; /** * DSA Public Key @@ -34,6 +35,14 @@ final class PublicKey extends DSA implements Common\PublicKey */ public function verify($message, $signature) { + if (self::$forcedEngine === 'libsodium') { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for DSA'); + } + + if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA'); + } + $format = $this->sigFormat; $params = $format::load($signature); @@ -43,13 +52,17 @@ public function verify($message, $signature) $r = $params['r']; $s = $params['s']; - if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { - $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; + if (function_exists('openssl_get_md_methods') && self::$forcedEngine !== 'PHP') { + if (in_array($this->hash->getHash(), openssl_get_md_methods())) { + $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; - $result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash()); + $result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash()); - if ($result != -1) { - return (bool) $result; + if ($result != -1) { + return (bool) $result; + } + } elseif (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for DSA / ' . $this->hash->getHash()); } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC.php index dc82dd0..fa4d91a 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC.php @@ -33,12 +33,15 @@ use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve; use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib3\Crypt\EC\Curves\Curve25519; +use phpseclib3\Crypt\EC\Curves\Curve448; use phpseclib3\Crypt\EC\Curves\Ed25519; use phpseclib3\Crypt\EC\Curves\Ed448; use phpseclib3\Crypt\EC\Formats\Keys\PKCS1; +use phpseclib3\Crypt\EC\Formats\Keys\PKCS8; use phpseclib3\Crypt\EC\Parameters; use phpseclib3\Crypt\EC\PrivateKey; use phpseclib3\Crypt\EC\PublicKey; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\UnsupportedAlgorithmException; use phpseclib3\Exception\UnsupportedCurveException; use phpseclib3\Exception\UnsupportedOperationException; @@ -74,13 +77,6 @@ abstract class EC extends AsymmetricKey */ protected $curve; - /** - * Signature Format - * - * @var string - */ - protected $format; - /** * Signature Format (Short) * @@ -130,6 +126,14 @@ abstract class EC extends AsymmetricKey */ protected $sigFormat; + /** + * Forced Engine + * + * @var ?string + * @see parent::forceEngine() + */ + protected static $forcedEngine = null; + /** * Create public / private key pair. * @@ -145,31 +149,7 @@ public static function createKey($curve) throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); } - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - - $curve = strtolower($curve); - if (self::$engines['libsodium'] && $curve == 'ed25519' && function_exists('sodium_crypto_sign_keypair')) { - $kp = sodium_crypto_sign_keypair(); - - $privatekey = EC::loadFormat('libsodium', sodium_crypto_sign_secretkey($kp)); - //$publickey = EC::loadFormat('libsodium', sodium_crypto_sign_publickey($kp)); - - $privatekey->curveName = 'Ed25519'; - //$publickey->curveName = $curve; - - return $privatekey; - } - - $privatekey = new PrivateKey(); - - $curveName = $curve; - if (preg_match('#(?:^curve|^ed)\d+$#', $curveName)) { - $curveName = ucfirst($curveName); - } elseif (substr($curveName, 0, 10) == 'brainpoolp') { - $curveName = 'brainpoolP' . substr($curveName, 10); - } + $curveName = self::getCurveCase($curve); $curve = '\phpseclib3\Crypt\EC\Curves\\' . $curveName; if (!class_exists($curve)) { @@ -180,6 +160,54 @@ public static function createKey($curve) $curveName = $reflect->isFinal() ? $reflect->getParentClass()->getShortName() : $reflect->getShortName(); + $curveEngineName = self::getOpenSSLCurveName(strtolower($curveName)); + + switch ($curveName) { + case 'Ed25519': + $providers = [ + 'libsodium' => function_exists('sodium_crypto_sign_keypair'), + // OPENSSL_KEYTYPE_ED25519 introduced in PHP 8.4.0 + 'OpenSSL' => defined('OPENSSL_KEYTYPE_ED25519'), + ]; + break; + case 'Ed448': + // OPENSSL_KEYTYPE_ED448 introduced in PHP 8.4.0 + $providers = ['OpenSSL' => defined('OPENSSL_KEYTYPE_ED448')]; + break; + case 'Curve25519': + $providers = [ + 'libsodium' => function_exists('sodium_crypto_box_publickey_from_secretkey'), + // OPENSSL_KEYTYPE_X25519 introduced in PHP 8.4.0 + 'OpenSSL' => defined('OPENSSL_KEYTYPE_X25519'), + ]; + break; + // OPENSSL_KEYTYPE_X448 introduced in PHP 8.4.0 + case 'Curve448': + $providers = ['OpenSSL' => defined('OPENSSL_KEYTYPE_X448')]; + break; + default: + // openssl_get_curve_names() was introduced in PHP 7.1.0 + // exclude curve25519 and curve448 from testing + $providers = ['OpenSSL' => function_exists('openssl_get_curve_names') && substr($curveEngineName, 0, 5) != 'curve' && in_array($curveEngineName, openssl_get_curve_names())]; + }; + + foreach ($providers as $engine => $isSupported) { + // if an engine is being forced and the forced engine doesn't match $engine, skip it + if (isset(self::$forcedEngine) && self::$forcedEngine !== $engine) { + continue; + } + if ($isSupported) { + $result = self::generateWithEngine($engine, $curveEngineName); + if (isset($result)) { + return $result; + } + } + if (self::$forcedEngine === $engine) { + throw new BadConfigurationException("EC::createKey: Engine $engine is forced but unsupported for $curve"); + } + } + + $privatekey = new PrivateKey(); $curve = new $curve(); if ($curve instanceof TwistedEdwardsCurve) { @@ -189,21 +217,14 @@ public static function createKey($curve) } else { $privatekey->dA = $dA = $curve->createRandomMultiplier(); } - if ($curve instanceof Curve25519 && self::$engines['libsodium']) { - //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000'); - //$QA = sodium_crypto_scalarmult($dA->toBytes(), $r); - $QA = sodium_crypto_box_publickey_from_secretkey($dA->toBytes()); - $privatekey->QA = [$curve->convertInteger(new BigInteger(strrev($QA), 256))]; - } else { - $privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA); - } $privatekey->curve = $curve; + $privatekey->curveName = $curveName; + $privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA); //$publickey = clone $privatekey; //unset($publickey->dA); //unset($publickey->x); - $privatekey->curveName = $curveName; //$publickey->curveName = $curveName; if ($privatekey->curve instanceof TwistedEdwardsCurve) { @@ -213,6 +234,130 @@ public static function createKey($curve) return $privatekey; } + /** + * Returns the actual case of the curve + * + * Useful for initializing the curve class + * + * @param string $curveName + * @return string + */ + private static function getCurveCase($curveName) + { + $curveName = strtolower($curveName); + if (preg_match('#(?:^curve|^ed)\d+$#', $curveName)) { + return ucfirst($curveName); + } + if (substr($curveName, 0, 10) == 'brainpoolp') { + return 'brainpoolP' . substr($curveName, 10); + } + return $curveName; + } + + /** + * Return the OpenSSL name for a curve + * + * @param string $curve + * @return string + */ + private static function getOpenSSLCurveName($curve) + { + switch ($curve) { + case 'secp256r1': + return 'prime256v1'; + case 'secp192r1': + return 'prime192v1'; + } + return $curve; + } + + /** + * Generate the key for a given curve / engine combo + * + * @param string $engine + * @param string $curve + * @return ?PrivateKey + */ + private static function generateWithEngine($engine, $curve) + { + if ($engine == 'libsodium') { + if ($curve == 'ed25519') { + $kp = sodium_crypto_sign_keypair(); + + $privatekey = EC::loadFormat('libsodium', sodium_crypto_sign_secretkey($kp)); + //$publickey = EC::loadFormat('libsodium', sodium_crypto_sign_publickey($kp)); + + $privatekey->curveName = 'Ed25519'; + //$publickey->curveName = $curve; + + return $privatekey; + } else { // $curve == 'curve25519 + $privatekey = new PrivateKey(); + $privatekey->curve = new Curve25519(); + $privatekey->curveName = 'Curve25519'; + $privatekey->dA = $privatekey->curve->createRandomMultiplier(); + $dA = str_pad($privatekey->dA->toBytes(), 32, "\0", STR_PAD_LEFT); + //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000'); + //$QA = sodium_crypto_scalarmult($dA, $r); + $QA = sodium_crypto_box_publickey_from_secretkey($dA); + $privatekey->QA = [$privatekey->curve->convertInteger(new BigInteger(strrev($QA), 256))]; + return $privatekey; + } + } + + // at this point $engine == 'OpenSSL' + + $curveName = self::getCurveCase($curve); + + $config = []; + if (self::$configFile) { + $config['config'] = self::$configFile; + } + $params = $config; + switch ($curve) { + case 'ed25519': + $params['private_key_type'] = OPENSSL_KEYTYPE_ED25519; + break; + case 'ed448': + $params['private_key_type'] = OPENSSL_KEYTYPE_ED448; + break; + case 'curve25519': + $params['private_key_type'] = OPENSSL_KEYTYPE_X25519; + break; + case 'curve448': + $params['private_key_type'] = OPENSSL_KEYTYPE_X448; + break; + default: + $params['private_key_type'] = OPENSSL_KEYTYPE_EC; + $params['curve_name'] = $curveName; + } + + $key = openssl_pkey_new($params); + if (!$key) { + return null; + } + $privateKeyStr = ''; + if (!openssl_pkey_export($key, $privateKeyStr, null, $config)) { + return null; + } + // clear the buffer of error strings + while (openssl_error_string() !== false) { + } + // some versions of OpenSSL / PHP return PKCS1 keys, others return PKCS8 keys + $privatekey = EC::load($privateKeyStr); + switch ($curveName) { + case 'prime256v1': + $privatekey->curveName = 'secp256r1'; + break; + case 'prime192v1': + $privatekey->curveName = 'secp192r1'; + break; + default: + $privatekey->curveName = $curveName; + } + return $privatekey; + } + /** * OnLoad Handler * @@ -220,10 +365,6 @@ public static function createKey($curve) */ protected static function onLoad(array $components) { - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - if (!isset($components['dA']) && !isset($components['QA'])) { $new = new Parameters(); $new->curve = $components['curve']; @@ -321,42 +462,63 @@ public function getLength() } /** - * Returns the current engine being used + * Returns the public key coordinates as a string + * + * Used by ECDH * - * @see self::useInternalEngine() - * @see self::useBestEngine() * @return string */ - public function getEngine() + public function getEncodedCoordinates() { - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); + if ($this->curve instanceof MontgomeryCurve) { + return strrev($this->QA[0]->toBytes(true)); } if ($this->curve instanceof TwistedEdwardsCurve) { - return $this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context) ? - 'libsodium' : 'PHP'; + return $this->curve->encodePoint($this->QA); } - - return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ? - 'OpenSSL' : 'PHP'; + return "\4" . $this->QA[0]->toBytes(true) . $this->QA[1]->toBytes(true); } /** - * Returns the public key coordinates as a string + * Convert point to public key * - * Used by ECDH + * For Weierstrass curves, if only the x coordinate is present (as is the case after doing a round of ECDH) + * then we'll guess at the y coordinate. There are only two possible y values and, atleast in-so-far as + * multiplication is concerned, neither value affects the resultant x value * - * @return string + * If $toPublicKey is set to false then a string will be returned - a kind of public key precursor + * + * @param string $curveName + * @param string $secret + * @param bool $toPublicKey optional + * @return PublicKey|string */ - public function getEncodedCoordinates() + public static function convertPointToPublicKey($curveName, $secret, $toPublicKey = true) { - if ($this->curve instanceof MontgomeryCurve) { - return strrev($this->QA[0]->toBytes(true)); + $curveName = self::getCurveCase($curveName); + $curve = '\phpseclib3\Crypt\EC\Curves\\' . $curveName; + + if (!class_exists($curve)) { + throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported'); } - if ($this->curve instanceof TwistedEdwardsCurve) { - return $this->curve->encodePoint($this->QA); + + $curve = new $curve(); + if (!$curve instanceof TwistedEdwardsCurve) { + if ($curve instanceof MontgomeryCurve) { + $secret = strrev($secret); + } elseif ($curve->getLengthInBytes() == strlen($secret)) { + $secret = "\3$secret"; + } + if (!$toPublicKey) { + return $secret; + } + $secret = "\0$secret"; + } elseif (!$toPublicKey) { + return $secret; } - return "\4" . $this->QA[0]->toBytes(true) . $this->QA[1]->toBytes(true); + $QA = PKCS8::extractPoint($secret, $curve); + $key = PKCS8::savePublicKey($curve, $QA); + return EC::loadFormat('PKCS8', $key); } /** @@ -463,18 +625,4 @@ public function withHash($hash) return parent::withHash($hash); } - - /** - * __toString() magic method - * - * @return string - */ - public function __toString() - { - if ($this->curve instanceof MontgomeryCurve) { - return ''; - } - - return parent::__toString(); - } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.php index 0f3f4d8..0aa81c8 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve25519.php @@ -18,6 +18,8 @@ class Curve25519 extends Montgomery { + const SIZE = 32; + public function __construct() { // 2^255 - 19 @@ -47,10 +49,12 @@ public function __construct() */ public function multiplyPoint(array $p, BigInteger $d) { - //$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes()))); + $d = $d->toBytes(); + $d = str_pad($d, 32, "\0", STR_PAD_LEFT); + + //$r = strrev(sodium_crypto_scalarmult($d, strrev($p[0]->toBytes()))); //return [$this->factory->newInteger(new BigInteger($r, 256))]; - $d = $d->toBytes(); $d &= "\xF8" . str_repeat("\xFF", 30) . "\x7F"; $d = strrev($d); $d |= "\x40"; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php index f4a4423..3a042e5 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Curves/Curve448.php @@ -18,6 +18,8 @@ class Curve448 extends Montgomery { + const SIZE = 56; + public function __construct() { // 2^448 - 2^224 - 1 @@ -58,10 +60,12 @@ public function __construct() */ public function multiplyPoint(array $p, BigInteger $d) { - //$r = strrev(sodium_crypto_scalarmult($d->toBytes(), strrev($p[0]->toBytes()))); + $d = $d->toBytes(); + $d = str_pad($d, 56, "\0", STR_PAD_LEFT); + + //$r = strrev(sodium_crypto_scalarmult($d, strrev($p[0]->toBytes()))); //return [$this->factory->newInteger(new BigInteger($r, 256))]; - $d = $d->toBytes(); $d[0] = $d[0] & "\xFC"; $d = strrev($d); $d |= "\x80"; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php index 743c07c..bf62d63 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/Common.php @@ -16,6 +16,7 @@ use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; use phpseclib3\Crypt\EC\BaseCurves\Binary as BinaryCurve; +use phpseclib3\Crypt\EC\BaseCurves\Montgomery; use phpseclib3\Crypt\EC\BaseCurves\Prime as PrimeCurve; use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; use phpseclib3\Exception\UnsupportedCurveException; @@ -274,6 +275,9 @@ protected static function loadCurveByParam(array $params) */ public static function extractPoint($str, BaseCurve $curve) { + if ($curve instanceof Montgomery) { + return [new BigInteger($str, 256)]; + } if ($curve instanceof TwistedEdwardsCurve) { // first step of point deciding as discussed at the following URL's: // https://tools.ietf.org/html/rfc8032#section-5.1.3 diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php index aa64f79..533259d 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/MontgomeryPrivate.php @@ -96,6 +96,6 @@ public static function savePrivateKey(BigInteger $privateKey, MontgomeryCurve $c throw new UnsupportedFormatException('MontgomeryPrivate private keys do not support encryption'); } - return $privateKey->toBytes(); + return str_pad($privateKey->toBytes(), $curve::SIZE, "\0", STR_PAD_RIGHT); } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.php index 0ef1160..5310d5a 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/OpenSSH.php @@ -111,6 +111,9 @@ private static function getAlias(BaseCurve $curve) $reflect = new \ReflectionClass($curve); $name = $reflect->getShortName(); + if (!isset(self::$curveOIDs[$name])) { + throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports'); + } $oid = self::$curveOIDs[$name]; $aliases = array_filter(self::$curveOIDs, function ($v) use ($oid) { return $v == $oid; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php index 9fc8405..c25d5a6 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php @@ -23,10 +23,13 @@ namespace phpseclib3\Crypt\EC\Formats\Keys; +use phpseclib3\Math\Common\FiniteField\Integer; use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve; use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve; +use phpseclib3\Crypt\EC\Curves\Curve25519; +use phpseclib3\Crypt\EC\Curves\Curve448; use phpseclib3\Crypt\EC\Curves\Ed25519; use phpseclib3\Crypt\EC\Curves\Ed448; use phpseclib3\Exception\UnsupportedCurveException; @@ -48,14 +51,14 @@ abstract class PKCS8 extends Progenitor * * @var array */ - const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448']; + const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448', 'id-X25519', 'id-X448']; /** * OID Value * * @var string */ - const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113']; + const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113', '1.3.101.110', '1.3.101.111']; /** * Break a public or private key down into its constituent components @@ -81,6 +84,9 @@ public static function load($key, $password = '') case 'id-Ed25519': case 'id-Ed448': return self::loadEdDSA($key); + case 'id-X25519': + case 'id-X448': + return self::loadECDH($key); } $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); @@ -158,20 +164,64 @@ private static function loadEdDSA(array $key) return $components; } + private static function loadECDH(array $key) + { + $components = []; + + if (isset($key['privateKey'])) { + $components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-X25519' ? new Curve25519() : new Curve448(); + $expected = chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($components['curve']::SIZE); + $privateKey = (string) $key['privateKey']; + if (substr($privateKey, 0, 2) != $expected) { + throw new \RuntimeException( + 'The first two bytes of the ' . + $key['privateKeyAlgorithm']['algorithm'] . + ' private key field should be 0x' . bin2hex($expected) + ); + } + $components['dA'] = new BigInteger(substr($privateKey, 2), 256); + } + + if (isset($key['publicKey'])) { + if (!isset($components['curve'])) { + $components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-X25519' ? new Curve25519() : new Curve448(); + } + + $components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($key['publicKey']), 256))]; + } + + if (isset($key['privateKey']) && !isset($components['QA'])) { + if ($components['curve'] instanceof Curve25519 && function_exists('sodium_crypto_box_publickey_from_secretkey')) { + //$r = pack('H*', '0900000000000000000000000000000000000000000000000000000000000000'); + //$QA = sodium_crypto_scalarmult($components['dA']->toBytes(), $r); + $QA = sodium_crypto_box_publickey_from_secretkey(str_pad($components['dA']->toBytes(), 32, chr(0), STR_PAD_LEFT)); + $components['QA'] = [$components['curve']->convertInteger(new BigInteger(strrev($QA), 256))]; + } else { + $components['QA'] = [$components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA'])[0]]; + } + } + + return $components; + } + /** * Convert an EC public key to the appropriate format * * @param BaseCurve $curve - * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey + * @param Integer[] $publicKey * @param array $options optional * @return string */ public static function savePublicKey(BaseCurve $curve, array $publicKey, array $options = []) { self::initialize_static_variables(); - if ($curve instanceof MontgomeryCurve) { - throw new UnsupportedCurveException('Montgomery Curves are not supported'); + return self::wrapPublicKey( + str_pad(strrev($publicKey[0]->toBytes()), $curve::SIZE, "\0", STR_PAD_RIGHT), + null, + $curve instanceof Curve25519 ? 'id-X25519' : 'id-X448', + $options + ); } if ($curve instanceof TwistedEdwardsCurve) { @@ -206,7 +256,13 @@ public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, self::initialize_static_variables(); if ($curve instanceof MontgomeryCurve) { - throw new UnsupportedCurveException('Montgomery Curves are not supported'); + return self::wrapPrivateKey( + chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength($curve::SIZE) . str_pad($privateKey->toBytes(), $curve::SIZE, "\0", STR_PAD_LEFT), + [], + null, + $password, + $curve instanceof Curve25519 ? 'id-X25519' : 'id-X448' + ); } if ($curve instanceof TwistedEdwardsCurve) { diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php index 9947bb7..383e8e0 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PrivateKey.php @@ -21,6 +21,7 @@ use phpseclib3\Crypt\EC\Formats\Keys\PKCS1; use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature; use phpseclib3\Crypt\Hash; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\UnsupportedOperationException; use phpseclib3\Math\BigInteger; @@ -59,18 +60,34 @@ final class PrivateKey extends EC implements Common\PrivateKey */ public function multiply($coordinates) { - if ($this->curve instanceof MontgomeryCurve) { - if ($this->curve instanceof Curve25519 && self::$engines['libsodium']) { - return sodium_crypto_scalarmult($this->dA->toBytes(), $coordinates); + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is not supported for the multiplication operation'); + } + + if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Curve25519) { + throw new BadConfigurationException('Engine libsodium is only supported for Curve25519'); + } + + if ($this->curve instanceof Curve25519 && self::$forcedEngine !== 'PHP') { + if (self::$forcedEngine === 'libsodium' && !function_exists('sodium_crypto_scalarmult')) { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for Curve25519'); + } + if (function_exists('sodium_crypto_scalarmult')) { + $dA = str_pad($this->dA->toBytes(), 32, "\0", STR_PAD_LEFT); + return sodium_crypto_scalarmult($dA, $coordinates); } + } + if ($this->curve instanceof MontgomeryCurve) { $point = [$this->curve->convertInteger(new BigInteger(strrev($coordinates), 256))]; $point = $this->curve->multiplyPoint($point, $this->dA); return strrev($point[0]->toBytes(true)); } + if (!$this->curve instanceof TwistedEdwardsCurve) { $coordinates = "\0$coordinates"; } + $point = PKCS1::extractPoint($coordinates, $this->curve); $point = $this->curve->multiplyPoint($point, $this->dA); if ($this->curve instanceof TwistedEdwardsCurve) { @@ -104,11 +121,56 @@ public function sign($message) return false; } - if ($this->curve instanceof TwistedEdwardsCurve) { - if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) { + if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Ed25519) { + throw new BadConfigurationException('Engine libsodium is only supported for Ed25519'); + } + + // at this point either self::$forcedEngine is NOT libsodium or the curve is Ed25519 + + if ($this->curve instanceof Ed25519 && self::$forcedEngine !== 'PHP' && self::$forcedEngine !== 'OpenSSL') { + if (self::$forcedEngine === 'libsodium') { + if (!function_exists('sodium_crypto_sign_detached')) { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519 / Ed448'); + } + if (isset($this->context)) { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519ctx (context)'); + } + } + if (function_exists('sodium_crypto_sign_detached') && !isset($this->context)) { $result = sodium_crypto_sign_detached($message, $this->withPassword()->toString('libsodium')); return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result) : $result; } + } + + // at this point self::$forcedEngine CAN'T be libsodium so we won't check for it henceforth + + if ($this->curve instanceof TwistedEdwardsCurve) { + if (self::$forcedEngine !== 'PHP') { + $keyTypeConstant = $this->curve instanceof Ed25519 ? 'OPENSSL_KEYTYPE_ED25519' : 'OPENSSL_KEYTYPE_ED448'; + if (self::$forcedEngine === 'OpenSSL') { + if (!defined($keyTypeConstant)) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448'); + } + // OpenSSL supports Ed25519/Ed448 but not Ed25519ctx (context), so skip if context is set + if (isset($this->context)) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448 curves with context\'s'); + } + } + if (defined($keyTypeConstant) && !isset($this->context)) { + $result = ''; + // algorithm 0 is used because EdDSA has a built-in hash + openssl_sign($message, $result, $this->withPassword()->toString('PKCS8'), 0); + if ($result) { + $signature = $shortFormat == 'SSH2' + ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result) + : $result; + return $signature; + } + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string()); + } + } + } // contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not. // quoting https://tools.ietf.org/html/rfc8032#section-8.5 , @@ -143,26 +205,37 @@ public function sign($message) return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $R . $S) : $R . $S; } - if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { - $signature = ''; - // altho PHP's OpenSSL bindings only supported EC key creation in PHP 7.1 they've long - // supported signing / verification - // we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve; - // doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even - // has curve-specific optimizations - $result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); - - if ($result) { - if ($shortFormat == 'ASN1') { - return $signature; - } - - $loaded = ASN1Signature::load($signature); - $r = $loaded['r']; - $s = $loaded['s']; - + if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA'); + } - return $this->formatSignature($r, $s); + // at this point $forcedEngine is either PHP or null. either that OR openssl_get_md_methods() exists + + if (self::$forcedEngine !== 'PHP') { + if (in_array($this->hash->getHash(), openssl_get_md_methods())) { + $signature = ''; + // altho PHP's OpenSSL bindings only supported EC key creation in PHP 7.1 they've long + // supported signing / verification + // we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve; + // doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even + // has curve-specific optimizations + $result = openssl_sign($message, $signature, $this->withPassword()->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); + + if ($result) { + if ($shortFormat == 'ASN1') { + return $signature; + } + + $loaded = ASN1Signature::load($signature); + $r = $loaded['r']; + $s = $loaded['s']; + + return $this->formatSignature($r, $s); + } elseif (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string()); + } + } elseif (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA / ' . $this->hash->getHash()); } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php index d34c6c4..2201497 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/PublicKey.php @@ -20,6 +20,7 @@ use phpseclib3\Crypt\EC\Formats\Keys\PKCS1; use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature; use phpseclib3\Crypt\Hash; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\UnsupportedOperationException; use phpseclib3\Math\BigInteger; @@ -52,17 +53,62 @@ public function verify($message, $signature) return false; } - $order = $this->curve->getOrder(); + if (self::$forcedEngine === 'libsodium' && !$this->curve instanceof Ed25519) { + throw new BadConfigurationException('Engine libsodium is only supported for Ed25519'); + } + + // at this point either self::$forcedEngine is NOT libsodium or the curve is Ed25519 + + if ($this->curve instanceof Ed25519 && self::$forcedEngine !== 'PHP' && self::$forcedEngine !== 'OpenSSL') { + if (self::$forcedEngine === 'libsodium') { + if (!function_exists('sodium_crypto_sign_verify_detached')) { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519 / Ed448'); + } + if (isset($this->context)) { + throw new BadConfigurationException('Engine libsodium is forced but unsupported for Ed25519ctx (context)'); + } + } + if (function_exists('sodium_crypto_sign_verify_detached') && !isset($this->context)) { + if ($shortFormat == 'SSH2') { + list(, $signature) = Strings::unpackSSH2('ss', $signature); + } + + return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium')); + } + } + + // at this point self::$forcedEngine CAN'T be libsodium so we won't check for it henceforth if ($this->curve instanceof TwistedEdwardsCurve) { if ($shortFormat == 'SSH2') { list(, $signature) = Strings::unpackSSH2('ss', $signature); } - if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) { - return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium')); + if (self::$forcedEngine !== 'PHP') { + $keyTypeConstant = $this->curve instanceof Ed25519 ? 'OPENSSL_KEYTYPE_ED25519' : 'OPENSSL_KEYTYPE_ED448'; + if (self::$forcedEngine === 'OpenSSL') { + if (!defined($keyTypeConstant)) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448'); + } + // OpenSSL supports Ed25519/Ed448 but not Ed25519ctx (context), so skip if context is set + if (isset($this->context)) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for Ed25519 / Ed448 curves with context\'s'); + } + } + if (defined($keyTypeConstant) && !isset($this->context)) { + // algorithm 0 is used because EdDSA has a built-in hash + $result = openssl_verify($message, $signature, $this->toString('PKCS8'), 0) === 1; + if ($result !== -1 && $result !== false) { + return (bool) $result; + } + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string()); + } + } } + $order = $this->curve->getOrder(); + $curve = $this->curve; if (strlen($signature) != 2 * $curve::SIZE) { return false; @@ -118,16 +164,31 @@ public function verify($message, $signature) $r = $params['r']; $s = $params['s']; - if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) { - $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; + if (self::$forcedEngine === 'OpenSSL' && !function_exists('openssl_get_md_methods')) { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA'); + } + + // at this point $forcedEngine is either PHP or null. either that OR openssl_get_md_methods() exists + + if (self::$forcedEngine !== 'PHP') { + if (in_array($this->hash->getHash(), openssl_get_md_methods())) { + $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature; - $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); + $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash()); - if ($result != -1) { - return (bool) $result; + if ($result !== -1 && $result !== false) { + return (bool) $result; + } + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to verify signature because of ' . openssl_error_string()); + } + } elseif (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but unsupported for ECDSA / ' . $this->hash->getHash()); } } + $order = $this->curve->getOrder(); + $n_1 = $order->subtract(self::$one); if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) { return false; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php index cc5b42c..f1105ca 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Hash.php @@ -295,7 +295,7 @@ public function getHash() public function setHash($hash) { $oldHash = $this->hashParam; - $this->hashParam = $hash = strtolower($hash); + $this->hashParam = $hash = strtolower(str_replace('/', '-', $hash)); switch ($hash) { case 'umac-32': case 'umac-64': @@ -323,8 +323,8 @@ public function setHash($hash) case 'sha256-96': case 'sha384-96': case 'sha512-96': - case 'sha512/224-96': - case 'sha512/256-96': + case 'sha512-224-96': + case 'sha512-256-96': $hash = substr($hash, 0, -3); $this->length = 12; // 96 / 8 = 12 break; @@ -336,7 +336,7 @@ public function setHash($hash) $this->length = 20; break; case 'sha224': - case 'sha512/224': + case 'sha512-224': case 'sha3-224': $this->length = 28; break; @@ -344,7 +344,7 @@ public function setHash($hash) $this->paddingType = self::PADDING_KECCAK; // fall-through case 'sha256': - case 'sha512/256': + case 'sha512-256': case 'sha3-256': $this->length = 32; break; @@ -424,12 +424,12 @@ public function setHash($hash) } } - if ($hash == 'sha512/224' || $hash == 'sha512/256') { + if ($hash == 'sha512-224' || $hash == 'sha512-256') { // PHP 7.1.0 introduced sha512/224 and sha512/256 support: // http://php.net/ChangeLog-7.php#7.1.0 if (version_compare(PHP_VERSION, '7.1.0') < 0) { // from http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf#page=24 - $initial = $hash == 'sha512/256' ? + $initial = $hash == 'sha512-256' ? [ '22312194FC2BF72C', '9F555FA3C84C64C2', '2393B86B6F53B151', '963877195940EABD', '96283EE2A88EFFE3', 'BE5E1E2553863992', '2B0199FC2C85B8AA', '0EB72DDC81C52CA2' @@ -459,6 +459,15 @@ public function setHash($hash) $this->opad = str_repeat(chr(0x5C), $b); } + // PHP's built in hash function does sha3-256 but sha512/256 so we'll update those accordingly + switch ($hash) { + case 'sha512-224': + $hash = 'sha512/224'; + break; + case 'sha512-256': + $hash = 'sha512/256'; + } + $this->algo = $hash; $this->computeKey(); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php index 0a11957..2961501 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA.php @@ -57,6 +57,7 @@ use phpseclib3\Crypt\RSA\Formats\Keys\PSS; use phpseclib3\Crypt\RSA\PrivateKey; use phpseclib3\Crypt\RSA\PublicKey; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\InconsistentSetupException; use phpseclib3\Exception\UnsupportedAlgorithmException; use phpseclib3\Math\BigInteger; @@ -227,14 +228,6 @@ abstract class RSA extends AsymmetricKey */ protected static $enableBlinding = true; - /** - * OpenSSL configuration file name. - * - * @see self::createKey() - * @var ?string - */ - protected static $configFile; - /** * Smallest Prime * @@ -256,6 +249,14 @@ abstract class RSA extends AsymmetricKey */ protected $publicExponent; + /** + * Forced Engine + * + * @var ?string + * @see parent::forceEngine() + */ + protected static $forcedEngine = null; + /** * Sets the public exponent for key generation * @@ -280,18 +281,6 @@ public static function setSmallestPrime($val) self::$smallestPrime = $val; } - /** - * Sets the OpenSSL config file path - * - * Set to the empty string to use the default config file - * - * @param string $val - */ - public static function setOpenSSLConfigPath($val) - { - self::$configFile = $val; - } - /** * Create a private key * @@ -309,6 +298,10 @@ public static function createKey($bits = 2048) throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); } + if (self::$forcedEngine == 'libsodium' || (self::$forcedEngine == 'OpenSSL' && !function_exists('openssl_pkey_new'))) { + throw new BadConfigurationException('Engine ' . self::$forcedEngine . ' is forced but unsupported for RSA'); + } + $regSize = $bits >> 1; // divide by two to see how many bits P and Q would be if ($regSize > self::$smallestPrime) { $num_primes = floor($bits / self::$smallestPrime); @@ -318,25 +311,27 @@ public static function createKey($bits = 2048) } if ($num_primes == 2 && $bits >= 384 && self::$defaultExponent == 65537) { - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - - // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum - if (self::$engines['OpenSSL']) { + // at this point the only two supported values for self::$forcedEngine are OpenSSL, PHP and null + // if it's either OpenSSL or null we'll use OpenSSL (if it's available) + if (self::$forcedEngine !== 'PHP' && function_exists('openssl_pkey_new')) { $config = []; if (self::$configFile) { $config['config'] = self::$configFile; } + // OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum $rsa = openssl_pkey_new(['private_key_bits' => $bits] + $config); - openssl_pkey_export($rsa, $privatekeystr, null, $config); + if (!$rsa || !openssl_pkey_export($rsa, $privatekeystr, null, $config)) { + if (isset(self::$forcedEngine)) { + throw new BadConfigurationException('Engine OpenSSL is forced but produced an error - ' . openssl_error_string()); + } + } else { + // clear the buffer of error strings stemming from a minimalistic openssl.cnf + // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up + while (openssl_error_string() !== false) { + } - // clear the buffer of error strings stemming from a minimalistic openssl.cnf - // https://github.com/php/php-src/issues/11054 talks about other errors this'll pick up - while (openssl_error_string() !== false) { + return RSA::load($privatekeystr); } - - return RSA::load($privatekeystr); } } @@ -478,18 +473,6 @@ protected static function onLoad(array $components) return $key; } - /** - * Initialize static variables - */ - protected static function initialize_static_variables() - { - if (!isset(self::$configFile)) { - self::$configFile = dirname(__FILE__) . '/../openssl.cnf'; - } - - parent::initialize_static_variables(); - } - /** * Constructor * @@ -581,6 +564,22 @@ protected function emsa_pkcs1_v1_5_encode($m, $emLen) break; case 'sha512/256': $t = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x05\x00\x04\x20"; + break; + // the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them: + // https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements + // the OIDs are from this URL: + // https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash + case 'sha3/224': + $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x05\x00\x04\x1c"; + break; + case 'sha3/256': + $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x05\x00\x04\x20"; + break; + case 'sha3/384': + $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x05\x00\x04\x30"; + break; + case 'sha3/512': + $t = "\x30\x2d\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x05\x00\x04\x40"; } $t .= $h; $tLen = strlen($t); @@ -638,6 +637,22 @@ protected function emsa_pkcs1_v1_5_encode_without_null($m, $emLen) case 'sha512/256': $t = "\x30\x2f\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x06\x04\x20"; break; + // the following 3x algorithms are not specified in PKCS1 v2.2, however, some standards none-the-less do use them: + // https://sk-eid.github.io/smart-id-documentation/rp-api/changes.html#_security_enhancements + // the OIDs are from this URL: + // https://csrc.nist.gov/projects/computer-security-objects-register/algorithm-registration#Hash + case 'sha3/224': + $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x07\x04\x1c"; + break; + case 'sha3/256': + $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x08\x04\x20"; + break; + case 'sha3/384': + $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x09\x04\x30"; + break; + case 'sha3/512': + $t = "\x30\x2b\x30\x0b\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x0A\x04\x40"; + break; default: throw new UnsupportedAlgorithmException('md2 and md5 require NULLs'); } @@ -713,11 +728,15 @@ public function withHash($hash) case 'sha224': case 'sha512/224': case 'sha512/256': + case 'sha3/224': + case 'sha3/256': + case 'sha3/384': + case 'sha3/512': $new->hash = new Hash($hash); break; default: throw new UnsupportedAlgorithmException( - 'The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256' + "The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided" ); } $new->hLen = $new->hash->getLengthInBytes(); @@ -748,11 +767,15 @@ public function withMGFHash($hash) case 'sha224': case 'sha512/224': case 'sha512/256': + case 'sha3/224': + case 'sha3/256': + case 'sha3/384': + case 'sha3/512': $new->mgfHash = new Hash($hash); break; default: throw new UnsupportedAlgorithmException( - 'The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256' + "The only supported hash algorithms are: md2, md5, sha1, sha256, sha384, sha512, sha224, sha512/224, sha512/256 - $hash provided" ); } $new->mgfHLen = $new->mgfHash->getLengthInBytes(); @@ -891,28 +914,6 @@ public function getPadding() return $this->signaturePadding | $this->encryptionPadding; } - /** - * Returns the current engine being used - * - * OpenSSL is only used in this class (and it's subclasses) for key generation - * Even then it depends on the parameters you're using. It's not used for - * multi-prime RSA nor is it used if the key length is outside of the range - * supported by OpenSSL - * - * @see self::useInternalEngine() - * @see self::useBestEngine() - * @return string - */ - public function getEngine() - { - if (!isset(self::$engines['PHP'])) { - self::useBestEngine(); - } - return self::$engines['OpenSSL'] && self::$defaultExponent == 65537 ? - 'OpenSSL' : - 'PHP'; - } - /** * Enable RSA Blinding * @@ -930,4 +931,180 @@ public static function disableBlinding() { static::$enableBlinding = false; } + + /** + * Handles OpenSSL encryption / decryption / signature creation / verification + * + * @param string $func + * @param string $message + * @param ?string $signature + * @return bool|string|null + */ + protected function handleOpenSSL($func, $message, $signature = null) + { + switch ($func) { + case 'openssl_verify': + case 'openssl_sign': + $paddingType = 'signaturePadding'; + break; + case 'openssl_public_encrypt': + case 'openssl_private_decrypt': + $paddingType = 'encryptionPadding'; + } + + if (self::$forcedEngine === 'libsodium') { + throw new BadConfigurationException('Engine libsodium is not supported for RSA'); + } + + if ((isset(self::$forcedEngine) && self::$forcedEngine !== 'PHP') && $this->$paddingType === self::SIGNATURE_RELAXED_PKCS1) { + throw new BadConfigurationException('Only the PHP engine can be used with relaxed PKCS1 padding'); + } + + if (self::$forcedEngine !== 'PHP') { + if (self::$forcedEngine === 'OpenSSL' && !function_exists($func)) { + throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA'); + } + if ($this->$paddingType === self::SIGNATURE_PSS) { + switch (true) { + case !defined('OPENSSL_PKCS1_PSS_PADDING'): + $error = 'Engine OpenSSL is forced but PSS encryption requires PHP >= 8.5.0'; + break; + case $this->hash->getHash() !== $this->mgfHash->getHash(): + $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match'; + break; + case $this->getSaltLength() !== $this->hLen: + $error = 'Engine OpenSSL is forced but can\'t be used because the salt length doesn\'t match the hash length'; + } + } + if ($this->$paddingType === self::ENCRYPTION_OAEP) { + switch (true) { + case $this->hash->getHash() !== $this->mgfHash->getHash(): + $error = 'Engine OpenSSL is forced but can\'t be used because the Hash and MGF Hash do not match'; + break; + case $this->hash->getHash() !== 'sha1' && PHP_VERSION_ID < 80500: + $error = 'Engine OpenSSL is forced but non-sha1 hashes are only supported on PHP 8.5.0+'; + break; + case strlen($this->label): + $error = 'Engine OpenSSL is forced but can\'t be used because the label is not the empty string'; + } + } + if (isset($error)) { + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException($error); + } + } elseif ($paddingType === 'signaturePadding') { + switch (true) { + case $this->signaturePadding === self::SIGNATURE_PSS && defined('OPENSSL_PKCS1_PSS_PADDING'): + case $this->signaturePadding !== self::SIGNATURE_PSS && function_exists($func): + $key = $this instanceof PrivateKey ? + $this->withPassword()->toString('PKCS8') : + $this->toString('PKCS8'); + if ($func === 'openssl_sign' && strpos($key, 'PUBLIC') !== false) { + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because the private key does not have the prime components within it'); + } + break; + } + $hash = $this->hash->getHash(); + + // on github actions, php 7.0 and 7.1 on windows emit the following warning: + // openssl_sign(): supplied key param cannot be coerced into a private key + set_error_handler(function ($errno, $errstr) { + throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr"); + }); + try { + $result = $this->signaturePadding === self::SIGNATURE_PSS ? + $func($message, $signature, $key, $hash, OPENSSL_PKCS1_PSS_PADDING) : + $func($message, $signature, $key, $hash); + } catch (BadConfigurationException $e) { + if (self::$forcedEngine === 'OpenSSL') { + throw $e; + } + $result = false; + } finally { + restore_error_handler(); + } + + if ($func === 'openssl_verify' && $result !== -1 && $result !== false) { + return (bool) $result; + } + if ($result) { + return $signature; + } + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but was unable to create signature because of ' . openssl_error_string()); + } + } + } else { + if ($this->encryptionPadding !== self::ENCRYPTION_OAEP || PHP_VERSION_ID >= 80500) { + $key = $this instanceof PrivateKey ? + $this->withPassword()->toString('PKCS8') : + $this->toString('PKCS8'); + if ($func === 'openssl_private_decrypt' && strpos($key, 'PUBLIC') !== false) { + if ($this->encryptionPadding === self::ENCRYPTION_OAEP) { + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used because openssl_public_decrypt() doesn\'t have a hash parameter like openssl_private_decrypt() does'); + } + return null; + } + $func = 'openssl_public_decrypt'; + } + if ($this->encryptionPadding === self::ENCRYPTION_PKCS1 && OPENSSL_VERSION_NUMBER >= 0x30200000) { + // quoting https://docs.openssl.org/3.4/man3/RSA_public_encrypt/#return-values : + // + // "Since version 3.2.0, the default provider in OpenSSL does not return an error when padding checks fail. + // Instead it generates a random message" + // + // the idea is that even a perfect implementation of PKCS1 padding can be used to conduct a Bleichenbacher + // padding oracle attack. + // + // so like if $rsa->decrypt() doesn't throw an exception it's liable to run additional code that'll take + // longer to run than it'd take if an exception would be thrown and in theory, with PKCS1, in particular, + // you can use that fact to guess at successive bits of the private key until you've figured it out. it's + // why you should use OAEP padding vs PKCS1 padding BUT if you need PKCS1 padding for interoperability then + // you're stuck with it. + // + // with the OpenSSL 3.2.0+ behavior they're making it harder to do the attack by making it harder to use PKCS1 + // in the real world. this isn't a design philosophy i agree with. like phpseclib lets you DES encryption. you + // shouldn't use DES encryption but if you need to you need to and phpseclib isn't here to judge. that's a big + // difference between phpseclib and stuff like libsodium. + if (self::$forcedEngine === 'OpenSSL') { + throw new BadConfigurationException('Engine OpenSSL is forced but cannot be used to decrypt PKCS1 encrypted strings with OpenSSL 3.2.0+'); + } + return null; + } + $hash = $this->hash->getHash(); + $output = ''; + switch ($this->encryptionPadding) { + case self::ENCRYPTION_NONE: + case self::ENCRYPTION_PKCS1: + $padding = $this->encryptionPadding === self::ENCRYPTION_NONE ? OPENSSL_NO_PADDING : OPENSSL_PKCS1_PADDING; + // on github actions, php 7.0 and 7.1 on windows emit the following warning: + // openssl_private_decrypt(): key parameter is not a valid private key + set_error_handler(function ($errno, $errstr) { + throw new BadConfigurationException("Engine OpenSSL is forced but got error: $errstr"); + }); + try { + $result = $func($message, $output, $key, $padding); + } catch (BadConfigurationException $e) { + if (self::$forcedEngine === 'OpenSSL') { + throw $e; + } + $result = false; + } finally { + restore_error_handler(); + } + break; + //case self::ENCRYPTION_OAEP: + default: + $result = $func($message, $output, $key, OPENSSL_PKCS1_OAEP_PADDING, $hash); + } + if ($result) { + return $output; + } + } + } + return null; + } + } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php index bf51bcf..ee9b992 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/Formats/Keys/PSS.php @@ -141,7 +141,7 @@ public static function load($key, $password = '') $result['hash'] = str_replace('id-', '', $params['hashAlgorithm']['algorithm']); $result['MGFHash'] = str_replace('id-', '', $params['maskGenAlgorithm']['parameters']['algorithm']); if (isset($params['saltLength'])) { - $result['saltLength'] = (int) $params['saltLength']->toString(); + $result['saltLength'] = (int) "$params[saltLength]"; } if (isset($key['meta'])) { diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php index 8c828b3..62a13a4 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PrivateKey.php @@ -216,7 +216,7 @@ private function emsa_pss_encode($m, $emBits) $db = $ps . chr(1) . $salt; $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); // ie. stlren($db) $maskedDB = $db ^ $dbMask; - $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0]; + $maskedDB[0] = ~chr(256 - (1 << ($emBits & 7))) & $maskedDB[0]; $em = $maskedDB . $h . chr(0xBC); return $em; @@ -288,6 +288,11 @@ private function rsassa_pkcs1_v1_5_sign($m) */ public function sign($message) { + $result = $this->handleOpenSSL('openssl_sign', $message); + if ($result !== null) { + return $result; + } + switch ($this->signaturePadding) { case self::SIGNATURE_PKCS1: case self::SIGNATURE_RELAXED_PKCS1: @@ -434,6 +439,11 @@ private function raw_encrypt($m) */ public function decrypt($ciphertext) { + $result = $this->handleOpenSSL('openssl_private_decrypt', $ciphertext); + if ($result !== null) { + return $result; + } + switch ($this->encryptionPadding) { case self::ENCRYPTION_NONE: return $this->raw_encrypt($ciphertext); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php index ff80ae7..07ee1e7 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/RSA/PublicKey.php @@ -17,6 +17,7 @@ use phpseclib3\Crypt\Random; use phpseclib3\Crypt\RSA; use phpseclib3\Crypt\RSA\Formats\Keys\PSS; +use phpseclib3\Exception\BadConfigurationException; use phpseclib3\Exception\UnsupportedAlgorithmException; use phpseclib3\Exception\UnsupportedFormatException; use phpseclib3\File\ASN1; @@ -116,7 +117,7 @@ private function rsassa_pkcs1_v1_5_verify($m, $s) } // Compare - return $r1 || $r2; + return boolval($r1 | $r2); } /** @@ -241,13 +242,13 @@ private function emsa_pss_verify($m, $em, $emBits) $maskedDB = substr($em, 0, -$this->hLen - 1); $h = substr($em, -$this->hLen - 1, $this->hLen); - $temp = chr(0xFF << ($emBits & 7)); + $temp = chr(256 - (1 << ($emBits & 7))); if ((~$maskedDB[0] & $temp) != $temp) { return false; } $dbMask = $this->mgf1($h, $emLen - $this->hLen - 1); $db = $maskedDB ^ $dbMask; - $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0]; + $db[0] = ~chr(256 - (1 << ($emBits & 7))) & $db[0]; $temp = $emLen - $this->hLen - $sLen - 2; if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) { return false; @@ -301,6 +302,49 @@ private function rsassa_pss_verify($m, $s) */ public function verify($message, $signature) { + /* + https://datatracker.ietf.org/doc/html/rfc4055#page-6 says the following: + + There are two possible encodings for the AlgorithmIdentifier + parameters field associated with these object identifiers. The two + alternatives arise from the loss of the OPTIONAL associated with the + algorithm identifier parameters when the 1988 syntax for + AlgorithmIdentifier was translated into the 1997 syntax. Later the + OPTIONAL was recovered via a defect report, but by then many people + thought that algorithm parameters were mandatory. Because of this + history some implementations encode parameters as a NULL element + while others omit them entirely. The correct encoding is to omit the + parameters field; however, when RSASSA-PSS and RSAES-OAEP were + defined, it was done using the NULL parameters rather than absent + parameters. + + All implementations MUST accept both NULL and absent parameters as + legal and equivalent encodings. + + OpenSSL does NOT accept both - it REQUIRES NULL be present. phpseclib, however, + DOES accept both. at first, it didn't. at first, not knowing why some small number + of PKCS1 signatures ommitted NULL, i added the SIGNATURE_RELAXED_PKCS1 mode on + 2015-08-26. https://phpseclib.com/docs/rsa#rsasignature_relaxed_pkcs1 talks more + about that mode. later, on 2021-04-05, there was CVE-2021-30130. consequently, + the SIGNATURE_PKCS1 mode was updated to accept either NULL or non-NULL. + + because phpseclib accepts PKCS1 signatures that OpenSSL doesn't, OpenSSL isn't + used for PKCS1. if the OpenSSL extension is installed then it'll be used to perform + unpadded RSA (ie. modular exponentation), however, the actual PKCS1 construction + takes place in PHP code vs OpenSSL. + + see https://security.stackexchange.com/questions/110330/encoding-of-optional-null-in-der + for an additional reference + */ + if ($this->signaturePadding === self::SIGNATURE_PKCS1 && isset(self::$forcedEngine) && self::$forcedEngine !== 'PHP') { + throw new BadConfigurationException('Engine OpenSSL is forced but unavailable for RSA PKCS1 signature verification'); + } + + $result = $this->handleOpenSSL('openssl_verify', $message, $signature); + if ($result !== null) { + return $result; + } + switch ($this->signaturePadding) { case self::SIGNATURE_RELAXED_PKCS1: return $this->rsassa_pkcs1_v1_5_relaxed_verify($message, $signature); @@ -450,6 +494,11 @@ private function raw_encrypt($m) */ public function encrypt($plaintext) { + $result = $this->handleOpenSSL('openssl_public_encrypt', $plaintext); + if ($result !== null) { + return $result; + } + switch ($this->encryptionPadding) { case self::ENCRYPTION_NONE: return $this->raw_encrypt($plaintext); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php index 5ba7cf7..07b196d 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Rijndael.php @@ -378,7 +378,7 @@ protected function encryptBlock($in) $k = $c[2]; $l = $c[3]; while ($i < $Nb) { - $temp[$i] = ($state[$i] & intval(0xFF000000)) ^ + $temp[$i] = ($state[$i] & (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216)) ^ ($state[$j] & 0x00FF0000) ^ ($state[$k] & 0x0000FF00) ^ ($state[$l] & 0x000000FF) ^ @@ -452,7 +452,7 @@ protected function decryptBlock($in) $l = $Nb - $c[3]; while ($i < $Nb) { - $word = ($state[$i] & intval(0xFF000000)) | + $word = ($state[$i] & (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216)) | ($state[$j] & 0x00FF0000) | ($state[$k] & 0x0000FF00) | ($state[$l] & 0x000000FF); @@ -528,7 +528,7 @@ protected function setupKey() 0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000, 0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000 ]; - $rcon = array_map('intval', $rcon); + $rcon = array_map([self::class, 'safe_intval'], $rcon); } if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) { @@ -568,7 +568,9 @@ protected function setupKey() // on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine, // 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and' // with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is. - $temp = (($temp << 8) & intval(0xFFFFFF00)) | (($temp >> 24) & 0x000000FF); // rotWord + $temp = PHP_INT_SIZE == 8 ? // rotWord + (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF) : + ($temp << 8) | (($temp >> 24) & 0x000000FF); $temp = $this->subWord($temp) ^ $rcon[$i / $this->Nk]; } elseif ($this->Nk > 6 && $i % $this->Nk == 4) { $temp = $this->subWord($temp); @@ -659,7 +661,7 @@ protected function &getTables() // according to (section 5.2.1), // precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so // those are the names we'll use. - $t3 = array_map('intval', [ + $t3 = array_map([self::class, 'safe_intval'], [ // with array_map('intval', ...) we ensure we have only int's and not // some slower floats converted by php automatically on high values 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, @@ -697,9 +699,9 @@ protected function &getTables() ]); foreach ($t3 as $t3i) { - $t0[] = (($t3i << 24) & intval(0xFF000000)) | (($t3i >> 8) & 0x00FFFFFF); - $t1[] = (($t3i << 16) & intval(0xFFFF0000)) | (($t3i >> 16) & 0x0000FFFF); - $t2[] = (($t3i << 8) & intval(0xFFFFFF00)) | (($t3i >> 24) & 0x000000FF); + $t0[] = (($t3i << 24) & self::safe_intval(0xFF000000)) | (($t3i >> 8) & 0x00FFFFFF); + $t1[] = (($t3i << 16) & self::safe_intval(0xFFFF0000)) | (($t3i >> 16) & 0x0000FFFF); + $t2[] = (($t3i << 8) & self::safe_intval(0xFFFFFF00)) | (($t3i >> 24) & 0x000000FF); } $tables = [ @@ -744,7 +746,7 @@ protected function &getInvTables() { static $tables; if (empty($tables)) { - $dt3 = array_map('intval', [ + $dt3 = array_map([self::class, 'safe_intval'], [ 0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B, 0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5, 0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B, @@ -779,11 +781,19 @@ protected function &getInvTables() 0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0 ]); - foreach ($dt3 as $dt3i) { - $dt0[] = (($dt3i << 24) & intval(0xFF000000)) | (($dt3i >> 8) & 0x00FFFFFF); - $dt1[] = (($dt3i << 16) & intval(0xFFFF0000)) | (($dt3i >> 16) & 0x0000FFFF); - $dt2[] = (($dt3i << 8) & intval(0xFFFFFF00)) | (($dt3i >> 24) & 0x000000FF); - }; + if (PHP_INT_SIZE === 8) { + foreach ($dt3 as $dt3i) { + $dt0[] = (($dt3i << 24) & 0xFF000000) | (($dt3i >> 8) & 0x00FFFFFF); + $dt1[] = (($dt3i << 16) & 0xFFFF0000) | (($dt3i >> 16) & 0x0000FFFF); + $dt2[] = (($dt3i << 8) & 0xFFFFFF00) | (($dt3i >> 24) & 0x000000FF); + }; + } else { + foreach ($dt3 as $dt3i) { + $dt0[] = ($dt3i << 24) | (($dt3i >> 8) & 0x00FFFFFF); + $dt1[] = ($dt3i << 16) | (($dt3i >> 16) & 0x0000FFFF); + $dt2[] = ($dt3i << 8) | (($dt3i >> 24) & 0x000000FF); + }; + } $tables = [ // The Precomputed inverse mixColumns tables dt0 - dt3 @@ -879,7 +889,7 @@ protected function setupInlineCrypt() $encrypt_block .= '$in = pack("N*"' . "\n"; for ($i = 0; $i < $Nb; ++$i) { $encrypt_block .= ', - ($' . $e . $i . ' & ' . ((int)0xFF000000) . ') ^ + ($' . $e . $i . ' & ' . (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216) . ') ^ ($' . $e . (($i + $c[1]) % $Nb) . ' & 0x00FF0000 ) ^ ($' . $e . (($i + $c[2]) % $Nb) . ' & 0x0000FF00 ) ^ ($' . $e . (($i + $c[3]) % $Nb) . ' & 0x000000FF ) ^ @@ -935,7 +945,7 @@ protected function setupInlineCrypt() $decrypt_block .= '$in = pack("N*"' . "\n"; for ($i = 0; $i < $Nb; ++$i) { $decrypt_block .= ', - ($' . $e . $i . ' & ' . ((int)0xFF000000) . ') ^ + ($' . $e . $i . ' & ' . (PHP_INT_SIZE == 8 ? 0xFF000000 : -16777216) . ') ^ ($' . $e . (($Nb + $i - $c[1]) % $Nb) . ' & 0x00FF0000 ) ^ ($' . $e . (($Nb + $i - $c[2]) % $Nb) . ' & 0x0000FF00 ) ^ ($' . $e . (($Nb + $i - $c[3]) % $Nb) . ' & 0x000000FF ) ^ diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php index 785e7aa..78c3000 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Salsa20.php @@ -411,7 +411,7 @@ protected static function leftRotate($x, $n) $r1 &= 0xFFFFFFFF; $r2 = ($x & 0xFFFFFFFF) >> (32 - $n); } else { - $x = (int) $x; + $x = self::safe_intval($x); $r1 = $x << $n; $r2 = $x >> (32 - $n); $r2 &= (1 << $n) - 1; @@ -482,7 +482,7 @@ protected static function salsa20($x) } for ($i = 1; $i <= 16; $i++) { - $x[$i] += $z[$i]; + $x[$i] = self::safe_intval($x[$i] + $z[$i]); } return pack('V*', ...$x); diff --git a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php index 141ad01..e89a776 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Crypt/Twofish.php @@ -373,12 +373,12 @@ public function __construct($mode) protected static function initialize_static_variables() { if (is_float(self::$m3[0])) { - self::$m0 = array_map('intval', self::$m0); - self::$m1 = array_map('intval', self::$m1); - self::$m2 = array_map('intval', self::$m2); - self::$m3 = array_map('intval', self::$m3); - self::$q0 = array_map('intval', self::$q0); - self::$q1 = array_map('intval', self::$q1); + self::$m0 = array_map([self::class, 'safe_intval'], self::$m0); + self::$m1 = array_map([self::class, 'safe_intval'], self::$m1); + self::$m2 = array_map([self::class, 'safe_intval'], self::$m2); + self::$m3 = array_map([self::class, 'safe_intval'], self::$m3); + self::$q0 = array_map([self::class, 'safe_intval'], self::$q0); + self::$q1 = array_map([self::class, 'safe_intval'], self::$q1); } parent::initialize_static_variables(); diff --git a/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php b/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php index 2f1fb8a..b2a7c12 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php +++ b/vendor/phpseclib/phpseclib/phpseclib/File/ASN1.php @@ -131,6 +131,8 @@ abstract class ASN1 */ private static $encoded; + private static $use64BitOIDHandling; + /** * Type mapping table for the ANY type. * @@ -190,6 +192,7 @@ abstract class ASN1 * * @param Element|string $encoded * @return ?array + * @changed in phpseclib 4.0.0 */ public static function decodeBER($encoded) { @@ -514,6 +517,7 @@ private static function decode_ber($encoded, $start = 0, $encoded_pos = 0) * @param array $mapping * @param array $special * @return array|bool|Element|string|null + * @changed in phpseclib 4.0.0 */ public static function asn1map(array $decoded, $mapping, $special = []) { @@ -789,10 +793,17 @@ public static function asn1map(array $decoded, $mapping, $special = []) case self::TYPE_ENUMERATED: $temp = $decoded['content']; if (isset($mapping['implicit'])) { - $temp = new BigInteger($decoded['content'], -256); + $temp = new BigInteger($temp, -256); + } + if (!$temp instanceof BigInteger) { + return false; } if (isset($mapping['mapping'])) { - $temp = (int) $temp->toString(); + $temp = $temp->toString(); + if (strlen($temp) > 1) { + return false; + } + $temp = (int) $temp; return isset($mapping['mapping'][$temp]) ? $mapping['mapping'][$temp] : false; @@ -833,6 +844,7 @@ public static function decodeLength(&$string) * @param array $mapping * @param array $special * @return string + * @changed in phpseclib 4.0.0 */ public static function encodeDER($source, $mapping, $special = []) { @@ -1141,6 +1153,19 @@ private static function encode_der($source, array $mapping, $idx = null, array $ return chr($tag) . self::encodeLength(strlen($value)) . $value; } + public static function enable64BitOIDHandling() + { + if (PHP_INT_SIZE === 4) { + throw new \RuntimeException('64-bit OID handling is unavailable on 32-bit PHP installs'); + } + self::$use64BitOIDHandling = true; + } + + public static function disable64BitOIDHandling() + { + self::$use64BitOIDHandling = false; + } + /** * BER-decode the OID * @@ -1148,6 +1173,7 @@ private static function encode_der($source, array $mapping, $idx = null, array $ * * @param string $content * @return string + * @changed in phpseclib 4.0.0 */ public static function decodeOID($content) { @@ -1158,12 +1184,16 @@ public static function decodeOID($content) $eighty = new BigInteger(80); } + if (!isset(self::$use64BitOIDHandling)) { + self::$use64BitOIDHandling = PHP_INT_SIZE === 8; + } + $oid = []; $pos = 0; $len = strlen($content); // see https://github.com/openjdk/jdk/blob/2deb318c9f047ec5a4b160d66a4b52f93688ec42/src/java.base/share/classes/sun/security/util/ObjectIdentifier.java#L55 - if ($len > 4096) { - //throw new \RuntimeException("Object identifier size is limited to 4096 bytes ($len bytes present)"); + if ($len > 128) { + //throw new \RuntimeException("Object identifier size is limited to 128 bytes ($len bytes present)"); return false; } @@ -1172,13 +1202,50 @@ public static function decodeOID($content) } $n = new BigInteger(); - while ($pos < $len) { - $temp = ord($content[$pos++]); - $n = $n->bitwise_leftShift(7); - $n = $n->bitwise_or(new BigInteger($temp & 0x7F)); - if (~$temp & 0x80) { - $oid[] = $n; - $n = new BigInteger(); + $subn = $numBytes = 0; + if (self::$use64BitOIDHandling) { + $prefix = ''; + while ($pos < $len) { + $temp = ord($content[$pos++]); + $subn <<= 7; + $subn |= ($temp & 0x7F); + $numBytes++; + $endByte = ~$temp & 0x80; + if ($numBytes === PHP_INT_SIZE) { + $prefix .= substr(pack('J', $subn), 1); // we're basically left shifting by 7 bytes + $subn = $numBytes = 0; + if ($endByte) { + $oid[] = new BigInteger($prefix, 256); + $prefix = ''; + } + } elseif ($endByte) { + if (strlen($prefix)) { + $arc = new BigInteger($prefix, 256); + $arc = $arc->bitwise_leftShift($numBytes * 7); + $oid[] = $arc->bitwise_or(new BigInteger($subn)); + $prefix = ''; + } else { + $oid[] = new BigInteger($subn); + } + $subn = $numBytes = 0; + } + } + } else { + while ($pos < $len) { + $temp = ord($content[$pos++]); + $subn <<= 7; + $subn |= ($temp & 0x7F); + $numBytes++; + $endByte = ~$temp & 0x80; + if ($numBytes === PHP_INT_SIZE || $endByte) { + $n = $n->bitwise_leftShift($numBytes * 7); + $n = $n->bitwise_or(new BigInteger($subn)); + $subn = $numBytes = 0; + if ($endByte) { + $oid[] = $n; + $n = new BigInteger(); + } + } } } $part1 = array_shift($oid); @@ -1265,6 +1332,7 @@ public static function encodeOID($source) * @param string $content * @param int $tag * @return \DateTime|false + * @changed in phpseclib 4.0.0 */ private static function decodeTime($content, $tag) { @@ -1310,6 +1378,7 @@ private static function decodeTime($content, $tag) * Sets the time / date format for asn1map(). * * @param string $format + * @removed in phpseclib 4.0.0 */ public static function setTimeFormat($format) { @@ -1323,6 +1392,7 @@ public static function setTimeFormat($format) * Previously loaded OIDs are retained. * * @param array $oids + * @changed in phpseclib 4.0.0 */ public static function loadOIDs(array $oids) { @@ -1337,6 +1407,7 @@ public static function loadOIDs(array $oids) * Previously loaded filters are not retained. * * @param array $filters + * @removed in phpseclib 4.0.0 */ public static function setFilters(array $filters) { @@ -1353,6 +1424,7 @@ public static function setFilters(array $filters) * @param int $from * @param int $to * @return string + * @removed in phpseclib 4.0.0 */ public static function convert($in, $from = self::TYPE_UTF8_STRING, $to = self::TYPE_UTF8_STRING) { @@ -1518,6 +1590,7 @@ public static function encodeLength($length) * * @param string $name * @return string + * @removed in phpseclib 4.0.0 */ public static function getOID($name) { diff --git a/vendor/phpseclib/phpseclib/phpseclib/File/X509.php b/vendor/phpseclib/phpseclib/phpseclib/File/X509.php index 80e0bab..813282b 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/File/X509.php +++ b/vendor/phpseclib/phpseclib/phpseclib/File/X509.php @@ -273,6 +273,7 @@ class X509 * Default Constructor. * * @return X509 + * @changed in phpseclib 4.0.0 */ public function __construct() { @@ -315,6 +316,7 @@ public function __construct() 'id-at-uniqueIdentifier' => '2.5.4.45', 'id-at-role' => '2.5.4.72', 'id-at-postalAddress' => '2.5.4.16', + 'id-at-organizationIdentifier' => '2.5.4.97', 'jurisdictionOfIncorporationCountryName' => '1.3.6.1.4.1.311.60.2.1.3', 'jurisdictionOfIncorporationStateOrProvinceName' => '1.3.6.1.4.1.311.60.2.1.2', 'jurisdictionLocalityName' => '1.3.6.1.4.1.311.60.2.1.1', @@ -428,6 +430,7 @@ public function __construct() * @param array|string $cert * @param int $mode * @return mixed + * @removed in phpseclib 4.0.0 */ public function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT) { @@ -501,6 +504,7 @@ public function loadX509($cert, $mode = self::FORMAT_AUTO_DETECT) * @param array $cert * @param int $format optional * @return string + * @removed in phpseclib 4.0.0 */ public function saveX509(array $cert, $format = self::FORMAT_PEM) { @@ -958,6 +962,7 @@ private function getMapping($extnId) * * @param string $cert * @return bool + * @removed in phpseclib 4.0.0 */ public function loadCA($cert) { @@ -1084,6 +1089,7 @@ public function validateURL($url) * * @param \DateTimeInterface|string $date optional * @return bool + * @removed in phpseclib 4.0.0 */ public function validateDate($date = null) { @@ -1241,6 +1247,7 @@ private function testForIntermediate($caonly, $count) * * @param bool $caonly optional * @return mixed + * @changed in phpseclib 4.0.0 */ public function validateSignature($caonly = true) { @@ -1471,7 +1478,6 @@ public static function setRecurLimit($count) /** * Prevents URIs from being automatically retrieved - * */ public static function disableURLFetch() { @@ -1480,7 +1486,6 @@ public static function disableURLFetch() /** * Allows URIs to be automatically retrieved - * */ public static function enableURLFetch() { @@ -1494,6 +1499,7 @@ public static function enableURLFetch() * * @param string $ip * @return string + * @removed in phpseclib 4.0.0 */ public static function decodeIP($ip) { @@ -1507,6 +1513,7 @@ public static function decodeIP($ip) * * @param string $ip * @return array + * @removed in phpseclib 4.0.0 */ public static function decodeNameConstraintIP($ip) { @@ -1523,6 +1530,7 @@ public static function decodeNameConstraintIP($ip) * * @param string|array $ip * @return string + * @removed in phpseclib 4.0.0 */ public static function encodeIP($ip) { @@ -1612,6 +1620,9 @@ private function translateDNProp($propName) case 'organizationalunitname': case 'ou': return 'id-at-organizationalUnitName'; + case 'id-at-organizationidentifier': + case 'organizationIdentifier': + return 'id-at-organizationIdentifier'; case 'id-at-pseudonym': case 'pseudonym': return 'id-at-pseudonym'; @@ -1643,6 +1654,7 @@ private function translateDNProp($propName) * @param mixed $propValue * @param string $type optional * @return bool + * @removed in phpseclib 4.0.0 */ public function setDNProp($propName, $propValue, $type = 'utf8String') { @@ -1673,6 +1685,7 @@ public function setDNProp($propName, $propValue, $type = 'utf8String') * Remove Distinguished Name properties * * @param string $propName + * @removed in phpseclib 4.0.0 */ public function removeDNProp($propName) { @@ -1706,6 +1719,7 @@ public function removeDNProp($propName) * @param array $dn optional * @param bool $withType optional * @return mixed + * @removed in phpseclib 4.0.0 */ public function getDNProp($propName, $dn = null, $withType = false) { @@ -1770,6 +1784,7 @@ public function getDNProp($propName, $dn = null, $withType = false) * @param bool $merge optional * @param string $type optional * @return bool + * @changed in phpseclib 4.0.0 */ public function setDN($dn, $merge = false, $type = 'utf8String') { @@ -1811,6 +1826,7 @@ public function setDN($dn, $merge = false, $type = 'utf8String') * @param mixed $format optional * @param array $dn optional * @return array|bool|string + * @changed in phpseclib 4.0.0 */ public function getDN($format = self::DN_ARRAY, $dn = null) { @@ -1952,6 +1968,7 @@ public function getDN($format = self::DN_ARRAY, $dn = null) * * @param int $format optional * @return mixed + * @changed in phpseclib 4.0.0 */ public function getIssuerDN($format = self::DN_ARRAY) { @@ -1973,6 +1990,7 @@ public function getIssuerDN($format = self::DN_ARRAY) * * @param int $format optional * @return mixed + * @changed in phpseclib 4.0.0 */ public function getSubjectDN($format = self::DN_ARRAY) { @@ -1996,6 +2014,7 @@ public function getSubjectDN($format = self::DN_ARRAY) * @param string $propName * @param bool $withType optional * @return mixed + * @removed in phpseclib 4.0.0 */ public function getIssuerDNProp($propName, $withType = false) { @@ -2017,6 +2036,7 @@ public function getIssuerDNProp($propName, $withType = false) * @param string $propName * @param bool $withType optional * @return mixed + * @removed in phpseclib 4.0.0 */ public function getSubjectDNProp($propName, $withType = false) { @@ -2038,6 +2058,7 @@ public function getSubjectDNProp($propName, $withType = false) * Get the certificate chain for the current cert * * @return mixed + * @removed in phpseclib 4.0.0 */ public function getChain() { @@ -2079,6 +2100,7 @@ public function getChain() * Returns the current cert * * @return array|bool + * @removed in phpseclib 4.0.0 */ public function &getCurrentCert() { @@ -2104,6 +2126,7 @@ public function setPublicKey(PublicKey $key) * Key needs to be a \phpseclib3\Crypt\RSA object * * @param PrivateKey $key + * @removed in phpseclib 4.0.0 */ public function setPrivateKey(PrivateKey $key) { @@ -2116,6 +2139,7 @@ public function setPrivateKey(PrivateKey $key) * Used for SPKAC CSR's * * @param string $challenge + * @removed in phpseclib 4.0.0 */ public function setChallenge($challenge) { @@ -2176,6 +2200,7 @@ public function getPublicKey() * @param string $csr * @param int $mode * @return mixed + * @removed in phpseclib 4.0.0 */ public function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT) { @@ -2250,6 +2275,7 @@ public function loadCSR($csr, $mode = self::FORMAT_AUTO_DETECT) * @param array $csr * @param int $format optional * @return string + * @removed in phpseclib 4.0.0 */ public function saveCSR(array $csr, $format = self::FORMAT_PEM) { @@ -2295,6 +2321,7 @@ public function saveCSR(array $csr, $format = self::FORMAT_PEM) * * @param string $spkac * @return mixed + * @removed in phpseclib 4.0.0 */ public function loadSPKAC($spkac) { @@ -2359,6 +2386,7 @@ public function loadSPKAC($spkac) * @param array $spkac * @param int $format optional * @return string + * @removed in phpseclib 4.0.0 */ public function saveSPKAC(array $spkac, $format = self::FORMAT_PEM) { @@ -2396,6 +2424,7 @@ public function saveSPKAC(array $spkac, $format = self::FORMAT_PEM) * @param string $crl * @param int $mode * @return mixed + * @removed in phpseclib 4.0.0 */ public function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT) { @@ -2462,6 +2491,7 @@ public function loadCRL($crl, $mode = self::FORMAT_AUTO_DETECT) * @param array $crl * @param int $format optional * @return string + * @removed in phpseclib 4.0.0 */ public function saveCRL(array $crl, $format = self::FORMAT_PEM) { @@ -2542,6 +2572,7 @@ private function timeField($date) * a CSR or something with the DN and public key explicitly set. * * @return mixed + * @removed in phpseclib 4.0.0 */ public function sign(X509 $issuer, X509 $subject) { @@ -2724,6 +2755,7 @@ public function sign(X509 $issuer, X509 $subject) * Sign a CSR * * @return mixed + * @removed in phpseclib 4.0.0 */ public function signCSR() { @@ -2779,6 +2811,7 @@ public function signCSR() * Sign a SPKAC * * @return mixed + * @removed in phpseclib 4.0.0 */ public function signSPKAC() { @@ -2841,6 +2874,7 @@ public function signSPKAC() * $issuer's private key needs to be loaded. * * @return mixed + * @removed in phpseclib 4.0.0 */ public function signCRL(X509 $issuer, X509 $crl) { @@ -3391,6 +3425,7 @@ public function getExtension($id, $cert = null, $path = null) * @param array $cert optional * @param string $path optional * @return array + * @removed in phpseclib 4.0.0 */ public function getExtensions($cert = null, $path = null) { @@ -3417,6 +3452,7 @@ public function setExtension($id, $value, $critical = false, $replace = true) * @param string $id * @param int $disposition optional * @return bool + * @removed in phpseclib 4.0.0 */ public function removeAttribute($id, $disposition = self::ATTR_ALL) { @@ -3467,6 +3503,7 @@ public function removeAttribute($id, $disposition = self::ATTR_ALL) * @param int $disposition optional * @param array $csr optional * @return mixed + * @removed in phpseclib 4.0.0 */ public function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null) { @@ -3508,6 +3545,7 @@ public function getAttribute($id, $disposition = self::ATTR_ALL, $csr = null) * * @param array $csr optional * @return mixed + * @removed in phpseclib 4.0.0 */ public function getRequestedCertificateExtensions($csr = null) { @@ -3528,6 +3566,7 @@ public function getRequestedCertificateExtensions($csr = null) * * @param array $csr optional * @return array + * @removed in phpseclib 4.0.0 */ public function getAttributes($csr = null) { @@ -3554,6 +3593,7 @@ public function getAttributes($csr = null) * @param mixed $value * @param int $disposition optional * @return bool + * @removed in phpseclib 4.0.0 */ public function setAttribute($id, $value, $disposition = self::ATTR_ALL) { @@ -3635,6 +3675,7 @@ public function setKeyIdentifier($value) * @param mixed $key optional * @param int $method optional * @return string binary key identifier + * @removed in phpseclib 4.0.0 */ public function computeKeyIdentifier($key = null, $method = 1) { @@ -3731,6 +3772,7 @@ private function formatSubjectPublicKey() * * @param mixed ...$domains * @return void + * @removed in phpseclib 4.0.0 */ public function setDomain(...$domains) { @@ -3743,6 +3785,7 @@ public function setDomain(...$domains) * Set the IP Addresses's which the cert is to be valid for * * @param mixed[] ...$ipAddresses + * @removed in phpseclib 4.0.0 */ public function setIPAddress(...$ipAddresses) { @@ -3839,6 +3882,7 @@ public function revoke($serial, $date = null) * * @param string $serial * @return bool + * @removed in phpseclib 4.0.0 */ public function unrevoke($serial) { @@ -3858,6 +3902,7 @@ public function unrevoke($serial) * * @param string $serial * @return mixed + * @removed in phpseclib 4.0.0 */ public function getRevoked($serial) { @@ -3875,6 +3920,7 @@ public function getRevoked($serial) * * @param array $crl optional * @return array|bool + * @removed in phpseclib 4.0.0 */ public function listRevoked($crl = null) { @@ -3903,6 +3949,7 @@ public function listRevoked($crl = null) * @param string $serial * @param string $id * @return bool + * @removed in phpseclib 4.0.0 */ public function removeRevokedCertificateExtension($serial, $id) { @@ -3924,6 +3971,7 @@ public function removeRevokedCertificateExtension($serial, $id) * @param string $id * @param array $crl optional * @return mixed + * @removed in phpseclib 4.0.0 */ public function getRevokedCertificateExtension($serial, $id, $crl = null) { @@ -3971,6 +4019,7 @@ public function getRevokedCertificateExtensions($serial, $crl = null) * @param bool $critical optional * @param bool $replace optional * @return bool + * @removed in phpseclib 4.0.0 */ public function setRevokedCertificateExtension($serial, $id, $value, $critical = false, $replace = true) { @@ -4021,6 +4070,7 @@ public static function getRegisteredExtension($id) * @param mixed $value * @param bool $critical * @param bool $replace + * @removed in phpseclib 4.0.0 */ public function setExtensionValue($id, $value, $critical = false, $replace = false) { diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php index 965d7ff..e6d420d 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger.php @@ -322,6 +322,7 @@ public function divide(BigInteger $y) * * @param BigInteger $n * @return BigInteger + * @changed in phpseclib 4.0.0 */ public function modInverse(BigInteger $n) { @@ -402,7 +403,7 @@ public function getPrecision() * * Will be called, automatically, when serialize() is called on a BigInteger object. * - * __sleep() / __wakeup() have been around since PHP 4.0 + * __sleep() / __wakeup() have been around since PHP 4.0 but were deprecated in PHP 8.5 * * \Serializable was introduced in PHP 5.1 and deprecated in PHP 8.1: * https://wiki.php.net/rfc/phase_out_serializable @@ -437,6 +438,38 @@ public function __wakeup() } } + /** + * __serialize() magic method + * + * @see self::__unserialize() + * @return array + * @access public + */ + public function __serialize() + { + $result = ['hex' => $this->toHex(true)]; + if ($this->getPrecision() > 0) { + $result['precision'] = $this->getPrecision(); + } + return $result; + } + + /** + * __unserialize() magic method + * + * @see self::__serialize() + * @access public + */ + public function __unserialize(array $data) + { + $temp = new static($data['hex'], -16); + $this->value = $temp->value; + if (isset($data['precision']) && $data['precision'] > 0) { + // recalculate $this->bitmask + $this->setPrecision($data['precision']); + } + } + /** * JSON Serialize * diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php index 7b62830..5fd78ec 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/BCMath.php @@ -154,7 +154,7 @@ public function toBytes($twos_compliment = false) while (bccomp($current, '0', 0) > 0) { $temp = self::BCMOD_THREE_PARAMS ? bcmod($current, '16777216', 0) : bcmod($current, '16777216'); - $value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value; + $value = chr($temp >> 16) . chr(($temp >> 8) & 0xFF) . chr($temp & 0xFF) . $value; $current = bcdiv($current, '16777216', 0); } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php index 1892042..e845acf 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Math/BigInteger/Engines/Engine.php @@ -364,6 +364,44 @@ public function __wakeup() } } + /** + * __serialize() magic method + * + * __sleep / __wakeup were depreciated in PHP 8.5 + * Will be called, automatically, when serialize() is called on a Math_BigInteger object. + * + * @see self::__unserialize() + * @access public + */ + public function __serialize() + { + $result = ['hex' => $this->toHex(true)]; + if ($this->precision > 0) { + $result['precision'] = $this->precision; + } + return $result; + } + + /** + * __unserialize() magic method + * + * __sleep / __wakeup were depreciated in PHP 8.5 + * Will be called, automatically, when unserialize() is called on a Math_BigInteger object. + * + * @see self::__serialize() + * @access public + */ + public function __unserialize(array $data) + { + $temp = new static($data['hex'], -16); + $this->value = $temp->value; + $this->is_negative = $temp->is_negative; + if (isset($data['precision']) && $data['precision'] > 0) { + // recalculate $this->bitmask + $this->setPrecision($data['precision']); + } + } + /** * JSON Serialize * @@ -511,8 +549,8 @@ protected static function base256_lshift(&$x, $shift) $carry = 0; for ($i = strlen($x) - 1; $i >= 0; --$i) { - $temp = ord($x[$i]) << $shift | $carry; - $x[$i] = chr($temp); + $temp = (ord($x[$i]) << $shift) | $carry; + $x[$i] = chr($temp & 0xFF); $carry = $temp >> 8; } $carry = ($carry != 0) ? chr($carry) : ''; diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php new file mode 100644 index 0000000..ae5c8ec --- /dev/null +++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SCP.php @@ -0,0 +1,303 @@ + + * login('username', 'password')) { + * exit('Login Failed'); + * } + * + * echo $scp->exec('pwd') . "\r\n"; + * $scp->put('filename.ext', 'hello, world!'); + * echo $scp->exec('ls -latr'); + * ?> + * + * + * @author Jim Wigginton + * @copyright 2009 Jim Wigginton + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link http://phpseclib.sourceforge.net + */ + +namespace phpseclib3\Net; + +use phpseclib3\Common\Functions\Strings; +use phpseclib3\Exception\FileNotFoundException; + +/** + * Pure-PHP implementations of SCP. + * + * @author Jim Wigginton + */ +class SCP extends SSH2 +{ + /** + * Reads data from a local file. + * + * @see \phpseclib3\Net\SCP::put() + */ + const SOURCE_LOCAL_FILE = 1; + /** + * Reads data from a string. + * + * @see \phpseclib3\Net\SCP::put() + */ + // this value isn't really used anymore but i'm keeping it reserved for historical reasons + const SOURCE_STRING = 2; + /** + * SCP.php doesn't support SOURCE_CALLBACK because, with that one, we don't know the size, in advance + */ + //const SOURCE_CALLBACK = 16; + + /** + * Error information + * + * @see self::getSCPErrors() + * @see self::getLastSCPError() + * @var array + */ + private $scp_errors = []; + + /** + * Uploads a file to the SCP server. + * + * By default, \phpseclib\Net\SCP::put() does not read from the local filesystem. $data is dumped directly into $remote_file. + * So, for example, if you set $data to 'filename.ext' and then do \phpseclib\Net\SCP::get(), you will get a file, twelve bytes + * long, containing 'filename.ext' as its contents. + * + * Setting $mode to self::SOURCE_LOCAL_FILE will change the above behavior. With self::SOURCE_LOCAL_FILE, $remote_file will + * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how + * large $remote_file will be, as well. + * + * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take + * care of that, yourself. + * + * @param string $remote_file + * @param string $data + * @param int $mode + * @param callable $callback + * @return bool + * @access public + */ + public function put($remote_file, $data, $mode = self::SOURCE_STRING, $callback = null) + { + if (!($this->bitmap & self::MASK_LOGIN)) { + return false; + } + + if (empty($remote_file)) { + // remote file cannot be blank + return false; + } + + if (!$this->exec('scp -t ' . escapeshellarg($remote_file), false)) { // -t = to + return false; + } + + $temp = $this->get_channel_packet(self::CHANNEL_EXEC, true); + if ($temp !== chr(0)) { + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + + $packet_size = $this->packet_size_client_to_server[self::CHANNEL_EXEC] - 4; + + $remote_file = basename($remote_file); + + $dataCallback = false; + switch (true) { + case is_resource($data): + $mode = $mode & ~self::SOURCE_LOCAL_FILE; + $info = stream_get_meta_data($data); + if (isset($info['wrapper_type']) && $info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') { + $fp = fopen('php://memory', 'w+'); + stream_copy_to_stream($data, $fp); + rewind($fp); + } else { + $fp = $data; + } + break; + case $mode & self::SOURCE_LOCAL_FILE: + if (!is_file($data)) { + throw new FileNotFoundException("$data is not a valid file"); + } + $fp = @fopen($data, 'rb'); + if (!$fp) { + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + } + + if (isset($fp)) { + $stat = fstat($fp); + $size = !empty($stat) ? $stat['size'] : 0; + } else { + $size = strlen($data); + } + + $sent = 0; + $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size; + + $temp = 'C0644 ' . $size . ' ' . $remote_file . "\n"; + $this->send_channel_packet(self::CHANNEL_EXEC, $temp); + + $temp = $this->get_channel_packet(self::CHANNEL_EXEC, true); + if ($temp !== chr(0)) { + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + + $sent = 0; + while ($sent < $size) { + $temp = $mode & self::SOURCE_STRING ? substr($data, $sent, $packet_size) : fread($fp, $packet_size); + $this->send_channel_packet(self::CHANNEL_EXEC, $temp); + $sent += strlen($temp); + + if (is_callable($callback)) { + call_user_func($callback, $sent); + } + } + $this->close_channel(self::CHANNEL_EXEC, true); + + if ($mode != self::SOURCE_STRING) { + fclose($fp); + } + + return true; + } + + /** + * Downloads a file from the SCP server. + * + * Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if + * the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the + * operation + * + * @param string $remote_file + * @param string $local_file + * @return mixed + * @access public + */ + public function get($remote_file, $local_file = null, $progressCallback = null) + { + if (!($this->bitmap & self::MASK_LOGIN)) { + return false; + } + + if (!$this->exec('scp -f ' . escapeshellarg($remote_file), false)) { // -f = from + return false; + } + + $this->send_channel_packet(self::CHANNEL_EXEC, chr(0)); + + $info = $this->get_channel_packet(self::CHANNEL_EXEC, true); + // per https://goteleport.com/blog/scp-familiar-simple-insecure-slow/ non-zero responses mean there are errors + if ($info[0] === chr(1) || $info[0] == chr(2)) { + $type = $info[0] === chr(1) ? 'warning' : 'error'; + $this->scp_errors[] = "$type: " . substr($info, 1); + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + + $this->send_channel_packet(self::CHANNEL_EXEC, chr(0)); + + if (!preg_match('#(?[^ ]+) (?\d+) (?.+)#', rtrim($info), $info)) { + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + + $fclose_check = false; + if (is_resource($local_file)) { + $fp = $local_file; + } elseif (!is_null($local_file)) { + $fp = @fopen($local_file, 'wb'); + if (!$fp) { + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + $fclose_check = true; + } else { + $content = ''; + } + + $size = 0; + while (true) { + $data = $this->get_channel_packet(self::CHANNEL_EXEC, true); + // Terminate the loop in case the server repeatedly sends an empty response + if ($data === false) { + $this->close_channel(self::CHANNEL_EXEC, true); + // no data received from server + return false; + } + // SCP usually seems to split stuff out into 16k chunks + $length = strlen($data); + $size += $length; + $end = $size > $info['size']; + if ($end) { + $diff = $size - $info['size']; + $offset = $length - $diff; + if ($data[$offset] === chr(0)) { + $data = substr($data, 0, -$diff); + } else { + $type = $data[$offset] === chr(1) ? 'warning' : 'error'; + $this->scp_errors[] = "$type: " . substr($data, 1); + $this->close_channel(self::CHANNEL_EXEC, true); + return false; + } + } + + if (is_null($local_file)) { + $content .= $data; + } else { + fputs($fp, $data); + } + + if (is_callable($progressCallback)) { + call_user_func($progressCallback, $size); + } + + if ($end) { + break; + } + } + + $this->close_channel(self::CHANNEL_EXEC, true); + + if ($fclose_check) { + fclose($fp); + } + + // if $content isn't set that means a file was written to + return isset($content) ? $content : true; + } + + /** + * Returns all errors on the SCP layer + * + * @return array + */ + public function getSCPErrors() + { + return $this->scp_errors; + } + + /** + * Returns the last error on the SCP layer + * + * @return string + */ + public function getLastSCPError() + { + return count($this->scp_errors) ? $this->scp_errors[count($this->scp_errors) - 1] : ''; + } +} diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php index 7e25544..ddc6715 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SFTP.php @@ -936,6 +936,9 @@ public function chdir($dir) } $dir = $this->realpath($dir); + if ($dir === false) { + return false; + } // confirm that $dir is, in fact, a valid directory if ($this->use_stat_cache && is_array($this->query_stat_cache($dir))) { @@ -1678,6 +1681,7 @@ public function chgrp($filename, $gid, $recursive = false) * @param bool $recursive * @throws \UnexpectedValueException on receipt of unexpected packets * @return mixed + * @changed in phpseclib 4.0.0 */ public function chmod($mode, $filename, $recursive = false) { @@ -3459,11 +3463,11 @@ public function getSFTPLog() return $this->packet_type_log; } } - /** * Returns all errors on the SFTP layer * * @return array + * @removed in phpseclib 4.0.0 */ public function getSFTPErrors() { @@ -3474,6 +3478,7 @@ public function getSFTPErrors() * Returns the last error on the SFTP layer * * @return string + * @removed in phpseclib 4.0.0 */ public function getLastSFTPError() { @@ -3562,7 +3567,6 @@ protected function disconnect_helper($reason) /** * Enable Date Preservation - * */ public function enableDatePreservation() { @@ -3571,13 +3575,101 @@ public function enableDatePreservation() /** * Disable Date Preservation - * */ public function disableDatePreservation() { $this->preserveTime = false; } + /** + * Copy + * + * This method (currently) only works if the copy-data extension is available + * + * @param string $oldname + * @param string $newname + * @return bool + */ + public function copy($oldname, $newname) + { + if (!$this->precheck()) { + return false; + } + + $oldname = $this->realpath($oldname); + $newname = $this->realpath($newname); + if ($oldname === false || $newname === false) { + return false; + } + + if (!isset($this->extensions['copy-data']) || $this->extensions['copy-data'] !== '1') { + throw new \RuntimeException( + "Extension 'copy-data' is not supported by the server. " . + "Call getSupportedVersions() to see a list of supported extension" + ); + } + + $size = $this->filesize($oldname); + + $packet = Strings::packSSH2('s', $oldname); + $packet .= $this->version >= 5 ? + pack('N3', 0, NET_SFTP_OPEN_OPEN_EXISTING, 0) : + pack('N2', NET_SFTP_OPEN_READ, 0); + $this->send_sftp_packet(NET_SFTP_OPEN, $packet); + + $response = $this->get_sftp_packet(); + switch ($this->packet_type) { + case NET_SFTP_HANDLE: + $oldhandle = substr($response, 4); + break; + case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED + $this->logError($response); + return false; + default: + throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' + . 'Got packet type: ' . $this->packet_type); + } + + if ($this->version >= 5) { + $flags = NET_SFTP_OPEN_OPEN_OR_CREATE; + } else { + $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE; + } + + $packet = Strings::packSSH2('s', $newname); + $packet .= $this->version >= 5 ? + pack('N3', 0, $flags, 0) : + pack('N2', $flags, 0); + $this->send_sftp_packet(NET_SFTP_OPEN, $packet); + + $response = $this->get_sftp_packet(); + switch ($this->packet_type) { + case NET_SFTP_HANDLE: + $newhandle = substr($response, 4); + break; + case NET_SFTP_STATUS: + $this->logError($response); + return false; + default: + throw new \UnexpectedValueException('Expected NET_SFTP_HANDLE or NET_SFTP_STATUS. ' + . 'Got packet type: ' . $this->packet_type); + } + + $packet = Strings::packSSH2('ssQQsQ', 'copy-data', $oldhandle, 0, $size, $newhandle, 0); + $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet); + + $response = $this->get_sftp_packet(); + if ($this->packet_type != NET_SFTP_STATUS) { + throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' + . 'Got packet type: ' . $this->packet_type); + } + + $this->close_handle($oldhandle); + $this->close_handle($newhandle); + + return true; + } + /** * POSIX Rename * @@ -3697,4 +3789,50 @@ public function statvfs($path) Strings::unpackSSH2('QQQQQQQQQQQ', $response) ); } + + public function hardlink($oldpath, $newpath) + { + if (!$this->precheck()) { + return false; + } + + if (!isset($this->extensions['hardlink@openssh.com']) || $this->extensions['hardlink@openssh.com'] !== '1') { + throw new \RuntimeException( + "Extension 'hardlink@openssh.com' is not supported by the server. " . + "Call getSupportedVersions() to see a list of supported extension" + ); + } + + $oldpath = $this->realpath($oldpath); + $newpath = $this->realpath($newpath); + if ($oldpath === false || $newpath === false) { + return false; + } + + $packet = Strings::packSSH2('sss', 'hardlink@openssh.com', $oldpath, $newpath); + $this->send_sftp_packet(NET_SFTP_EXTENDED, $packet); + + $response = $this->get_sftp_packet(); + if ($this->packet_type !== NET_SFTP_STATUS) { + throw new \UnexpectedValueException('Expected NET_SFTP_STATUS. ' + . 'Got packet type: ' . $this->packet_type); + } + + // if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED + list($status) = Strings::unpackSSH2('N', $response); + if ($status !== NET_SFTP_STATUS_OK) { + $this->logError($response, $status); + return false; + } + + // this operation will change the ctime and link-count attributes + // which could be cached depending on sftp version + $this->remove_from_stat_cache($oldpath); + + // hardlink creation should fail if $newpath exists; + // removing it from the cache anyway, just to be sure + $this->remove_from_stat_cache($newpath); + + return true; + } } diff --git a/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php index 1c8a0e2..6f844e1 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php +++ b/vendor/phpseclib/phpseclib/phpseclib/Net/SSH2.php @@ -679,7 +679,7 @@ class SSH2 * @see self::send_channel_packet() * @var array */ - private $packet_size_client_to_server = []; + protected $packet_size_client_to_server = []; /** * Message Number Log @@ -2941,6 +2941,9 @@ public function exec($command, $callback = null) $this->channel_id_last_interactive = self::CHANNEL_EXEC; return true; } + if ($callback === false) { + return true; + } $output = ''; while (true) { @@ -3735,12 +3738,12 @@ private function get_binary_packet() substr($packet->raw, 0, -$this->hmac_size); if (($this->hmac_check->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') { $this->hmac_check->setNonce("\0\0\0\0" . pack('N', $this->get_seq_no)); - if ($hmac != $this->hmac_check->hash($reconstructed)) { + if (!hash_equals($hmac, $this->hmac_check->hash($reconstructed))) { $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR); throw new ConnectionClosedException('Invalid UMAC'); } } else { - if ($hmac != $this->hmac_check->hash(pack('Na*', $this->get_seq_no, $reconstructed))) { + if (!hash_equals($hmac, $this->hmac_check->hash(pack('Na*', $this->get_seq_no, $reconstructed)))) { $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR); throw new ConnectionClosedException('Invalid HMAC'); } @@ -3997,9 +4000,11 @@ private function filter($payload) break; case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4 Strings::shift($payload, 1); - list($request_name) = Strings::unpackSSH2('s', $payload); + list($request_name, $want_reply) = Strings::unpackSSH2('sb', $payload); $this->errors[] = "SSH_MSG_GLOBAL_REQUEST: $request_name"; - $this->send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE)); + if ($want_reply) { + $this->send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE)); + } $payload = $this->get_binary_packet(); break; case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1 @@ -4236,7 +4241,6 @@ protected function get_channel_packet($client_channel, $skip_extended = false) if (strlen($error_message)) { $this->errors[count($this->errors) - 1] .= "\r\n$error_message"; } - if (isset($this->channel_status[$channel]) && $this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_CLOSE) { if ($this->channel_status[$channel] != NET_SSH2_MSG_CHANNEL_EOF) { $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_EOF, $this->server_channels[$channel])); @@ -4245,7 +4249,6 @@ protected function get_channel_packet($client_channel, $skip_extended = false) $this->channel_status[$channel] = NET_SSH2_MSG_CHANNEL_CLOSE; } - continue 3; case 'exit-status': list(, $this->exit_status) = Strings::unpackSSH2('CN', $response); @@ -4255,8 +4258,13 @@ protected function get_channel_packet($client_channel, $skip_extended = false) continue 3; default: - // "Some systems may not implement signals, in which case they SHOULD ignore this message." - // -- http://tools.ietf.org/html/rfc4254#section-6.9 + list($want_reply) = Strings::unpackSSH2('b', $response); + if ($want_reply) { + // "If the request is not recognized or is not supported for the channel, + // SSH_MSG_CHANNEL_FAILURE is returned." + // -- https://datatracker.ietf.org/doc/html/rfc4254#page-10 + $this->send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_FAILURE, $this->server_channels[$channel])); + } continue 3; } } @@ -4714,7 +4722,7 @@ protected function send_channel_packet($client_channel, $data) * @param bool $want_reply * @return void */ - private function close_channel($client_channel) + protected function close_channel($client_channel) { // see http://tools.ietf.org/html/rfc4254#section-5.3 @@ -4905,6 +4913,7 @@ private static function array_intersect_first(array $array1, array $array2) * If you are looking for messages from the SFTP layer, please see SFTP::getSFTPErrors() * * @return string[] + * @removed in phpseclib 4.0.0 */ public function getErrors() { @@ -4917,6 +4926,7 @@ public function getErrors() * If you are looking for messages from the SFTP layer, please see SFTP::getLastSFTPError() * * @return string + * @removed in phpseclib 4.0.0 */ public function getLastError() { diff --git a/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf b/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf index 2b8b52f..6a5c0f5 100644 --- a/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf +++ b/vendor/phpseclib/phpseclib/phpseclib/openssl.cnf @@ -2,5 +2,8 @@ HOME = . RANDFILE = $ENV::HOME/.rnd +# without this line you'll get this error with openssl_pkey_new(): +# Warning: openssl_pkey_new(): Private key length must be at least 384 bits, configured to 0 +default_bits = 384 [ v3_ca ] diff --git a/vendor/unzerdev/php-sdk/CHANGELOG.md b/vendor/unzerdev/php-sdk/CHANGELOG.md index 468e50c..1e63b31 100644 --- a/vendor/unzerdev/php-sdk/CHANGELOG.md +++ b/vendor/unzerdev/php-sdk/CHANGELOG.md @@ -5,6 +5,60 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [4.0.1](https://github.com/unzerdev/php-sdk/compare/4.0.0..4.0.1) + +### Changed + +* `\UnzerSDK\Unzer` can now be initialised with a public key (`s-pub-*` / `p-pub-*`), enabling `fetchConfig()` to be called without a private key. + +## [4.0.0](https://github.com/unzerdev/php-sdk/compare/3.15.0..4.0.0) + +### Added + +* Add `company` field to `\UnzerSDK\Resources\EmbeddedResources\Address` class. +* Add PHP 8.5 to supported versions in `composer.json`. + +### Changed + +* Allow `null` return for `getCompany()` in `\UnzerSDK\Resources\EmbeddedResources\Address`. +* Remove deprecated `curl_close` and `\ReflectionMethod::setAccessible` calls to address PHP 8.5 deprecation warnings. +* Drop support for PHP 7.4 and PHP 8.0. + +### Deprecated + +* Mark `\UnzerSDK\Resources\PaymentTypes\Giropay` as deprecated. + +## [3.15.0](https://github.com/unzerdev/php-sdk/compare/3.14.0..3.15.0) + +### Added + +* Add the SCA (Strong Customer Authentication) transaction type. + * Add class `\UnzerSDK\Resources\TransactionTypes\Sca`. + * Add methods in `\UnzerSDK\Unzer` class: + * `performSca(Sca $sca, $paymentType, $customer = null, ?Metadata $metadata = null, ?Basket $basket = null): Sca` - + Perform an SCA transaction. + * `fetchSca(Sca $sca): Sca` - Fetch an SCA transaction. + * `fetchScaById($payment, string $scaId): Sca` - Fetch an SCA transaction by ID. + * `chargeScaTransaction($payment, Charge $charge, $customer = null, ?Metadata $metadata = null, ?Basket $basket = null): Charge` - + Charge an SCA transaction. + * `authorizeScaTransaction($payment, Authorization $authorization, $customer = null, ?Metadata $metadata = null, ?Basket $basket = null): Authorization` - + Authorize an SCA transaction. + * Add methods in `\UnzerSDK\Resources\Payment` class: + * `getSca(bool $lazy = false): ?Sca` - Get the SCA transaction. + * `setSca(Sca $sca): self` - Set the SCA transaction. + +## [3.14.0](https://github.com/unzerdev/php-sdk/compare/3.13.2..3.14.0) + +### Changed + +* Add `subscriptionAgreement` property for v2 Paypage creation to `\UnzerSDK\Resources\EmbeddedResources\Paypage\Urls` + +## [3.13.2](https://github.com/unzerdev/php-sdk/compare/3.13.1..3.13.2) + +### Changed + +* Added chargeback handling for `fetchResourceFromEvent()` method. + ## [3.13.1](https://github.com/unzerdev/php-sdk/compare/3.13.0..3.13.1) ### Added diff --git a/vendor/unzerdev/php-sdk/composer.json b/vendor/unzerdev/php-sdk/composer.json index 91dee32..7a6a2a7 100644 --- a/vendor/unzerdev/php-sdk/composer.json +++ b/vendor/unzerdev/php-sdk/composer.json @@ -4,11 +4,11 @@ "minimum-stability": "stable", "license": "Apache-2.0", "require": { - "php": "~7.4.0|~8.0.0|~8.1.0|~8.2.0|~8.3.0|~8.4.0", + "php": "~8.1.0|~8.2.0|~8.3.0|~8.4.0|~8.5.0", "ext-json": "*" }, "require-dev": { - "phpunit/phpunit": ">6.5 <10.0", + "phpunit/phpunit": "^9.6", "friendsofphp/php-cs-fixer": "^3.0" }, "suggest": { diff --git a/vendor/unzerdev/php-sdk/phpunit.xml b/vendor/unzerdev/php-sdk/phpunit.xml index df90057..b89b9dd 100644 --- a/vendor/unzerdev/php-sdk/phpunit.xml +++ b/vendor/unzerdev/php-sdk/phpunit.xml @@ -7,6 +7,7 @@ convertErrorsToExceptions="true" convertNoticesToExceptions="false" convertWarningsToExceptions="false" + convertDeprecationsToExceptions="true" processIsolation="false" stopOnFailure="false" verbose="true" diff --git a/vendor/unzerdev/php-sdk/src/Adapter/ApplepayAdapter.php b/vendor/unzerdev/php-sdk/src/Adapter/ApplepayAdapter.php index b23a463..820655c 100644 --- a/vendor/unzerdev/php-sdk/src/Adapter/ApplepayAdapter.php +++ b/vendor/unzerdev/php-sdk/src/Adapter/ApplepayAdapter.php @@ -42,7 +42,6 @@ public function validateApplePayMerchant( $this->setOption(CURLOPT_POSTFIELDS, $payload); $sessionResponse = $this->execute(); - $this->close(); return $sessionResponse; } @@ -131,14 +130,6 @@ public function execute(): ?string throw new ApplepayMerchantValidationException($errorMessage); } - /** - * @inheritDoc - */ - public function close(): void - { - curl_close($this->request); - } - /** * @inheritDoc */ diff --git a/vendor/unzerdev/php-sdk/src/Adapter/CurlAdapter.php b/vendor/unzerdev/php-sdk/src/Adapter/CurlAdapter.php index 5535eb4..43a781e 100644 --- a/vendor/unzerdev/php-sdk/src/Adapter/CurlAdapter.php +++ b/vendor/unzerdev/php-sdk/src/Adapter/CurlAdapter.php @@ -95,14 +95,6 @@ public function getResponseCode(): string return curl_getinfo($this->request, CURLINFO_HTTP_CODE); } - /** - * {@inheritDoc} - */ - public function close(): void - { - curl_close($this->request); - } - /** * {@inheritDoc} */ diff --git a/vendor/unzerdev/php-sdk/src/Adapter/HttpAdapterInterface.php b/vendor/unzerdev/php-sdk/src/Adapter/HttpAdapterInterface.php index 2e2bd0a..be80576 100644 --- a/vendor/unzerdev/php-sdk/src/Adapter/HttpAdapterInterface.php +++ b/vendor/unzerdev/php-sdk/src/Adapter/HttpAdapterInterface.php @@ -43,11 +43,6 @@ public function execute(): ?string; */ public function getResponseCode(): string; - /** - * Closes the connection of the request. - */ - public function close(): void; - /** * Sets the headers for the request. * Expects an associative array with $key being the header name and $value being the header value. diff --git a/vendor/unzerdev/php-sdk/src/Constants/ApiResponseCodes.php b/vendor/unzerdev/php-sdk/src/Constants/ApiResponseCodes.php index 38c943f..c25d8aa 100644 --- a/vendor/unzerdev/php-sdk/src/Constants/ApiResponseCodes.php +++ b/vendor/unzerdev/php-sdk/src/Constants/ApiResponseCodes.php @@ -41,6 +41,7 @@ class ApiResponseCodes public const API_ERROR_CUSTOMER_DOES_NOT_EXIST = 'API.410.100.100'; public const API_ERROR_CUSTOMER_ID_ALREADY_EXISTS = 'API.410.200.010'; public const API_ERROR_ADDRESS_NAME_TO_LONG = 'API.410.200.031'; + public const API_CANNOT_CHARGE_UNSUCCESSFUL_SCA_TRANSACTION = 'API.500.100.060'; public const API_ERROR_CUSTOMER_CAN_NOT_BE_FOUND = 'API.500.100.100'; public const API_ERROR_REQUEST_DATA_IS_INVALID = 'API.500.300.999'; public const API_ERROR_RECURRING_PAYMENT_NOT_SUPPORTED = 'API.500.550.004'; diff --git a/vendor/unzerdev/php-sdk/src/Constants/IdStrings.php b/vendor/unzerdev/php-sdk/src/Constants/IdStrings.php index 662c9ea..4634335 100644 --- a/vendor/unzerdev/php-sdk/src/Constants/IdStrings.php +++ b/vendor/unzerdev/php-sdk/src/Constants/IdStrings.php @@ -16,6 +16,7 @@ class IdStrings public const CHARGEBACK = 'cbk'; public const PAYOUT = 'out'; public const PREAUTHORIZE = 'preaut'; + public const SCA = 'sca'; public const SHIPMENT = 'shp'; // Payment Types diff --git a/vendor/unzerdev/php-sdk/src/Constants/TransactionTypes.php b/vendor/unzerdev/php-sdk/src/Constants/TransactionTypes.php index 3a4721b..e2ce38a 100644 --- a/vendor/unzerdev/php-sdk/src/Constants/TransactionTypes.php +++ b/vendor/unzerdev/php-sdk/src/Constants/TransactionTypes.php @@ -18,4 +18,5 @@ class TransactionTypes public const SHIPMENT = 'shipment'; public const PAYOUT = 'payout'; public const CHARGEBACK = 'chargeback'; + public const SCA = 'strong_customer_authentication'; } diff --git a/vendor/unzerdev/php-sdk/src/Interfaces/PaymentServiceInterface.php b/vendor/unzerdev/php-sdk/src/Interfaces/PaymentServiceInterface.php index d461397..ad05a50 100644 --- a/vendor/unzerdev/php-sdk/src/Interfaces/PaymentServiceInterface.php +++ b/vendor/unzerdev/php-sdk/src/Interfaces/PaymentServiceInterface.php @@ -24,6 +24,7 @@ use UnzerSDK\Resources\TransactionTypes\Authorization; use UnzerSDK\Resources\TransactionTypes\Charge; use UnzerSDK\Resources\TransactionTypes\Payout; +use UnzerSDK\Resources\TransactionTypes\Sca; use UnzerSDK\Resources\TransactionTypes\Shipment; interface PaymentServiceInterface @@ -389,4 +390,20 @@ public function fetchInstallmentPlans( * @return PaylaterInstallmentPlans */ public function fetchPaylaterInstallmentPlans(InstallmentPlansQuery $plansRequest): PaylaterInstallmentPlans; + + /** + * Perform an SCA transaction. + * + * @param Sca $sca The SCA object. + * @param BasePaymentType|string $paymentType The payment type object or ID. + * @param Customer|string|null $customer The customer object or ID. + * @param Metadata|null $metadata The metadata object. + * @param Basket|null $basket The basket object. + * + * @return Sca The resulting SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function performSca(Sca $sca, $paymentType, $customer = null, ?Metadata $metadata = null, ?Basket $basket = null): Sca; } diff --git a/vendor/unzerdev/php-sdk/src/Interfaces/ResourceServiceInterface.php b/vendor/unzerdev/php-sdk/src/Interfaces/ResourceServiceInterface.php index 6f26b0a..22c752c 100644 --- a/vendor/unzerdev/php-sdk/src/Interfaces/ResourceServiceInterface.php +++ b/vendor/unzerdev/php-sdk/src/Interfaces/ResourceServiceInterface.php @@ -25,6 +25,7 @@ use UnzerSDK\Resources\TransactionTypes\Charge; use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\TransactionTypes\Payout; +use UnzerSDK\Resources\TransactionTypes\Sca; use UnzerSDK\Resources\TransactionTypes\Shipment; interface ResourceServiceInterface @@ -452,4 +453,29 @@ public function fetchShipment($payment, string $shipmentId): Shipment; * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. */ public function fetchConfig(BasePaymentType $paymentType, ?Config $config = null): Config; + + /** + * Fetches an SCA transaction. + * + * @param Sca $sca The SCA object to fetch. + * + * @return Sca The fetched SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function fetchSca(Sca $sca): Sca; + + /** + * Fetches an SCA transaction by payment ID and SCA ID. + * + * @param Payment|string $payment The payment object or payment ID. + * @param string $scaId The SCA transaction ID. + * + * @return Sca The fetched SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function fetchScaById($payment, string $scaId): Sca; } diff --git a/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Address.php b/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Address.php index 48e3b6f..a86a76e 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Address.php +++ b/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Address.php @@ -30,6 +30,9 @@ class Address extends AbstractUnzerResource /** @var string country */ protected $country; + /** @var string company */ + protected $company; + /** @var string|null shippingType */ protected $shippingType; @@ -165,4 +168,15 @@ public function setShippingType(?string $shippingType): Address $this->shippingType = $shippingType; return $this; } + + public function getCompany(): ?string + { + return $this->company; + } + + public function setCompany(?string $company): Address + { + $this->company = $company; + return $this; + } } diff --git a/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Urls.php b/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Urls.php index 5437d33..5796b00 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Urls.php +++ b/vendor/unzerdev/php-sdk/src/Resources/EmbeddedResources/Paypage/Urls.php @@ -11,11 +11,15 @@ class Urls extends AbstractUnzerResource protected ?string $imprint = null; protected ?string $help = null; protected ?string $contact = null; + /** @deprecated Use Style::$favicon instead. + * @see Style::$favicon + */ protected ?string $favicon = null; protected ?string $returnSuccess = null; protected ?string $returnPending = null; protected ?string $returnFailure = null; protected ?string $returnCancel = null; + protected ?string $subscriptionAgreement = null; public function getTermsAndCondition(): ?string { @@ -126,4 +130,15 @@ public function setReturnCancel(?string $returnCancel): Urls $this->returnCancel = $returnCancel; return $this; } + + public function getSubscriptionAgreement(): ?string + { + return $this->subscriptionAgreement; + } + + public function setSubscriptionAgreement(?string $subscriptionAgreement): Urls + { + $this->subscriptionAgreement = $subscriptionAgreement; + return $this; + } } \ No newline at end of file diff --git a/vendor/unzerdev/php-sdk/src/Resources/Payment.php b/vendor/unzerdev/php-sdk/src/Resources/Payment.php index 4a75656..80c49a1 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/Payment.php +++ b/vendor/unzerdev/php-sdk/src/Resources/Payment.php @@ -19,6 +19,7 @@ use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\TransactionTypes\Payout; use UnzerSDK\Resources\TransactionTypes\PreAuthorization; +use UnzerSDK\Resources\TransactionTypes\Sca; use UnzerSDK\Resources\TransactionTypes\Shipment; use UnzerSDK\Services\IdService; use UnzerSDK\Traits\HasInvoiceId; @@ -58,6 +59,9 @@ class Payment extends AbstractUnzerResource /** @var Chargeback[] $chargebacks */ private $chargebacks = []; + /** @var Sca|null $sca */ + private $sca; + /** * Associative array using the ID of the cancellations as the key. @@ -337,6 +341,33 @@ public function getChargeByIndex(int $index, bool $lazy = false) return $resource; } + /** + * Returns the SCA transaction of this Payment. + */ + public function getSca(bool $lazy = false): ?Sca + { + $sca = $this->sca; + if (!$lazy && $sca !== null) { + /** @var Sca */ + return $this->getResource($sca); + } + return $sca; + } + + /** + * Adds an SCA object to this Payment. + * + * @param Sca $sca + * + * @return $this + */ + public function setSca(Sca $sca): self + { + $sca->setPayment($this); + $this->sca = $sca; + return $this; + } + /** * Reference this payment object to the passed Customer resource. * The Customer resource can be passed as Customer object or the Id of a Customer resource. @@ -924,6 +955,9 @@ private function updateResponseTransactions(array $transactions = []): void case TransactionTypes::CHARGEBACK: $this->updateChargebackTransaction($transaction); break; + case TransactionTypes::SCA: + $this->updateScaTransaction($transaction); + break; default: // skip break; @@ -1191,4 +1225,25 @@ private function updateChargebackTransaction(stdClass $transaction): void $chargeback->handleResponse($transaction); } + + /** + * This updates the local SCA object referenced by this Payment with the given SCA transaction + * from the Payment response. + * + * @param stdClass $transaction The transaction from the Payment response containing the SCA data. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + private function updateScaTransaction(stdClass $transaction): void + { + $transactionId = IdService::getResourceIdFromUrl($transaction->url, IdStrings::SCA); + $sca = $this->sca; + if (!$sca instanceof Sca) { + $sca = (new Sca())->setPayment($this)->setId($transactionId); + $this->setSca($sca); + } + + $sca->handleResponse($transaction); + } } diff --git a/vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Giropay.php b/vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Giropay.php index 9d2a6f2..975fea6 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Giropay.php +++ b/vendor/unzerdev/php-sdk/src/Resources/PaymentTypes/Giropay.php @@ -4,6 +4,7 @@ use UnzerSDK\Traits\CanDirectCharge; +/** @deprecated Giropay payment type is no longer supported and will be removed in a future version. */ class Giropay extends BasePaymentType { use CanDirectCharge; diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/AbstractTransactionType.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/AbstractTransactionType.php index 70bd080..c15adfe 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/AbstractTransactionType.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/AbstractTransactionType.php @@ -39,6 +39,9 @@ abstract class AbstractTransactionType extends AbstractUnzerResource use HasAdditionalTransactionData; use HasDate; + /** @var float $amount */ + protected $amount; + /** @var Payment $payment */ private $payment; @@ -242,4 +245,23 @@ protected function handleWeroTransactionData(stdClass $additionalTransactionData $this->setWeroTransactionData($weroTransactionData); } } + + /** + * @param float|null $amount + * + * @return self + */ + public function setAmount(?float $amount): self + { + $this->amount = $amount !== null ? round($amount, 4) : null; + return $this; + } + + /** + * @return float|null + */ + public function getAmount(): ?float + { + return $this->amount; + } } diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Authorization.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Authorization.php index 6936b8b..4df8d11 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Authorization.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Authorization.php @@ -62,25 +62,6 @@ public function __construct(?float $amount = null, ?string $currency = null, ?st $this->setReturnUrl($returnUrl); } - /** - * @return float|null - */ - public function getAmount(): ?float - { - return $this->amount; - } - - /** - * @param float|null $amount - * - * @return self - */ - public function setAmount(?float $amount): self - { - $this->amount = $amount !== null ? round($amount, 4) : null; - return $this; - } - /** * @return float|null */ diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Cancellation.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Cancellation.php index ad41d1c..51f0d86 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Cancellation.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Cancellation.php @@ -16,13 +16,6 @@ */ class Cancellation extends AbstractTransactionType { - /** - * The cancellation amount will be transferred as grossAmount in case of Installment Secured payment type. - * - * @var float $amount - */ - protected $amount; - /** @var string $reasonCode */ protected $reasonCode; @@ -53,29 +46,6 @@ public function __construct(?float $amount = null) $this->setAmount($amount); } - /** - * Returns the cancellationAmount (equals grossAmount in case of Installment Secured). - * - * @return float|null - */ - public function getAmount(): ?float - { - return $this->amount; - } - - /** - * Sets the cancellationAmount (equals grossAmount in case of Installment Secured). - * - * @param float|null $amount - * - * @return Cancellation - */ - public function setAmount(?float $amount): self - { - $this->amount = $amount !== null ? round($amount, 4) : null; - return $this; - } - /** * Returns the reason code of the cancellation if set. * diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Charge.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Charge.php index 278cc9c..338bca7 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Charge.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Charge.php @@ -25,9 +25,6 @@ class Charge extends AbstractTransactionType use HasDescriptor; use HasChargebacks; - /** @var float $amount */ - protected $amount; - /** @var string $currency */ protected $currency; @@ -54,25 +51,6 @@ public function __construct(?float $amount = null, ?string $currency = null, ?st $this->setReturnUrl($returnUrl); } - /** - * @return float|null - */ - public function getAmount(): ?float - { - return $this->amount; - } - - /** - * @param float|null $amount - * - * @return self - */ - public function setAmount(?float $amount): self - { - $this->amount = $amount !== null ? round($amount, 4) : null; - return $this; - } - /** * @return float|null */ diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Chargeback.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Chargeback.php index 2ef22d0..607ebe7 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Chargeback.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Chargeback.php @@ -12,9 +12,6 @@ */ class Chargeback extends AbstractTransactionType { - /** @var float $amount */ - protected $amount; - /** @var string $currency */ protected $currency; @@ -29,27 +26,6 @@ public function __construct(?float $amount = null) $this->setAmount($amount); } - /** - * @return float|null - */ - public function getAmount(): ?float - { - return $this->amount; - } - - /** - * Sets the cancellationAmount (equals grossAmount in case of Installment Secured). - * - * @param float|null $amount - * - * @return Cancellation - */ - public function setAmount(?float $amount): self - { - $this->amount = $amount !== null ? round($amount, 4) : null; - return $this; - } - /** * @return string */ diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Payout.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Payout.php index 15f0767..2f39d5a 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Payout.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Payout.php @@ -12,9 +12,6 @@ */ class Payout extends AbstractTransactionType { - /** @var float|null $amount */ - protected $amount; - /** @var string|null $currency */ protected $currency; @@ -31,25 +28,6 @@ public function __construct(?float $amount = null, ?string $currency = null, $re $this->setReturnUrl($returnUrl); } - /** - * @return float|null - */ - public function getAmount(): ?float - { - return $this->amount; - } - - /** - * @param float|null $amount - * - * @return self - */ - public function setAmount(?float $amount): self - { - $this->amount = $amount !== null ? round($amount, 4) : null; - return $this; - } - /** * @return string|null */ diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Sca.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Sca.php new file mode 100644 index 0000000..b9119d7 --- /dev/null +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Sca.php @@ -0,0 +1,107 @@ +setAmount($amount); + $this->setCurrency($currency); + $this->setReturnUrl($returnUrl); + } + + /** + * @return string|null + */ + public function getCurrency(): ?string + { + return $this->currency; + } + + /** + * @param string|null $currency + * + * @return self + */ + public function setCurrency(?string $currency): self + { + $this->currency = $currency; + return $this; + } + + /** + * @return string|null + */ + public function getReturnUrl(): ?string + { + return $this->returnUrl; + } + + /** + * @param string|null $returnUrl + * + * @return self + */ + public function setReturnUrl(?string $returnUrl): self + { + $this->returnUrl = $returnUrl; + return $this; + } + + /** + * @return string|null + */ + public function getPaymentReference(): ?string + { + return $this->paymentReference; + } + + /** + * @param string|null $referenceText + * + * @return Sca + */ + public function setPaymentReference(?string $referenceText): Sca + { + $this->paymentReference = $referenceText; + return $this; + } + + /** + * {@inheritDoc} + */ + protected function getResourcePath(string $httpMethod = HttpAdapterInterface::REQUEST_GET): string + { + return 'sca'; + } +} diff --git a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Shipment.php b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Shipment.php index 55dfbc7..d29e09c 100644 --- a/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Shipment.php +++ b/vendor/unzerdev/php-sdk/src/Resources/TransactionTypes/Shipment.php @@ -12,28 +12,6 @@ */ class Shipment extends AbstractTransactionType { - /** @var float|null $amount */ - protected $amount; - - /** - * @return float|null - */ - public function getAmount(): ?float - { - return $this->amount; - } - - /** - * @param float|null $amount - * - * @return Shipment - */ - public function setAmount(?float $amount): self - { - $this->amount = $amount !== null ? round($amount, 4) : null; - return $this; - } - /** * {@inheritDoc} */ diff --git a/vendor/unzerdev/php-sdk/src/Services/HttpService.php b/vendor/unzerdev/php-sdk/src/Services/HttpService.php index cce644c..68bcdc0 100644 --- a/vendor/unzerdev/php-sdk/src/Services/HttpService.php +++ b/vendor/unzerdev/php-sdk/src/Services/HttpService.php @@ -135,7 +135,6 @@ public function sendRequest(ApiRequest $request): string $httpAdapter = $this->getAdapter(); $response = $httpAdapter->execute(); $responseCode = $httpAdapter->getResponseCode(); - $httpAdapter->close(); // handle response try { diff --git a/vendor/unzerdev/php-sdk/src/Services/PaymentService.php b/vendor/unzerdev/php-sdk/src/Services/PaymentService.php index 8eefc35..e05dd4c 100644 --- a/vendor/unzerdev/php-sdk/src/Services/PaymentService.php +++ b/vendor/unzerdev/php-sdk/src/Services/PaymentService.php @@ -22,6 +22,7 @@ use UnzerSDK\Resources\TransactionTypes\Authorization; use UnzerSDK\Resources\TransactionTypes\Charge; use UnzerSDK\Resources\TransactionTypes\Payout; +use UnzerSDK\Resources\TransactionTypes\Sca; use UnzerSDK\Resources\TransactionTypes\Shipment; use UnzerSDK\Unzer; @@ -87,7 +88,10 @@ public function performAuthorization( $paymentType = $payment->getPaymentType(); $authorization->setSpecialParams($paymentType !== null ? $paymentType->getTransactionParams() : []); - $payment->setAuthorization($authorization)->setCustomer($customer)->setMetadata($metadata)->setBasket($basket); + $payment->setAuthorization($authorization) + ->setCustomer($customer) + ->setMetadata($metadata) + ->setBasket($basket); $this->getResourceService()->createResource($authorization); return $authorization; @@ -392,4 +396,32 @@ private function createPayment($paymentType): AbstractUnzerResource { return (new Payment($this->unzer))->setPaymentType($paymentType); } + + /** + * Perform an SCA transaction. + * + * @param Sca $sca The SCA object to be executed. + * @param BasePaymentType|string $paymentType The payment type object or its ID. + * @param Customer|string|null $customer The customer object or ID. + * @param Metadata|null $metadata The metadata object. + * @param Basket|null $basket The basket object. + * + * @return Sca The resulting SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function performSca(Sca $sca, $paymentType, $customer = null, ?Metadata $metadata = null, ?Basket $basket = null): Sca + { + $payment = $this->createPayment($paymentType); + $paymentType = $payment->getPaymentType(); + + /** @var Sca $sca */ + $sca->setSpecialParams($paymentType->getTransactionParams() ?? []); + $payment->setSca($sca)->setCustomer($customer)->setMetadata($metadata)->setBasket($basket); + + $this->getResourceService()->createResource($sca); + + return $sca; + } } diff --git a/vendor/unzerdev/php-sdk/src/Services/ResourceService.php b/vendor/unzerdev/php-sdk/src/Services/ResourceService.php index b4bedfe..90b0957 100644 --- a/vendor/unzerdev/php-sdk/src/Services/ResourceService.php +++ b/vendor/unzerdev/php-sdk/src/Services/ResourceService.php @@ -59,6 +59,7 @@ use UnzerSDK\Resources\TransactionTypes\Charge; use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\TransactionTypes\Payout; +use UnzerSDK\Resources\TransactionTypes\Sca; use UnzerSDK\Resources\TransactionTypes\Shipment; use UnzerSDK\Resources\V2\Customer as CustomerV2; use UnzerSDK\Resources\V2\Paypage as PaypageV2; @@ -209,9 +210,25 @@ public function fetchResourceByUrl($url) } $resource = $unzer->fetchReversal($paymentId, $resourceId); break; + case $resourceType === IdStrings::CHARGEBACK: + $paymentId = IdService::getResourceIdFromUrl($url, IdStrings::PAYMENT); + $chargeId = IdService::getResourceIdOrNullFromUrl($url, IdStrings::CHARGE); + + $resource = $this->fetchChargebackById( + $paymentId, + $resourceId, + $chargeId + ); + break; case $resourceType === IdStrings::PAYOUT: $resource = $unzer->fetchPayout(IdService::getResourceIdFromUrl($url, IdStrings::PAYMENT)); break; + case $resourceType === IdStrings::SCA: + $resource = $unzer->fetchScaById( + IdService::getResourceIdFromUrl($url, IdStrings::PAYMENT), + $resourceId + ); + break; case $resourceType === IdStrings::PAYMENT: $resource = $unzer->fetchPayment($resourceId); break; @@ -970,4 +987,44 @@ public static function getTypeInstanceFromIdString($typeId): BasePaymentType } return $paymentType; } + + /** + * Fetches an SCA transaction. + * + * @param Sca $sca The SCA object to fetch. + * + * @return Sca The fetched SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function fetchSca(Sca $sca): Sca + { + $this->fetchResource($sca); + return $sca; + } + + /** + * Fetches an SCA transaction by payment ID and SCA ID. + * + * @param Payment|string $payment The payment object or payment ID. + * @param string $scaId The SCA transaction ID. + * + * @return Sca The fetched SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function fetchScaById($payment, string $scaId): Sca + { + $paymentObject = $this->fetchPayment($payment); + $sca = $paymentObject->getSca($scaId, true); + + if (!$sca instanceof Sca) { + throw new RuntimeException('The SCA object could not be found.'); + } + + $this->fetchResource($sca); + return $sca; + } } diff --git a/vendor/unzerdev/php-sdk/src/Unzer.php b/vendor/unzerdev/php-sdk/src/Unzer.php index b4dc186..b34caf1 100644 --- a/vendor/unzerdev/php-sdk/src/Unzer.php +++ b/vendor/unzerdev/php-sdk/src/Unzer.php @@ -33,6 +33,7 @@ use UnzerSDK\Resources\TransactionTypes\Charge; use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\TransactionTypes\Payout; +use UnzerSDK\Resources\TransactionTypes\Sca; use UnzerSDK\Resources\TransactionTypes\Shipment; use UnzerSDK\Resources\V2\Paypage as PaypageV2; use UnzerSDK\Resources\Webhook; @@ -43,6 +44,7 @@ use UnzerSDK\Services\ResourceService; use UnzerSDK\Services\WebhookService; use UnzerSDK\Validators\PrivateKeyValidator; +use UnzerSDK\Validators\PublicKeyValidator; /** * This is the Unzer object which is the base object providing all functionalities needed to @@ -58,7 +60,7 @@ class Unzer implements public const BASE_URL = 'api.unzer.com'; public const API_VERSION = ApiVersions::V1; public const SDK_TYPE = 'UnzerPHP'; - public const SDK_VERSION = '3.13.1'; + public const SDK_VERSION = '4.0.1'; /** @var string $key */ private $key; @@ -94,10 +96,10 @@ class Unzer implements /** * Construct a new Unzer object. * - * @param string $key The private key your received from your Unzer contact person. + * @param string $key The private or public key your received from your Unzer contact person. * @param string|null $locale The locale of the customer defining defining the translation (e.g. 'en-GB' or 'de-DE'). * - * @throws RuntimeException A RuntimeException will be thrown if the key is not of type private. + * @throws RuntimeException A RuntimeException will be thrown if the key is not a valid private or public key. * * @link https://docs.unzer.com/integrate/web-integration/#section-localization-and-languages * @@ -115,7 +117,7 @@ public function __construct(string $key, ?string $locale = '') } /** - * Returns the set private key used to connect to the API. + * Returns the set key used to connect to the API. * * @return string The key that is currently set. */ @@ -125,9 +127,9 @@ public function getKey(): string } /** - * Sets your private key used to connect to the API. + * Sets your private or public key used to connect to the API. * - * @param string $key The private key. + * @param string $key The private or public key. * * @return Unzer This Unzer object. * @@ -137,8 +139,8 @@ public function getKey(): string */ public function setKey(string $key): Unzer { - if (!PrivateKeyValidator::validate($key)) { - throw new RuntimeException('Illegal key: Use a valid private key with this SDK!'); + if (!PrivateKeyValidator::validate($key) && !PublicKeyValidator::validate($key)) { + throw new RuntimeException('Illegal key: Use a valid private or public key with this SDK!'); } $this->key = $key; @@ -812,6 +814,146 @@ public function performChargeOnPayment($payment, Charge $charge): Charge return $this->paymentService->performChargeOnPayment($payment, $charge); } + /** + * Perform an SCA transaction. + * + * @param Sca $sca The SCA object. + * @param BasePaymentType|string $paymentType The payment type object or ID. + * @param Customer|string|null $customer The customer object or ID. + * @param Metadata|null $metadata The metadata object. + * @param Basket|null $basket The basket object. + * + * @return Sca The resulting SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function performSca(Sca $sca, $paymentType, $customer = null, ?Metadata $metadata = null, ?Basket $basket = null): Sca + { + return $this->paymentService->performSca($sca, $paymentType, $customer, $metadata, $basket); + } + + /** + * Fetch an SCA transaction. + * + * @param Sca $sca The SCA object to fetch. + * + * @return Sca The fetched SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function fetchSca(Sca $sca): Sca + { + return $this->resourceService->fetchSca($sca); + } + + /** + * Fetch an SCA transaction by payment ID and SCA ID. + * + * @param Payment|string $payment The payment object or payment ID. + * @param string $scaId The SCA transaction ID. + * + * @return Sca The fetched SCA object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function fetchScaById($payment, string $scaId): Sca + { + return $this->resourceService->fetchScaById($payment, $scaId); + } + + /** + * Charge an SCA transaction. + * + * @param Payment|string $payment The payment object or payment ID. + * @param Charge $charge The Charge object to process. + * @param Customer|string|null $customer The customer object or customer ID. + * @param Metadata|null $metadata The metadata object. + * @param Basket|null $basket The basket object. + * + * @return Charge The resulting Charge object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function chargeScaTransaction( + $payment, + Charge $charge, + $customer = null, + ?Metadata $metadata = null, + ?Basket $basket = null): Charge + { + $paymentObject = $this->resourceService->getPaymentResource($payment); + $sca = $paymentObject->getSca(true); + + if (!$sca instanceof Sca) { + throw new RuntimeException('SCA transaction not found.'); + } + + // Set Sca object without id as a parent to match the URI path. + $scaParent = new Sca(); + $scaParent->setParentResource($paymentObject); + + $paymentObject->addCharge($charge) + ->setCustomer($customer) + ->setMetadata($metadata) + ->setBasket($basket); + + $charge->setPayment($paymentObject); + $charge->setParentResource($scaParent); + + $this->resourceService->createResource($charge); + + return $charge; + } + + /** + * Authorize an SCA transaction. + * + * @param Payment|string $payment The payment object or payment ID. + * @param Authorization $authorization The Authorization object to process. + * @param Customer|string|null $customer The customer object or customer ID. + * @param Metadata|null $metadata The metadata object. + * @param Basket|null $basket The basket object. + * + * @return Authorization The resulting Authorization object. + * + * @throws UnzerApiException An UnzerApiException is thrown if there is an error returned on API-request. + * @throws RuntimeException A RuntimeException is thrown when there is an error while using the SDK. + */ + public function authorizeScaTransaction( + $payment, + Authorization $authorization, + $customer = null, + ?Metadata $metadata = null, + ?Basket $basket = null): Authorization + { + $paymentObject = $this->resourceService->getPaymentResource($payment); + $sca = $paymentObject->getSca(true); + + if (!$sca instanceof Sca) { + throw new RuntimeException('SCA transaction not found.'); + } + + // Set Sca object without id as a parent to match the URI path. + $scaParent = new Sca(); + $scaParent->setParentResource($paymentObject); + + $paymentObject->setAuthorization($authorization) + ->setCustomer($customer) + ->setMetadata($metadata) + ->setBasket($basket); + + $authorization->setPayment($paymentObject); + $authorization->setParentResource($scaParent); + + $this->resourceService->createResource($authorization); + + return $authorization; + } + /** * {@inheritDoc} */ diff --git a/vendor/unzerdev/php-sdk/test/Fixtures/CustomerFixtureTrait.php b/vendor/unzerdev/php-sdk/test/Fixtures/CustomerFixtureTrait.php index 6055e81..5fe4ca2 100644 --- a/vendor/unzerdev/php-sdk/test/Fixtures/CustomerFixtureTrait.php +++ b/vendor/unzerdev/php-sdk/test/Fixtures/CustomerFixtureTrait.php @@ -153,6 +153,7 @@ public function getBillingAddress(): Address ->setZip('60386') ->setCity('Frankfurt am Main') ->setCountry('DE') + ->setCompany('Your Company Name') ->setState('DE-BO'); } @@ -170,6 +171,7 @@ public function getShippingAddress(): Address ->setCity('Frankfurt am Main') ->setCountry('DE') ->setState('DE-BO') + ->setCompany('Your Company Name') ->setShippingType(ShippingTypes::EQUALS_BILLING); } } diff --git a/vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaPaymentResponse.json b/vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaPaymentResponse.json new file mode 100644 index 0000000..f897f5a --- /dev/null +++ b/vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaPaymentResponse.json @@ -0,0 +1,33 @@ +{ + "id": "s-sca-1", + "isSuccess": true, + "isPending": false, + "isResumed": false, + "isError": false, + "card3ds": true, + "redirectUrl": "", + "message": { + "code": "COR.000.100.200", + "merchant": "Transaction succeeded", + "customer": "Your payments have been successfully processed." + }, + "amount": "119.0000", + "currency": "EUR", + "date": "2023-02-28 08:00:00", + "resources": { + "customerId": "", + "paymentId": "s-pay-123", + "basketId": "", + "metadataId": "", + "payPageId": "", + "traceId": "trace-123", + "typeId": "s-crd-123" + }, + "paymentReference": "", + "processing": { + "uniqueId": "31HA0xyz", + "shortId": "1234.1234.1234", + "3dsEci": "3DS_SUCCESS", + "traceId": "trace-123" + } +} \ No newline at end of file diff --git a/vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaResponse.json b/vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaResponse.json new file mode 100644 index 0000000..f897f5a --- /dev/null +++ b/vendor/unzerdev/php-sdk/test/Fixtures/jsonData/scaResponse.json @@ -0,0 +1,33 @@ +{ + "id": "s-sca-1", + "isSuccess": true, + "isPending": false, + "isResumed": false, + "isError": false, + "card3ds": true, + "redirectUrl": "", + "message": { + "code": "COR.000.100.200", + "merchant": "Transaction succeeded", + "customer": "Your payments have been successfully processed." + }, + "amount": "119.0000", + "currency": "EUR", + "date": "2023-02-28 08:00:00", + "resources": { + "customerId": "", + "paymentId": "s-pay-123", + "basketId": "", + "metadataId": "", + "payPageId": "", + "traceId": "trace-123", + "typeId": "s-crd-123" + }, + "paymentReference": "", + "processing": { + "uniqueId": "31HA0xyz", + "shortId": "1234.1234.1234", + "3dsEci": "3DS_SUCCESS", + "traceId": "trace-123" + } +} \ No newline at end of file diff --git a/vendor/unzerdev/php-sdk/test/Helper/TestEnvironmentService.php b/vendor/unzerdev/php-sdk/test/Helper/TestEnvironmentService.php index 755eaa5..5267475 100644 --- a/vendor/unzerdev/php-sdk/test/Helper/TestEnvironmentService.php +++ b/vendor/unzerdev/php-sdk/test/Helper/TestEnvironmentService.php @@ -16,6 +16,10 @@ class TestEnvironmentService extends EnvironmentService public const ENV_VAR_TEST_PRIVATE_KEY_DEFAULT = 'UNZER_PAPI_TEST_PRIVATE_KEY_DEFAULT'; public const ENV_VAR_TEST_PUBLIC_KEY_DEFAULT = 'UNZER_PAPI_TEST_PUBLIC_KEY_DEFAULT'; + /** Primary testing Keypair used as default for most payment types. */ + public const ENV_VAR_TEST_PRIVATE_KEY_UNZER_ONE = 'UNZER_PAPI_TEST_PRIVATE_KEY_UNZER_ONE'; + public const ENV_VAR_TEST_PUBLIC_KEY_UNZER_ONE = 'UNZER_PAPI_TEST_PUBLIC_KEY_UNZER_ONE'; + /** Secondary keypair mainly used for payment methods that need a second configuration to be tested. */ public const ENV_VAR_TEST_PRIVATE_KEY_ALTERNATIVE = 'UNZER_PAPI_TEST_PRIVATE_KEY_ALTERNATIVE'; public const ENV_VAR_TEST_PUBLIC_KEY_ALTERNATIVE = 'UNZER_PAPI_TEST_PUBLIC_KEY_ALTERNATIVE'; @@ -106,4 +110,9 @@ public static function getLegacyTestPrivateKey(): string { return stripslashes($_SERVER[self::ENV_VAR_TEST_PRIVATE_KEY_LEGACY] ?? ''); } + + public static function getUnzerOneTestPrivateKey(): string + { + return stripslashes($_SERVER[self::ENV_VAR_TEST_PRIVATE_KEY_UNZER_ONE] ?? ''); + } } diff --git a/vendor/unzerdev/php-sdk/test/integration/PaymentTypes/GiropayTest.php b/vendor/unzerdev/php-sdk/test/integration/PaymentTypes/GiropayTest.php deleted file mode 100644 index c6b5351..0000000 --- a/vendor/unzerdev/php-sdk/test/integration/PaymentTypes/GiropayTest.php +++ /dev/null @@ -1,79 +0,0 @@ -unzer->createPaymentType($giropay); - $this->assertInstanceOf(Giropay::class, $giropay); - $this->assertNotNull($giropay->getId()); - } - - /** - * Verify that an exception is thrown when giropay authorize is called. - * - * @test - */ - public function giroPayShouldThrowExceptionOnAuthorize(): void - { - $this->expectException(UnzerApiException::class); - $this->expectExceptionCode(ApiResponseCodes::API_ERROR_TRANSACTION_AUTHORIZE_NOT_ALLOWED); - - $giropay = $this->unzer->createPaymentType(new Giropay()); - $this->unzer->authorize(1.0, 'EUR', $giropay, self::RETURN_URL); - } - - /** - * Verify that GiroPay is chargeable. - * - * @test - */ - public function giroPayShouldBeChargeable(): void - { - /** @var Giropay $giropay */ - $giropay = $this->unzer->createPaymentType(new Giropay()); - $charge = $giropay->charge(1.0, 'EUR', self::RETURN_URL); - $this->assertNotNull($charge); - $this->assertNotNull($charge->getId()); - $this->assertNotEmpty($charge->getRedirectUrl()); - - $fetchCharge = $this->unzer->fetchChargeById($charge->getPayment()->getId(), $charge->getId()); - $this->assertEquals($charge->setCard3ds(false)->expose(), $fetchCharge->expose()); - } - - /** - * Verify a GiroPay object can be fetched from the api. - * - * @test - */ - public function giroPayCanBeFetched(): void - { - $giropay = $this->unzer->createPaymentType(new Giropay()); - $fetchedGiropay = $this->unzer->fetchPaymentType($giropay->getId()); - $this->assertInstanceOf(Giropay::class, $fetchedGiropay); - $this->assertEquals($giropay->getId(), $fetchedGiropay->getId()); - } -} diff --git a/vendor/unzerdev/php-sdk/test/integration/Resources/PaypageV2Test.php b/vendor/unzerdev/php-sdk/test/integration/Resources/PaypageV2Test.php index 18ca4ac..73c4fd0 100644 --- a/vendor/unzerdev/php-sdk/test/integration/Resources/PaypageV2Test.php +++ b/vendor/unzerdev/php-sdk/test/integration/Resources/PaypageV2Test.php @@ -146,7 +146,6 @@ public function createPaypageWithOptionalStringProperties() /** * @test - * @group skip */ public function createPaypageWithUrls() { @@ -156,11 +155,11 @@ public function createPaypageWithUrls() $urls->setImprint('https://imprint.com'); $urls->setHelp('https://help.com'); $urls->setContact('https://contact.com'); - $urls->setFavicon('https://favicon.com'); $urls->setReturnSuccess('https://returnsuccess.com'); $urls->setReturnPending('https://returnpending.com'); $urls->setReturnFailure('https://returnfailure.com'); $urls->setReturnCancel('https://returncancel.com'); + $urls->setSubscriptionAgreement('https://subscriptionagreement.com'); $paypage = new Paypage(9.99, 'EUR', 'charge'); $paypage->setUrls($urls); diff --git a/vendor/unzerdev/php-sdk/test/integration/TransactionTypes/ScaTest.php b/vendor/unzerdev/php-sdk/test/integration/TransactionTypes/ScaTest.php new file mode 100644 index 0000000..1e76cc4 --- /dev/null +++ b/vendor/unzerdev/php-sdk/test/integration/TransactionTypes/ScaTest.php @@ -0,0 +1,191 @@ +getUnzerObject(TestEnvironmentService::getUnzerOneTestPrivateKey()); + } + /** + * Verify SCA transaction can be performed using the id of a payment type. + * + * @test + */ + public function scaShouldWorkWithTypeId(): Sca + { + /** @var Card $paymentType */ + $paymentType = $this->unzer->createPaymentType($this->createCardObject()); + $sca = new Sca(100.0, 'EUR', self::RETURN_URL); + $sca = $this->unzer->performSca($sca, $paymentType->getId()); + + $this->assertTransactionResourceHasBeenCreated($sca); + $this->assertInstanceOf(Payment::class, $sca->getPayment()); + $this->assertNotEmpty($sca->getPayment()->getId()); + $this->assertEquals(self::RETURN_URL, $sca->getReturnUrl()); + + return $sca; + } + + /** + * Verify SCA transaction can be performed with payment type object. + * + * @test + */ + public function scaShouldWorkWithTypeObject(): Sca + { + /** @var Card $paymentType */ + $paymentType = $this->unzer->createPaymentType($this->createCardObject()); + $sca = new Sca(100.0, 'EUR', self::RETURN_URL); + $sca = $this->unzer->performSca($sca, $paymentType); + + $this->assertTransactionResourceHasBeenCreated($sca); + $this->assertInstanceOf(Payment::class, $sca->getPayment()); + $this->assertNotEmpty($sca->getPayment()->getId()); + $this->assertEquals(self::RETURN_URL, $sca->getReturnUrl()); + + return $sca; + } + + /** + * Verify SCA transaction accepts all parameters. + * + * @test + */ + public function scaShouldAcceptAllParameters(): Sca + { + // prepare test data + /** @var Card $paymentType */ + $paymentType = $this->unzer->createPaymentType($this->createCardObject()); + $customer = $this->getMinimalCustomer(); + $metadata = (new Metadata())->addMetadata('key', 'value'); + $basket = $this->createBasket(); + $paymentReference = 'scaPaymentReference'; + + // perform request + $sca = new Sca(119.0, 'EUR', self::RETURN_URL); + $sca->setPaymentReference($paymentReference); + + $sca = $this->unzer->performSca($sca, $paymentType, $customer, $metadata, $basket); + + // verify the data sent and received match + $payment = $sca->getPayment(); + $this->assertSame($paymentType, $payment->getPaymentType()); + $this->assertEquals(119.0, $sca->getAmount()); + $this->assertEquals('EUR', $sca->getCurrency()); + $this->assertEquals(self::RETURN_URL, $sca->getReturnUrl()); + $this->assertSame($customer, $payment->getCustomer()); + $this->assertSame($metadata, $payment->getMetadata()); + $this->assertSame($basket, $payment->getBasket()); + $this->assertEquals($paymentReference, $sca->getPaymentReference()); + + return $sca; + } + + /** + * Verify SCA transaction can be fetched. + * + * @test + * @depends scaShouldWorkWithTypeId + */ + public function scaTransactionCanBeFetched($sca): void + { + $this->assertTransactionResourceHasBeenCreated($sca); + + // Fetch the SCA transaction + $fetchedSca = $this->unzer->fetchScaById($sca->getPaymentId(), $sca->getId()); + + // Verify the fetched transaction matches the initial transaction + $this->assertEquals($sca->getId(), $fetchedSca->getId()); + $this->assertEquals($sca->getPaymentId(), $fetchedSca->getPaymentId()); + $this->assertEquals($sca->getAmount(), $fetchedSca->getAmount()); + $this->assertEquals($sca->getCurrency(), $fetchedSca->getCurrency()); + } + + /** + * Verify SCA transaction can be fetched using Sca object. + * + * @test + * + * @depends scaShouldWorkWithTypeId + */ + public function scaTransactionCanBeFetchedUsingSca($sca): void + { + $this->assertTransactionResourceHasBeenCreated($sca); + + // Fetch the SCA transaction using the Sca object + $fetchedSca = $this->unzer->fetchSca($sca); + + // Verify the fetched transaction matches the initial transaction + $this->assertEquals($sca->getId(), $fetchedSca->getId()); + $this->assertEquals($sca->getAmount(), $fetchedSca->getAmount()); + $this->assertEquals($sca->getCurrency(), $fetchedSca->getCurrency()); + } + + /** + * Verify charge can be performed on SCA transaction. + * + * @test + * + * @depends scaShouldWorkWithTypeId + */ + public function chargeFailsOnPendingSCATransactionWithErrorCode($sca): void + { + $charge = new Charge(100, "EUR"); + + // Expect charge to fail on pending transaction with error code + $this->expectException(UnzerApiException::class); + $this->expectExceptionCode(ApiResponseCodes::API_CANNOT_CHARGE_UNSUCCESSFUL_SCA_TRANSACTION); + $this->expectExceptionMessage('Cannot perform payment on an unsuccessful strong customer authentication.'); + + $this->unzer->chargeScaTransaction($sca->getPayment(), $charge); + } + + /** + * Verify authorize can be performed on SCA transaction. + * + * @test + * + * @depends scaShouldWorkWithTypeObject + */ + public function authorizeCanBePerformedOnScaTransaction($sca): void + { + $authorization = new Authorization(100, "EUR"); + + // Expect authorization to fail on pending transaction with error code + $this->expectException(UnzerApiException::class); + $this->expectExceptionCode(ApiResponseCodes::API_CANNOT_CHARGE_UNSUCCESSFUL_SCA_TRANSACTION); + $this->expectExceptionMessage('Cannot perform payment on an unsuccessful strong customer authentication.'); + + // Perform an authorize on SCA transaction + $authorization = $this->unzer->authorizeScaTransaction($sca->getPayment(), $authorization); + } +} diff --git a/vendor/unzerdev/php-sdk/test/integration/WebhookTest.php b/vendor/unzerdev/php-sdk/test/integration/WebhookTest.php index beeb0f5..bdae8ad 100644 --- a/vendor/unzerdev/php-sdk/test/integration/WebhookTest.php +++ b/vendor/unzerdev/php-sdk/test/integration/WebhookTest.php @@ -14,6 +14,7 @@ use UnzerSDK\Constants\ApiResponseCodes; use UnzerSDK\Constants\WebhookEvents; use UnzerSDK\Exceptions\UnzerApiException; +use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\Webhook; use UnzerSDK\test\BaseIntegrationTest; use function count; @@ -22,6 +23,7 @@ class WebhookTest extends BaseIntegrationTest { // + const CHARGEDBACK_PAYMENT_ID = 's-pay-341196'; /** * Verify Webhook resource can be registered and fetched. @@ -221,6 +223,27 @@ public function bulkSettingOnlyOneWebhookShouldBePossible(): void $this->assertEquals($url, $webhook->getUrl()); } + /** + * @test + */ + public function testFetchResourceFromEvent(): void + { + $webhookNotification = [ + 'event' => 'chargebacks', + 'publicKey' => 's-pub-xyz', + 'retrieveUrl' => 'https://sbx-api.unzer.com/v1/payments/' . self::CHARGEDBACK_PAYMENT_ID . '/charges/s-chg-1/chargebacks/s-cbk-1', + 'paymentId' => self::CHARGEDBACK_PAYMENT_ID + ]; + + // when + $chargeback = $this->unzer->fetchResourceFromEvent(json_encode($webhookNotification)); + + // then + $this->assertInstanceOf(Chargeback::class, $chargeback); + $this->assertNotNull($chargeback); + $this->assertEquals('s-cbk-1', $chargeback->getId()); + } + // // diff --git a/vendor/unzerdev/php-sdk/test/unit/Resources/CustomerTest.php b/vendor/unzerdev/php-sdk/test/unit/Resources/CustomerTest.php index 0f11b1f..7b17d3c 100644 --- a/vendor/unzerdev/php-sdk/test/unit/Resources/CustomerTest.php +++ b/vendor/unzerdev/php-sdk/test/unit/Resources/CustomerTest.php @@ -14,15 +14,15 @@ use UnzerSDK\Constants\CompanyCommercialSectorItems; use UnzerSDK\Constants\CompanyRegistrationTypes; use UnzerSDK\Constants\Salutations; -use UnzerSDK\Resources\EmbeddedResources\CompanyOwner; -use UnzerSDK\Unzer; use UnzerSDK\Interfaces\ResourceServiceInterface; use UnzerSDK\Resources\Customer; use UnzerSDK\Resources\EmbeddedResources\Address; use UnzerSDK\Resources\EmbeddedResources\CompanyInfo; +use UnzerSDK\Resources\EmbeddedResources\CompanyOwner; use UnzerSDK\Resources\EmbeddedResources\GeoLocation; use UnzerSDK\Services\ResourceService; use UnzerSDK\test\BasePaymentTest; +use UnzerSDK\Unzer; class CustomerTest extends BasePaymentTest { @@ -121,6 +121,7 @@ public function settersAndGettersOfShippingAddressShouldWork(): void ->setCity('shipping_city') ->setZip('shipping_zip') ->setStreet('shipping_street') + ->setCompany('shipping_company') ->setShippingType('shipping_type'); $customer = new Customer(); @@ -132,6 +133,7 @@ public function settersAndGettersOfShippingAddressShouldWork(): void $this->assertNull($shippingAddress->getZip()); $this->assertNull($shippingAddress->getStreet()); $this->assertNull($shippingAddress->getShippingType()); + $this->assertNull($shippingAddress->getCompany()); $customer->setShippingAddress($address); $shippingAddress = $customer->getShippingAddress(); @@ -142,6 +144,7 @@ public function settersAndGettersOfShippingAddressShouldWork(): void $this->assertEquals('shipping_zip', $shippingAddress->getZip()); $this->assertEquals('shipping_street', $shippingAddress->getStreet()); $this->assertEquals('shipping_type', $shippingAddress->getShippingType()); + $this->assertEquals('shipping_company', $shippingAddress->getCompany()); } /** diff --git a/vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/ScaTest.php b/vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/ScaTest.php new file mode 100644 index 0000000..40ee6e5 --- /dev/null +++ b/vendor/unzerdev/php-sdk/test/unit/Resources/TransactionTypes/ScaTest.php @@ -0,0 +1,42 @@ +assertEquals(99.99, $sca->getAmount()); + $this->assertEquals("EUR", $sca->getCurrency()); + $this->assertEquals("https://return-url.com", $sca->getReturnUrl()); + } + + /** + * @test + */ + public function getterSetterTest() + { + $sca = new Sca(99.99, "EUR", "https://return-url.com"); + $sca->setPaymentReference('reference'); + $this->assertEquals(99.99, $sca->getAmount()); + $this->assertEquals("EUR", $sca->getCurrency()); + $this->assertEquals("reference", $sca->getPaymentReference()); + $this->assertEquals("https://return-url.com", $sca->getReturnUrl()); + } +} diff --git a/vendor/unzerdev/php-sdk/test/unit/Services/CancelServiceTest.php b/vendor/unzerdev/php-sdk/test/unit/Services/CancelServiceTest.php index 8b56bfd..a2a6ab6 100644 --- a/vendor/unzerdev/php-sdk/test/unit/Services/CancelServiceTest.php +++ b/vendor/unzerdev/php-sdk/test/unit/Services/CancelServiceTest.php @@ -11,6 +11,7 @@ namespace UnzerSDK\test\unit\Services; +use PHPUnit\Framework\MockObject\MockObject; use UnzerSDK\Constants\ApiResponseCodes; use UnzerSDK\Exceptions\UnzerApiException; use UnzerSDK\Resources\EmbeddedResources\Amount; @@ -24,7 +25,6 @@ use UnzerSDK\Services\CancelService; use UnzerSDK\Services\ResourceService; use UnzerSDK\test\BasePaymentTest; -use PHPUnit\Framework\MockObject\MockObject; class CancelServiceTest extends BasePaymentTest { @@ -119,7 +119,6 @@ public function maxCancelAmountShouldBeRoundedCorrectly(): void $cancelSrvMock = new CancelService($this->unzer); $reflection = new \ReflectionClass(get_class($cancelSrvMock)); $method = $reflection->getMethod('calculateMaxReversalAmount'); - $method->setAccessible(true); $chargeAmount = 12.3; $receiptAmount = 10.0; diff --git a/vendor/unzerdev/php-sdk/test/unit/Services/DummyAdapter.php b/vendor/unzerdev/php-sdk/test/unit/Services/DummyAdapter.php index a377870..7ed18f2 100644 --- a/vendor/unzerdev/php-sdk/test/unit/Services/DummyAdapter.php +++ b/vendor/unzerdev/php-sdk/test/unit/Services/DummyAdapter.php @@ -39,14 +39,6 @@ public function getResponseCode(): string return 'responseCode'; } - /** - * {@inheritDoc} - */ - public function close(): void - { - // do nothing - } - /** * {@inheritDoc} */ diff --git a/vendor/unzerdev/php-sdk/test/unit/Services/HttpServiceTest.php b/vendor/unzerdev/php-sdk/test/unit/Services/HttpServiceTest.php index 8892f32..816b43f 100644 --- a/vendor/unzerdev/php-sdk/test/unit/Services/HttpServiceTest.php +++ b/vendor/unzerdev/php-sdk/test/unit/Services/HttpServiceTest.php @@ -112,7 +112,6 @@ static function ($url) { $adapterMock->expects($this->once())->method('setHeaders')->with($headers); $adapterMock->expects($this->once())->method('execute')->willReturn('myResponseString'); $adapterMock->expects($this->once())->method('getResponseCode')->willReturn('399'); - $adapterMock->expects($this->once())->method('close'); $httpServiceMock->method('getAdapter')->willReturn($adapterMock); diff --git a/vendor/unzerdev/php-sdk/test/unit/Services/ResourceServiceTest.php b/vendor/unzerdev/php-sdk/test/unit/Services/ResourceServiceTest.php index 1bcc708..6cb6de5 100644 --- a/vendor/unzerdev/php-sdk/test/unit/Services/ResourceServiceTest.php +++ b/vendor/unzerdev/php-sdk/test/unit/Services/ResourceServiceTest.php @@ -1391,7 +1391,8 @@ public function fetchResourceByUrlShouldFetchTheDesiredResourceDP(): array 'v2Customer' => ['fetchCustomer', ['s-cst-123e4567-e89b-12d3-a456-426614174000'], 'https://api.unzer.com/v2/customers/s-cst-123e4567-e89b-12d3-a456-426614174000'], 'v1Basket' => ['fetchBasket', ['s-bsk-1254'], 'https://api.unzer.com/v1/baskets/s-bsk-1254/'], 'v2Basket' => ['fetchBasket', ['s-bsk-1254'], 'https://api.unzer.com/v2/baskets/s-bsk-1254/'], - 'Payout' => ['fetchPayout', ['s-pay-100746'], 'https://api.unzer.com/v1/payments/s-pay-100746/payout/s-out-1/'] + 'Payout' => ['fetchPayout', ['s-pay-100746'], 'https://api.unzer.com/v1/payments/s-pay-100746/payout/s-out-1/'], + 'Sca' => ['fetchScaById', ['s-pay-100746', 's-sca-1'], 'https://api.unzer.com/v1/payments/s-pay-100746/sca/s-sca-1/'] ]; } diff --git a/vendor/unzerdev/php-sdk/test/unit/Services/WebhooksServiceTest.php b/vendor/unzerdev/php-sdk/test/unit/Services/WebhooksServiceTest.php index b21f940..df5519c 100644 --- a/vendor/unzerdev/php-sdk/test/unit/Services/WebhooksServiceTest.php +++ b/vendor/unzerdev/php-sdk/test/unit/Services/WebhooksServiceTest.php @@ -11,16 +11,18 @@ namespace UnzerSDK\test\unit\Services; -use UnzerSDK\Unzer; +use RuntimeException; +use stdClass; use UnzerSDK\Interfaces\ResourceServiceInterface; +use UnzerSDK\Resources\TransactionTypes\Charge; +use UnzerSDK\Resources\TransactionTypes\Chargeback; use UnzerSDK\Resources\Webhook; use UnzerSDK\Resources\Webhooks; use UnzerSDK\Services\ResourceService; use UnzerSDK\Services\WebhookService; use UnzerSDK\test\BasePaymentTest; use UnzerSDK\test\unit\DummyResource; -use RuntimeException; -use stdClass; +use UnzerSDK\Unzer; class WebhooksServiceTest extends BasePaymentTest { @@ -328,6 +330,54 @@ public function fetchResourceByEventWithEmptyRetrieveUrlShouldThrowException(): $webhookService->fetchResourceFromEvent(); } + /** + * Verify that a chargeback is returned from a webhook event. + * + * @test + */ + public function fetchChargebackByEventShouldReturnChargeback(): void + { + // given + $unzer = new Unzer('s-priv-1234'); + $webhookService = new WebhookService($unzer); + + $paymentId = 's-pay-42'; + $chargeId = 's-chg-1'; + $chargebackId = 's-cbk-1'; + $retrieveUrl = "https://api.unzer.com/v1/payments/{$paymentId}/charges/{$chargeId}/chargebacks/{$chargebackId}"; + + // Partial mock: keep original behavior except fetchChargebackById which we want to intercept + $resourceServiceMock = $this->getMockBuilder(ResourceService::class) + ->setConstructorArgs([$unzer]) + ->setMethods(['fetchChargebackById']) + ->getMock(); + + $chargeback = (new Chargeback(10.0)) + ->setId($chargebackId) + ->setParentResource((new Charge())->setId($chargeId)); + + $resourceServiceMock->expects($this->once()) + ->method('fetchChargebackById') + ->with($paymentId, $chargebackId, $chargeId) + ->willReturn($chargeback); + + $webhookService->setResourceService($resourceServiceMock); + + $eventJson = json_encode([ + 'event' => 'chargeback', + 'publicKey' => 's-pub-xyz', + 'retrieveUrl' => $retrieveUrl, + 'paymentId' => $paymentId + ]); + + // when + $fetchedChargeback = $webhookService->fetchResourceFromEvent($eventJson); + + // then + $this->assertSame($chargeback, $fetchedChargeback); + $this->assertNotNull($fetchedChargeback); + } + /** * Verify exception is thrown if the retrieveURL is empty. * diff --git a/vendor/unzerdev/php-sdk/test/unit/UnzerTest.php b/vendor/unzerdev/php-sdk/test/unit/UnzerTest.php index 771196b..c9c2248 100644 --- a/vendor/unzerdev/php-sdk/test/unit/UnzerTest.php +++ b/vendor/unzerdev/php-sdk/test/unit/UnzerTest.php @@ -12,7 +12,8 @@ namespace UnzerSDK\test\unit; use DateTime; -use UnzerSDK\Unzer; +use PHPUnit\Framework\MockObject\MockObject; +use RuntimeException; use UnzerSDK\Resources\Basket; use UnzerSDK\Resources\Customer; use UnzerSDK\Resources\Metadata; @@ -30,8 +31,7 @@ use UnzerSDK\Services\WebhookService; use UnzerSDK\test\BasePaymentTest; use UnzerSDK\test\unit\Services\DummyDebugHandler; -use PHPUnit\Framework\MockObject\MockObject; -use RuntimeException; +use UnzerSDK\Unzer; class UnzerTest extends BasePaymentTest { @@ -56,6 +56,12 @@ public function constructorShouldInitPropertiesProperly(): void $unzerGerman = new Unzer('s-priv-1234', 'de-DE'); $this->assertEquals('de-DE', $unzerGerman->getLocale()); + + $unzerPub = new Unzer('s-pub-1234'); + $this->assertEquals('s-pub-1234', $unzerPub->getKey()); + + $unzerProdPub = new Unzer('p-pub-1234'); + $this->assertEquals('p-pub-1234', $unzerProdPub->getKey()); } /** @@ -75,9 +81,14 @@ public function gettersAndSettersShouldWorkProperly(): void $unzer->setKey('this is not a valid key'); $this->assertTrue(false, 'This exception should have been thrown'); } catch (RuntimeException $e) { - $this->assertEquals('Illegal key: Use a valid private key with this SDK!', $e->getMessage()); + $this->assertEquals('Illegal key: Use a valid private or public key with this SDK!', $e->getMessage()); } + $unzer->setKey('s-pub-1234'); + $this->assertEquals('s-pub-1234', $unzer->getKey()); + $unzer->setKey('p-pub-1234'); + $this->assertEquals('p-pub-1234', $unzer->getKey()); + $httpService = new HttpService(); $this->assertNotSame($httpService, $unzer->getHttpService()); $unzer->setHttpService($httpService);