renren-api 0.3.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/README ADDED
@@ -0,0 +1 @@
1
+ renren-api provides capability to request the service of Renren Social Network.
@@ -0,0 +1,13 @@
1
+ module RenrenAPI
2
+
3
+ VERSION = [0, 3, 3]
4
+
5
+ def self.version
6
+ VERSION * "."
7
+ end
8
+
9
+ autoload :Authentication, "renren-api/authentication"
10
+ autoload :SignatureCalculator, "renren-api/signature_calculator"
11
+ autoload :HTTPAdapter, "renren-api/http_adapter"
12
+
13
+ end
@@ -0,0 +1,41 @@
1
+ require "rack"
2
+ require_relative "signature_calculator"
3
+
4
+ module RenrenAPI
5
+ class Authentication
6
+ def initialize(app, api_key, secret_key, &failed_handler)
7
+ @app = app
8
+ @api_key = api_key
9
+ @secret_key = secret_key
10
+ @signature_calculator = SignatureCalculator.new(@secret_key)
11
+ @required_keys = %w{user session_key ss expires}.collect { |e| @api_key + "_" + e } << @api_key
12
+ @failed_handler = block_given? ? failed_handler : proc { [401, {"Content-Type" => "text/plain"}, ["Unauthorized!"]] }
13
+ end
14
+ def call(env)
15
+ request = Rack::Request.new(env)
16
+ if %r{^/people/(?<person_id>\d+)} =~ request.path_info
17
+ cookies = request.cookies
18
+ if valid?(cookies) && cookies["#{@api_key}_user"] == person_id
19
+ @app.call(env)
20
+ else
21
+ @failed_handler.call(env)
22
+ end
23
+ else
24
+ @app.call(env)
25
+ end
26
+ end
27
+ private
28
+ def valid?(cookies)
29
+ @required_keys.each do |k|
30
+ return false unless cookies.has_key?(k)
31
+ end
32
+ return false if cookies["#{@api_key}_expires"].to_i < Time.now.to_i
33
+ cookies[@api_key] == @signature_calculator.calculate(filter(cookies))
34
+ end
35
+ def filter(cookies)
36
+ hash = {}
37
+ %w{user session_key ss expires}.each { |e| hash[e] = cookies["#{@api_key}_#{e}"] }
38
+ hash
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,48 @@
1
+ require_relative "signature_calculator"
2
+ require "uri"
3
+ require "zlib"
4
+
5
+ module RenrenAPI
6
+ class HTTPAdapter
7
+ def initialize(http, api_key, secret_key, session_key)
8
+ @http, @api_key, @secret_key, @session_key = http, api_key, secret_key, session_key
9
+ @signature_calculator = SignatureCalculator.new(@secret_key)
10
+ end
11
+ def get_friends
12
+ params = {
13
+ :api_key => @api_key,
14
+ :method => "friends.getFriends",
15
+ :call_id => current_time_in_millisecond,
16
+ :v => "1.0",
17
+ :session_key => @session_key,
18
+ :format => "JSON"
19
+ }
20
+ request(params)
21
+ end
22
+ def get_info(uids, fields)
23
+ params = {
24
+ :api_key => @api_key,
25
+ :method => "users.getInfo",
26
+ :call_id => current_time_in_millisecond,
27
+ :v => "1.0",
28
+ :session_key => @session_key,
29
+ :fields => fields * ",",
30
+ :uids => uids * ",",
31
+ :format => "JSON"
32
+ }
33
+ request(params)
34
+ end
35
+ private
36
+ def current_time_in_millisecond
37
+ "%.3f" % Time.now.to_f
38
+ end
39
+ def request(params)
40
+ params[:sig] = @signature_calculator.calculate(params)
41
+ response = @http.post("/restserver.do", URI.encode_www_form(params), {"Accept-Encoding" => "gzip"})
42
+ gzip_reader = Zlib::GzipReader.new(StringIO.new(response.body))
43
+ result = JSON.parse(gzip_reader.read)
44
+ gzip_reader.close
45
+ result
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,12 @@
1
+ require "digest/md5"
2
+
3
+ module RenrenAPI
4
+ class SignatureCalculator
5
+ def initialize(secret_key)
6
+ @secret_key = secret_key
7
+ end
8
+ def calculate(hash)
9
+ Digest::MD5.hexdigest(hash.collect { |(k, v)| "#{k}=#{v}" }.sort * "" << @secret_key)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,163 @@
1
+ require_relative "../lib/renren-api/authentication"
2
+ require "rack/test"
3
+ require "helpers"
4
+
5
+ class Rack::MockResponse
6
+ def unauthorized?
7
+ @status == 401
8
+ end
9
+ end
10
+
11
+ describe RenrenAPI::Authentication do
12
+ include Rack::Test::Methods
13
+ include Helpers
14
+ def app
15
+ RenrenAPI::Authentication.new(lambda { |env| [200, {}, ["OK"]] }, "8802f8e9b2cf4eb993e8c8adb1e02b06", "34d3d1e26cd44c05a0c450c0a0f8147b") do |env|
16
+ [401, {}, ["Get out of #{env["PATH_INFO"]}!"]]
17
+ end
18
+ end
19
+ subject { request(path, @env); last_response }
20
+ before { @env = {} }
21
+
22
+ context "when path does not have prefix /people/{person-id}" do
23
+ let(:path) { "/" }
24
+ %w{GET POST PUT DELETE}.each do |m|
25
+ context(m) do
26
+ before { @env[:method] = m }
27
+ it { should be_ok }
28
+ its(:body) { should == "OK" }
29
+ end
30
+ end
31
+ end
32
+
33
+ context "when path has prefix /people/{person-id}" do
34
+ let(:path) { "/people/#{person_id}" }
35
+ let(:person_id) { rand(9999).to_s }
36
+ context "when no login information provided" do
37
+ %w{GET POST PUT DELETE}.each do |m|
38
+ context(m) do
39
+ before { @env[:method] = m }
40
+ it { should be_unauthorized }
41
+ its(:body) { should == "Get out of #{path}!" }
42
+ end
43
+ end
44
+ end
45
+ context "when correct login information provided" do
46
+ before { @env[:cookie] = generate_cookie(secret_key, api_key, hash) }
47
+ let(:secret_key) { "34d3d1e26cd44c05a0c450c0a0f8147b" }
48
+ let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
49
+ let(:hash) do
50
+ {
51
+ "user" => person_id,
52
+ "session_key" => "session_key",
53
+ "ss" => "session_key_secret",
54
+ "expires" => (Time.now.to_i + rand(9999) + 1).to_s
55
+ }
56
+ end
57
+ %w{GET POST PUT DELETE}.each do |m|
58
+ context(m) do
59
+ before { @env[:method] = m }
60
+ it { should be_ok }
61
+ its(:body) { should == "OK" }
62
+ end
63
+ end
64
+ end
65
+ context "when incorrect login information provided" do
66
+ before { @env[:cookie] = generate_cookie("xxxx", api_key, hash) }
67
+ let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
68
+ let(:hash) do
69
+ {
70
+ "user" => person_id,
71
+ "session_key" => "session_key",
72
+ "ss" => "session_key_secret",
73
+ "expires" => (Time.now.to_i + rand(9999) + 1).to_s
74
+ }
75
+ end
76
+ %w{GET POST PUT DELETE}.each do |m|
77
+ context(m) do
78
+ before { @env[:method] = m }
79
+ it { should be_unauthorized }
80
+ its(:body) { should == "Get out of #{path}!" }
81
+ end
82
+ end
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ describe RenrenAPI::Authentication, "no failed handler is provided" do
89
+ include Rack::Test::Methods
90
+ include Helpers
91
+ def app
92
+ RenrenAPI::Authentication.new(lambda { |env| [200, {}, ["OK"]] }, "8802f8e9b2cf4eb993e8c8adb1e02b06", "34d3d1e26cd44c05a0c450c0a0f8147b")
93
+ end
94
+ subject { request(path, @env); last_response }
95
+ before { @env = {} }
96
+
97
+ context "when path does not have prefix /people/{person-id}" do
98
+ let(:path) { "/" }
99
+ %w{GET POST PUT DELETE}.each do |m|
100
+ context(m) do
101
+ before { @env[:method] = m }
102
+ it { should be_ok }
103
+ its(:body) { should == "OK" }
104
+ end
105
+ end
106
+ end
107
+
108
+ context "when path has prefix /people/{person-id}" do
109
+ let(:path) { "/people/#{person_id}" }
110
+ let(:person_id) { rand(9999).to_s }
111
+ context "when no login information provided" do
112
+ %w{GET POST PUT DELETE}.each do |m|
113
+ context(m) do
114
+ before { @env[:method] = m }
115
+ it { should be_unauthorized }
116
+ its(:content_type) { should == "text/plain"}
117
+ its(:body) { should == "Unauthorized!" }
118
+ end
119
+ end
120
+ end
121
+ context "when correct login information provided" do
122
+ before { @env[:cookie] = generate_cookie(secret_key, api_key, hash) }
123
+ let(:secret_key) { "34d3d1e26cd44c05a0c450c0a0f8147b" }
124
+ let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
125
+ let(:hash) do
126
+ {
127
+ "user" => person_id,
128
+ "session_key" => "session_key",
129
+ "ss" => "session_key_secret",
130
+ "expires" => (Time.now.to_i + rand(9999) + 1).to_s
131
+ }
132
+ end
133
+ %w{GET POST PUT DELETE}.each do |m|
134
+ context(m) do
135
+ before { @env[:method] = m }
136
+ it { should be_ok }
137
+ its(:body) { should == "OK" }
138
+ end
139
+ end
140
+ end
141
+ context "when incorrect login information provided" do
142
+ before { @env[:cookie] = generate_cookie("xxxx", api_key, hash) }
143
+ let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
144
+ let(:hash) do
145
+ {
146
+ "user" => person_id,
147
+ "session_key" => "session_key",
148
+ "ss" => "session_key_secret",
149
+ "expires" => (Time.now.to_i + rand(9999) + 1).to_s
150
+ }
151
+ end
152
+ %w{GET POST PUT DELETE}.each do |m|
153
+ context(m) do
154
+ before { @env[:method] = m }
155
+ it { should be_unauthorized }
156
+ its(:content_type) { should == "text/plain" }
157
+ its(:body) { should == "Unauthorized!" }
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ end
@@ -0,0 +1,12 @@
1
+ require "uuidtools"
2
+ require "digest/md5"
3
+
4
+ module Helpers
5
+ def generate_hash(secret_key, api_key, hash = {})
6
+ auth_code = Digest::MD5.hexdigest(hash.sort.collect { |e| e * "=" } * "" << secret_key)
7
+ Hash[hash.collect { |k, v| [api_key + "_" + k, v] }].merge!(api_key => auth_code)
8
+ end
9
+ def generate_cookie(secret_key, api_key, hash = {})
10
+ generate_hash(secret_key, api_key, hash).collect { |(k, v)| "#{k}=#{v}" }
11
+ end
12
+ end
@@ -0,0 +1,98 @@
1
+ require_relative "../lib/renren-api/http_adapter"
2
+ require_relative "../lib/renren-api/signature_calculator"
3
+ require "json"
4
+ require "net/http"
5
+ require "zlib"
6
+ require "stringio"
7
+
8
+ describe RenrenAPI::HTTPAdapter, "#get_friends" do
9
+ subject { described_class.new(http, api_key, secret_key, session_key).get_friends }
10
+ let(:http) { Net::HTTP.new("api.renren.com") }
11
+ let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
12
+ let(:secret_key) { "34d3d1e26cd44c05a0c450c0a0f8147b" }
13
+ let(:session_key) { "session_key" }
14
+ let(:result) do
15
+ [
16
+ {"id" => 12345, "name" => "Levin", "tinyurl" => "http://renren.com/1.jpg"},
17
+ {"id" => 12346, "name" => "James", "tinyurl" => "http://renren.com/2.jpg"}
18
+ ]
19
+ end
20
+ let!(:now) do
21
+ Time.now
22
+ end
23
+ let(:params) do
24
+ {
25
+ :api_key => api_key,
26
+ :method => "friends.getFriends",
27
+ :call_id => "%.3f" % now.to_f,
28
+ :v => "1.0",
29
+ :session_key => session_key,
30
+ :format => "JSON"
31
+ }
32
+ end
33
+ let(:form_params) do
34
+ signature_calculator = RenrenAPI::SignatureCalculator.new(secret_key)
35
+ signature = signature_calculator.calculate(params)
36
+ URI.encode_www_form(params.merge(:sig => signature))
37
+ end
38
+ before :each do
39
+ Time.stub(:now).and_return(now)
40
+ response = mock(Net::HTTPResponse)
41
+ gzip_writer = Zlib::GzipWriter.new(StringIO.new(buffer = ""))
42
+ gzip_writer << JSON.generate(result)
43
+ gzip_writer.close
44
+ response.stub(:code => '200', :message => "OK", :content_type => "application/json", :body => buffer)
45
+ http.should_receive(:post).with("/restserver.do", form_params, {"Accept-Encoding" => "gzip"}).once.and_return(response)
46
+ end
47
+ it { should == result }
48
+ end
49
+
50
+ describe RenrenAPI::HTTPAdapter, "#get_info" do
51
+ subject { described_class.new(http, api_key, secret_key, session_key).get_info(uids, fields) }
52
+ let(:http) { Net::HTTP.new("api.renren.com") }
53
+ let(:api_key) { "8802f8e9b2cf4eb993e8c8adb1e02b06" }
54
+ let(:secret_key) { "34d3d1e26cd44c05a0c450c0a0f8147b" }
55
+ let(:session_key) { "session_key" }
56
+ let(:result) do
57
+ [
58
+ {"uid" => 12345, "name" => "Levin", "tinyurl" => "http://renren.com/1.jpg"},
59
+ {"uid" => 12346, "name" => "James", "tinyurl" => "http://renren.com/2.jpg"}
60
+ ]
61
+ end
62
+ let!(:now) do
63
+ Time.now
64
+ end
65
+ let(:fields) do
66
+ %w{uid name tinyurl}
67
+ end
68
+ let(:uids) do
69
+ [12345, 12346]
70
+ end
71
+ let(:params) do
72
+ {
73
+ :api_key => api_key,
74
+ :method => "users.getInfo",
75
+ :call_id => "%.3f" % now.to_f,
76
+ :v => "1.0",
77
+ :session_key => session_key,
78
+ :fields => fields * ",",
79
+ :uids => uids * ",",
80
+ :format => "JSON"
81
+ }
82
+ end
83
+ let(:form_params) do
84
+ signature_calculator = RenrenAPI::SignatureCalculator.new(secret_key)
85
+ signature = signature_calculator.calculate(params)
86
+ URI.encode_www_form(params.merge(:sig => signature))
87
+ end
88
+ before :each do
89
+ Time.stub(:now).and_return(now)
90
+ response = mock(Net::HTTPResponse)
91
+ gzip_writer = Zlib::GzipWriter.new(StringIO.new(buffer = ""))
92
+ gzip_writer << JSON.generate(result)
93
+ gzip_writer.close
94
+ response.stub(:code => '200', :message => "OK", :content_type => "application/json", :body => buffer)
95
+ http.should_receive(:post).with("/restserver.do", form_params, {"Accept-Encoding" => "gzip"}).once.and_return(response)
96
+ end
97
+ it { should == result }
98
+ end
@@ -0,0 +1,22 @@
1
+ require_relative "../lib/renren-api/signature_calculator"
2
+
3
+ describe RenrenAPI::SignatureCalculator do
4
+ let(:calculator) { RenrenAPI::SignatureCalculator.new(secret_key) }
5
+ describe "#calculate" do
6
+ subject { calculator.calculate(hash) }
7
+ context "when secret_key is 7fbf9791036749cb82e74efd62e9eb38" do
8
+ let(:secret_key) { "7fbf9791036749cb82e74efd62e9eb38" }
9
+ example_hash = {
10
+ "v" => "1.0",
11
+ "api_key" => "ec9e57913c5b42b282ab7b743559e1b0",
12
+ "method" => "xiaonei.users.getLoggedInUser",
13
+ "call_id" => 1232095295656,
14
+ "session_key" => "L6Xe8dXVGISZ17LJy7GzZaeYGpeGfeNdqEPLNUtCJfxPCxCRLWT83x+s/Ur94PqP-700001044"
15
+ }
16
+ context "when hash is #{example_hash.inspect}" do
17
+ let(:hash) { example_hash }
18
+ it { should == "66f332c08191b8a5dd3477d36f3af49f" }
19
+ end
20
+ end
21
+ end
22
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: renren-api
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.3.3
6
+ platform: ruby
7
+ authors:
8
+ - Lei, Zhi-Qiang
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-30 00:00:00 +08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: " renren-api provides capability to request the service of Renren Social Network.\n"
18
+ email: zhiqiang.lei@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - README
25
+ files:
26
+ - lib/renren-api/authentication.rb
27
+ - lib/renren-api/http_adapter.rb
28
+ - lib/renren-api/signature_calculator.rb
29
+ - lib/renren-api.rb
30
+ - spec/authentication_spec.rb
31
+ - spec/helpers.rb
32
+ - spec/http_adapter_spec.rb
33
+ - spec/signature_calculator_spec.rb
34
+ - README
35
+ has_rdoc: true
36
+ homepage: https://github.com/siegfried/renren-api
37
+ licenses:
38
+ - BSD
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.9.2
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ requirements: []
57
+
58
+ rubyforge_project:
59
+ rubygems_version: 1.5.0
60
+ signing_key:
61
+ specification_version: 3
62
+ summary: a library to request Renren's API
63
+ test_files:
64
+ - spec/authentication_spec.rb
65
+ - spec/http_adapter_spec.rb
66
+ - spec/signature_calculator_spec.rb