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 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