alipay 0.6.0.beta1 → 0.6.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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/wap'
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/notify/wap'
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
- Sign.verify?(params) && verify_notify_id?(params['notify_id'])
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
- Net::HTTP.get(URI("https://mapi.alipay.com/gateway.do?service=notify_verify&partner=#{Alipay.pid}&notify_id=#{CGI.escape(notify_id.to_s)}")) == 'true'
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
@@ -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
- CREATE_PARTNER_TRADE_BY_BUYER_REQUIRED_OPTIONS = %w( service partner _input_charset out_trade_no subject payment_type logistics_type logistics_fee logistics_payment seller_email price quantity )
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
- options = {
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(Utils.stringify_keys(options))
17
+ }.merge(params)
17
18
 
18
- check_required_options(options, CREATE_PARTNER_TRADE_BY_BUYER_REQUIRED_OPTIONS)
19
-
20
- request_uri(options).to_s
19
+ request_uri(params, options).to_s
21
20
  end
22
21
 
23
- TRADE_CREATE_BY_BUYER_REQUIRED_OPTIONS = %w( service partner _input_charset out_trade_no subject payment_type logistics_type logistics_fee logistics_payment seller_email price quantity )
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
- options = {
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(Utils.stringify_keys(options))
34
+ }.merge(params)
33
35
 
34
- check_required_options(options, TRADE_CREATE_BY_BUYER_REQUIRED_OPTIONS)
35
-
36
- request_uri(options).to_s
36
+ request_uri(params, options).to_s
37
37
  end
38
38
 
39
- CREATE_DIRECT_PAY_BY_USER_REQUIRED_OPTIONS = %w( service partner _input_charset out_trade_no subject payment_type seller_email )
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
- options = {
43
- 'service' => 'create_direct_pay_by_user',
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 options['total_fee'].nil? and (options['price'].nil? || options['quantity'].nil?)
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
- request_uri(options).to_s
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
- CREATE_REFUND_URL_REQUIRED_OPTIONS = %w( batch_no data notify_url )
60
+ CREATE_REFUND_URL_REQUIRED_PARAMS = %w( batch_no data notify_url )
60
61
  # 支付宝即时到帐批量退款有密接口(此为异步接口,有密指通过此接口打开 url 后需要用户输入支付宝的支付密码进行退款)
61
- def self.create_refund_url(options)
62
- options = Utils.stringify_keys(options)
63
- check_required_options(options, CREATE_REFUND_URL_REQUIRED_OPTIONS)
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 = options.delete('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
- options = {
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(options)
80
+ }.merge(params)
80
81
 
81
- request_uri(options).to_s
82
+ request_uri(params, options).to_s
82
83
  end
83
84
 
84
- CREATE_FOREX_SINGLE_REFUND_URL_REQUIRED_OPTIONS = %w( out_return_no out_trade_no return_amount currency reason )
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.create_forex_single_refund_url(options)
91
- options = {
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(Utils.stringify_keys(options))
100
+ }.merge(params)
97
101
 
98
- check_required_options(options, CREATE_FOREX_SINGLE_REFUND_URL_REQUIRED_OPTIONS)
99
-
100
- request_uri(options).to_s
102
+ request_uri(params, options).to_s
101
103
  end
102
104
 
103
- SEND_GOODS_CONFIRM_BY_PLATFORM_REQUIRED_OPTIONS = %w( service partner _input_charset trade_no logistics_name )
104
- def self.send_goods_confirm_by_platform(options)
105
- options = {
106
- 'service' => 'send_goods_confirm_by_platform',
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 options['transport_type'].nil? and options['create_transport_type'].nil?
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
- Net::HTTP.get(request_uri(options))
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
- CREATE_FOREX_TRADE_REQUIRED_OPTIONS = %w(service partner _input_charset notify_url subject out_trade_no currency total_fee)
121
- def self.create_forex_trade(options)
122
- options = {
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(Utils.stringify_keys(options))
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
- CLOSE_TRADE_REQUIRED_OPTIONS = %w( service partner _input_charset)
135
- CLOSE_TRADE_REQUIRED_OPTIONAL_OPTIONS = %w( trade_no out_order_no )
136
- def self.close_trade(options)
137
- options = {
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(Utils.stringify_keys(options))
146
+ 'partner' => options[:pid] || Alipay.pid
147
+ }.merge(params)
142
148
 
143
- check_required_options(options, CLOSE_TRADE_REQUIRED_OPTIONS)
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
- SINGLE_TRADE_QUERY_OPTIONS = %w( service partner _input_charset)
150
- SINGLE_TRADE_QUERY_OPTIONAL_OPTIONS = %w( trade_no out_trade_no )
151
- def self.single_trade_query(options)
152
- options = {
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(Utils.stringify_keys(options))
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 = params.merge('sign_type' => Alipay.sign_type) if params['sign_type'].nil?
172
- params.merge('sign' => Alipay::Sign.generate(params))
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.check_required_options(options, names)
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 options.has_key?(name)
183
+ warn("Ailpay Warn: missing required option: #{name}") unless params.has_key?(name)
180
184
  end
181
185
  end
182
186
 
183
- def self.check_optional_options(options, names)
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| options[name].nil? }
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 = params.delete('sign_type') || Alipay.sign_type
10
- key = params.delete('key') || Alipay.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
- generate_md5(key, params)
11
+ MD5.sign(key, string)
15
12
  when 'RSA'
16
- raise NotImplementedError, "RSA sign is unimplemented"
13
+ RSA.sign(key, string)
17
14
  when 'DSA'
18
- raise NotImplementedError, "DSA sign is unimplemented"
15
+ DSA.sign(key, string)
19
16
  else
20
- raise ArgumentError, "wrong sign_type #{sign_type}, allow values: 'MD5', 'RSA', 'DSA'"
17
+ raise ArgumentError, "[Alipay] Invalid sign_type #{sign_type}, allow value: 'MD5', 'RSA', 'DSA'"
21
18
  end
22
19
  end
23
20
 
24
- def self.generate_md5(key, params)
25
- Digest::MD5.hexdigest("#{params_to_string(params)}#{key}")
26
- end
27
-
28
- def self.params_to_string(params)
29
- params.sort.map { |item| item.join('=') }.join('&')
30
- end
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
- verify_md5?(params)
39
+ key = options[:key] || Alipay.key
40
+ MD5.verify?(key, string, sign)
40
41
  when 'RSA'
41
- verify_rsa?(params)
42
+ RSA.verify?(ALIPAY_RSA_PUBLIC_KEY, string, sign)
42
43
  when 'DSA'
43
- raise NotImplementedError, "DSA verify is unimplemented"
44
+ DSA.verify?(string, sign)
44
45
  else
45
- raise ArgumentError, "wrong sign_type #{sign_type}, allow values: 'MD5', 'RSA', 'DSA'"
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.verify_md5?(params)
50
- key = params.delete('key') || Alipay.key
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