alipay 0.6.0.beta1 → 0.6.0.beta2
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/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.md +11 -1
- data/README.md +418 -142
- data/lib/alipay.rb +7 -3
- data/lib/alipay/notify.rb +11 -4
- data/lib/alipay/service.rb +104 -100
- data/lib/alipay/sign.rb +26 -44
- data/lib/alipay/sign/dsa.rb +13 -0
- data/lib/alipay/sign/md5.rb +15 -0
- data/lib/alipay/sign/rsa.rb +18 -0
- data/lib/alipay/version.rb +1 -1
- data/lib/alipay/wap/notify.rb +13 -0
- data/lib/alipay/wap/service.rb +73 -0
- data/lib/alipay/wap/sign.rb +37 -0
- data/test/alipay/notify_test.rb +9 -6
- data/test/alipay/service_test.rb +6 -6
- data/test/alipay/sign/md5_test.rb +20 -0
- data/test/alipay/sign_test.rb +7 -5
- data/test/alipay/{notify/wap_test.rb → wap/notify_test.rb} +4 -4
- data/test/alipay/{service/wap_test.rb → wap/service_test.rb} +4 -4
- data/test/alipay/{sign/wap_test.rb → wap/sign_test.rb} +2 -2
- metadata +17 -11
- data/lib/alipay/notify/wap.rb +0 -12
- data/lib/alipay/service/wap.rb +0 -69
- data/lib/alipay/sign/wap.rb +0 -17
data/lib/alipay.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'cgi'
|
2
3
|
require 'alipay/version'
|
3
4
|
require 'alipay/utils'
|
4
5
|
require 'alipay/sign'
|
5
|
-
require 'alipay/sign/
|
6
|
+
require 'alipay/sign/md5'
|
7
|
+
require 'alipay/sign/rsa'
|
8
|
+
require 'alipay/sign/dsa'
|
6
9
|
require 'alipay/service'
|
7
|
-
require 'alipay/service/wap'
|
8
10
|
require 'alipay/notify'
|
9
|
-
require 'alipay/
|
11
|
+
require 'alipay/wap/service'
|
12
|
+
require 'alipay/wap/notify'
|
13
|
+
require 'alipay/wap/sign'
|
10
14
|
|
11
15
|
module Alipay
|
12
16
|
@debug_mode = true
|
data/lib/alipay/notify.rb
CHANGED
@@ -1,12 +1,19 @@
|
|
1
1
|
module Alipay
|
2
2
|
module Notify
|
3
|
-
def self.verify?(params)
|
3
|
+
def self.verify?(params, options = {})
|
4
4
|
params = Utils.stringify_keys(params)
|
5
|
-
|
5
|
+
pid = options[:pid] || Alipay.pid
|
6
|
+
Sign.verify?(params, options) && verify_notify_id?(pid, params['notify_id'])
|
6
7
|
end
|
7
8
|
|
8
|
-
def self.verify_notify_id?(notify_id)
|
9
|
-
|
9
|
+
def self.verify_notify_id?(pid, notify_id)
|
10
|
+
uri = URI("https://mapi.alipay.com/gateway.do")
|
11
|
+
uri.query = URI.encode_www_form(
|
12
|
+
'service' => 'notify_verify',
|
13
|
+
'partner' => pid,
|
14
|
+
'notify_id' => notify_id
|
15
|
+
)
|
16
|
+
Net::HTTP.get(uri) == 'true'
|
10
17
|
end
|
11
18
|
end
|
12
19
|
end
|
data/lib/alipay/service.rb
CHANGED
@@ -1,188 +1,192 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
|
3
1
|
module Alipay
|
4
2
|
module Service
|
5
3
|
GATEWAY_URL = 'https://mapi.alipay.com/gateway.do'
|
6
4
|
|
7
|
-
|
5
|
+
CREATE_PARTNER_TRADE_BY_BUYER_REQUIRED_PARAMS = %w( out_trade_no subject logistics_type logistics_fee logistics_payment price quantity )
|
8
6
|
# alipayescow
|
9
|
-
def self.create_partner_trade_by_buyer_url(options)
|
10
|
-
|
7
|
+
def self.create_partner_trade_by_buyer_url(params, options = {})
|
8
|
+
params = Utils.stringify_keys(params)
|
9
|
+
check_required_params(params, CREATE_PARTNER_TRADE_BY_BUYER_REQUIRED_PARAMS)
|
10
|
+
|
11
|
+
params = {
|
11
12
|
'service' => 'create_partner_trade_by_buyer',
|
12
13
|
'_input_charset' => 'utf-8',
|
13
|
-
'partner' => Alipay.pid,
|
14
|
-
'seller_email' => Alipay.seller_email,
|
14
|
+
'partner' => options[:pid] || Alipay.pid,
|
15
|
+
'seller_email' => options[:seller_email] || Alipay.seller_email,
|
15
16
|
'payment_type' => '1'
|
16
|
-
}.merge(
|
17
|
+
}.merge(params)
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
request_uri(options).to_s
|
19
|
+
request_uri(params, options).to_s
|
21
20
|
end
|
22
21
|
|
23
|
-
|
22
|
+
TRADE_CREATE_BY_BUYER_REQUIRED_PARAMS = %w( out_trade_no subject logistics_type logistics_fee logistics_payment price quantity )
|
24
23
|
# alipaydualfun
|
25
|
-
def self.trade_create_by_buyer_url(options = {})
|
26
|
-
|
24
|
+
def self.trade_create_by_buyer_url(params, options = {})
|
25
|
+
params = Utils.stringify_keys(params)
|
26
|
+
check_required_params(params, TRADE_CREATE_BY_BUYER_REQUIRED_PARAMS)
|
27
|
+
|
28
|
+
params = {
|
27
29
|
'service' => 'trade_create_by_buyer',
|
28
30
|
'_input_charset' => 'utf-8',
|
29
|
-
'partner' => Alipay.pid,
|
30
|
-
'seller_email' => Alipay.seller_email,
|
31
|
+
'partner' => options[:pid] || Alipay.pid,
|
32
|
+
'seller_email' => options[:seller_email] || Alipay.seller_email,
|
31
33
|
'payment_type' => '1'
|
32
|
-
}.merge(
|
34
|
+
}.merge(params)
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
request_uri(options).to_s
|
36
|
+
request_uri(params, options).to_s
|
37
37
|
end
|
38
38
|
|
39
|
-
|
39
|
+
CREATE_DIRECT_PAY_BY_USER_REQUIRED_PARAMS = %w( out_trade_no subject )
|
40
40
|
# direct
|
41
|
-
def self.create_direct_pay_by_user_url(options)
|
42
|
-
|
43
|
-
|
44
|
-
'_input_charset' => 'utf-8',
|
45
|
-
'partner' => Alipay.pid,
|
46
|
-
'seller_email' => Alipay.seller_email,
|
47
|
-
'payment_type' => '1'
|
48
|
-
}.merge(Utils.stringify_keys(options))
|
49
|
-
|
50
|
-
check_required_options(options, CREATE_DIRECT_PAY_BY_USER_REQUIRED_OPTIONS)
|
41
|
+
def self.create_direct_pay_by_user_url(params, options = {})
|
42
|
+
params = Utils.stringify_keys(params)
|
43
|
+
check_required_params(params, CREATE_DIRECT_PAY_BY_USER_REQUIRED_PARAMS)
|
51
44
|
|
52
|
-
if
|
45
|
+
if params['total_fee'].nil? and (params['price'].nil? || params['quantity'].nil?)
|
53
46
|
warn("Ailpay Warn: total_fee or (price && quantiry) must have one")
|
54
47
|
end
|
55
48
|
|
56
|
-
|
49
|
+
params = {
|
50
|
+
'service' => 'create_direct_pay_by_user',
|
51
|
+
'_input_charset' => 'utf-8',
|
52
|
+
'partner' => options[:pid] || Alipay.pid,
|
53
|
+
'seller_email' => options[:seller_email] || Alipay.seller_email,
|
54
|
+
'payment_type' => '1'
|
55
|
+
}.merge(params)
|
56
|
+
|
57
|
+
request_uri(params, options).to_s
|
57
58
|
end
|
58
59
|
|
59
|
-
|
60
|
+
CREATE_REFUND_URL_REQUIRED_PARAMS = %w( batch_no data notify_url )
|
60
61
|
# 支付宝即时到帐批量退款有密接口(此为异步接口,有密指通过此接口打开 url 后需要用户输入支付宝的支付密码进行退款)
|
61
|
-
def self.
|
62
|
-
|
63
|
-
|
62
|
+
def self.refund_fastpay_by_platform_pwd_url(params, options = {})
|
63
|
+
params = Utils.stringify_keys(params)
|
64
|
+
check_required_params(params, CREATE_REFUND_URL_REQUIRED_PARAMS)
|
64
65
|
|
65
|
-
data =
|
66
|
+
data = params.delete('data')
|
66
67
|
detail_data = data.map do|item|
|
67
68
|
item = Utils.stringify_keys(item)
|
68
69
|
"#{item['trade_no']}^#{item['amount']}^#{item['reason']}"
|
69
70
|
end.join('#')
|
70
71
|
|
71
|
-
|
72
|
+
params = {
|
72
73
|
'service' => 'refund_fastpay_by_platform_pwd', # 接口名称
|
73
74
|
'_input_charset' => 'utf-8',
|
74
|
-
'partner' => Alipay.pid,
|
75
|
-
'seller_email' => Alipay.seller_email,
|
75
|
+
'partner' => options[:pid] || Alipay.pid,
|
76
|
+
'seller_email' => options[:seller_email] || Alipay.seller_email,
|
76
77
|
'refund_date' => Time.now.strftime('%Y-%m-%d %H:%M:%S'), # 申请退款时间
|
77
78
|
'batch_num' => data.size, # 总笔数
|
78
79
|
'detail_data' => detail_data # 转换后的单笔数据集字符串
|
79
|
-
}.merge(
|
80
|
+
}.merge(params)
|
80
81
|
|
81
|
-
request_uri(options).to_s
|
82
|
+
request_uri(params, options).to_s
|
82
83
|
end
|
83
84
|
|
84
|
-
|
85
|
+
CREATE_FOREX_SINGLE_REFUND_URL_REQUIRED_PARAMS = %w( out_return_no out_trade_no return_amount currency reason )
|
85
86
|
# 支付宝境外收单单笔退款接口
|
86
87
|
# out_return_no 退款流水单号
|
87
88
|
# out_trade_no 交易创建时的订单号
|
88
89
|
# return_amount 退款金额
|
89
90
|
# currency 退款币种,与交易创建时的币种一致
|
90
|
-
def self.
|
91
|
-
|
91
|
+
def self.forex_refund_url(params, options = {})
|
92
|
+
params = Utils.stringify_keys(params)
|
93
|
+
check_required_params(params, CREATE_FOREX_SINGLE_REFUND_URL_REQUIRED_PARAMS)
|
94
|
+
|
95
|
+
params = {
|
92
96
|
'service' => 'forex_refund',
|
93
|
-
'partner' => Alipay.pid,
|
97
|
+
'partner' => options[:pid] || Alipay.pid,
|
94
98
|
'_input_charset' => 'utf-8',
|
95
99
|
'gmt_return' => Time.now.strftime('%Y%m%d%H%M%S')
|
96
|
-
}.merge(
|
100
|
+
}.merge(params)
|
97
101
|
|
98
|
-
|
99
|
-
|
100
|
-
request_uri(options).to_s
|
102
|
+
request_uri(params, options).to_s
|
101
103
|
end
|
102
104
|
|
103
|
-
|
104
|
-
def self.send_goods_confirm_by_platform(options)
|
105
|
-
|
106
|
-
|
107
|
-
'partner' => Alipay.pid,
|
108
|
-
'_input_charset' => 'utf-8'
|
109
|
-
}.merge(Utils.stringify_keys(options))
|
110
|
-
|
111
|
-
check_required_options(options, SEND_GOODS_CONFIRM_BY_PLATFORM_REQUIRED_OPTIONS)
|
105
|
+
SEND_GOODS_CONFIRM_BY_PLATFORM_REQUIRED_PARAMS = %w( trade_no logistics_name )
|
106
|
+
def self.send_goods_confirm_by_platform(params, options = {})
|
107
|
+
params = Utils.stringify_keys(params)
|
108
|
+
check_required_params(params, SEND_GOODS_CONFIRM_BY_PLATFORM_REQUIRED_PARAMS)
|
112
109
|
|
113
|
-
if
|
110
|
+
if params['transport_type'].nil? and params['create_transport_type'].nil?
|
114
111
|
warn("Ailpay Warn: transport_type or create_transport_type must have one")
|
115
112
|
end
|
116
113
|
|
117
|
-
|
114
|
+
params = {
|
115
|
+
'service' => 'send_goods_confirm_by_platform',
|
116
|
+
'partner' => options[:pid] || Alipay.pid,
|
117
|
+
'_input_charset' => 'utf-8'
|
118
|
+
}.merge(params)
|
119
|
+
|
120
|
+
Net::HTTP.get(request_uri(params, options))
|
118
121
|
end
|
119
122
|
|
120
|
-
|
121
|
-
def self.
|
122
|
-
|
123
|
+
CREATE_FOREX_TRADE_REQUIRED_PARAMS = %w( notify_url subject out_trade_no currency total_fee)
|
124
|
+
def self.create_forex_trade_url(params, options = {})
|
125
|
+
params = Utils.stringify_keys(params)
|
126
|
+
check_required_params(params, CREATE_FOREX_TRADE_REQUIRED_PARAMS)
|
127
|
+
|
128
|
+
params = {
|
123
129
|
'service' => 'create_forex_trade',
|
124
130
|
'_input_charset' => 'utf-8',
|
125
|
-
'partner' => Alipay.pid,
|
126
|
-
'seller_email' => Alipay.seller_email
|
127
|
-
}.merge(
|
128
|
-
|
129
|
-
check_required_options(options, CREATE_FOREX_TRADE_REQUIRED_OPTIONS)
|
131
|
+
'partner' => options[:pid] || Alipay.pid,
|
132
|
+
'seller_email' => options[:seller_email] || Alipay.seller_email
|
133
|
+
}.merge(params)
|
130
134
|
|
131
|
-
request_uri(options).to_s
|
135
|
+
request_uri(params, options).to_s
|
132
136
|
end
|
133
137
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
+
CLOSE_TRADE_REQUIRED_OPTIONAL_PARAMS = %w( trade_no out_order_no )
|
139
|
+
def self.close_trade(params, options = {})
|
140
|
+
params = Utils.stringify_keys(params)
|
141
|
+
check_optional_params(params, CLOSE_TRADE_REQUIRED_OPTIONAL_PARAMS)
|
142
|
+
|
143
|
+
params = {
|
138
144
|
'service' => 'close_trade',
|
139
145
|
'_input_charset' => 'utf-8',
|
140
|
-
'partner' => Alipay.pid
|
141
|
-
}.merge(
|
146
|
+
'partner' => options[:pid] || Alipay.pid
|
147
|
+
}.merge(params)
|
142
148
|
|
143
|
-
|
144
|
-
check_optional_options(options, CLOSE_TRADE_REQUIRED_OPTIONAL_OPTIONS)
|
145
|
-
|
146
|
-
Net::HTTP.get(request_uri(options))
|
149
|
+
Net::HTTP.get(request_uri(params, options))
|
147
150
|
end
|
148
151
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
152
|
+
SINGLE_TRADE_QUERY_OPTIONAL_PARAMS = %w( trade_no out_trade_no )
|
153
|
+
def self.single_trade_query(params, options = {})
|
154
|
+
params = Utils.stringify_keys(params)
|
155
|
+
check_optional_params(params, SINGLE_TRADE_QUERY_OPTIONAL_PARAMS)
|
156
|
+
|
157
|
+
params = {
|
153
158
|
"service" => 'single_trade_query',
|
154
159
|
"_input_charset" => "utf-8",
|
155
|
-
"partner" => Alipay.pid,
|
156
|
-
}.merge(
|
157
|
-
|
158
|
-
check_required_options(options, SINGLE_TRADE_QUERY_OPTIONS)
|
159
|
-
check_optional_options(options, SINGLE_TRADE_QUERY_OPTIONAL_OPTIONS)
|
160
|
+
"partner" => options[:pid] || Alipay.pid,
|
161
|
+
}.merge(params)
|
160
162
|
|
161
|
-
Net::HTTP.get(request_uri(options))
|
163
|
+
Net::HTTP.get(request_uri(params, options))
|
162
164
|
end
|
163
165
|
|
164
|
-
def self.request_uri(options)
|
166
|
+
def self.request_uri(params, options = {})
|
165
167
|
uri = URI(GATEWAY_URL)
|
166
|
-
uri.query = URI.encode_www_form(sign_params(options))
|
168
|
+
uri.query = URI.encode_www_form(sign_params(params, options))
|
167
169
|
uri
|
168
170
|
end
|
169
171
|
|
170
|
-
def self.sign_params(params)
|
171
|
-
params
|
172
|
-
|
172
|
+
def self.sign_params(params, optinos = {})
|
173
|
+
params.merge(
|
174
|
+
'sign_type' => (optinos[:sign_type] || Alipay.sign_type),
|
175
|
+
'sign' => Alipay::Sign.generate(params, optinos)
|
176
|
+
)
|
173
177
|
end
|
174
178
|
|
175
|
-
def self.
|
179
|
+
def self.check_required_params(params, names)
|
176
180
|
return if !Alipay.debug_mode?
|
177
181
|
|
178
182
|
names.each do |name|
|
179
|
-
warn("Ailpay Warn: missing required option: #{name}") unless
|
183
|
+
warn("Ailpay Warn: missing required option: #{name}") unless params.has_key?(name)
|
180
184
|
end
|
181
185
|
end
|
182
186
|
|
183
|
-
def self.
|
187
|
+
def self.check_optional_params(params, names)
|
184
188
|
return if !Alipay.debug_mode?
|
185
|
-
warn("Ailpay Warn: must specify either #{names.join(' or ')}") if names.all? {|name|
|
189
|
+
warn("Ailpay Warn: must specify either #{names.join(' or ')}") if names.all? {|name| params[name].nil? }
|
186
190
|
end
|
187
191
|
end
|
188
192
|
end
|
data/lib/alipay/sign.rb
CHANGED
@@ -1,72 +1,54 @@
|
|
1
|
-
require 'digest/md5'
|
2
|
-
require 'openssl'
|
3
|
-
require 'base64'
|
4
|
-
|
5
1
|
module Alipay
|
6
2
|
module Sign
|
7
|
-
def self.generate(params)
|
3
|
+
def self.generate(params, options = {})
|
8
4
|
params = Utils.stringify_keys(params)
|
9
|
-
sign_type =
|
10
|
-
key =
|
5
|
+
sign_type = options[:sign_type] || Alipay.sign_type
|
6
|
+
key = options[:key] || Alipay.key
|
7
|
+
string = params_to_string(params)
|
11
8
|
|
12
9
|
case sign_type
|
13
10
|
when 'MD5'
|
14
|
-
|
11
|
+
MD5.sign(key, string)
|
15
12
|
when 'RSA'
|
16
|
-
|
13
|
+
RSA.sign(key, string)
|
17
14
|
when 'DSA'
|
18
|
-
|
15
|
+
DSA.sign(key, string)
|
19
16
|
else
|
20
|
-
raise ArgumentError, "
|
17
|
+
raise ArgumentError, "[Alipay] Invalid sign_type #{sign_type}, allow value: 'MD5', 'RSA', 'DSA'"
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
ALIPAY_RSA_PUBLIC_KEY = <<-EOF
|
22
|
+
-----BEGIN PUBLIC KEY-----
|
23
|
+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRA
|
24
|
+
FljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQE
|
25
|
+
B/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5Ksi
|
26
|
+
NG9zpgmLCUYuLkxpLQIDAQAB
|
27
|
+
-----END PUBLIC KEY-----
|
28
|
+
EOF
|
31
29
|
|
32
|
-
def self.verify?(params)
|
30
|
+
def self.verify?(params, options = {})
|
33
31
|
params = Utils.stringify_keys(params)
|
34
32
|
|
35
33
|
sign_type = params.delete('sign_type')
|
34
|
+
sign = params.delete('sign')
|
35
|
+
string = params_to_string(params)
|
36
36
|
|
37
37
|
case sign_type
|
38
38
|
when 'MD5'
|
39
|
-
|
39
|
+
key = options[:key] || Alipay.key
|
40
|
+
MD5.verify?(key, string, sign)
|
40
41
|
when 'RSA'
|
41
|
-
|
42
|
+
RSA.verify?(ALIPAY_RSA_PUBLIC_KEY, string, sign)
|
42
43
|
when 'DSA'
|
43
|
-
|
44
|
+
DSA.verify?(string, sign)
|
44
45
|
else
|
45
|
-
raise ArgumentError, "
|
46
|
+
raise ArgumentError, "[Alipay] Invalid sign_type #{sign_type}, allow values: 'MD5', 'RSA', 'DSA'"
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
49
|
-
def self.
|
50
|
-
|
51
|
-
sign = params.delete('sign')
|
52
|
-
generate_md5(key, params) == sign
|
53
|
-
end
|
54
|
-
|
55
|
-
ALIPAY_RSA_PUBLIC_KEY = <<-EOF
|
56
|
-
-----BEGIN PUBLIC KEY-----
|
57
|
-
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRA
|
58
|
-
FljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQE
|
59
|
-
B/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5Ksi
|
60
|
-
NG9zpgmLCUYuLkxpLQIDAQAB
|
61
|
-
-----END PUBLIC KEY-----
|
62
|
-
EOF
|
63
|
-
|
64
|
-
def self.verify_rsa?(params)
|
65
|
-
pkey = OpenSSL::PKey::RSA.new(ALIPAY_RSA_PUBLIC_KEY)
|
66
|
-
digest = OpenSSL::Digest::SHA1.new
|
67
|
-
sign = params.delete('sign')
|
68
|
-
|
69
|
-
pkey.verify(digest, Base64.decode64(sign), params_to_string(params))
|
50
|
+
def self.params_to_string(params)
|
51
|
+
params.sort.map { |item| item.join('=') }.join('&')
|
70
52
|
end
|
71
53
|
end
|
72
54
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Alipay
|
2
|
+
module Sign
|
3
|
+
class DSA
|
4
|
+
def self.sign(key, string)
|
5
|
+
raise NotImplementedError, '[Alipay] DSA sign is not implemented'
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.verify?(string, sign)
|
9
|
+
raise NotImplementedError, '[Alipay] DSA verify is not implemented'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|