alipay 0.0.4 → 0.0.5
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 +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
|