From de78450e27059505edbf43b08dd18e5ddcfd912a Mon Sep 17 00:00:00 2001 From: lazychanger Date: Tue, 11 Jun 2024 18:28:03 +0800 Subject: [PATCH 1/4] fix: https://github.com/yansongda/pay/issues/992 --- src/Functions.php | 21 +++++++++++++++ src/Plugin/Alipay/V2/ResponsePlugin.php | 27 +++++++++++++++++-- tests/Plugin/Alipay/V2/ResponsePluginTest.php | 24 +++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/Functions.php b/src/Functions.php index 5f7c30292..f4d468a20 100644 --- a/src/Functions.php +++ b/src/Functions.php @@ -95,6 +95,27 @@ function get_alipay_url(array $config, ?Collection $payload): string return Alipay::URL[$config['mode'] ?? Pay::MODE_NORMAL]; } +/** + * "{\"alipay_fund_trans_uni_transfer_response\":{\"code\":\"40002\",\"msg\":\"Invalid Arguments\",\"sub_code\":\"isv.invalid-app-id\",\"sub_msg\":\"无效的AppID参数\"}}". + */ +function get_alipay_error_response_message(array $contents): string +{ + // 格式化响应内容 + foreach (array_keys($contents) as $key) { + if (str_ends_with($key, '_response')) { + $contents = $contents[$key]; + break; + } + } + + $code = $contents['code'] ?? '未知code'; + $msg = $contents['msg'] ?? '未知异常'; + $subCode = $contents['sub_code'] ?? '未知sub_code'; + $subMsg = $contents['sub_msg'] ?? '未知sub_msg'; + + return sprintf('alipay-%s: %s; 错误详情-%s: %s;', $code, $msg, $subCode, $subMsg); +} + /** * @throws InvalidConfigException * @throws InvalidSignException diff --git a/src/Plugin/Alipay/V2/ResponsePlugin.php b/src/Plugin/Alipay/V2/ResponsePlugin.php index 5ceafa7e8..e04595cdf 100644 --- a/src/Plugin/Alipay/V2/ResponsePlugin.php +++ b/src/Plugin/Alipay/V2/ResponsePlugin.php @@ -6,14 +6,22 @@ use Closure; use Yansongda\Artful\Contract\PluginInterface; +use Yansongda\Artful\Exception\Exception; +use Yansongda\Artful\Exception\InvalidParamsException; +use Yansongda\Artful\Exception\InvalidResponseException; use Yansongda\Artful\Logger; use Yansongda\Artful\Rocket; use Yansongda\Supports\Collection; use function Yansongda\Artful\should_do_http_request; +use function Yansongda\Pay\get_alipay_error_response_message; class ResponsePlugin implements PluginInterface { + /** + * @throws InvalidResponseException + * @throws InvalidParamsException + */ public function assembly(Rocket $rocket, Closure $next): Rocket { /* @var Rocket $rocket */ @@ -26,9 +34,24 @@ public function assembly(Rocket $rocket, Closure $next): Rocket $resultKey = str_replace('.', '_', $payload->get('method')).'_response'; if (should_do_http_request($rocket->getDirection()) && $destination instanceof Collection) { + $sign = $destination->get('sign', ''); + $response = $destination->get($resultKey, $destination->all()); + + // 支付宝返回sign为空时候,非应用异常,属于网关错误。 + // 例如AppID配置错误 + if (empty($sign)) { + if (empty($response['code'])) { + throw new InvalidParamsException(Exception::RESPONSE_EMPTY, '参数异常: 支付宝响应内容异常; 缺失code', $destination); + } + + if ('10000' !== $response['code']) { + throw new InvalidResponseException(Exception::RESPONSE_ERROR, sprintf('支付宝网关响应异常; %s', get_alipay_error_response_message($response)), $rocket->getDestination()); + } + } + $rocket->setDestination(new Collection(array_merge( - ['_sign' => $destination->get('sign', '')], - $destination->get($resultKey, $destination->all()) + ['_sign' => $sign], + $response ))); } diff --git a/tests/Plugin/Alipay/V2/ResponsePluginTest.php b/tests/Plugin/Alipay/V2/ResponsePluginTest.php index db93a5db1..64fe32887 100644 --- a/tests/Plugin/Alipay/V2/ResponsePluginTest.php +++ b/tests/Plugin/Alipay/V2/ResponsePluginTest.php @@ -2,6 +2,8 @@ namespace Yansongda\Pay\Tests\Plugin\Alipay\V2; +use Yansongda\Artful\Exception\Exception; +use Yansongda\Artful\Exception\InvalidResponseException; use Yansongda\Pay\Plugin\Alipay\V2\ResponsePlugin; use Yansongda\Artful\Rocket; use Yansongda\Pay\Tests\TestCase; @@ -82,4 +84,26 @@ public function testErrorResponseWithNoMethodKey() self::assertEquals(array_merge(['_sign' => '123'], $destination), $result->getDestination()->all()); } + + public function testErrorResponseWithEmptySignKey() + { + self::expectException(InvalidResponseException::class); + self::expectExceptionCode(Exception::RESPONSE_ERROR); + + $destination = [ + 'alipay_fund_trans_uni_transfer_response' => [ + 'code' => '40002', + 'msg' => 'Invalid Arguments', + 'sub_code' => 'isv.invalid-app-id', + 'sub_msg' => '无效的AppID参数', + ], + 'sign' => '' + ]; + + $rocket = (new Rocket()) + ->mergePayload(['method' => 'alipay_fund_trans_uni_transfer']) + ->setDestination(new Collection($destination)); + + $this->plugin->assembly($rocket, function ($rocket) {return $rocket; }); + } } From 0f6f99eb54ad8588b7519b377fe56b6424719ff5 Mon Sep 17 00:00:00 2001 From: yansongda Date: Tue, 11 Jun 2024 21:52:00 +0800 Subject: [PATCH 2/4] update --- src/Exception/Exception.php | 2 ++ src/Functions.php | 21 ------------------- src/Plugin/Alipay/V2/ResponsePlugin.php | 17 +++------------ tests/Plugin/Alipay/V2/ResponsePluginTest.php | 5 +++-- 4 files changed, 8 insertions(+), 37 deletions(-) diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php index 1085168ff..73801209e 100644 --- a/src/Exception/Exception.php +++ b/src/Exception/Exception.php @@ -44,6 +44,8 @@ class Exception extends \Exception public const RESPONSE_MISSING_NECESSARY_PARAMS = 9305; + public const RESPONSE_BUSINESS_CODE_WRONG = 9306; + /* * 关于配置. */ diff --git a/src/Functions.php b/src/Functions.php index f4d468a20..5f7c30292 100644 --- a/src/Functions.php +++ b/src/Functions.php @@ -95,27 +95,6 @@ function get_alipay_url(array $config, ?Collection $payload): string return Alipay::URL[$config['mode'] ?? Pay::MODE_NORMAL]; } -/** - * "{\"alipay_fund_trans_uni_transfer_response\":{\"code\":\"40002\",\"msg\":\"Invalid Arguments\",\"sub_code\":\"isv.invalid-app-id\",\"sub_msg\":\"无效的AppID参数\"}}". - */ -function get_alipay_error_response_message(array $contents): string -{ - // 格式化响应内容 - foreach (array_keys($contents) as $key) { - if (str_ends_with($key, '_response')) { - $contents = $contents[$key]; - break; - } - } - - $code = $contents['code'] ?? '未知code'; - $msg = $contents['msg'] ?? '未知异常'; - $subCode = $contents['sub_code'] ?? '未知sub_code'; - $subMsg = $contents['sub_msg'] ?? '未知sub_msg'; - - return sprintf('alipay-%s: %s; 错误详情-%s: %s;', $code, $msg, $subCode, $subMsg); -} - /** * @throws InvalidConfigException * @throws InvalidSignException diff --git a/src/Plugin/Alipay/V2/ResponsePlugin.php b/src/Plugin/Alipay/V2/ResponsePlugin.php index e04595cdf..d6662a144 100644 --- a/src/Plugin/Alipay/V2/ResponsePlugin.php +++ b/src/Plugin/Alipay/V2/ResponsePlugin.php @@ -6,21 +6,18 @@ use Closure; use Yansongda\Artful\Contract\PluginInterface; -use Yansongda\Artful\Exception\Exception; -use Yansongda\Artful\Exception\InvalidParamsException; use Yansongda\Artful\Exception\InvalidResponseException; use Yansongda\Artful\Logger; use Yansongda\Artful\Rocket; +use Yansongda\Pay\Exception\Exception; use Yansongda\Supports\Collection; use function Yansongda\Artful\should_do_http_request; -use function Yansongda\Pay\get_alipay_error_response_message; class ResponsePlugin implements PluginInterface { /** * @throws InvalidResponseException - * @throws InvalidParamsException */ public function assembly(Rocket $rocket, Closure $next): Rocket { @@ -37,16 +34,8 @@ public function assembly(Rocket $rocket, Closure $next): Rocket $sign = $destination->get('sign', ''); $response = $destination->get($resultKey, $destination->all()); - // 支付宝返回sign为空时候,非应用异常,属于网关错误。 - // 例如AppID配置错误 - if (empty($sign)) { - if (empty($response['code'])) { - throw new InvalidParamsException(Exception::RESPONSE_EMPTY, '参数异常: 支付宝响应内容异常; 缺失code', $destination); - } - - if ('10000' !== $response['code']) { - throw new InvalidResponseException(Exception::RESPONSE_ERROR, sprintf('支付宝网关响应异常; %s', get_alipay_error_response_message($response)), $rocket->getDestination()); - } + if (empty($sign) && '10000' !== ($response['code'] ?? '0')) { + throw new InvalidResponseException(Exception::RESPONSE_BUSINESS_CODE_WRONG, '支付宝网关响应异常: '.($response['sub_msg'] ?? $response['msg'] ?? '未知错误,请查看支付宝原始响应'), $rocket->getDestination()); } $rocket->setDestination(new Collection(array_merge( diff --git a/tests/Plugin/Alipay/V2/ResponsePluginTest.php b/tests/Plugin/Alipay/V2/ResponsePluginTest.php index 64fe32887..951b990ad 100644 --- a/tests/Plugin/Alipay/V2/ResponsePluginTest.php +++ b/tests/Plugin/Alipay/V2/ResponsePluginTest.php @@ -2,8 +2,8 @@ namespace Yansongda\Pay\Tests\Plugin\Alipay\V2; -use Yansongda\Artful\Exception\Exception; use Yansongda\Artful\Exception\InvalidResponseException; +use Yansongda\Pay\Exception\Exception; use Yansongda\Pay\Plugin\Alipay\V2\ResponsePlugin; use Yansongda\Artful\Rocket; use Yansongda\Pay\Tests\TestCase; @@ -88,7 +88,8 @@ public function testErrorResponseWithNoMethodKey() public function testErrorResponseWithEmptySignKey() { self::expectException(InvalidResponseException::class); - self::expectExceptionCode(Exception::RESPONSE_ERROR); + self::expectExceptionCode(Exception::RESPONSE_BUSINESS_CODE_WRONG); + self::expectExceptionMessage('支付宝网关响应异常: 无效的AppID参数'); $destination = [ 'alipay_fund_trans_uni_transfer_response' => [ From fc0681b1483714dced95dc61a5ccb7cb6acba292 Mon Sep 17 00:00:00 2001 From: yansongda Date: Tue, 11 Jun 2024 21:54:21 +0800 Subject: [PATCH 3/4] update --- CHANGELOG.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc98e69d2..8411cf3ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ -## TBD - v3.7.5 +## v3.7.5 + +### fixed + +- fix: 支付宝响应空签名时签名验证逻辑错误的问题(#998) ### optimized From 645645665edc8416fc6e1999fa6cb07aac7f7783 Mon Sep 17 00:00:00 2001 From: yansongda Date: Wed, 12 Jun 2024 09:46:40 +0800 Subject: [PATCH 4/4] update --- src/Plugin/Alipay/V2/ResponsePlugin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugin/Alipay/V2/ResponsePlugin.php b/src/Plugin/Alipay/V2/ResponsePlugin.php index d6662a144..36f2870e6 100644 --- a/src/Plugin/Alipay/V2/ResponsePlugin.php +++ b/src/Plugin/Alipay/V2/ResponsePlugin.php @@ -34,7 +34,7 @@ public function assembly(Rocket $rocket, Closure $next): Rocket $sign = $destination->get('sign', ''); $response = $destination->get($resultKey, $destination->all()); - if (empty($sign) && '10000' !== ($response['code'] ?? '0')) { + if (empty($sign) && '10000' !== ($response['code'] ?? 'null')) { throw new InvalidResponseException(Exception::RESPONSE_BUSINESS_CODE_WRONG, '支付宝网关响应异常: '.($response['sub_msg'] ?? $response['msg'] ?? '未知错误,请查看支付宝原始响应'), $rocket->getDestination()); }