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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce1fec3c892e0b55b191bc1316243ac589e68873
4
- data.tar.gz: 42685dccfaa74f0e8134d5acf3221aa0d325a0ac
3
+ metadata.gz: 57cea4f9dd8f88244a11f40af581f3cd89114ec3
4
+ data.tar.gz: a12dbafc0010a072db445ab1071537eb5e0d6313
5
5
  SHA512:
6
- metadata.gz: bea8090f90b37e26cb1afa2fdc4c6f07a490f46d5a40496f7b1ad8f127966c69de850bb110e04aabc2c753a6e9ca8cac4b1cdd1cde83f8a27705a132e3f42682
7
- data.tar.gz: 47cd59837789a0586b62af90d9e7b8b7c5bfc88f5a9d9d8fa30d9a4706623626f0763f95fa2b066f96deeb07e670f0aa71067382fa2d4919cef8baa8511cecb7
6
+ metadata.gz: d3ab2395763dc02a5eaad833cb39c7445deea0c7b0a8647a08b61d26adc20f483b75ab5c55bb99178d421c873e6d05d5faa46e1bc9c883bf60eafdb4bedb6ead
7
+ data.tar.gz: 96f194bcbd5163ef2b331a35acc931529f5c5ff19ca2b3643ba0fd9057b279898e8460ecdffd77b23551f67aef57e8bd5dc36ddee252a7e37e5a16da688c157b
@@ -0,0 +1,10 @@
1
+
2
+ ## v0.0.5 (2014-06-15)
3
+
4
+ - Add Wap API
5
+
6
+ via @HungYuHei
7
+
8
+ - Add App API
9
+
10
+ via @HungYuHei
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
- # example in rails
104
- # The notify url MUST be set when generate payment url
105
- def alipay_notify
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: https://me.alipay.com/chloerei .
187
+ Alipay donate link: http://chloerei.com/donate/ .
@@ -1,7 +1,8 @@
1
- require "alipay/version"
1
+ require 'alipay/version'
2
2
  require 'alipay/utils'
3
3
  require 'alipay/sign'
4
4
  require 'alipay/service'
5
+ require 'alipay/service/wap'
5
6
  require 'alipay/notify'
6
7
 
7
8
  module Alipay
@@ -1,12 +1,30 @@
1
1
  module Alipay
2
- class Notify
3
- def self.verify?(params)
4
- if Sign.verify?(params)
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
- open("https://mapi.alipay.com/gateway.do?service=notify_verify&partner=#{Alipay.pid}&notify_id=#{CGI.escape params['notify_id'].to_s}").read == 'true'
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}&notify_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
@@ -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
@@ -11,8 +11,9 @@ module Alipay
11
11
  # 退款批次号,支付宝通过此批次号来防止重复退款操作,所以此号生成后最好直接保存至数据库,不要在显示页面的时候生成
12
12
  # 共 24 位(8 位当前日期 + 9 位纳秒 + 1 位随机数)
13
13
  def self.generate_batch_no
14
- time = Time.now
15
- time.strftime('%Y%m%d%H%M%S') + time.nsec.to_s + Random.new.rand(1..9).to_s
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
@@ -1,3 +1,3 @@
1
1
  module Alipay
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -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}&notify_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}&notify_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}&notify_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&notify_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
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-05-13 00:00:00.000000000 Z
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