alipay-easysdk-ruby 1.0.2 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/lib/alipay/easysdk/kernel/alipay_constants.rb +20 -22
- data/lib/alipay/easysdk/kernel/cert_environment.rb +35 -0
- data/lib/alipay/easysdk/kernel/config.rb +91 -64
- data/lib/alipay/easysdk/kernel/easy_sdk_kernel.rb +102 -89
- data/lib/alipay/easysdk/kernel/factory.rb +28 -18
- data/lib/alipay/easysdk/kernel/util/aes.rb +75 -0
- data/lib/alipay/easysdk/kernel/util/ant_certification_util.rb +63 -0
- data/lib/alipay/easysdk/kernel/util/json_util.rb +50 -8
- data/lib/alipay/easysdk/kernel/util/page_util.rb +34 -0
- data/lib/alipay/easysdk/kernel/util/response_checker.rb +6 -1
- data/lib/alipay/easysdk/kernel/util/signer.rb +15 -5
- data/lib/alipay/easysdk/payment/app/client.rb +75 -0
- data/lib/alipay/easysdk/payment/app/models/alipay_trade_app_pay_response.rb +19 -0
- data/lib/alipay/easysdk/payment/common/client.rb +30 -5
- data/lib/alipay/easysdk/payment/common/models/base_response.rb +0 -14
- data/lib/alipay/easysdk/payment/page/client.rb +1 -1
- data/lib/alipay/easysdk/payment/page/models/alipay_trade_page_pay_response.rb +1 -17
- data/lib/alipay/easysdk/payment/wap/client.rb +1 -1
- data/lib/alipay/easysdk/payment/wap/models/alipay_trade_wap_pay_response.rb +1 -17
- data/lib/alipay/easysdk/version.rb +1 -1
- data/lib/alipay/easysdk.rb +4 -0
- metadata +8 -4
- data/examples/demo.rb +0 -133
- data/examples/demo_with_get.rb +0 -33
- data/examples/demo_with_post.rb +0 -239
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9fbf7bcd464b1d9f4c42aaec6030ba6dfc9a4beda7eb5c3ea2587722b2fdff01
|
|
4
|
+
data.tar.gz: 43c10156f010ca3f98696361f9d9a07478bd1ea44c1533a086f5c2c066956c9b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d10e78d464ea90c15a6b9e17bcbbf1e6414fb3a842eda95f2662e69e3de245e6209214b096b8b3dd38f8bd0daefcd4c12b664b8947de02feb544b83f0be41b8e
|
|
7
|
+
data.tar.gz: fddc8561482df008189ba3cfcd93fc3751e1ea192d07c9008f201ee6c211f780da96ddd2de9d90395c48d575481e8f50c766a63e0792b05c1c55f5992f95d728
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.0.3 - 2024-06-06
|
|
4
|
+
|
|
5
|
+
- Add `payment/app` client and response model to match PHP EasySDK behaviour.
|
|
6
|
+
- Align kernel utilities (Config, Factory, EasySDKKernel, PageUtil, AES, Signer, JsonUtil, ResponseChecker) with the PHP implementation.
|
|
7
|
+
- Update Payment::Common/Page/Wap clients and models to PHP parity while retaining the custom `payment_url` extension.
|
|
8
|
+
- Refresh parity fixtures, expand test coverage, and remove the deprecated `examples/` directory.
|
|
9
|
+
|
|
10
|
+
## 1.0.2 - 2024-04-15
|
|
11
|
+
|
|
12
|
+
- Align `payment/page`, `payment/wap`, and `payment/common` dependencies with the PHP EasySDK implementation.
|
|
13
|
+
- Extend `Kernel::Config` to support certificate paths, proxy, notify URL, and encryption settings used by PHP clients.
|
|
14
|
+
- Introduce certificate environment utilities to derive certificate serial numbers and cached public keys.
|
|
15
|
+
- Update `Payment::Common::Client` to honour proxy and SSL settings and improve parity with PHP HTTP behaviour.
|
|
16
|
+
- Add comprehensive test coverage for certificate handling, extended configuration, and HTTP proxy behaviour.
|
|
17
|
+
|
|
18
|
+
## 1.0.1 - 2024-03-01
|
|
19
|
+
|
|
20
|
+
- Initial public release of the Ruby EasySDK port.
|
|
@@ -4,41 +4,39 @@ module Alipay
|
|
|
4
4
|
module EasySDK
|
|
5
5
|
module Kernel
|
|
6
6
|
module AlipayConstants
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
# Config键名(对齐PHP版)
|
|
8
|
+
PROTOCOL_CONFIG_KEY = "protocol"
|
|
9
|
+
HOST_CONFIG_KEY = "gatewayHost"
|
|
10
|
+
ALIPAY_CERT_PATH_CONFIG_KEY = "alipayCertPath"
|
|
11
|
+
MERCHANT_CERT_PATH_CONFIG_KEY = "merchantCertPath"
|
|
12
|
+
ALIPAY_ROOT_CERT_PATH_CONFIG_KEY = "alipayRootCertPath"
|
|
13
|
+
SIGN_TYPE_CONFIG_KEY = "signType"
|
|
14
|
+
NOTIFY_URL_CONFIG_KEY = "notifyUrl"
|
|
12
15
|
|
|
13
|
-
#
|
|
14
|
-
APP_ID_FIELD = "app_id"
|
|
15
|
-
METHOD_FIELD = "method"
|
|
16
|
-
FORMAT_FIELD = "format"
|
|
17
|
-
TIMESTAMP_FIELD = "timestamp"
|
|
18
|
-
VERSION_FIELD = "version"
|
|
19
|
-
SIGN_TYPE_FIELD = "sign_type"
|
|
20
|
-
SIGN_FIELD = "sign"
|
|
16
|
+
# 与网关交互使用的字段
|
|
21
17
|
BIZ_CONTENT_FIELD = "biz_content"
|
|
22
|
-
CHARSET_FIELD = "charset"
|
|
23
|
-
BODY_FIELD = "body"
|
|
24
18
|
ALIPAY_CERT_SN_FIELD = "alipay_cert_sn"
|
|
19
|
+
SIGN_FIELD = "sign"
|
|
20
|
+
BODY_FIELD = "http_body"
|
|
25
21
|
NOTIFY_URL_FIELD = "notify_url"
|
|
26
|
-
|
|
27
|
-
PROTOCOL_CONFIG_KEY = "protocol"
|
|
28
|
-
HOST_CONFIG_KEY = "gatewayHost"
|
|
22
|
+
METHOD_FIELD = "method"
|
|
29
23
|
RESPONSE_SUFFIX = "_response"
|
|
30
24
|
ERROR_RESPONSE = "error_response"
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
DEFAULT_CHARSET = "UTF-8"
|
|
33
27
|
DEFAULT_FORMAT = "json"
|
|
34
28
|
DEFAULT_VERSION = "1.0"
|
|
35
|
-
DEFAULT_SIGN_TYPE =
|
|
29
|
+
DEFAULT_SIGN_TYPE = "RSA2"
|
|
30
|
+
|
|
31
|
+
SIGN_TYPE_RSA = "RSA"
|
|
32
|
+
SIGN_TYPE_RSA2 = "RSA2"
|
|
33
|
+
RSA2 = "RSA2"
|
|
34
|
+
SHA_256_WITH_RSA = "SHA256WithRSA"
|
|
35
|
+
RSA = "RSA"
|
|
36
36
|
|
|
37
|
-
# 请求方式
|
|
38
37
|
GET = "GET"
|
|
39
38
|
POST = "POST"
|
|
40
39
|
|
|
41
|
-
# SDK信息
|
|
42
40
|
SDK_VERSION = "alipay-easysdk-ruby-#{Alipay::EasySDK::VERSION}"
|
|
43
41
|
end
|
|
44
42
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
|
|
4
|
+
require_relative 'util/ant_certification_util'
|
|
5
|
+
|
|
6
|
+
module Alipay
|
|
7
|
+
module EasySDK
|
|
8
|
+
module Kernel
|
|
9
|
+
class CertEnvironment
|
|
10
|
+
attr_reader :root_cert_sn, :merchant_cert_sn
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@cert_util = Util::AntCertificationUtil.new
|
|
14
|
+
@root_cert_sn = nil
|
|
15
|
+
@merchant_cert_sn = nil
|
|
16
|
+
@cached_alipay_public_key = nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def setup(merchant_cert_path, alipay_cert_path, alipay_root_cert_path)
|
|
20
|
+
if [merchant_cert_path, alipay_cert_path, alipay_root_cert_path].any? { |path| path.nil? || path.to_s.strip.empty? }
|
|
21
|
+
raise RuntimeError, '证书参数merchantCertPath、alipayCertPath或alipayRootCertPath设置不完整。'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
@root_cert_sn = @cert_util.root_cert_sn(alipay_root_cert_path)
|
|
25
|
+
@merchant_cert_sn = @cert_util.cert_sn(merchant_cert_path)
|
|
26
|
+
@cached_alipay_public_key = @cert_util.public_key(alipay_cert_path)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def cached_alipay_public_key
|
|
30
|
+
@cached_alipay_public_key
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,81 +1,108 @@
|
|
|
1
|
-
require_relative 'alipay_constants'
|
|
2
|
-
|
|
3
1
|
module Alipay
|
|
4
2
|
module EasySDK
|
|
5
3
|
module Kernel
|
|
6
4
|
class Config
|
|
7
5
|
attr_accessor :protocol,
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
:
|
|
11
|
-
:
|
|
12
|
-
:
|
|
13
|
-
:
|
|
14
|
-
:
|
|
15
|
-
:
|
|
16
|
-
:
|
|
17
|
-
:
|
|
18
|
-
:
|
|
19
|
-
:
|
|
20
|
-
:
|
|
21
|
-
:
|
|
22
|
-
:
|
|
23
|
-
:charset,
|
|
24
|
-
:format,
|
|
25
|
-
:version
|
|
26
|
-
|
|
27
|
-
def initialize(options = {})
|
|
28
|
-
opts = options || {}
|
|
29
|
-
|
|
30
|
-
@protocol = fetch_option(opts, :protocol, 'protocol') || 'https'
|
|
31
|
-
@gateway_host = fetch_option(opts, :gateway_host, 'gateway_host', :gatewayHost, 'gatewayHost') || 'openapi.alipay.com/gateway.do'
|
|
32
|
-
@app_id = fetch_option(opts, :app_id, 'app_id', :appId, 'appId')
|
|
33
|
-
@sign_type = fetch_option(opts, :sign_type, 'sign_type', :signType, 'signType') || AlipayConstants::DEFAULT_SIGN_TYPE
|
|
34
|
-
@alipay_public_key = fetch_option(opts, :alipay_public_key, 'alipay_public_key', :alipayPublicKey, 'alipayPublicKey')
|
|
35
|
-
@merchant_private_key = fetch_option(opts, :merchant_private_key, 'merchant_private_key', :merchantPrivateKey, 'merchantPrivateKey')
|
|
36
|
-
@merchant_cert_path = fetch_option(opts, :merchant_cert_path, 'merchant_cert_path', :merchantCertPath, 'merchantCertPath')
|
|
37
|
-
@alipay_cert_path = fetch_option(opts, :alipay_cert_path, 'alipay_cert_path', :alipayCertPath, 'alipayCertPath')
|
|
38
|
-
@alipay_root_cert_path = fetch_option(opts, :alipay_root_cert_path, 'alipay_root_cert_path', :alipayRootCertPath, 'alipayRootCertPath')
|
|
39
|
-
@merchant_cert_sn = fetch_option(opts, :merchant_cert_sn, 'merchant_cert_sn', :merchantCertSN, 'merchantCertSN')
|
|
40
|
-
@alipay_cert_sn = fetch_option(opts, :alipay_cert_sn, 'alipay_cert_sn', :alipayCertSN, 'alipayCertSN')
|
|
41
|
-
@alipay_root_cert_sn = fetch_option(opts, :alipay_root_cert_sn, 'alipay_root_cert_sn', :alipayRootCertSN, 'alipayRootCertSN')
|
|
42
|
-
@notify_url = fetch_option(opts, :notify_url, 'notify_url', :notifyUrl, 'notifyUrl')
|
|
43
|
-
@encrypt_key = fetch_option(opts, :encrypt_key, 'encrypt_key', :encryptKey, 'encryptKey')
|
|
44
|
-
@http_proxy = fetch_option(opts, :http_proxy, 'http_proxy', :httpProxy, 'httpProxy')
|
|
45
|
-
@ignore_ssl = fetch_option(opts, :ignore_ssl, 'ignore_ssl', :ignoreSSL, 'ignoreSSL')
|
|
46
|
-
@charset = fetch_option(opts, :charset, 'charset') || AlipayConstants::DEFAULT_CHARSET
|
|
47
|
-
@format = fetch_option(opts, :format, 'format') || AlipayConstants::DEFAULT_FORMAT
|
|
48
|
-
@version = fetch_option(opts, :version, 'version') || AlipayConstants::DEFAULT_VERSION
|
|
49
|
-
end
|
|
6
|
+
:gatewayHost,
|
|
7
|
+
:appId,
|
|
8
|
+
:signType,
|
|
9
|
+
:alipayPublicKey,
|
|
10
|
+
:merchantPrivateKey,
|
|
11
|
+
:merchantCertPath,
|
|
12
|
+
:alipayCertPath,
|
|
13
|
+
:alipayRootCertPath,
|
|
14
|
+
:merchantCertSN,
|
|
15
|
+
:alipayCertSN,
|
|
16
|
+
:alipayRootCertSN,
|
|
17
|
+
:notifyUrl,
|
|
18
|
+
:encryptKey,
|
|
19
|
+
:httpProxy,
|
|
20
|
+
:ignoreSSL
|
|
50
21
|
|
|
51
|
-
def
|
|
52
|
-
|
|
22
|
+
def initialize(options = nil)
|
|
23
|
+
assign_attributes(options) if options
|
|
53
24
|
end
|
|
54
25
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
26
|
+
# 下划线风格的访问器保持向后兼容
|
|
27
|
+
alias_method :gateway_host, :gatewayHost
|
|
28
|
+
alias_method :gateway_host=, :gatewayHost=
|
|
29
|
+
|
|
30
|
+
alias_method :app_id, :appId
|
|
31
|
+
alias_method :app_id=, :appId=
|
|
32
|
+
|
|
33
|
+
alias_method :sign_type, :signType
|
|
34
|
+
alias_method :sign_type=, :signType=
|
|
35
|
+
|
|
36
|
+
alias_method :alipay_public_key, :alipayPublicKey
|
|
37
|
+
alias_method :alipay_public_key=, :alipayPublicKey=
|
|
38
|
+
|
|
39
|
+
alias_method :merchant_private_key, :merchantPrivateKey
|
|
40
|
+
alias_method :merchant_private_key=, :merchantPrivateKey=
|
|
41
|
+
|
|
42
|
+
alias_method :merchant_cert_path, :merchantCertPath
|
|
43
|
+
alias_method :merchant_cert_path=, :merchantCertPath=
|
|
44
|
+
|
|
45
|
+
alias_method :alipay_cert_path, :alipayCertPath
|
|
46
|
+
alias_method :alipay_cert_path=, :alipayCertPath=
|
|
47
|
+
|
|
48
|
+
alias_method :alipay_root_cert_path, :alipayRootCertPath
|
|
49
|
+
alias_method :alipay_root_cert_path=, :alipayRootCertPath=
|
|
50
|
+
|
|
51
|
+
alias_method :merchant_cert_sn, :merchantCertSN
|
|
52
|
+
alias_method :merchant_cert_sn=, :merchantCertSN=
|
|
53
|
+
|
|
54
|
+
alias_method :alipay_cert_sn, :alipayCertSN
|
|
55
|
+
alias_method :alipay_cert_sn=, :alipayCertSN=
|
|
56
|
+
|
|
57
|
+
alias_method :alipay_root_cert_sn, :alipayRootCertSN
|
|
58
|
+
alias_method :alipay_root_cert_sn=, :alipayRootCertSN=
|
|
59
|
+
|
|
60
|
+
alias_method :notify_url, :notifyUrl
|
|
61
|
+
alias_method :notify_url=, :notifyUrl=
|
|
62
|
+
|
|
63
|
+
alias_method :encrypt_key, :encryptKey
|
|
64
|
+
alias_method :encrypt_key=, :encryptKey=
|
|
65
|
+
|
|
66
|
+
alias_method :http_proxy, :httpProxy
|
|
67
|
+
alias_method :http_proxy=, :httpProxy=
|
|
68
|
+
|
|
69
|
+
alias_method :ignore_ssl, :ignoreSSL
|
|
70
|
+
alias_method :ignore_ssl=, :ignoreSSL=
|
|
60
71
|
|
|
61
72
|
private
|
|
62
73
|
|
|
63
|
-
def
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
return options[key] if options.key?(key)
|
|
68
|
-
return options[symbol_key] if options.key?(symbol_key)
|
|
69
|
-
elsif key.is_a?(Symbol)
|
|
70
|
-
string_key = key.to_s
|
|
71
|
-
camel_case_key = string_key.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
|
|
72
|
-
return options[key] if options.key?(key)
|
|
73
|
-
return options[string_key] if options.key?(string_key)
|
|
74
|
-
return options[camel_case_key] if options.key?(camel_case_key)
|
|
75
|
-
end
|
|
74
|
+
def assign_attributes(options)
|
|
75
|
+
options.each do |key, value|
|
|
76
|
+
setter = attribute_writer_for(key)
|
|
77
|
+
public_send(setter, value) if setter && respond_to?(setter, true)
|
|
76
78
|
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def attribute_writer_for(key)
|
|
82
|
+
string_key = key.to_s
|
|
83
|
+
writer = "#{string_key}="
|
|
84
|
+
return writer if respond_to?(writer, true)
|
|
85
|
+
|
|
86
|
+
camel_case = underscore_to_camel(string_key)
|
|
87
|
+
writer = "#{camel_case}="
|
|
88
|
+
return writer if respond_to?(writer, true)
|
|
89
|
+
|
|
90
|
+
snake_case = camel_to_snake(string_key)
|
|
91
|
+
writer = "#{snake_case}="
|
|
92
|
+
return writer if respond_to?(writer, true)
|
|
93
|
+
|
|
77
94
|
nil
|
|
78
95
|
end
|
|
96
|
+
|
|
97
|
+
def underscore_to_camel(str)
|
|
98
|
+
str.split('_').inject do |memo, part|
|
|
99
|
+
memo + part.capitalize
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def camel_to_snake(str)
|
|
104
|
+
str.gsub(/([A-Z]+)/) { "_#{$1.downcase}" }.sub(/^_/, '')
|
|
105
|
+
end
|
|
79
106
|
end
|
|
80
107
|
end
|
|
81
108
|
end
|
|
@@ -3,6 +3,8 @@ require_relative 'config'
|
|
|
3
3
|
require_relative 'util/json_util'
|
|
4
4
|
require_relative 'util/signer'
|
|
5
5
|
require_relative 'util/sign_content_extractor'
|
|
6
|
+
require_relative 'util/aes'
|
|
7
|
+
require_relative 'util/page_util'
|
|
6
8
|
require 'net/http'
|
|
7
9
|
require 'uri'
|
|
8
10
|
require 'cgi'
|
|
@@ -39,47 +41,16 @@ module Alipay
|
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def get_config(key)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
'signType' => :sign_type,
|
|
53
|
-
'sign_type' => :sign_type,
|
|
54
|
-
'charset' => :charset,
|
|
55
|
-
'format' => :format,
|
|
56
|
-
'version' => :version,
|
|
57
|
-
'notifyUrl' => :notify_url,
|
|
58
|
-
'notify_url' => :notify_url,
|
|
59
|
-
'encryptKey' => :encrypt_key,
|
|
60
|
-
'encrypt_key' => :encrypt_key,
|
|
61
|
-
'httpProxy' => :http_proxy,
|
|
62
|
-
'http_proxy' => :http_proxy,
|
|
63
|
-
'ignoreSSL' => :ignore_ssl,
|
|
64
|
-
'ignore_ssl' => :ignore_ssl,
|
|
65
|
-
'merchantCertPath' => :merchant_cert_path,
|
|
66
|
-
'merchant_cert_path' => :merchant_cert_path,
|
|
67
|
-
'alipayCertPath' => :alipay_cert_path,
|
|
68
|
-
'alipay_cert_path' => :alipay_cert_path,
|
|
69
|
-
'alipayRootCertPath' => :alipay_root_cert_path,
|
|
70
|
-
'alipay_root_cert_path' => :alipay_root_cert_path,
|
|
71
|
-
'merchantCertSN' => :merchant_cert_sn,
|
|
72
|
-
'merchant_cert_sn' => :merchant_cert_sn,
|
|
73
|
-
'alipayCertSN' => :alipay_cert_sn,
|
|
74
|
-
'alipay_cert_sn' => :alipay_cert_sn,
|
|
75
|
-
'alipayRootCertSN' => :alipay_root_cert_sn,
|
|
76
|
-
'alipay_root_cert_sn' => :alipay_root_cert_sn
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
method = lookup[key]
|
|
80
|
-
return unless method
|
|
81
|
-
|
|
82
|
-
@config.public_send(method)
|
|
44
|
+
method = key.to_s
|
|
45
|
+
return @config.public_send(method) if @config.respond_to?(method)
|
|
46
|
+
|
|
47
|
+
snake = method.gsub(/([A-Z]+)/) { "_#{$1.downcase}" }.sub(/^_/, '')
|
|
48
|
+
return @config.public_send(snake) if @config.respond_to?(snake)
|
|
49
|
+
|
|
50
|
+
camel = snake.split('_').inject { |memo, part| memo + part.capitalize }
|
|
51
|
+
return @config.public_send(camel) if camel && @config.respond_to?(camel)
|
|
52
|
+
|
|
53
|
+
nil
|
|
83
54
|
end
|
|
84
55
|
|
|
85
56
|
def get_sdk_version
|
|
@@ -97,9 +68,9 @@ module Alipay
|
|
|
97
68
|
def read_as_json(response, method)
|
|
98
69
|
response_body = response.body
|
|
99
70
|
map = {}
|
|
100
|
-
map[
|
|
101
|
-
map[
|
|
102
|
-
|
|
71
|
+
map[AlipayConstants::BODY_FIELD] = response_body
|
|
72
|
+
map[AlipayConstants::METHOD_FIELD] = method
|
|
73
|
+
map
|
|
103
74
|
end
|
|
104
75
|
|
|
105
76
|
def get_random_boundary
|
|
@@ -109,11 +80,12 @@ module Alipay
|
|
|
109
80
|
def generate_page(method, system_params, biz_params, text_params, sign)
|
|
110
81
|
puts "[DEBUG] generate_page - sign长度: #{sign.length}" if ENV['DEBUG']
|
|
111
82
|
signed_params = build_signed_params(system_params, biz_params, text_params, sign)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
83
|
+
case method
|
|
84
|
+
when AlipayConstants::GET
|
|
85
|
+
build_gateway_url(signed_params)
|
|
86
|
+
when AlipayConstants::POST
|
|
115
87
|
puts "[DEBUG] generate_page POST - sorted_map中sign长度: #{signed_params[AlipayConstants::SIGN_FIELD].length}" if ENV['DEBUG']
|
|
116
|
-
|
|
88
|
+
build_form(get_gateway_server_url, signed_params)
|
|
117
89
|
else
|
|
118
90
|
raise "不支持" + method
|
|
119
91
|
end
|
|
@@ -130,8 +102,8 @@ module Alipay
|
|
|
130
102
|
|
|
131
103
|
def get_alipay_cert_sn(resp_map)
|
|
132
104
|
if !@config.merchant_cert_sn.nil? && !@config.merchant_cert_sn.empty?
|
|
133
|
-
body = JSON.parse(resp_map[
|
|
134
|
-
alipay_cert_sn = body[
|
|
105
|
+
body = JSON.parse(resp_map[AlipayConstants::BODY_FIELD])
|
|
106
|
+
alipay_cert_sn = body[AlipayConstants::ALIPAY_CERT_SN_FIELD]
|
|
135
107
|
return alipay_cert_sn
|
|
136
108
|
end
|
|
137
109
|
end
|
|
@@ -150,10 +122,10 @@ module Alipay
|
|
|
150
122
|
end
|
|
151
123
|
|
|
152
124
|
def verify(resp_map, alipay_public_key)
|
|
153
|
-
resp = JSON.parse(resp_map[
|
|
125
|
+
resp = JSON.parse(resp_map[AlipayConstants::BODY_FIELD])
|
|
154
126
|
sign = resp[AlipayConstants::SIGN_FIELD]
|
|
155
127
|
sign_content_extractor = Alipay::EasySDK::Kernel::Util::SignContentExtractor.new
|
|
156
|
-
content = sign_content_extractor.get_sign_source_data(resp_map[
|
|
128
|
+
content = sign_content_extractor.get_sign_source_data(resp_map[AlipayConstants::BODY_FIELD], resp_map[AlipayConstants::METHOD_FIELD])
|
|
157
129
|
signer = Alipay::EasySDK::Kernel::Util::Signer.new
|
|
158
130
|
return signer.verify(content, sign, alipay_public_key)
|
|
159
131
|
end
|
|
@@ -178,18 +150,55 @@ module Alipay
|
|
|
178
150
|
URI.encode_www_form(sorted_map)
|
|
179
151
|
end
|
|
180
152
|
|
|
153
|
+
def to_multipart_request_body(text_params, file_params, boundary)
|
|
154
|
+
@text_params = text_params
|
|
155
|
+
@biz_params = nil
|
|
156
|
+
if text_params != nil && !@optional_text_params.empty?
|
|
157
|
+
@text_params = text_params.merge(@optional_text_params)
|
|
158
|
+
elsif text_params == nil
|
|
159
|
+
@text_params = @optional_text_params.dup
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
parts = []
|
|
163
|
+
(@text_params || {}).each do |key, value|
|
|
164
|
+
parts << build_multipart_text_part(boundary, key, value)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
(file_params || {}).each do |key, path|
|
|
168
|
+
raise "文件#{path}不存在" unless File.exist?(path.to_s)
|
|
169
|
+
file_content = File.binread(path)
|
|
170
|
+
filename = File.basename(path)
|
|
171
|
+
parts << build_multipart_file_part(boundary, key, filename, file_content)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
return nil if parts.empty?
|
|
175
|
+
|
|
176
|
+
parts << "--#{boundary}--\r\n"
|
|
177
|
+
parts.join
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def aes_encrypt(content, encrypt_key)
|
|
181
|
+
aes = Alipay::EasySDK::Kernel::Util::AES.new
|
|
182
|
+
aes.aes_encrypt(content, encrypt_key)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def aes_decrypt(content, encrypt_key)
|
|
186
|
+
aes = Alipay::EasySDK::Kernel::Util::AES.new
|
|
187
|
+
aes.aes_decrypt(content, encrypt_key)
|
|
188
|
+
end
|
|
189
|
+
|
|
181
190
|
def sort_map(random_map)
|
|
182
191
|
return random_map
|
|
183
192
|
end
|
|
184
193
|
|
|
185
194
|
def to_resp_model(resp_map)
|
|
186
|
-
body = resp_map[
|
|
187
|
-
method_name = resp_map[
|
|
195
|
+
body = resp_map[AlipayConstants::BODY_FIELD]
|
|
196
|
+
method_name = resp_map[AlipayConstants::METHOD_FIELD]
|
|
188
197
|
response_node_name = method_name.gsub(".", "_") + "_response"
|
|
189
198
|
|
|
190
199
|
model = JSON.parse(body)
|
|
191
|
-
if body.include?(
|
|
192
|
-
result = model[
|
|
200
|
+
if body.include?(AlipayConstants::ERROR_RESPONSE)
|
|
201
|
+
result = model[AlipayConstants::ERROR_RESPONSE]
|
|
193
202
|
result['body'] = body
|
|
194
203
|
else
|
|
195
204
|
result = model[response_node_name]
|
|
@@ -236,15 +245,15 @@ module Alipay
|
|
|
236
245
|
@biz_params = @optional_biz_params
|
|
237
246
|
end
|
|
238
247
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
end
|
|
248
|
+
json_util = Alipay::EasySDK::Kernel::Util::JsonUtil.new
|
|
249
|
+
biz_content = json_util.to_json_string(@biz_params) unless @biz_params.nil?
|
|
250
|
+
|
|
243
251
|
sorted_map = (system_params || {}).dup
|
|
244
|
-
if !
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
252
|
+
if !biz_content.nil?
|
|
253
|
+
unless biz_content.respond_to?(:empty?) && biz_content.empty?
|
|
254
|
+
serialized = JSON.generate(biz_content, ascii_only: false).gsub('/', '\\/')
|
|
255
|
+
sorted_map[AlipayConstants::BIZ_CONTENT_FIELD] = serialized
|
|
256
|
+
end
|
|
248
257
|
end
|
|
249
258
|
if !@text_params.nil? && !@text_params.empty?
|
|
250
259
|
if !sorted_map.empty?
|
|
@@ -253,15 +262,19 @@ module Alipay
|
|
|
253
262
|
sorted_map = @text_params
|
|
254
263
|
end
|
|
255
264
|
end
|
|
256
|
-
|
|
257
|
-
|
|
265
|
+
notify_value = get_config(AlipayConstants::NOTIFY_URL_CONFIG_KEY)
|
|
266
|
+
if !notify_value.nil? && notify_value.to_s.strip != ''
|
|
267
|
+
sorted_map[AlipayConstants::NOTIFY_URL_FIELD] = notify_value
|
|
258
268
|
end
|
|
259
269
|
return sorted_map
|
|
260
270
|
end
|
|
261
271
|
|
|
262
272
|
def get_sign_content(params)
|
|
263
273
|
# 模拟PHP的ksort
|
|
264
|
-
|
|
274
|
+
normalized = params.each_with_object({}) do |(key, value), acc|
|
|
275
|
+
acc[key.to_s] = value
|
|
276
|
+
end
|
|
277
|
+
sorted_params = normalized.sort.to_h
|
|
265
278
|
|
|
266
279
|
string_to_be_signed = ""
|
|
267
280
|
i = 0
|
|
@@ -281,7 +294,9 @@ module Alipay
|
|
|
281
294
|
end
|
|
282
295
|
|
|
283
296
|
def get_gateway_server_url
|
|
284
|
-
|
|
297
|
+
protocol = get_config(AlipayConstants::PROTOCOL_CONFIG_KEY)
|
|
298
|
+
host = get_config(AlipayConstants::HOST_CONFIG_KEY)
|
|
299
|
+
return protocol + '://' + host.gsub('/gateway.do', '') + '/gateway.do'
|
|
285
300
|
end
|
|
286
301
|
|
|
287
302
|
def check_empty(value)
|
|
@@ -322,25 +337,8 @@ module Alipay
|
|
|
322
337
|
puts "[DEBUG] build_form - 原始params keys: #{params.keys.join(', ')}" if ENV['DEBUG']
|
|
323
338
|
puts "[DEBUG] build_form - sign长度: #{params[AlipayConstants::SIGN_FIELD].length}" if ENV['DEBUG'] && params[AlipayConstants::SIGN_FIELD]
|
|
324
339
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
params.each do |key, val|
|
|
328
|
-
if !check_empty(val) # 与PHP版本的checkEmpty逻辑完全一致
|
|
329
|
-
# 按照PHP版本:将单引号替换为&apos;
|
|
330
|
-
escaped_val = val.to_s.gsub("'", "'")
|
|
331
|
-
form_fields += "<input type='hidden' name='#{key}' value='#{escaped_val}'/>"
|
|
332
|
-
end
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
# 完全按照PHP版本:在action URL中添加charset参数
|
|
336
|
-
action_url = "#{url}?charset=#{AlipayConstants::DEFAULT_CHARSET}"
|
|
337
|
-
|
|
338
|
-
<<~HTML
|
|
339
|
-
<form id='alipaysubmit' name='alipaysubmit' action='#{action_url}' method='POST'>
|
|
340
|
-
#{form_fields}
|
|
341
|
-
<input type='submit' value='ok' style='display:none;'></form>
|
|
342
|
-
<script>document.forms['alipaysubmit'].submit();</script>
|
|
343
|
-
HTML
|
|
340
|
+
page_util = Alipay::EasySDK::Kernel::Util::PageUtil.new
|
|
341
|
+
page_util.build_form(url, params)
|
|
344
342
|
end
|
|
345
343
|
|
|
346
344
|
def build_signed_params(system_params, biz_params, text_params, sign)
|
|
@@ -350,10 +348,25 @@ module Alipay
|
|
|
350
348
|
end
|
|
351
349
|
|
|
352
350
|
def build_gateway_url(signed_params)
|
|
353
|
-
base_url = get_gateway_server_url
|
|
351
|
+
base_url = get_gateway_server_url
|
|
354
352
|
query = build_query_string(signed_params)
|
|
355
353
|
return base_url if query.nil? || query.empty?
|
|
356
|
-
base_url + '
|
|
354
|
+
base_url + '?' + query
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def build_multipart_text_part(boundary, key, value)
|
|
358
|
+
"--#{boundary}\r\n" \
|
|
359
|
+
"Content-Disposition: form-data; name=\"#{key}\"\r\n" \
|
|
360
|
+
"\r\n" \
|
|
361
|
+
"#{value}\r\n"
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def build_multipart_file_part(boundary, key, filename, content)
|
|
365
|
+
"--#{boundary}\r\n" \
|
|
366
|
+
"Content-Disposition: form-data; name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
|
|
367
|
+
"Content-Type: application/octet-stream\r\n" \
|
|
368
|
+
"\r\n" \
|
|
369
|
+
"#{content}\r\n"
|
|
357
370
|
end
|
|
358
371
|
end
|
|
359
372
|
end
|