alipay 0.0.4 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +59 -7
- data/lib/alipay.rb +2 -1
- data/lib/alipay/notify.rb +24 -6
- data/lib/alipay/service/wap.rb +68 -0
- data/lib/alipay/sign.rb +39 -0
- data/lib/alipay/utils.rb +3 -2
- data/lib/alipay/version.rb +1 -1
- data/test/alipay/notify/wap_test.rb +32 -0
- data/test/alipay/service/wap_test.rb +40 -0
- data/test/alipay/sign/wap_test.rb +17 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57cea4f9dd8f88244a11f40af581f3cd89114ec3
|
4
|
+
data.tar.gz: a12dbafc0010a072db445ab1071537eb5e0d6313
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3ab2395763dc02a5eaad833cb39c7445deea0c7b0a8647a08b61d26adc20f483b75ab5c55bb99178d421c873e6d05d5faa46e1bc9c883bf60eafdb4bedb6ead
|
7
|
+
data.tar.gz: 96f194bcbd5163ef2b331a35acc931529f5c5ff19ca2b3643ba0fd9057b279898e8460ecdffd77b23551f67aef57e8bd5dc36ddee252a7e37e5a16da688c157b
|
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -4,9 +4,9 @@ A simple alipay ruby gem, without unnecessary magic or wraper, it's directly fac
|
|
4
4
|
|
5
5
|
It contain this API:
|
6
6
|
|
7
|
-
* Generate payment url
|
7
|
+
* Generate payment url (web, wap)
|
8
8
|
* Send goods
|
9
|
-
* Verify notify
|
9
|
+
* Verify notify (web, wap, app)
|
10
10
|
|
11
11
|
Please read alipay official document first: https://b.alipay.com/order/techService.htm .
|
12
12
|
|
@@ -40,7 +40,7 @@ Alipay.key = 'YOUR_KEY'
|
|
40
40
|
Alipay.seller_email = 'YOUR_SELLER_EMAIL'
|
41
41
|
```
|
42
42
|
|
43
|
-
### Generate payment url
|
43
|
+
### Generate payment url for web
|
44
44
|
|
45
45
|
```ruby
|
46
46
|
options = {
|
@@ -68,6 +68,30 @@ Current support three payment type:
|
|
68
68
|
Alipay::Service#trade_create_by_buyer_url # 标准双接口
|
69
69
|
Alipay::Service#create_direct_pay_by_user_url # 即时到帐
|
70
70
|
|
71
|
+
### Generate payment url for wap
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
options = {
|
75
|
+
:req_data => {
|
76
|
+
:out_trade_no => 'YOUR_ORDER_ID', # 20130801000001
|
77
|
+
:subject => 'YOUR_ORDER_SUBJECCT', # Writings.io Base Account x 12
|
78
|
+
:total_fee => 'TOTAL_FEE',
|
79
|
+
:notify_url => 'YOUR_ORDER_NOTIFY_URL', # https://writings.io/orders/20130801000001/alipay_notify
|
80
|
+
:call_back_url => 'YOUR_ORDER_RETURN_URL' # https://writings.io/orders/20130801000001
|
81
|
+
}
|
82
|
+
}
|
83
|
+
|
84
|
+
token = Alipay::Service::Wap.trade_create_direct_token(options)
|
85
|
+
Alipay::Service::Wap.auth_and_execute(request_token: token)
|
86
|
+
# => 'http://wappaygw.alipay.com/service/rest.htm?req_data=...'
|
87
|
+
```
|
88
|
+
|
89
|
+
You can redirect user to this payment url, and user will see a payment page for his/her order.
|
90
|
+
|
91
|
+
Current only support this payment type:
|
92
|
+
|
93
|
+
Alipay::Service::Wap.auth_and_execute # 即时到帐
|
94
|
+
|
71
95
|
### Send goods
|
72
96
|
|
73
97
|
```ruby
|
@@ -100,11 +124,13 @@ Notify Url Demo: http://git.io/pst4Tw
|
|
100
124
|
### Verify notify
|
101
125
|
|
102
126
|
```ruby
|
103
|
-
#
|
104
|
-
#
|
105
|
-
|
127
|
+
# Example in rails,
|
128
|
+
# notify url MUST be set when generate payment url
|
129
|
+
|
130
|
+
def alipay_web_notify
|
106
131
|
# except :controller_name, :action_name, :host, etc.
|
107
132
|
notify_params = params.except(*request.path_parameters.keys)
|
133
|
+
|
108
134
|
if Alipay::Notify.verify?(notify_params)
|
109
135
|
# valid notify, code your business logic.
|
110
136
|
render :text => 'success'
|
@@ -112,6 +138,32 @@ def alipay_notify
|
|
112
138
|
render :text => 'error'
|
113
139
|
end
|
114
140
|
end
|
141
|
+
|
142
|
+
def alipay_wap_notify
|
143
|
+
# except :controller_name, :action_name, :host, etc.
|
144
|
+
notify_params = params.except(*request.path_parameters.keys)
|
145
|
+
|
146
|
+
if Alipay::Notify::Wap.verify?(notify_params)
|
147
|
+
# valid notify, code your business logic.
|
148
|
+
# you may want to get you order id:
|
149
|
+
# order_id = Hash.from_xml(params[:notify_data])['notify']['out_trade_no']
|
150
|
+
render :text => 'success'
|
151
|
+
else
|
152
|
+
render :text => 'error'
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def alipay_app_notify
|
157
|
+
# except :controller_name, :action_name, :host, etc.
|
158
|
+
notify_params = params.except(*request.path_parameters.keys)
|
159
|
+
|
160
|
+
if Alipay::Notify::App.verify?(notify_params)
|
161
|
+
# valid notify, code your business logic.
|
162
|
+
render :text => 'success'
|
163
|
+
else
|
164
|
+
render :text => 'error'
|
165
|
+
end
|
166
|
+
end
|
115
167
|
```
|
116
168
|
|
117
169
|
## Contributing
|
@@ -132,4 +184,4 @@ Please write unit test with your code if necessary.
|
|
132
184
|
|
133
185
|
Donate to maintainer let him make this gem better.
|
134
186
|
|
135
|
-
Alipay donate link:
|
187
|
+
Alipay donate link: http://chloerei.com/donate/ .
|
data/lib/alipay.rb
CHANGED
data/lib/alipay/notify.rb
CHANGED
@@ -1,12 +1,30 @@
|
|
1
1
|
module Alipay
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
module Notify
|
3
|
+
module Wap
|
4
|
+
def self.verify?(params)
|
5
|
+
params = Utils.stringify_keys(params)
|
6
|
+
notify_id = params['notify_data'].scan(/\<notify_id\>(.*)\<\/notify_id\>/).flatten.first
|
7
|
+
|
8
|
+
Sign::Wap.verify?(params) && Notify.verify_notify_id?(notify_id)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module App
|
13
|
+
def self.verify?(params)
|
5
14
|
params = Utils.stringify_keys(params)
|
6
|
-
|
7
|
-
else
|
8
|
-
false
|
15
|
+
Sign::App.verify?(params) && Notify.verify_notify_id?(params['notify_id'])
|
9
16
|
end
|
10
17
|
end
|
18
|
+
|
19
|
+
def self.verify?(params)
|
20
|
+
params = Utils.stringify_keys(params)
|
21
|
+
Sign.verify?(params) && verify_notify_id?(params['notify_id'])
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def self.verify_notify_id?(notify_id)
|
27
|
+
open("https://mapi.alipay.com/gateway.do?service=notify_verify&partner=#{Alipay.pid}¬ify_id=#{CGI.escape(notify_id.to_s)}").read == 'true'
|
28
|
+
end
|
11
29
|
end
|
12
30
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
module Alipay
|
4
|
+
module Service
|
5
|
+
module Wap
|
6
|
+
GATEWAY_URL = 'https://wappaygw.alipay.com/service/rest.htm'
|
7
|
+
|
8
|
+
REQ_DATA_REQUIRED_OPTIONS = %w( subject out_trade_no total_fee seller_account_name call_back_url )
|
9
|
+
WAP_TRADE_REQUIRED_OPTIONS = %w( service format v partner req_id req_data )
|
10
|
+
|
11
|
+
def self.trade_create_direct_token(options)
|
12
|
+
options = Utils.stringify_keys(options)
|
13
|
+
|
14
|
+
req_data_options = { 'seller_account_name' => Alipay.seller_email }.merge(
|
15
|
+
Utils.stringify_keys(options.delete('req_data'))
|
16
|
+
)
|
17
|
+
|
18
|
+
Alipay::Service.check_required_options(req_data_options, REQ_DATA_REQUIRED_OPTIONS)
|
19
|
+
|
20
|
+
xml = req_data_options.map {|k, v| "<#{k}>#{v}</#{k}>" }.join
|
21
|
+
req_data_xml = "<direct_trade_create_req>#{xml}</direct_trade_create_req>"
|
22
|
+
|
23
|
+
# About req_id: http://club.alipay.com/read-htm-tid-10078020-fpage-2.html
|
24
|
+
options = {
|
25
|
+
'service' => 'alipay.wap.trade.create.direct',
|
26
|
+
'req_data' => req_data_xml,
|
27
|
+
'partner' => Alipay.pid,
|
28
|
+
'req_id' => Time.now.strftime('%Y%m%d%H%M%s'),
|
29
|
+
'format' => 'xml',
|
30
|
+
'v' => '2.0'
|
31
|
+
}.merge(options)
|
32
|
+
|
33
|
+
Alipay::Service.check_required_options(options, WAP_TRADE_REQUIRED_OPTIONS)
|
34
|
+
|
35
|
+
xml = open("#{GATEWAY_URL}?#{query_string(options)}").read
|
36
|
+
CGI.unescape(xml).scan(/\<request_token\>(.*)\<\/request_token\>/).flatten.first
|
37
|
+
end
|
38
|
+
|
39
|
+
AUTH_AND_EXECUTE_REQUIRED_OPTIONS = %w( service format v partner )
|
40
|
+
|
41
|
+
def self.auth_and_execute(options)
|
42
|
+
options = Utils.stringify_keys(options)
|
43
|
+
Alipay::Service.check_required_options(options, ['request_token'])
|
44
|
+
|
45
|
+
req_data_xml = "<auth_and_execute_req><request_token>#{options.delete('request_token')}</request_token></auth_and_execute_req>"
|
46
|
+
|
47
|
+
options = {
|
48
|
+
'service' => 'alipay.wap.auth.authAndExecute',
|
49
|
+
'req_data' => req_data_xml,
|
50
|
+
'partner' => Alipay.pid,
|
51
|
+
'format' => 'xml',
|
52
|
+
'v' => '2.0'
|
53
|
+
}.merge(options)
|
54
|
+
|
55
|
+
Alipay::Service.check_required_options(options, AUTH_AND_EXECUTE_REQUIRED_OPTIONS)
|
56
|
+
"#{GATEWAY_URL}?#{query_string(options)}"
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.query_string(options)
|
60
|
+
options.merge!('sec_id' => 'MD5')
|
61
|
+
|
62
|
+
options.merge('sign' => Alipay::Sign.generate(options)).map do |key, value|
|
63
|
+
"#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
|
64
|
+
end.join('&')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/alipay/sign.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'digest/md5'
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
2
4
|
|
3
5
|
module Alipay
|
4
6
|
module Sign
|
@@ -17,5 +19,42 @@ module Alipay
|
|
17
19
|
|
18
20
|
generate(params) == sign
|
19
21
|
end
|
22
|
+
|
23
|
+
module Wap
|
24
|
+
SORTED_VERIFY_PARAMS = %w( service v sec_id notify_data )
|
25
|
+
|
26
|
+
def self.verify?(params)
|
27
|
+
params = Utils.stringify_keys(params)
|
28
|
+
|
29
|
+
query = SORTED_VERIFY_PARAMS.map do |key|
|
30
|
+
"#{key}=#{params[key]}"
|
31
|
+
end.join('&')
|
32
|
+
|
33
|
+
params['sign'] == Digest::MD5.hexdigest("#{query}#{Alipay.key}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
module App
|
38
|
+
# Alipay public key
|
39
|
+
PEM = "-----BEGIN PUBLIC KEY-----\n" \
|
40
|
+
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRA\n" \
|
41
|
+
"FljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQE\n" \
|
42
|
+
"B/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5Ksi\n" \
|
43
|
+
"NG9zpgmLCUYuLkxpLQIDAQAB\n" \
|
44
|
+
"-----END PUBLIC KEY-----"
|
45
|
+
|
46
|
+
def self.verify?(params)
|
47
|
+
params = Utils.stringify_keys(params)
|
48
|
+
|
49
|
+
pkey = OpenSSL::PKey::RSA.new(PEM)
|
50
|
+
digest = OpenSSL::Digest::SHA1.new
|
51
|
+
|
52
|
+
params.delete('sign_type')
|
53
|
+
sign = params.delete('sign')
|
54
|
+
to_sign = params.sort.map { |item| item.join('=') }.join('&')
|
55
|
+
|
56
|
+
pkey.verify(digest, Base64.decode64(sign), to_sign)
|
57
|
+
end
|
58
|
+
end
|
20
59
|
end
|
21
60
|
end
|
data/lib/alipay/utils.rb
CHANGED
@@ -11,8 +11,9 @@ module Alipay
|
|
11
11
|
# 退款批次号,支付宝通过此批次号来防止重复退款操作,所以此号生成后最好直接保存至数据库,不要在显示页面的时候生成
|
12
12
|
# 共 24 位(8 位当前日期 + 9 位纳秒 + 1 位随机数)
|
13
13
|
def self.generate_batch_no
|
14
|
-
|
15
|
-
|
14
|
+
t = Time.now
|
15
|
+
batch_no = t.strftime('%Y%m%d%H%M%S') + t.nsec.to_s
|
16
|
+
batch_no.ljust(24, Random.new.rand(1..9).to_s)
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
data/lib/alipay/version.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Alipay::Notify::WapTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@notify_id = 'notify_id_test'
|
6
|
+
|
7
|
+
@notify_params = {
|
8
|
+
:service => 'alipay.wap.trade.create.direct',
|
9
|
+
:v => '1.0',
|
10
|
+
:sec_id => 'MD5',
|
11
|
+
:notify_data => "<notify><notify_id>#{@notify_id}</notify_id><other_key>other_value</other_key></notify>"
|
12
|
+
}
|
13
|
+
|
14
|
+
query = [ :service, :v, :sec_id, :notify_data ].map {|key| "#{key}=#{@notify_params[key]}"}.join('&')
|
15
|
+
@sign_params = @notify_params.merge(:sign => Digest::MD5.hexdigest("#{query}#{Alipay.key}"))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_unsign_notify
|
19
|
+
FakeWeb.register_uri(:get, "https://mapi.alipay.com/gateway.do?service=notify_verify&partner=#{Alipay.pid}¬ify_id=#{@notify_id}", :body => "true")
|
20
|
+
assert !Alipay::Notify::Wap.verify?(@notify_params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_verify_notify_when_true
|
24
|
+
FakeWeb.register_uri(:get, "https://mapi.alipay.com/gateway.do?service=notify_verify&partner=#{Alipay.pid}¬ify_id=#{@notify_id}", :body => "true")
|
25
|
+
assert Alipay::Notify::Wap.verify?(@sign_params)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_verify_notify_when_false
|
29
|
+
FakeWeb.register_uri(:get, "https://mapi.alipay.com/gateway.do?service=notify_verify&partner=#{Alipay.pid}¬ify_id=#{@notify_id}", :body => "false")
|
30
|
+
assert !Alipay::Notify::Wap.verify?(@sign_params)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Alipay::Service::WapTest < Test::Unit::TestCase
|
4
|
+
def test_trade_create_direct_token
|
5
|
+
token = 'REQUEST_TOKEN'
|
6
|
+
body = <<-EOS
|
7
|
+
res_data=
|
8
|
+
<?xmlversion="1.0" encoding="utf-8"?>
|
9
|
+
<direct_trade_create_res>
|
10
|
+
<request_token>#{token}</request_token>
|
11
|
+
</direct_trade_create_res>
|
12
|
+
&partner=PID
|
13
|
+
&req_id=REQ_ID
|
14
|
+
&sec_id=MD5
|
15
|
+
&service=alipay.wap.trade.create.direct
|
16
|
+
&v=2.0
|
17
|
+
&sign=SIGN
|
18
|
+
EOS
|
19
|
+
|
20
|
+
FakeWeb.register_uri(
|
21
|
+
:get,
|
22
|
+
%r|https://wappaygw\.alipay\.com/service/rest\.htm.*|,
|
23
|
+
:body => body
|
24
|
+
)
|
25
|
+
|
26
|
+
assert_equal token, Alipay::Service::Wap.trade_create_direct_token(
|
27
|
+
:req_data => {
|
28
|
+
:out_trade_no => '1',
|
29
|
+
:subject => 'subject',
|
30
|
+
:total_fee => '0.01',
|
31
|
+
:call_back_url => 'http://www.yoursite.com/call_back'
|
32
|
+
}
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_auth_and_execute
|
37
|
+
options = { :request_token => 'token_test' }
|
38
|
+
assert_not_nil Alipay::Service::Wap.auth_and_execute(options)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Alipay::Sign::WapTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@params = {
|
6
|
+
:v => '1.0',
|
7
|
+
:sec_id => 'MD5',
|
8
|
+
:service => 'test',
|
9
|
+
:notify_data => 'notify_data'
|
10
|
+
}
|
11
|
+
@sign = Digest::MD5.hexdigest("service=test&v=1.0&sec_id=MD5¬ify_data=notify_data#{Alipay.key}")
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_verify_sign
|
15
|
+
assert Alipay::Sign::Wap.verify?(@params.merge(:sign => @sign, :whatever => 'x'))
|
16
|
+
end
|
17
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alipay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rei
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -60,6 +60,7 @@ extensions: []
|
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
62
|
- ".gitignore"
|
63
|
+
- CHANGELOG.md
|
63
64
|
- Gemfile
|
64
65
|
- LICENSE.txt
|
65
66
|
- README.md
|
@@ -68,11 +69,15 @@ files:
|
|
68
69
|
- lib/alipay.rb
|
69
70
|
- lib/alipay/notify.rb
|
70
71
|
- lib/alipay/service.rb
|
72
|
+
- lib/alipay/service/wap.rb
|
71
73
|
- lib/alipay/sign.rb
|
72
74
|
- lib/alipay/utils.rb
|
73
75
|
- lib/alipay/version.rb
|
76
|
+
- test/alipay/notify/wap_test.rb
|
74
77
|
- test/alipay/notify_test.rb
|
78
|
+
- test/alipay/service/wap_test.rb
|
75
79
|
- test/alipay/service_test.rb
|
80
|
+
- test/alipay/sign/wap_test.rb
|
76
81
|
- test/alipay/sign_test.rb
|
77
82
|
- test/alipay/utils_test.rb
|
78
83
|
- test/test_helper.rb
|
@@ -101,8 +106,11 @@ signing_key:
|
|
101
106
|
specification_version: 4
|
102
107
|
summary: An unofficial simple alipay gem
|
103
108
|
test_files:
|
109
|
+
- test/alipay/notify/wap_test.rb
|
104
110
|
- test/alipay/notify_test.rb
|
111
|
+
- test/alipay/service/wap_test.rb
|
105
112
|
- test/alipay/service_test.rb
|
113
|
+
- test/alipay/sign/wap_test.rb
|
106
114
|
- test/alipay/sign_test.rb
|
107
115
|
- test/alipay/utils_test.rb
|
108
116
|
- test/test_helper.rb
|