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
|
@@ -2,6 +2,7 @@ require_relative 'alipay_constants'
|
|
|
2
2
|
require_relative 'config'
|
|
3
3
|
require_relative 'cert_environment'
|
|
4
4
|
require_relative 'easy_sdk_kernel'
|
|
5
|
+
require_relative '../payment/app/client'
|
|
5
6
|
require_relative '../payment/wap/client'
|
|
6
7
|
require_relative '../payment/page/client'
|
|
7
8
|
require_relative '../payment/common/client'
|
|
@@ -13,10 +14,13 @@ module Alipay
|
|
|
13
14
|
class ConfigurationNotSetError < StandardError; end
|
|
14
15
|
|
|
15
16
|
class << self
|
|
16
|
-
def set_options(options
|
|
17
|
+
def set_options(options)
|
|
18
|
+
raise ArgumentError, '配置参数不能为空' if options.nil?
|
|
19
|
+
return @instance if defined?(@instance) && @instance
|
|
20
|
+
|
|
17
21
|
config = normalize_config(options)
|
|
18
22
|
initialize_context(config)
|
|
19
|
-
@instance
|
|
23
|
+
@instance = self
|
|
20
24
|
end
|
|
21
25
|
|
|
22
26
|
alias setOptions set_options
|
|
@@ -27,14 +31,18 @@ module Alipay
|
|
|
27
31
|
@config
|
|
28
32
|
end
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
def payment
|
|
35
|
+
ensure_context_set!
|
|
36
|
+
@payment
|
|
37
|
+
end
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
def app
|
|
40
|
+
payment.app
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def wap
|
|
44
|
+
payment.wap
|
|
45
|
+
end
|
|
38
46
|
|
|
39
47
|
def page
|
|
40
48
|
payment.page
|
|
@@ -56,17 +64,15 @@ module Alipay
|
|
|
56
64
|
private
|
|
57
65
|
|
|
58
66
|
def normalize_config(options)
|
|
59
|
-
|
|
60
|
-
|
|
67
|
+
return options if options.is_a?(Config)
|
|
68
|
+
Config.new(options)
|
|
61
69
|
end
|
|
62
70
|
|
|
63
71
|
def initialize_context(config)
|
|
64
72
|
apply_cert_environment(config)
|
|
65
|
-
config.validate
|
|
66
73
|
@config = config
|
|
67
74
|
@kernel = EasySDKKernel.new(config)
|
|
68
75
|
@payment = Payment.new(@kernel)
|
|
69
|
-
@instance = self
|
|
70
76
|
end
|
|
71
77
|
|
|
72
78
|
def ensure_context_set!
|
|
@@ -74,13 +80,13 @@ module Alipay
|
|
|
74
80
|
end
|
|
75
81
|
|
|
76
82
|
def apply_cert_environment(config)
|
|
77
|
-
return if config.
|
|
83
|
+
return if config.alipayCertPath.nil? || config.alipayCertPath.to_s.strip.empty?
|
|
78
84
|
|
|
79
85
|
cert_env = CertEnvironment.new
|
|
80
|
-
cert_env.setup(config.
|
|
81
|
-
config.
|
|
82
|
-
config.
|
|
83
|
-
config.
|
|
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
|
|
84
90
|
end
|
|
85
91
|
end
|
|
86
92
|
|
|
@@ -89,6 +95,10 @@ module Alipay
|
|
|
89
95
|
@kernel = kernel
|
|
90
96
|
end
|
|
91
97
|
|
|
98
|
+
def app
|
|
99
|
+
@app ||= Alipay::EasySDK::Payment::App::Client.new(@kernel)
|
|
100
|
+
end
|
|
101
|
+
|
|
92
102
|
def wap
|
|
93
103
|
@wap ||= Alipay::EasySDK::Payment::Wap::Client.new(@kernel)
|
|
94
104
|
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
require 'base64'
|
|
3
|
+
|
|
4
|
+
module Alipay
|
|
5
|
+
module EasySDK
|
|
6
|
+
module Kernel
|
|
7
|
+
module Util
|
|
8
|
+
class AES
|
|
9
|
+
def aes_encrypt(plain_text, key)
|
|
10
|
+
raise encryption_error(plain_text, key) if key.to_s.empty?
|
|
11
|
+
|
|
12
|
+
secret_key = Base64.decode64(key)
|
|
13
|
+
padded = add_pkcs7_padding(plain_text.to_s)
|
|
14
|
+
|
|
15
|
+
cipher = OpenSSL::Cipher.new('AES-128-CBC')
|
|
16
|
+
cipher.encrypt
|
|
17
|
+
cipher.key = secret_key
|
|
18
|
+
cipher.iv = "\0" * 16
|
|
19
|
+
cipher.padding = 0
|
|
20
|
+
|
|
21
|
+
encrypted = cipher.update(padded) + cipher.final
|
|
22
|
+
Base64.strict_encode64(encrypted)
|
|
23
|
+
rescue StandardError => e
|
|
24
|
+
raise StandardError, "AES加密失败,plainText=#{plain_text},keySize=#{key.to_s.length}。#{e.message}"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def aes_decrypt(cipher_text, key)
|
|
28
|
+
raise decryption_error(cipher_text, key) if key.to_s.empty?
|
|
29
|
+
|
|
30
|
+
secret_key = Base64.decode64(key)
|
|
31
|
+
encrypted = Base64.decode64(cipher_text)
|
|
32
|
+
|
|
33
|
+
decipher = OpenSSL::Cipher.new('AES-128-CBC')
|
|
34
|
+
decipher.decrypt
|
|
35
|
+
decipher.key = secret_key
|
|
36
|
+
decipher.iv = "\0" * 16
|
|
37
|
+
decipher.padding = 0
|
|
38
|
+
|
|
39
|
+
decrypted = decipher.update(encrypted) + decipher.final
|
|
40
|
+
strip_pkcs7_padding(decrypted)
|
|
41
|
+
rescue StandardError => e
|
|
42
|
+
raise StandardError, "AES解密失败,cipherText=#{cipher_text},keySize=#{key.to_s.length}。#{e.message}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def add_pkcs7_padding(source)
|
|
48
|
+
str = source.to_s.strip
|
|
49
|
+
block = 16
|
|
50
|
+
pad = block - (str.bytesize % block)
|
|
51
|
+
pad = block if pad.zero?
|
|
52
|
+
str + (pad.chr * pad)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def strip_pkcs7_padding(source)
|
|
56
|
+
return source if source.nil? || source.empty?
|
|
57
|
+
|
|
58
|
+
char = source[-1]
|
|
59
|
+
num = char.ord
|
|
60
|
+
return source if num == 62
|
|
61
|
+
source[0...-num]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def encryption_error(plain_text, key)
|
|
65
|
+
StandardError.new("AES加密失败,plainText=#{plain_text},AES密钥为空。")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def decryption_error(cipher_text, key)
|
|
69
|
+
StandardError.new("AES解密失败,cipherText=#{cipher_text},AES密钥为空。")
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
require 'digest/md5'
|
|
3
|
+
|
|
4
|
+
module Alipay
|
|
5
|
+
module EasySDK
|
|
6
|
+
module Kernel
|
|
7
|
+
module Util
|
|
8
|
+
class AntCertificationUtil
|
|
9
|
+
SUPPORTED_SIGNATURES = %w[sha1WithRSAEncryption sha256WithRSAEncryption].freeze
|
|
10
|
+
|
|
11
|
+
def cert_sn(cert_path)
|
|
12
|
+
cert = load_certificate(cert_path)
|
|
13
|
+
signature_digest(cert.issuer.to_a, cert.serial)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def public_key(cert_path)
|
|
17
|
+
cert = load_certificate(cert_path)
|
|
18
|
+
key_pem = cert.public_key.to_pem
|
|
19
|
+
key_pem.gsub(/-----BEGIN PUBLIC KEY-----/, '')
|
|
20
|
+
.gsub(/-----END PUBLIC KEY-----/, '')
|
|
21
|
+
.gsub(/\s+/, '')
|
|
22
|
+
.strip
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def root_cert_sn(cert_path)
|
|
26
|
+
certs = load_cert_chain(cert_path)
|
|
27
|
+
sns = certs.each_with_object([]) do |cert, acc|
|
|
28
|
+
next unless SUPPORTED_SIGNATURES.include?(cert.signature_algorithm)
|
|
29
|
+
|
|
30
|
+
acc << signature_digest(cert.issuer.to_a, cert.serial)
|
|
31
|
+
end
|
|
32
|
+
sns.join('_')
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def load_certificate(path)
|
|
38
|
+
raise ArgumentError, '证书路径不能为空' if path.nil? || path.to_s.strip.empty?
|
|
39
|
+
|
|
40
|
+
OpenSSL::X509::Certificate.new(File.read(path))
|
|
41
|
+
rescue Errno::ENOENT => e
|
|
42
|
+
raise RuntimeError, "无法读取证书文件: #{path} - #{e.message}"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def load_cert_chain(path)
|
|
46
|
+
pem = File.read(path)
|
|
47
|
+
pem.split(/(?=-----BEGIN CERTIFICATE-----)/)
|
|
48
|
+
.reject(&:empty?)
|
|
49
|
+
.map { |chunk| OpenSSL::X509::Certificate.new(chunk) }
|
|
50
|
+
rescue Errno::ENOENT => e
|
|
51
|
+
raise RuntimeError, "无法读取证书链文件: #{path} - #{e.message}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def signature_digest(issuer_array, serial)
|
|
55
|
+
issuer_str = issuer_array.reverse.map { |name, data, _| "#{name}=#{data}" }.join(',')
|
|
56
|
+
serial_str = serial.to_i.to_s
|
|
57
|
+
Digest::MD5.hexdigest("#{issuer_str}#{serial_str}")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -7,14 +7,9 @@ module Alipay
|
|
|
7
7
|
class JsonUtil
|
|
8
8
|
# 完全复制PHP版本的toJsonString方法
|
|
9
9
|
def to_json_string(obj)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
when String
|
|
14
|
-
obj
|
|
15
|
-
else
|
|
16
|
-
obj.to_s
|
|
17
|
-
end
|
|
10
|
+
return {} if obj.nil?
|
|
11
|
+
raise ArgumentError, 'to_json_string expects a Hash' unless obj.is_a?(Hash)
|
|
12
|
+
convert_map(obj)
|
|
18
13
|
end
|
|
19
14
|
|
|
20
15
|
def self.from_json_string(json_string)
|
|
@@ -23,6 +18,53 @@ module Alipay
|
|
|
23
18
|
rescue JSON::ParserError
|
|
24
19
|
json_string
|
|
25
20
|
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def convert_map(hash)
|
|
25
|
+
return hash unless hash.is_a?(Hash)
|
|
26
|
+
|
|
27
|
+
hash.each_with_object({}) do |(key, value), result|
|
|
28
|
+
result[underscore_key(key)] = convert_value(value)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def convert_value(value)
|
|
33
|
+
case value
|
|
34
|
+
when Hash
|
|
35
|
+
convert_map(value)
|
|
36
|
+
when Array
|
|
37
|
+
value.map { |item| convert_value(item) }
|
|
38
|
+
else
|
|
39
|
+
convert_object(value)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def convert_object(value)
|
|
44
|
+
return value if primitive?(value)
|
|
45
|
+
|
|
46
|
+
if value.respond_to?(:to_h)
|
|
47
|
+
convert_map(value.to_h)
|
|
48
|
+
elsif value.respond_to?(:to_hash)
|
|
49
|
+
convert_map(value.to_hash)
|
|
50
|
+
else
|
|
51
|
+
value
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def underscore_key(key)
|
|
56
|
+
str = key.to_s
|
|
57
|
+
underscored = str.gsub(/([A-Z]+)/) { "_#{$1.downcase}" }
|
|
58
|
+
underscored.gsub(/__+/, '_').sub(/^_/, '')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def primitive?(value)
|
|
62
|
+
value.is_a?(String) ||
|
|
63
|
+
value.is_a?(Numeric) ||
|
|
64
|
+
value == true ||
|
|
65
|
+
value == false ||
|
|
66
|
+
value.nil?
|
|
67
|
+
end
|
|
26
68
|
end
|
|
27
69
|
end
|
|
28
70
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Alipay
|
|
2
|
+
module EasySDK
|
|
3
|
+
module Kernel
|
|
4
|
+
module Util
|
|
5
|
+
class PageUtil
|
|
6
|
+
def build_form(action_url, parameters)
|
|
7
|
+
charset = Alipay::EasySDK::Kernel::AlipayConstants::DEFAULT_CHARSET
|
|
8
|
+
form = "<form id='alipaysubmit' name='alipaysubmit' action='#{action_url}?charset=#{charset}' method='POST'>"
|
|
9
|
+
params_enum(parameters).each do |key, val|
|
|
10
|
+
next if check_empty(val)
|
|
11
|
+
|
|
12
|
+
escaped = val.to_s.gsub("'", "'")
|
|
13
|
+
form += "<input type='hidden' name='#{key}' value='#{escaped}'/>"
|
|
14
|
+
end
|
|
15
|
+
form += "<input type='submit' value='ok' style='display:none;'></form>"
|
|
16
|
+
form += "<script>document.forms['alipaysubmit'].submit();</script>"
|
|
17
|
+
form
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def params_enum(parameters)
|
|
23
|
+
return [] if parameters.nil?
|
|
24
|
+
parameters.to_a
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def check_empty(value)
|
|
28
|
+
!value || value.to_s.strip == ''
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -7,7 +7,12 @@ module Alipay
|
|
|
7
7
|
return true if response.respond_to?(:code) && response.code.to_s == '10000'
|
|
8
8
|
|
|
9
9
|
code_blank = !response.respond_to?(:code) || blank?(response.code)
|
|
10
|
-
|
|
10
|
+
sub_code_value = if response.respond_to?(:subCode)
|
|
11
|
+
response.subCode
|
|
12
|
+
elsif response.respond_to?(:sub_code)
|
|
13
|
+
response.sub_code
|
|
14
|
+
end
|
|
15
|
+
sub_code_blank = blank?(sub_code_value)
|
|
11
16
|
|
|
12
17
|
code_blank && sub_code_blank
|
|
13
18
|
end
|
|
@@ -49,7 +49,7 @@ module Alipay
|
|
|
49
49
|
# 调用openssl内置方法验签,完全模仿PHP的openssl_verify
|
|
50
50
|
public_key = OpenSSL::PKey::RSA.new(res)
|
|
51
51
|
digest = OpenSSL::Digest::SHA256.new
|
|
52
|
-
decoded_sign = Base64.decode64(sign)
|
|
52
|
+
decoded_sign = Base64.decode64(sign.to_s)
|
|
53
53
|
|
|
54
54
|
result = public_key.verify(digest, decoded_sign, content)
|
|
55
55
|
return result
|
|
@@ -59,14 +59,16 @@ module Alipay
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
def verify_params(parameters, public_key)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
normalized = stringify_keys(parameters)
|
|
63
|
+
sign = normalized['sign'] || ''
|
|
64
|
+
content = get_sign_content(normalized)
|
|
65
|
+
verify(content, sign, public_key)
|
|
65
66
|
end
|
|
66
67
|
|
|
67
68
|
def get_sign_content(params)
|
|
69
|
+
normalized = stringify_keys(params)
|
|
68
70
|
# 模拟PHP的ksort
|
|
69
|
-
sorted_params =
|
|
71
|
+
sorted_params = normalized.sort.to_h
|
|
70
72
|
|
|
71
73
|
# 移除sign和sign_type字段
|
|
72
74
|
sorted_params.delete('sign')
|
|
@@ -89,6 +91,14 @@ module Alipay
|
|
|
89
91
|
|
|
90
92
|
private
|
|
91
93
|
|
|
94
|
+
def stringify_keys(hash)
|
|
95
|
+
return {} if hash.nil?
|
|
96
|
+
|
|
97
|
+
hash.each_with_object({}) do |(key, value), acc|
|
|
98
|
+
acc[key.to_s] = value
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
92
102
|
# 完全复制PHP的wordwrap函数
|
|
93
103
|
def wordwrap(str, width = 75, break_str = "\n", cut = false)
|
|
94
104
|
if str.nil? || str.empty?
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require_relative '../../kernel/easy_sdk_kernel'
|
|
2
|
+
require_relative 'models/alipay_trade_app_pay_response'
|
|
3
|
+
|
|
4
|
+
module Alipay
|
|
5
|
+
module EasySDK
|
|
6
|
+
module Payment
|
|
7
|
+
module App
|
|
8
|
+
class Client
|
|
9
|
+
def initialize(kernel)
|
|
10
|
+
@kernel = kernel
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def pay(subject, out_trade_no, total_amount)
|
|
14
|
+
system_params = {
|
|
15
|
+
'method' => 'alipay.trade.app.pay',
|
|
16
|
+
'app_id' => @kernel.get_config('appId'),
|
|
17
|
+
'timestamp' => @kernel.get_timestamp,
|
|
18
|
+
'format' => 'json',
|
|
19
|
+
'version' => '1.0',
|
|
20
|
+
'alipay_sdk' => @kernel.get_sdk_version,
|
|
21
|
+
'charset' => 'UTF-8',
|
|
22
|
+
'sign_type' => @kernel.get_config('signType'),
|
|
23
|
+
'app_cert_sn' => @kernel.get_merchant_cert_sn,
|
|
24
|
+
'alipay_root_cert_sn' => @kernel.get_alipay_root_cert_sn
|
|
25
|
+
}
|
|
26
|
+
biz_params = {
|
|
27
|
+
'subject' => subject,
|
|
28
|
+
'out_trade_no' => out_trade_no,
|
|
29
|
+
'total_amount' => total_amount
|
|
30
|
+
}
|
|
31
|
+
text_params = {}
|
|
32
|
+
|
|
33
|
+
sign = @kernel.sign(system_params, biz_params, text_params, @kernel.get_config('merchantPrivateKey'))
|
|
34
|
+
response = {
|
|
35
|
+
Alipay::EasySDK::Kernel::AlipayConstants::BODY_FIELD => @kernel.generate_order_string(system_params, biz_params, text_params, sign)
|
|
36
|
+
}
|
|
37
|
+
Models::AlipayTradeAppPayResponse.from_map(response)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def agent(app_auth_token)
|
|
41
|
+
@kernel.inject_text_param('app_auth_token', app_auth_token)
|
|
42
|
+
self
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def auth(auth_token)
|
|
46
|
+
@kernel.inject_text_param('auth_token', auth_token)
|
|
47
|
+
self
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def async_notify(url)
|
|
51
|
+
@kernel.inject_text_param('notify_url', url)
|
|
52
|
+
self
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def route(test_url)
|
|
56
|
+
@kernel.inject_text_param('ws_service_url', test_url)
|
|
57
|
+
self
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def optional(key, value)
|
|
61
|
+
@kernel.inject_biz_param(key, value)
|
|
62
|
+
self
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def batch_optional(optional_args)
|
|
66
|
+
optional_args.each do |opt_key, opt_value|
|
|
67
|
+
@kernel.inject_biz_param(opt_key, opt_value)
|
|
68
|
+
end
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Alipay
|
|
2
|
+
module EasySDK
|
|
3
|
+
module Payment
|
|
4
|
+
module App
|
|
5
|
+
module Models
|
|
6
|
+
class AlipayTradeAppPayResponse
|
|
7
|
+
attr_accessor :body
|
|
8
|
+
|
|
9
|
+
def self.from_map(response)
|
|
10
|
+
new.tap do |instance|
|
|
11
|
+
instance.body = response[Alipay::EasySDK::Kernel::AlipayConstants::BODY_FIELD]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -17,6 +17,27 @@ module Alipay
|
|
|
17
17
|
module Payment
|
|
18
18
|
module Common
|
|
19
19
|
class Client
|
|
20
|
+
class TeaError < StandardError
|
|
21
|
+
attr_reader :data, :code
|
|
22
|
+
|
|
23
|
+
def initialize(data = {}, message = '', code = nil, cause = nil)
|
|
24
|
+
super(message)
|
|
25
|
+
@data = data
|
|
26
|
+
@code = code
|
|
27
|
+
set_backtrace(cause.backtrace) if cause
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class TeaUnableRetryError < StandardError
|
|
32
|
+
attr_reader :last_request, :last_exception
|
|
33
|
+
|
|
34
|
+
def initialize(last_request, last_exception)
|
|
35
|
+
super(last_exception&.message)
|
|
36
|
+
@last_request = last_request
|
|
37
|
+
@last_exception = last_exception
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
20
41
|
def initialize(kernel)
|
|
21
42
|
@kernel = kernel
|
|
22
43
|
end
|
|
@@ -72,7 +93,7 @@ module Alipay
|
|
|
72
93
|
|
|
73
94
|
def verify_notify(parameters)
|
|
74
95
|
if @kernel.is_cert_mode
|
|
75
|
-
@kernel.verify_params(parameters, @kernel.extract_alipay_public_key(
|
|
96
|
+
@kernel.verify_params(parameters, @kernel.extract_alipay_public_key(''))
|
|
76
97
|
else
|
|
77
98
|
@kernel.verify_params(parameters, @kernel.get_config('alipayPublicKey'))
|
|
78
99
|
end
|
|
@@ -118,7 +139,7 @@ module Alipay
|
|
|
118
139
|
sign = @kernel.sign(system_params, biz_params, text_params, @kernel.get_config('merchantPrivateKey'))
|
|
119
140
|
|
|
120
141
|
text_query = (@kernel.text_params || {}).dup
|
|
121
|
-
query_params = {
|
|
142
|
+
query_params = { Alipay::EasySDK::Kernel::AlipayConstants::SIGN_FIELD => sign }.merge(system_params)
|
|
122
143
|
query_params.merge!(text_query) unless text_query.empty?
|
|
123
144
|
|
|
124
145
|
uri = build_gateway_uri(query_params)
|
|
@@ -131,11 +152,15 @@ module Alipay
|
|
|
131
152
|
resp_map = @kernel.read_as_json(response, api_method)
|
|
132
153
|
|
|
133
154
|
unless verify_response(resp_map)
|
|
134
|
-
raise '验签失败,请检查支付宝公钥设置是否正确。'
|
|
155
|
+
raise TeaError.new({}, '验签失败,请检查支付宝公钥设置是否正确。')
|
|
135
156
|
end
|
|
136
157
|
|
|
137
158
|
map = @kernel.to_resp_model(resp_map)
|
|
138
159
|
response_class.from_map(map)
|
|
160
|
+
rescue TeaError => e
|
|
161
|
+
raise e
|
|
162
|
+
rescue StandardError => e
|
|
163
|
+
raise TeaError.new({}, e.message, nil, e)
|
|
139
164
|
ensure
|
|
140
165
|
clear_optional_params
|
|
141
166
|
end
|
|
@@ -156,8 +181,8 @@ module Alipay
|
|
|
156
181
|
end
|
|
157
182
|
|
|
158
183
|
def build_gateway_uri(query_params)
|
|
159
|
-
host = @kernel.get_config(
|
|
160
|
-
scheme = @kernel.get_config(
|
|
184
|
+
host = @kernel.get_config(Alipay::EasySDK::Kernel::AlipayConstants::HOST_CONFIG_KEY).to_s.sub(%r{/gateway\.do$}, '')
|
|
185
|
+
scheme = @kernel.get_config(Alipay::EasySDK::Kernel::AlipayConstants::PROTOCOL_CONFIG_KEY) || 'https'
|
|
161
186
|
uri = URI("#{scheme}://#{host}/gateway.do")
|
|
162
187
|
uri.query = URI.encode_www_form(query_params.sort.to_h)
|
|
163
188
|
uri
|
|
@@ -20,20 +20,6 @@ module Alipay
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
|
-
|
|
24
|
-
def success?
|
|
25
|
-
respond_to?('code') ? public_send('code') == '10000' : false
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def error_message
|
|
29
|
-
if respond_to?('sub_msg') && public_send('sub_msg')
|
|
30
|
-
public_send('sub_msg')
|
|
31
|
-
elsif respond_to?('msg')
|
|
32
|
-
public_send('msg')
|
|
33
|
-
else
|
|
34
|
-
nil
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
23
|
end
|
|
38
24
|
end
|
|
39
25
|
end
|
|
@@ -36,7 +36,7 @@ module Alipay
|
|
|
36
36
|
sign = @kernel.sign(system_params, biz_params, text_params, @kernel.get_config('merchantPrivateKey'))
|
|
37
37
|
|
|
38
38
|
response = {
|
|
39
|
-
|
|
39
|
+
Alipay::EasySDK::Kernel::AlipayConstants::BODY_FIELD => @kernel.generate_page('POST', system_params, biz_params, text_params, sign),
|
|
40
40
|
'payment_url' => @kernel.generate_payment_url(system_params, biz_params, text_params, sign)
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -8,26 +8,10 @@ module Alipay
|
|
|
8
8
|
|
|
9
9
|
def self.from_map(response)
|
|
10
10
|
new.tap do |instance|
|
|
11
|
-
instance.body = response[
|
|
11
|
+
instance.body = response[Alipay::EasySDK::Kernel::AlipayConstants::BODY_FIELD]
|
|
12
12
|
instance.payment_url = response['payment_url']
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
|
-
|
|
16
|
-
def success?
|
|
17
|
-
!body.nil? && !body.to_s.empty?
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def form
|
|
21
|
-
body
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def error_message
|
|
25
|
-
nil
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def to_s
|
|
29
|
-
body || ''
|
|
30
|
-
end
|
|
31
15
|
end
|
|
32
16
|
end
|
|
33
17
|
end
|
|
@@ -39,7 +39,7 @@ module Alipay
|
|
|
39
39
|
sign = @kernel.sign(system_params, biz_params, text_params, @kernel.get_config("merchantPrivateKey"))
|
|
40
40
|
|
|
41
41
|
response = {
|
|
42
|
-
|
|
42
|
+
Alipay::EasySDK::Kernel::AlipayConstants::BODY_FIELD => @kernel.generate_page("POST", system_params, biz_params, text_params, sign),
|
|
43
43
|
"payment_url" => @kernel.generate_payment_url(system_params, biz_params, text_params, sign)
|
|
44
44
|
}
|
|
45
45
|
return Alipay::EasySDK::Payment::Wap::Models::AlipayTradeWapPayResponse.from_map(response)
|
|
@@ -8,26 +8,10 @@ module Alipay
|
|
|
8
8
|
|
|
9
9
|
def self.from_map(response)
|
|
10
10
|
new.tap do |instance|
|
|
11
|
-
instance.body = response[
|
|
11
|
+
instance.body = response[Alipay::EasySDK::Kernel::AlipayConstants::BODY_FIELD]
|
|
12
12
|
instance.payment_url = response['payment_url']
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
|
-
|
|
16
|
-
def success?
|
|
17
|
-
!body.nil? && !body.to_s.empty?
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def form
|
|
21
|
-
body
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def error_message
|
|
25
|
-
nil
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
def to_s
|
|
29
|
-
body || ''
|
|
30
|
-
end
|
|
31
15
|
end
|
|
32
16
|
end
|
|
33
17
|
end
|