alipay-easysdk-ruby 1.0.1 → 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 +96 -25
- data/lib/alipay/easysdk/kernel/easy_sdk_kernel.rb +104 -71
- data/lib/alipay/easysdk/kernel/factory.rb +33 -11
- 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 +59 -7
- 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 +9 -4
- data/examples/demo.rb +0 -133
- 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,36 +1,107 @@
|
|
|
1
|
-
require_relative 'alipay_constants'
|
|
2
|
-
|
|
3
1
|
module Alipay
|
|
4
2
|
module EasySDK
|
|
5
3
|
module Kernel
|
|
6
4
|
class Config
|
|
7
|
-
attr_accessor :protocol,
|
|
8
|
-
:
|
|
9
|
-
:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
5
|
+
attr_accessor :protocol,
|
|
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
|
|
21
|
+
|
|
22
|
+
def initialize(options = nil)
|
|
23
|
+
assign_attributes(options) if options
|
|
24
|
+
end
|
|
25
|
+
|
|
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=
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
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)
|
|
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
|
+
|
|
94
|
+
nil
|
|
24
95
|
end
|
|
25
96
|
|
|
26
|
-
def
|
|
27
|
-
|
|
97
|
+
def underscore_to_camel(str)
|
|
98
|
+
str.split('_').inject do |memo, part|
|
|
99
|
+
memo + part.capitalize
|
|
100
|
+
end
|
|
28
101
|
end
|
|
29
102
|
|
|
30
|
-
def
|
|
31
|
-
|
|
32
|
-
raise "merchant_private_key is required" if @merchant_private_key.nil? || @merchant_private_key.empty?
|
|
33
|
-
raise "alipay_public_key is required" if @alipay_public_key.nil? || @alipay_public_key.empty?
|
|
103
|
+
def camel_to_snake(str)
|
|
104
|
+
str.gsub(/([A-Z]+)/) { "_#{$1.downcase}" }.sub(/^_/, '')
|
|
34
105
|
end
|
|
35
106
|
end
|
|
36
107
|
end
|
|
@@ -3,9 +3,12 @@ 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'
|
|
11
|
+
require 'json'
|
|
9
12
|
|
|
10
13
|
module Alipay
|
|
11
14
|
module EasySDK
|
|
@@ -38,28 +41,16 @@ module Alipay
|
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
def get_config(key)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
@config.alipay_public_key
|
|
52
|
-
when 'signType'
|
|
53
|
-
@config.sign_type
|
|
54
|
-
when 'charset'
|
|
55
|
-
@config.charset
|
|
56
|
-
when 'format'
|
|
57
|
-
@config.format
|
|
58
|
-
when 'version'
|
|
59
|
-
@config.version
|
|
60
|
-
else
|
|
61
|
-
nil
|
|
62
|
-
end
|
|
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
|
|
63
54
|
end
|
|
64
55
|
|
|
65
56
|
def get_sdk_version
|
|
@@ -77,9 +68,9 @@ module Alipay
|
|
|
77
68
|
def read_as_json(response, method)
|
|
78
69
|
response_body = response.body
|
|
79
70
|
map = {}
|
|
80
|
-
map[
|
|
81
|
-
map[
|
|
82
|
-
|
|
71
|
+
map[AlipayConstants::BODY_FIELD] = response_body
|
|
72
|
+
map[AlipayConstants::METHOD_FIELD] = method
|
|
73
|
+
map
|
|
83
74
|
end
|
|
84
75
|
|
|
85
76
|
def get_random_boundary
|
|
@@ -89,11 +80,12 @@ module Alipay
|
|
|
89
80
|
def generate_page(method, system_params, biz_params, text_params, sign)
|
|
90
81
|
puts "[DEBUG] generate_page - sign长度: #{sign.length}" if ENV['DEBUG']
|
|
91
82
|
signed_params = build_signed_params(system_params, biz_params, text_params, sign)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
case method
|
|
84
|
+
when AlipayConstants::GET
|
|
85
|
+
build_gateway_url(signed_params)
|
|
86
|
+
when AlipayConstants::POST
|
|
95
87
|
puts "[DEBUG] generate_page POST - sorted_map中sign长度: #{signed_params[AlipayConstants::SIGN_FIELD].length}" if ENV['DEBUG']
|
|
96
|
-
|
|
88
|
+
build_form(get_gateway_server_url, signed_params)
|
|
97
89
|
else
|
|
98
90
|
raise "不支持" + method
|
|
99
91
|
end
|
|
@@ -110,8 +102,8 @@ module Alipay
|
|
|
110
102
|
|
|
111
103
|
def get_alipay_cert_sn(resp_map)
|
|
112
104
|
if !@config.merchant_cert_sn.nil? && !@config.merchant_cert_sn.empty?
|
|
113
|
-
body = JSON.parse(resp_map[
|
|
114
|
-
alipay_cert_sn = body[
|
|
105
|
+
body = JSON.parse(resp_map[AlipayConstants::BODY_FIELD])
|
|
106
|
+
alipay_cert_sn = body[AlipayConstants::ALIPAY_CERT_SN_FIELD]
|
|
115
107
|
return alipay_cert_sn
|
|
116
108
|
end
|
|
117
109
|
end
|
|
@@ -130,10 +122,10 @@ module Alipay
|
|
|
130
122
|
end
|
|
131
123
|
|
|
132
124
|
def verify(resp_map, alipay_public_key)
|
|
133
|
-
resp = JSON.parse(resp_map[
|
|
125
|
+
resp = JSON.parse(resp_map[AlipayConstants::BODY_FIELD])
|
|
134
126
|
sign = resp[AlipayConstants::SIGN_FIELD]
|
|
135
127
|
sign_content_extractor = Alipay::EasySDK::Kernel::Util::SignContentExtractor.new
|
|
136
|
-
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])
|
|
137
129
|
signer = Alipay::EasySDK::Kernel::Util::Signer.new
|
|
138
130
|
return signer.verify(content, sign, alipay_public_key)
|
|
139
131
|
end
|
|
@@ -158,18 +150,55 @@ module Alipay
|
|
|
158
150
|
URI.encode_www_form(sorted_map)
|
|
159
151
|
end
|
|
160
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
|
+
|
|
161
190
|
def sort_map(random_map)
|
|
162
191
|
return random_map
|
|
163
192
|
end
|
|
164
193
|
|
|
165
194
|
def to_resp_model(resp_map)
|
|
166
|
-
body = resp_map[
|
|
167
|
-
method_name = resp_map[
|
|
195
|
+
body = resp_map[AlipayConstants::BODY_FIELD]
|
|
196
|
+
method_name = resp_map[AlipayConstants::METHOD_FIELD]
|
|
168
197
|
response_node_name = method_name.gsub(".", "_") + "_response"
|
|
169
198
|
|
|
170
199
|
model = JSON.parse(body)
|
|
171
|
-
if body.include?(
|
|
172
|
-
result = model[
|
|
200
|
+
if body.include?(AlipayConstants::ERROR_RESPONSE)
|
|
201
|
+
result = model[AlipayConstants::ERROR_RESPONSE]
|
|
173
202
|
result['body'] = body
|
|
174
203
|
else
|
|
175
204
|
result = model[response_node_name]
|
|
@@ -216,15 +245,15 @@ module Alipay
|
|
|
216
245
|
@biz_params = @optional_biz_params
|
|
217
246
|
end
|
|
218
247
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
248
|
+
json_util = Alipay::EasySDK::Kernel::Util::JsonUtil.new
|
|
249
|
+
biz_content = json_util.to_json_string(@biz_params) unless @biz_params.nil?
|
|
250
|
+
|
|
251
|
+
sorted_map = (system_params || {}).dup
|
|
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
|
|
228
257
|
end
|
|
229
258
|
if !@text_params.nil? && !@text_params.empty?
|
|
230
259
|
if !sorted_map.empty?
|
|
@@ -233,15 +262,19 @@ module Alipay
|
|
|
233
262
|
sorted_map = @text_params
|
|
234
263
|
end
|
|
235
264
|
end
|
|
236
|
-
|
|
237
|
-
|
|
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
|
|
238
268
|
end
|
|
239
269
|
return sorted_map
|
|
240
270
|
end
|
|
241
271
|
|
|
242
272
|
def get_sign_content(params)
|
|
243
273
|
# 模拟PHP的ksort
|
|
244
|
-
|
|
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
|
|
245
278
|
|
|
246
279
|
string_to_be_signed = ""
|
|
247
280
|
i = 0
|
|
@@ -261,7 +294,9 @@ module Alipay
|
|
|
261
294
|
end
|
|
262
295
|
|
|
263
296
|
def get_gateway_server_url
|
|
264
|
-
|
|
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'
|
|
265
300
|
end
|
|
266
301
|
|
|
267
302
|
def check_empty(value)
|
|
@@ -302,25 +337,8 @@ module Alipay
|
|
|
302
337
|
puts "[DEBUG] build_form - 原始params keys: #{params.keys.join(', ')}" if ENV['DEBUG']
|
|
303
338
|
puts "[DEBUG] build_form - sign长度: #{params[AlipayConstants::SIGN_FIELD].length}" if ENV['DEBUG'] && params[AlipayConstants::SIGN_FIELD]
|
|
304
339
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
params.each do |key, val|
|
|
308
|
-
if !check_empty(val) # 与PHP版本的checkEmpty逻辑完全一致
|
|
309
|
-
# 按照PHP版本:将单引号替换为&apos;
|
|
310
|
-
escaped_val = val.to_s.gsub("'", "'")
|
|
311
|
-
form_fields += "<input type='hidden' name='#{key}' value='#{escaped_val}'/>"
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
# 完全按照PHP版本:在action URL中添加charset参数
|
|
316
|
-
action_url = "#{url}?charset=#{AlipayConstants::DEFAULT_CHARSET}"
|
|
317
|
-
|
|
318
|
-
<<~HTML
|
|
319
|
-
<form id='alipaysubmit' name='alipaysubmit' action='#{action_url}' method='POST'>
|
|
320
|
-
#{form_fields}
|
|
321
|
-
<input type='submit' value='ok' style='display:none;'></form>
|
|
322
|
-
<script>document.forms['alipaysubmit'].submit();</script>
|
|
323
|
-
HTML
|
|
340
|
+
page_util = Alipay::EasySDK::Kernel::Util::PageUtil.new
|
|
341
|
+
page_util.build_form(url, params)
|
|
324
342
|
end
|
|
325
343
|
|
|
326
344
|
def build_signed_params(system_params, biz_params, text_params, sign)
|
|
@@ -330,10 +348,25 @@ module Alipay
|
|
|
330
348
|
end
|
|
331
349
|
|
|
332
350
|
def build_gateway_url(signed_params)
|
|
333
|
-
base_url = get_gateway_server_url
|
|
351
|
+
base_url = get_gateway_server_url
|
|
334
352
|
query = build_query_string(signed_params)
|
|
335
353
|
return base_url if query.nil? || query.empty?
|
|
336
|
-
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"
|
|
337
370
|
end
|
|
338
371
|
end
|
|
339
372
|
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require_relative 'alipay_constants'
|
|
2
2
|
require_relative 'config'
|
|
3
|
+
require_relative 'cert_environment'
|
|
3
4
|
require_relative 'easy_sdk_kernel'
|
|
5
|
+
require_relative '../payment/app/client'
|
|
4
6
|
require_relative '../payment/wap/client'
|
|
5
7
|
require_relative '../payment/page/client'
|
|
6
8
|
require_relative '../payment/common/client'
|
|
@@ -12,10 +14,13 @@ module Alipay
|
|
|
12
14
|
class ConfigurationNotSetError < StandardError; end
|
|
13
15
|
|
|
14
16
|
class << self
|
|
15
|
-
def set_options(options
|
|
17
|
+
def set_options(options)
|
|
18
|
+
raise ArgumentError, '配置参数不能为空' if options.nil?
|
|
19
|
+
return @instance if defined?(@instance) && @instance
|
|
20
|
+
|
|
16
21
|
config = normalize_config(options)
|
|
17
22
|
initialize_context(config)
|
|
18
|
-
@instance
|
|
23
|
+
@instance = self
|
|
19
24
|
end
|
|
20
25
|
|
|
21
26
|
alias setOptions set_options
|
|
@@ -26,14 +31,18 @@ module Alipay
|
|
|
26
31
|
@config
|
|
27
32
|
end
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
34
|
+
def payment
|
|
35
|
+
ensure_context_set!
|
|
36
|
+
@payment
|
|
37
|
+
end
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
39
|
+
def app
|
|
40
|
+
payment.app
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def wap
|
|
44
|
+
payment.wap
|
|
45
|
+
end
|
|
37
46
|
|
|
38
47
|
def page
|
|
39
48
|
payment.page
|
|
@@ -55,21 +64,30 @@ module Alipay
|
|
|
55
64
|
private
|
|
56
65
|
|
|
57
66
|
def normalize_config(options)
|
|
58
|
-
raise ArgumentError, '配置参数不能为空' if options.nil?
|
|
59
67
|
return options if options.is_a?(Config)
|
|
60
68
|
Config.new(options)
|
|
61
69
|
end
|
|
62
70
|
|
|
63
71
|
def initialize_context(config)
|
|
72
|
+
apply_cert_environment(config)
|
|
64
73
|
@config = config
|
|
65
74
|
@kernel = EasySDKKernel.new(config)
|
|
66
75
|
@payment = Payment.new(@kernel)
|
|
67
|
-
@instance = self
|
|
68
76
|
end
|
|
69
77
|
|
|
70
78
|
def ensure_context_set!
|
|
71
79
|
raise ConfigurationNotSetError, '请先调用Factory.set_options(config)设置SDK配置' unless @config
|
|
72
80
|
end
|
|
81
|
+
|
|
82
|
+
def apply_cert_environment(config)
|
|
83
|
+
return if config.alipayCertPath.nil? || config.alipayCertPath.to_s.strip.empty?
|
|
84
|
+
|
|
85
|
+
cert_env = CertEnvironment.new
|
|
86
|
+
cert_env.setup(config.merchantCertPath, config.alipayCertPath, config.alipayRootCertPath)
|
|
87
|
+
config.merchantCertSN = cert_env.merchant_cert_sn
|
|
88
|
+
config.alipayRootCertSN = cert_env.root_cert_sn
|
|
89
|
+
config.alipayPublicKey ||= cert_env.cached_alipay_public_key
|
|
90
|
+
end
|
|
73
91
|
end
|
|
74
92
|
|
|
75
93
|
class Payment
|
|
@@ -77,6 +95,10 @@ module Alipay
|
|
|
77
95
|
@kernel = kernel
|
|
78
96
|
end
|
|
79
97
|
|
|
98
|
+
def app
|
|
99
|
+
@app ||= Alipay::EasySDK::Payment::App::Client.new(@kernel)
|
|
100
|
+
end
|
|
101
|
+
|
|
80
102
|
def wap
|
|
81
103
|
@wap ||= Alipay::EasySDK::Payment::Wap::Client.new(@kernel)
|
|
82
104
|
end
|