qq_17up 3.0.3

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 zires
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ open_qq
2
+ =======
3
+
4
+ 腾讯开放平台ruby版SDK(v3版本)
5
+
6
+ ## 安装
7
+
8
+ ```ruby
9
+ gem install open_qq
10
+ ```
11
+
12
+ ## 使用
13
+
14
+ 使用非常简单,传入应用的`appid`, `appkey`和环境地址`env`
15
+
16
+ ```ruby
17
+ require 'rubygems'
18
+ require 'open_qq'
19
+
20
+ OpenQq.setup(:appid => '123', :appkey => '456', :env => 'https://graph.qq.com')
21
+
22
+ # 或者https
23
+ OpenQq.setup(:appid => '123', :appkey => '456', :env => 'https://graph.qq.com')
24
+
25
+ # get请求
26
+ user_info = OpenQq.get('/user/get_info', :openid => '111',:openkey => '222')
27
+
28
+ # 或者post请求
29
+ user_info = OpenQq.post('/user/get_info',:openid => '111',:openkey => '222')
30
+
31
+ user_info.ret # => 0
32
+ user_info.nickname # => 'foo'
33
+ ```
34
+
35
+ 如果你只想原样返回未加工的数据,使用`raw => true`
36
+
37
+ ```ruby
38
+ user_info = OpenQq.post('/user/get_info', {:openid => '111', :openkey => '222'}, :raw => true)
39
+ puts user_info
40
+ # => '{ "ret": 0, "is_lost": 0, "nickname": "foo" }'
41
+ ```
42
+
43
+ 如果你不想使用全局的配置
44
+
45
+ ```ruby
46
+ options = {:appid => 'newappid', :appkey => 'newappkey', :env => 'https://graph.qq.com'}
47
+
48
+ user_info = OpenQq.call('/user/get_info', options) do |request|
49
+
50
+ request.get {:openid => '111',:openkey => '222'}
51
+
52
+ #或者
53
+ request.post {:openid => '111',:openkey => '222'}
54
+
55
+ end
56
+
57
+ user_info.nickname
58
+ # => 'foo'
59
+ ```
60
+
61
+ 回调协议签名验证
62
+
63
+ ```ruby
64
+ params = {openid: 'test001', appid: '33758', sig: 'VvKwcaMqUNpKhx0XfCvOqPRiAnU%3D'}
65
+ OpenQq.verify_callback_sig(:get, '/cgi-bin/temp.py', params)
66
+ # => true or false
67
+
68
+ #指定特定的appkey
69
+ OpenQq.verify_callback_sig(:get, '/cgi-bin/temp.py', params, 'xxxxxx')
70
+
71
+ # 在rails中使用
72
+ class OpenQqController < ApplicationController
73
+ include OpenQq::Rails::ActionController
74
+
75
+ def index
76
+ if verify_callback_sig
77
+ ...do something
78
+ end
79
+ end
80
+ end
81
+
82
+ ```
83
+
84
+ ## 在rails中使用
85
+
86
+ 首先在Gemfile中添加
87
+ ```
88
+ gem 'open_qq'
89
+ ```
90
+
91
+ 执行`bundle install`
92
+
93
+ 在config目录下生成配置文件config/open_qq.yml
94
+ ```
95
+ rails g open_qq:install
96
+ ```
97
+
98
+ 在配置文件中填入appid, appkey和env的值,启动服务后全局都可以使用,例如:
99
+
100
+ ```ruby
101
+ class OpenQqController < ApplicationController
102
+
103
+ # 假设这里是应用的入口
104
+ def index
105
+ user_info = OpenQq.post('/user/get_info', params.slice!(:action, :controller))
106
+ if user_info.ret == 0
107
+ # do something
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+ ```
114
+
115
+ ## 注意和说明
116
+
117
+ * 当传入的format为xml时,不会对返回的结果做处理,直接字符串返回
118
+ * 当传入的format不为xml时,会使用`JSON#parse`转换成hash,并且使用[OpenStruct](http://www.ruby-doc.org/stdlib-1.8.7/libdoc/ostruct/rdoc/OpenStruct.html, 'OpenStruct')封装
119
+ * 当ret返回`2001`时,是由本api抛出
120
+ * 关于*signature verification failed*,先仔细对照[文档](http://wiki.open.qq.com/wiki/%E8%85%BE%E8%AE%AF%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0%E7%AC%AC%E4%B8%89%E6%96%B9%E5%BA%94%E7%94%A8%E7%AD%BE%E5%90%8D%E5%8F%82%E6%95%B0sig%E7%9A%84%E8%AF%B4%E6%98%8E#.E4.B8.BA.E4.BB.80.E4.B9.88.E6.80.BB.E6.98.AF.E8.BF.94.E5.9B.9E.E2.80.9C-5.EF.BC.9Asignature_verification_failed.E2.80.9D.EF.BC.9F)
121
+
122
+ ```
123
+ 可以通过联调工具看下签名是否一致
124
+
125
+ opts = {:openid => '1111',:openkey => '2222',:pf => 'pengyou'}
126
+ sig = OpenQq.wrap(:post, '/v3/user/get_info', opts)['sig']
127
+
128
+ puts sig # 与联调结果比对
129
+
130
+ ```
131
+
132
+ * 如果不想使用open_qq.yml,只要在使用前全局配置好`OpenQq`即可
133
+ * 测试基本覆盖,可以下载下来执行`rake`
134
+ * bug反馈[Issue](https://github.com/zires/open_qq/issues)
135
+
136
+ ## Changelog
137
+
138
+ * 2012/09/11
139
+ 增加对https的支持
140
+ 支持支付回调协议签名验证
141
+
142
+
143
+ ## This project rocks and uses MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ require 'yard'
9
+ YARD::Rake::YardocTask.new
10
+
11
+ require 'rake/testtask'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib'
14
+ t.libs << 'test'
15
+ t.pattern = 'test/**/*_test.rb'
16
+ t.verbose = true
17
+ end
18
+
19
+ task :default => :test
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ module OpenQq
3
+ module Generators
4
+ class InstallGenerator < ::Rails::Generators::Base
5
+ # Create open_qq.yml under config/initializers/
6
+ source_root File.expand_path("../../templates", __FILE__)
7
+
8
+ desc "Creates a ThemePark initializer file."
9
+ def copy_initializer
10
+ template "open_qq.yml", "config/open_qq.yml"
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # open_qq configruation.
2
+ # see http://open.qq.com/
3
+ development:
4
+ appid:
5
+ appkey:
6
+ env: http://119.147.19.43
7
+
8
+ test:
9
+ appid:
10
+ appkey:
11
+ env: http://119.147.19.43
12
+
13
+ production:
14
+ appid:
15
+ appkey:
16
+ env: http://openapi.tencentyun.com
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ module OpenQq
7
+ # behavior response to body method
8
+ class Error
9
+
10
+ def initialize(ret, msg, format = 'json')
11
+ @ret, @msg, @format = ret, msg, format.to_s
12
+ end
13
+
14
+ def body
15
+ if @format == 'xml'
16
+ %Q(<?xml version="1.0" encoding="UTF-8"?><data><ret>#{@ret}</ret><msg>#{@msg}</msg></data>)
17
+ else
18
+ {:ret => @ret, :msg => @msg}.to_json
19
+ end
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,105 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ require 'open_qq/signature'
7
+ require 'open_qq/error'
8
+ require 'ostruct'
9
+ require 'net/https'
10
+
11
+ module OpenQq
12
+ class Gateway
13
+
14
+ OPEN_HTTP_TRANSLATE_ERROR = 2001
15
+
16
+ attr_accessor :appid, :appkey, :env
17
+
18
+ # @param [String] appid
19
+ # @param [String] appkey
20
+ # @param [String] env 调用的环境地址
21
+ #
22
+ # @example
23
+ # OpenQq::Gateway.new('1111', '2222', 'http://119.147.19.43')
24
+ # OpenQq::Gateway.new('1111', '2222', 'https://openapi.tencentyun.com')
25
+ def initialize(appid, appkey, env)
26
+ @appid = appid
27
+ @appkey = appkey
28
+ self.env = env
29
+ end
30
+
31
+ # override
32
+ def env=(env)
33
+ @env = env
34
+ uri = URI.parse(env)
35
+ @http = Net::HTTP.new(uri.host, uri.port)
36
+ # HTTPS
37
+ if uri.scheme == "https"
38
+ @http.use_ssl = true
39
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
40
+ end
41
+ end
42
+
43
+ # @param [String] url which api you want to call
44
+ # @param [Hash] params extra params attach to the url
45
+ # @param [options] options
46
+ #
47
+ # @example
48
+ # gateway = OpenQq::Gateway.new('1111', '2222', 'http://119.147.19.43')
49
+ # user_info = gateway.get('/v3/user/get_info', {:openid => '11'} )
50
+ # user_info.nickname # => foo
51
+ #
52
+ # @example available option
53
+ # :raw => true will raw the output
54
+ # user_info = gateway.get('/v3/user/get_info', {:openid => '11'}, {:raw => true} )
55
+ # user_info.nickname # => '{"nickname":"foo"}'
56
+ #
57
+ # @return (see #call)
58
+ def get(url, params = {}, options = {})
59
+ parsed_params = Gateway.parsed_params( wrap(:get, url, params) )
60
+ get_request = Net::HTTP::Get.new("#{url}?#{parsed_params}")
61
+ self.call( get_request, options.merge(:format => params[:format]) )
62
+ end
63
+
64
+ # @param (see #get)
65
+ #
66
+ # @return (see #call)
67
+ def post(url, params = {}, options = {})
68
+ post_request = Net::HTTP::Post.new(url)
69
+ post_request.body = Gateway.parsed_params( wrap(:post, url, params) )
70
+ post_request.content_type = 'application/x-www-form-urlencoded'
71
+ self.call( post_request, options.merge(:format => params[:format]) )
72
+ end
73
+
74
+ # wrap `http_method`, `url`, `params` together
75
+ def wrap(http_method, url, params)
76
+ params = params.merge(:appid => @appid)
77
+ params[:sig] = Gateway.signature( "#{@appkey}&", Gateway.make_source(http_method.to_s.upcase, url, params) )
78
+ params
79
+ end
80
+
81
+ class << self
82
+ include Signature
83
+ end
84
+
85
+ protected
86
+
87
+ # Call the request and format the output
88
+ # @param [Net::HTTP::Request] request be called
89
+ # @param [Hash] options some option used to format output
90
+ #
91
+ # @return [String, Object] unformatted string result or parsed OpenStruct instance
92
+ def call(request, options)
93
+ response = begin
94
+ @http.request(request)
95
+ rescue Exception => e
96
+ Error.new(OPEN_HTTP_TRANSLATE_ERROR, "#{e.message}\n#{e.backtrace.inspect}", options[:format])
97
+ end
98
+
99
+ return response.body if options[:raw] || options[:format] == 'xml'
100
+
101
+ OpenStruct.new( JSON.parse(response.body) )
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ module OpenQq
7
+ module Rails
8
+ module ActionController
9
+ extend ActiveSupport::Concern
10
+
11
+ private
12
+ # @example
13
+ # class OpenQqController < ApplicationController
14
+ # include OpenQq::Rails::ActionController
15
+ #
16
+ # def index
17
+ # if verify_callback_sig
18
+ # ...do something
19
+ # end
20
+ # end
21
+ # end
22
+ # @return [Boolean]
23
+ def verify_callback_sig(key = nil)
24
+ logger.debug "Appkey: #{key ||= OpenQq.appkey} method: #{request.method} url: #{request.fullpath.split("?")[0]}"
25
+ logger.debug "params: #{params.slice!(:action, :controller).inspect}"
26
+ OpenQq.verify_callback_sig(request.method, request.fullpath.split("?")[0], params.slice!(:action, :controller), key)
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ module OpenQq
7
+ class Railtie < ::Rails::Railtie
8
+
9
+ generators do
10
+ require "generators/open_qq/install_generator"
11
+ end
12
+
13
+ initializer "open_qq.setup" do
14
+ config_file = Rails.root.join("config", "open_qq.yml")
15
+ if config_file.file?
16
+ begin
17
+ options = YAML.load_file(config_file)[Rails.env]
18
+ OpenQq.setup(options)
19
+ rescue Exception => e
20
+ puts "There is a configuration error with the current open_qq.yml"
21
+ puts e.message
22
+ end
23
+ end
24
+ end
25
+
26
+ initializer "load open_qq controller method" do
27
+ ActiveSupport.on_load(:action_controller) do
28
+ require 'open_qq/rails/action_controller'
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ require 'open_qq/gateway'
7
+
8
+ module OpenQq
9
+ class Request < Gateway
10
+
11
+ attr_accessor :url, :options
12
+
13
+ def initialize(options)
14
+ options = options.dup
15
+ appid = options.delete(:appid)
16
+ appkey = options.delete(:appkey)
17
+ env = options.delete(:env)
18
+ @url = options.delete(:url)
19
+ @options = options || {}
20
+ super(appid, appkey, env)
21
+ end
22
+
23
+ # @see Gateway#get
24
+ def get(params = {}, options = nil)
25
+ options ||= @options
26
+ super(@url, params, options)
27
+ end
28
+
29
+ # @see Gateway#get
30
+ def post(params = {}, options = nil)
31
+ options ||= @options
32
+ super(@url, params, options)
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ require 'base64'
7
+ require 'openssl'
8
+ require 'uri'
9
+
10
+ module OpenQq
11
+ module Signature
12
+
13
+ def signature(key, source)
14
+ Base64.encode64( OpenSSL::HMAC.digest('sha1', key, source) ).rstrip
15
+ end
16
+
17
+ def url_escape(url)
18
+ URI.escape(url, /[^\.\-_\da-zA-Z]/)
19
+ end
20
+
21
+ def parsed_params(params)
22
+ params.map{|k,v| "#{url_escape(k.to_s)}=#{url_escape(v.to_s)}"}.join('&')
23
+ end
24
+
25
+ def make_source(http_method, url, params)
26
+ escape_opt = url_escape( params.sort_by{|k,v| k.to_s}.map{|kv| "#{kv.first}=#{kv.last}" }.join('&') )
27
+ "#{http_method}&#{url_escape(url)}&#{escape_opt}"
28
+ end
29
+
30
+ def make_callback_source(http_method, url, params)
31
+ escape_opt = params.sort_by{|k,v| k.to_s}.map do |kv|
32
+ value = URI.escape(kv.last, /[^0-9a-zA-Z!*()]/)
33
+ "#{kv.first}=#{value}"
34
+ end.join('&')
35
+ "#{http_method}&#{url_escape(url)}&#{url_escape(escape_opt)}"
36
+ end
37
+
38
+ def verify_sig(sig, key, http_method, url, params)
39
+ sig == url_escape( signature(key, make_callback_source(http_method, url, params)) )
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ module OpenQq
7
+ # 3.0表示OpenAPI版本, 小数点第二位表示SDK版本
8
+ VERSION = "3.0.3"
9
+ end
data/lib/open_qq.rb ADDED
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ #
3
+ # --
4
+ # @author zires
5
+ #
6
+ require 'rubygems' if RUBY_VERSION < '1.9'
7
+ require 'json'
8
+ require 'open_qq/request'
9
+ require 'active_support/core_ext/module/delegation'
10
+ require 'active_support/core_ext/hash/indifferent_access'
11
+
12
+ module OpenQq
13
+ class << self
14
+
15
+ def setup(options = {})
16
+ options = options.with_indifferent_access
17
+ @gateway ||= OpenQq::Gateway.new(options[:appid], options[:appkey], options[:env])
18
+ yield @gateway if block_given?
19
+ end
20
+
21
+ # @see Gateway#get
22
+ delegate :appid, :appkey, :env, :get, :post, :wrap, :to => :@gateway
23
+
24
+ # @example
25
+ # OpenQq.call('/v3/user/get_info', { :appid => 123 }) do |request|
26
+ # request.get({:openid => '111'})
27
+ # end
28
+ def call(url, options)
29
+ request = OpenQq::Request.new(options.with_indifferent_access)
30
+ if block_given?
31
+ yield request
32
+ else
33
+ request
34
+ end
35
+ end
36
+
37
+ alias start call
38
+
39
+ # @example
40
+ # params = {openid: 'test001', appid: '33758', sig: 'VvKwcaMqUNpKhx0XfCvOqPRiAnU%3D'}
41
+ # OpenQq.verify_callback_sig(:get, '/cgi-bin/temp.py', params)
42
+ # #diffenert key
43
+ # OpenQq.verify_callback_sig(:get, '/cgi-bin/temp.py', params, 'xxxxxx')
44
+ #
45
+ # @return [Boolean]
46
+ def verify_callback_sig(http_method, url, params, key = nil)
47
+ key ||= appkey
48
+ params = params.dup
49
+ sig = params.delete('sig') || params.delete(:sig)
50
+ Gateway.verify_sig(sig, "#{key}&", http_method.to_s.upcase, url, params)
51
+ end
52
+
53
+ end
54
+ end
55
+
56
+ require 'open_qq/railtie' if defined?(Rails)
data/test/benchmark.rb ADDED
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'benchmark'
3
+ require 'ostruct'
4
+ require 'json'
5
+
6
+ n = 500000
7
+ @os = { :ret => 0,
8
+ :is_lost => 0,
9
+ :nickname => 'Peter',
10
+ :gender => 'boy',
11
+ :country => 'country',
12
+ :province => 'province',
13
+ :city => 'city',
14
+ :figureurl => 'http://imgcache.qq.com/qzone_v4/client/userinfo_icon/1236153759.gif',
15
+ :is_yellow_vip => 1,
16
+ :is_yellow_year_vip => 1,
17
+ :yellow_vip_level => 7
18
+ }
19
+
20
+ @os_obj = OpenStruct.new(@os)
21
+
22
+ Benchmark.bm do |x|
23
+
24
+ x.report { for i in 1..n; @os_obj.nickname; end }
25
+ x.report { for i in 1..n; @os['nickname']; end }
26
+
27
+ end
28
+
29
+ @os_json = @os.to_json
30
+
31
+ m = 10
32
+
33
+ Benchmark.bm do |x|
34
+
35
+ x.report { for i in 1..m; JSON.parse(@os_json); end }
36
+ x.report { for i in 1..m; OpenStruct.new( JSON.parse(@os_json) ); end }
37
+
38
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ class OpenQq::ErrorTest < MiniTest::Unit::TestCase
4
+
5
+ def test_symbol_format
6
+ error = OpenQq::Error.new(100, 'error!', :json)
7
+ assert_equal '{"ret":100,"msg":"error!"}', error.body
8
+ end
9
+
10
+ def test_json_format
11
+ error = OpenQq::Error.new(100, 'error!', 'json')
12
+ assert_equal '{"ret":100,"msg":"error!"}', error.body
13
+ end
14
+
15
+ def test_xml_format
16
+ error = OpenQq::Error.new(100, 'error!', 'xml')
17
+ assert_equal '<?xml version="1.0" encoding="UTF-8"?><data><ret>100</ret><msg>error!</msg></data>', error.body
18
+ end
19
+
20
+ def test_no_format
21
+ error = OpenQq::Error.new(100, 'error!')
22
+ assert_equal '{"ret":100,"msg":"error!"}', error.body
23
+ end
24
+
25
+ def test_unsupported_format
26
+ error = OpenQq::Error.new(100, 'error!', :ruby)
27
+ assert_equal '{"ret":100,"msg":"error!"}', error.body
28
+ end
29
+
30
+ end
@@ -0,0 +1,61 @@
1
+ require 'test_helper'
2
+
3
+ class OpenQq::GatewayTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ # 测试用例的签名通过腾讯联调工具产生 http://open.qq.com/tools
7
+ @appid = 12345
8
+ @appkey = '228bf094169a40a3bd188ba37ebe8723'
9
+ @env = 'http://119.147.19.43'
10
+ @gateway = OpenQq::Gateway.new(@appid, @appkey, @env)
11
+ end
12
+
13
+ def test_call_get_request_without_params
14
+ assert_equal 'foo', @gateway.get('/v3/user/get_info').nickname
15
+ end
16
+
17
+ def test_call_get_request_with_params
18
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'json' }
19
+ assert_equal 'foo', @gateway.get('/v3/user/get_info', params).nickname
20
+ end
21
+
22
+ def test_call_get_request_with_xml_format
23
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'xml' }
24
+ assert_equal '<?xml version="1.0" encoding="UTF-8"?>', @gateway.get('/v3/user/get_info', params)
25
+ end
26
+
27
+ def test_call_get_request_without_format_param
28
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou }
29
+ assert_equal 'foo', @gateway.get('/v3/user/get_info', params).nickname
30
+ end
31
+
32
+ def test_call_get_request_with_unknow_format_param
33
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'ruby'}
34
+ assert_equal 'foo', @gateway.get('/v3/user/get_info', params).nickname
35
+ end
36
+
37
+ def test_call_post_request
38
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
39
+ assert_equal 'foo', @gateway.post('/v3/user/get_info', params).nickname
40
+ end
41
+
42
+ def test_call_post_request_with_raw_output
43
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
44
+ assert_equal '{ "ret": 0, "is_lost": 0, "nickname": "foo" }', @gateway.post('/v3/user/get_info', params, :raw => true)
45
+ end
46
+
47
+ def test_open_http_translate_error
48
+ gateway = OpenQq::Gateway.new('123456', @appkey, @env)
49
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
50
+ assert_equal 2001, gateway.get('/v3/user/get_info', params).ret
51
+ end
52
+
53
+ def test_https_request
54
+ gateway = OpenQq::Gateway.new(@appid, @appkey, 'https://119.147.19.43')
55
+ http = gateway.instance_variable_get(:@http)
56
+ assert_equal 443, http.port
57
+ assert_equal '119.147.19.43', http.address
58
+ assert http.use_ssl?
59
+ end
60
+
61
+ end
@@ -0,0 +1,34 @@
1
+ require 'test_helper'
2
+
3
+ class OpenQq::RequestTest < MiniTest::Unit::TestCase
4
+
5
+ def setup
6
+ # 测试用例的签名通过腾讯联调工具产生 http://open.qq.com/tools
7
+ options = { :appid => 12345,
8
+ :appkey => '228bf094169a40a3bd188ba37ebe8723',
9
+ :env => 'http://119.147.19.43',
10
+ :url => '/v3/user/get_info',
11
+ }
12
+ @request = OpenQq::Request.new(options)
13
+ end
14
+
15
+ def test_call_get_request_without_params
16
+ assert_equal 'foo', @request.get.nickname
17
+ end
18
+
19
+ def test_call_get_request_with_params
20
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'json' }
21
+ assert_equal 'foo', @request.get(params).nickname
22
+ end
23
+
24
+ def test_call_post_request
25
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
26
+ assert_equal 'foo', @request.post(params).nickname
27
+ end
28
+
29
+ def test_call_post_request_with_raw_output
30
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
31
+ assert_equal '{ "ret": 0, "is_lost": 0, "nickname": "foo" }', @request.post(params, :raw => true)
32
+ end
33
+
34
+ end
@@ -0,0 +1,71 @@
1
+ require 'test_helper'
2
+
3
+ class Foo
4
+ include OpenQq::Signature
5
+ end
6
+
7
+ class OpenQq::SignatureTest < MiniTest::Unit::TestCase
8
+
9
+ def setup
10
+ @foo = Foo.new
11
+ # 测试数据是通过腾讯开放平台联调工具集生成
12
+ # 详见:http://open.qq.com/tools
13
+ @url = '/v3/user/get_info'
14
+ @http_method = :GET
15
+ @appkey = '228bf094169a40a3bd188ba37ebe8723'
16
+
17
+ #openid=11111111111111111&openkey=2222222222222222&pf=qzone&appid=123456&format=json&userip=10.0.0.1
18
+ @options = { :openid => '11111111111111111', :openkey => '2222222222222222',
19
+ 'appid' => '123456', 'pf' => 'qzone',
20
+ :userip => '10.0.0.1', :format => :json
21
+ }
22
+ end
23
+
24
+ def test_signature_is_a_module
25
+ assert_equal Module, ::OpenQq::Signature.class
26
+ end
27
+
28
+ def test_make_source
29
+ expect_source = 'GET&%2Fv3%2Fuser%2Fget_info&appid%3D123456%26format%3Djson%26openid%3D11111111111111111%26openkey%3D2222222222222222%26pf%3Dqzone%26userip%3D10.0.0.1'
30
+ assert_equal expect_source, @foo.make_source(@http_method, @url, @options)
31
+ end
32
+
33
+ def test_parsed_params
34
+ opt = { '/ +=&' => '123@*!' }
35
+ assert_equal( "%2F%20%2B%3D%26=123%40%2A%21", @foo.parsed_params(opt) )
36
+ end
37
+
38
+ def test_url_escape
39
+ assert_equal 'o%2FnGo1QkVEiiN6Bqn%2FfRJtEJwLc%3D', @foo.url_escape('o/nGo1QkVEiiN6Bqn/fRJtEJwLc=')
40
+ end
41
+
42
+ def test_signature
43
+ source = @foo.make_source(@http_method, @url, @options)
44
+ assert_equal( 'o/nGo1QkVEiiN6Bqn/fRJtEJwLc=', @foo.signature("#{@appkey}&", source) )
45
+ end
46
+
47
+ #测试用例通过http://wiki.open.qq.com/wiki/回调发货URL的协议说明_V3获得
48
+ def test_make_callback_source
49
+ params = 'openid=test001&appid=33758&ts=1328855301&payitem=323003*8*1&token=53227955F80B805B50FFB511E5AD51E025360&billno=-APPDJT18700-20120210-1428215572&version=v3&zoneid=1&providetype=0&amt=80&payamt_coins=20&pubacct_payamt_coins=10'
50
+ options = {}
51
+ params.split('&').each do |param|
52
+ param = param.split('=')
53
+ options[param.first] = param.last
54
+ end
55
+ expect = 'GET&%2Fcgi-bin%2Ftemp.py&amt%3D80%26appid%3D33758%26billno%3D%252DAPPDJT18700%252D20120210%252D1428215572%26openid%3Dtest001%26payamt_coins%3D20%26payitem%3D323003%2A8%2A1%26providetype%3D0%26pubacct_payamt_coins%3D10%26token%3D53227955F80B805B50FFB511E5AD51E025360%26ts%3D1328855301%26version%3Dv3%26zoneid%3D1'
56
+ assert_equal expect, @foo.make_callback_source(:GET, '/cgi-bin/temp.py', options)
57
+ end
58
+
59
+ def test_verify_sig
60
+ key = '12345f9a47df4d1eaeb3bad9a7e54321&'
61
+ sig = 'VvKwcaMqUNpKhx0XfCvOqPRiAnU%3D'
62
+ params = 'openid=test001&appid=33758&ts=1328855301&payitem=323003*8*1&token=53227955F80B805B50FFB511E5AD51E025360&billno=-APPDJT18700-20120210-1428215572&version=v3&zoneid=1&providetype=0&amt=80&payamt_coins=20&pubacct_payamt_coins=10'
63
+ options = {}
64
+ params.split('&').each do |param|
65
+ param = param.split('=')
66
+ options[param.first] = param.last
67
+ end
68
+ assert @foo.verify_sig(sig, key, :GET, '/cgi-bin/temp.py', options), 'Verify sig failure'
69
+ end
70
+
71
+ end
@@ -0,0 +1,131 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ class OpenQqTest < MiniTest::Unit::TestCase
5
+
6
+ def setup
7
+ @options = { :appid => 12345,
8
+ :appkey => '228bf094169a40a3bd188ba37ebe8723',
9
+ :env => 'http://119.147.19.43',
10
+ :url => '/v3/user/get_info',
11
+ }
12
+ OpenQq.setup(@options)
13
+ end
14
+
15
+ def teardown
16
+ # Need setup back for the rest test
17
+ OpenQq.setup{|c|
18
+ c.appid = 12345
19
+ c.appkey ='228bf094169a40a3bd188ba37ebe8723'
20
+ c.env ='http://119.147.19.43'
21
+ }
22
+ end
23
+
24
+ def test_OpenQq_is_a_module
25
+ assert_kind_of Module, OpenQq
26
+ end
27
+
28
+ def test_setup
29
+ assert_equal 12345, OpenQq.appid
30
+ assert_equal '228bf094169a40a3bd188ba37ebe8723', OpenQq.appkey
31
+ assert_equal 'http://119.147.19.43', OpenQq.env
32
+ OpenQq.setup do |config|
33
+ config.appid = 'foo'
34
+ end
35
+ assert_equal 'foo', OpenQq.appid
36
+ end
37
+
38
+ # Copy from gateway_test
39
+
40
+ def test_call_get_request_without_params
41
+ assert_equal 'foo', OpenQq.get('/v3/user/get_info').nickname
42
+ end
43
+
44
+ def test_call_get_request_with_params
45
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'json' }
46
+ assert_equal 'foo', OpenQq.get('/v3/user/get_info', params).nickname
47
+ end
48
+
49
+ def test_call_get_request_with_xml_format
50
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'xml' }
51
+ assert_equal '<?xml version="1.0" encoding="UTF-8"?>', OpenQq.get('/v3/user/get_info', params)
52
+ end
53
+
54
+ def test_call_get_request_without_format_param
55
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou }
56
+ assert_equal 'foo', OpenQq.get('/v3/user/get_info', params).nickname
57
+ end
58
+
59
+ def test_call_get_request_with_unknow_format_param
60
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'ruby'}
61
+ assert_equal 'foo', OpenQq.get('/v3/user/get_info', params).nickname
62
+ end
63
+
64
+ def test_call_post_request
65
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
66
+ assert_equal 'foo', OpenQq.post('/v3/user/get_info', params).nickname
67
+ end
68
+
69
+ def test_call_post_request_with_raw_output
70
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
71
+ assert_equal '{ "ret": 0, "is_lost": 0, "nickname": "foo" }', OpenQq.post('/v3/user/get_info', params, :raw => true)
72
+ end
73
+
74
+ def test_open_http_translate_error
75
+ OpenQq.setup do |config|
76
+ config.appid = '123456'
77
+ end
78
+ params = {:openid => '1111', :openkey => '2222', :pf => 'pengyou'}
79
+ assert_equal 2001, OpenQq.get('/v3/user/get_info', params).ret
80
+ end
81
+
82
+ def test_call_wont_change_get_and_post_method
83
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'json' }
84
+ respond = OpenQq.call('/v3/user/get_info', @options){|r| r.get(params) }
85
+ assert_equal 'foo', OpenQq.get('/v3/user/get_info', params).nickname
86
+ assert_equal 'foo', respond.nickname
87
+ end
88
+
89
+ def test_call_has_alise_method_start
90
+ params = { :openid => 1111, 'openkey' => '2222', :pf => :pengyou, :format => 'json' }
91
+ respond = OpenQq.start('/v3/user/get_info', @options){|r| r.get(params) }
92
+ assert_equal 'foo', OpenQq.get('/v3/user/get_info', params).nickname
93
+ assert_equal 'foo', respond.nickname
94
+ end
95
+
96
+ def test_verify_callback_sig
97
+ key = '12345f9a47df4d1eaeb3bad9a7e54321'
98
+ params = 'openid=test001&appid=33758&ts=1328855301&payitem=323003*8*1&token=53227955F80B805B50FFB511E5AD51E025360&billno=-APPDJT18700-20120210-1428215572&version=v3&zoneid=1&providetype=0&amt=80&payamt_coins=20&pubacct_payamt_coins=10'
99
+ options = {:sig => 'VvKwcaMqUNpKhx0XfCvOqPRiAnU%3D'}
100
+ params.split('&').each do |param|
101
+ param = param.split('=')
102
+ options[param.first] = param.last
103
+ end
104
+ assert OpenQq.verify_callback_sig(:GET, '/cgi-bin/temp.py', options, key), 'Verify sig failure 1'
105
+ OpenQq.setup{|c| c.appkey = key }
106
+ assert OpenQq.verify_callback_sig(:GET, '/cgi-bin/temp.py', options), 'Verify sig failure 2'
107
+ assert OpenQq.verify_callback_sig(:get, '/cgi-bin/temp.py', options), 'Verify sig failure 3'
108
+ end
109
+
110
+ #http://wiki.open.qq.com/wiki/v3/pay/buy_goods
111
+ def test_buy_goods
112
+ options = { :appid => 600,
113
+ :appkey => '12345f9a47df4d1eaeb3bad9a7e54321',
114
+ :env => 'https://119.147.19.43'
115
+ }
116
+ params = { :amt => 4,:appmode => 1,:format => 'json',:goodsmeta => '道具*测试描述信息!!!',
117
+ :goodsurl => 'http://qzonestyle.gtimg.cn/qzonestyle/act/qzone_app_img/app613_613_75.png',
118
+ :openid => '0000000000000000000000000E111111',
119
+ :openkey => '1111806DC5D1C52150CF405E42222222',
120
+ :payitem => '50005*4*1',
121
+ :pf => 'qzone',
122
+ :pfkey => '1B59A5C3D77C7C56D7AFC3E2C823105D',
123
+ :ts => '1333674935'
124
+ }
125
+ sig = 'fVcr1Imq8FjJZgf3h24haUE18rA='
126
+ OpenQq.call('/v3/pay/buy_goods', options) do |request|
127
+ assert_equal sig, request.wrap(:get, '/v3/pay/buy_goods', params)[:sig]
128
+ end
129
+ end
130
+
131
+ end
@@ -0,0 +1,57 @@
1
+ begin
2
+ Bundler.setup(:default, :development)
3
+ rescue Bundler::BundlerError => e
4
+ $stderr.puts e.message
5
+ $stderr.puts "Run `bundle install` to install missing gems"
6
+ exit e.status_code
7
+ end
8
+
9
+ require "test/unit"
10
+ require 'minitest/autorun'
11
+
12
+ # Enable turn if it is available
13
+ begin
14
+ require 'turn'
15
+ rescue LoadError
16
+ end
17
+
18
+ require 'open_qq'
19
+
20
+ # fake qq response
21
+ require 'fakeweb'
22
+
23
+ # 测试用例的签名通过腾讯联调工具产生 http://open.qq.com/tools
24
+ # get
25
+ FakeWeb.register_uri(:get, "http://119.147.19.43/v3/user/get_info?appid=12345&sig=CRkzTEcrnfRkNMt9LnVtHjGTocI%3D",
26
+ :body => '{ "ret": 0, "is_lost": 0, "nickname": "foo" }')
27
+
28
+ # get with json format
29
+ FakeWeb.register_uri(:get,
30
+ "http://119.147.19.43/v3/user/get_info?openid=1111&openkey=2222&pf=pengyou&appid=12345&format=json&sig=qjReS%2Fg%2FGM9qStD9gmYNI%2B65nWo%3D",
31
+ :body => '{ "ret": 0, "is_lost": 0, "nickname": "foo" }')
32
+
33
+ # get without format
34
+ FakeWeb.register_uri(:get,
35
+ "http://119.147.19.43/v3/user/get_info?openid=1111&openkey=2222&pf=pengyou&appid=12345&sig=CtBQwNTqB24SnqMnWrSJyh4atg8%3D",
36
+ :body => '{ "ret": 0, "is_lost": 0, "nickname": "foo" }')
37
+
38
+ # get with xml format
39
+ FakeWeb.register_uri(:get,
40
+ "http://119.147.19.43/v3/user/get_info?openid=1111&openkey=2222&pf=pengyou&appid=12345&format=xml&sig=t4WtmJ2pG6RDgGAOfiLWMf8E4%2FM%3D",
41
+ :body => '<?xml version="1.0" encoding="UTF-8"?>')
42
+
43
+ # get with unsupported format
44
+ FakeWeb.register_uri(:get,
45
+ "http://119.147.19.43/v3/user/get_info?openid=1111&openkey=2222&pf=pengyou&appid=12345&format=ruby&sig=egeboQvMq5HbfntN5jdwbQaB6go%3D",
46
+ :body => '{ "ret": 0, "is_lost": 0, "nickname": "foo" }')
47
+
48
+ # post without set format
49
+ FakeWeb.register_uri(:post,
50
+ "http://119.147.19.43/v3/user/get_info",
51
+ :parameters => {:openid => '1111', :openkey => '2222', :pf => 'pengyou', :appid => '12345', :sig => 'CtBQwNTqB24SnqMnWrSJyh4atg8%3D'},
52
+ :body => '{ "ret": 0, "is_lost": 0, "nickname": "foo" }')
53
+
54
+ # http translate error
55
+ FakeWeb.register_uri(:get,
56
+ "http://119.147.19.43/v3/user/get_info?openid=1111&openkey=2222&pf=pengyou&appid=123456&sig=b67OwPW%2BfHFsKwgpu1b82k4dHZU%3D",
57
+ :exception => Net::HTTPError)
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qq_17up
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 3
7
+ - 0
8
+ - 3
9
+ version: 3.0.3
10
+ platform: ruby
11
+ authors:
12
+ - veggie
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2013-09-07 00:00:00 +08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activesupport
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ version_requirements: *id001
32
+ - !ruby/object:Gem::Dependency
33
+ name: turn
34
+ prerelease: false
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :development
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: minitest
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ type: :development
55
+ version_requirements: *id003
56
+ - !ruby/object:Gem::Dependency
57
+ name: yard
58
+ prerelease: false
59
+ requirement: &id004 !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ type: :development
67
+ version_requirements: *id004
68
+ - !ruby/object:Gem::Dependency
69
+ name: rake
70
+ prerelease: false
71
+ requirement: &id005 !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ type: :development
79
+ version_requirements: *id005
80
+ - !ruby/object:Gem::Dependency
81
+ name: fakeweb
82
+ prerelease: false
83
+ requirement: &id006 !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ type: :development
91
+ version_requirements: *id006
92
+ description: !binary |
93
+ 6IW+6K6v5byA5pS+5bmz5Y+wcnVieeeJiFNESyBodHRwOi8vb3Blbi5xcS5j
94
+ b20v
95
+
96
+ email:
97
+ - kkxlkkxllb@gmail.com
98
+ executables: []
99
+
100
+ extensions: []
101
+
102
+ extra_rdoc_files: []
103
+
104
+ files:
105
+ - lib/generators/open_qq/install_generator.rb
106
+ - lib/generators/templates/open_qq.yml
107
+ - lib/open_qq/error.rb
108
+ - lib/open_qq/gateway.rb
109
+ - lib/open_qq/rails/action_controller.rb
110
+ - lib/open_qq/railtie.rb
111
+ - lib/open_qq/request.rb
112
+ - lib/open_qq/signature.rb
113
+ - lib/open_qq/version.rb
114
+ - lib/open_qq.rb
115
+ - MIT-LICENSE
116
+ - Rakefile
117
+ - README.md
118
+ has_rdoc: true
119
+ homepage: https://github.com/17up/qq_17up
120
+ licenses: []
121
+
122
+ post_install_message:
123
+ rdoc_options: []
124
+
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ segments:
139
+ - 0
140
+ version: "0"
141
+ requirements: []
142
+
143
+ rubyforge_project:
144
+ rubygems_version: 1.3.6
145
+ signing_key:
146
+ specification_version: 3
147
+ summary: open qq ruby sdk
148
+ test_files:
149
+ - test/benchmark.rb
150
+ - test/open_qq/error_test.rb
151
+ - test/open_qq/gateway_test.rb
152
+ - test/open_qq/request_test.rb
153
+ - test/open_qq/signature_test.rb
154
+ - test/open_qq_test.rb
155
+ - test/test_helper.rb