grosser-rpx_now 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +1 -0
- data/README.markdown +24 -3
- data/Rakefile +1 -1
- data/lib/rpx_now.rb +43 -6
- data/rpx_now.gemspec +4 -4
- data/spec/rpx_now_spec.rb +135 -0
- data/spec/spec_helper.rb +36 -0
- metadata +7 -3
data/CHANGELOG
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3 -- RPXNow::ServerError will be thrown when something is invalid/goes wrong, so watch out (not for invalid tokens in user_data)...
|
data/README.markdown
CHANGED
@@ -36,7 +36,7 @@ Controller
|
|
36
36
|
----------
|
37
37
|
# simple: use defaults
|
38
38
|
def rpx_token
|
39
|
-
data =
|
39
|
+
data = RPXNow.user_data(params[:token],'YOUR RPX API KEY') # :name=>'John Doe',:email=>'john@doe.com',:identifier=>'blug.google.com/openid/dsdfsdfs3f3'
|
40
40
|
#when no user_data was found, data is empty, you may want to handle that seperatly...
|
41
41
|
#your user model must have an identifier column
|
42
42
|
self.current_user = User.find_by_identifier(data[:identifier]) || User.create!(data)
|
@@ -44,10 +44,31 @@ Controller
|
|
44
44
|
end
|
45
45
|
|
46
46
|
# process the raw response yourself:
|
47
|
-
|
47
|
+
RPXNow.user_data(params[:token],'YOUR RPX API KEY'){|raw| {:email=>raw['profile']['verifiedEmail']}}
|
48
48
|
|
49
49
|
# request extended parameters (most users and APIs do not supply them)
|
50
|
-
|
50
|
+
RPXNow.user_data(params[:token],'YOUR RPX API KEY',:extended=>'true'){|raw| ...have a look at the RPX API DOCS...}
|
51
|
+
|
52
|
+
Advanced: Mappings
|
53
|
+
------------------
|
54
|
+
You can map your primary keys (e.g. user.id) to identifiers, so that
|
55
|
+
users can login to the same account with multiple identifiers.
|
56
|
+
#add a mapping
|
57
|
+
RPXNow.map(identifier,primary_key,'YOUR RPX API KEY')
|
58
|
+
|
59
|
+
#remove a mapping
|
60
|
+
RPXNow.unmap(identifier,primary_key,'YOUR RPX API KEY')
|
61
|
+
|
62
|
+
#show mappings
|
63
|
+
RPXNow.mappings(primary_key,'YOUR RPX API KEY') # [identifier1,identifier2,...]
|
64
|
+
|
65
|
+
After a primary key is mapped to an identifier, when a user logs in with this identifier,
|
66
|
+
`RPXNow.user_data` will contain his `primaryKey` as `:id`.
|
67
|
+
|
68
|
+
TODO
|
69
|
+
====
|
70
|
+
- remove activesupport dependency, use something smaller (json gem looks good but: JSON.parse("{x:1}")==BOOM)
|
71
|
+
- validate RPXNow.com SSL certificate
|
51
72
|
|
52
73
|
Author
|
53
74
|
======
|
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ end
|
|
10
10
|
|
11
11
|
#Gemspec
|
12
12
|
porject_name = 'rpx_now'
|
13
|
-
Echoe.new(porject_name , '0.
|
13
|
+
Echoe.new(porject_name , '0.3') do |p|
|
14
14
|
p.description = "Helper to simplify RPX Now user login/creation"
|
15
15
|
p.url = "http://github.com/grosser/#{porject_name}"
|
16
16
|
p.author = "Michael Grosser"
|
data/lib/rpx_now.rb
CHANGED
@@ -1,14 +1,34 @@
|
|
1
1
|
require 'activesupport'
|
2
2
|
module RPXNow
|
3
3
|
extend self
|
4
|
+
|
5
|
+
# retrieve the users data, or return nil when nothing could be read/token was invalid or data was not found
|
4
6
|
def user_data(token,api_key,parameters={})
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
7
|
+
begin
|
8
|
+
data = secure_json_post('https://rpxnow.com/api/v2/auth_info',{:token=>token,:apiKey=>api_key}.merge(parameters))
|
9
|
+
rescue ServerError
|
10
|
+
return nil if $!.to_s =~ /token/ or $!.to_s=~/Data not found/
|
11
|
+
raise
|
12
|
+
end
|
9
13
|
if block_given? then yield(data) else read_user_data_from_response(data) end
|
10
14
|
end
|
11
15
|
|
16
|
+
# maps an identifier to an primary-key (e.g. user.id)
|
17
|
+
def map(identifier,primary_key,api_key,options={})
|
18
|
+
secure_json_post('https://rpxnow.com/api/v2/map',{:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key}.merge(options))
|
19
|
+
end
|
20
|
+
|
21
|
+
# un-maps an identifier to an primary-key (e.g. user.id)
|
22
|
+
def unmap(identifier,primary_key,api_key)
|
23
|
+
secure_json_post('https://rpxnow.com/api/v2/unmap',{:identifier=>identifier,:primaryKey=>primary_key,:apiKey=>api_key})
|
24
|
+
end
|
25
|
+
|
26
|
+
# returns an array of identifiers which are mapped to one of your primary-keys (e.g. user.id)
|
27
|
+
def mappings(primary_key,api_key)
|
28
|
+
data = secure_json_post('https://rpxnow.com/api/v2/mappings',{:primaryKey=>primary_key,:apiKey=>api_key})
|
29
|
+
data['identifiers']
|
30
|
+
end
|
31
|
+
|
12
32
|
def embed_code(subdomain,url)
|
13
33
|
<<EOF
|
14
34
|
<iframe src="https://#{subdomain}.rpxnow.com/openid/embed?token_url=#{url}"
|
@@ -19,7 +39,7 @@ EOF
|
|
19
39
|
|
20
40
|
def popup_code(text,subdomain,url,options={})
|
21
41
|
<<EOF
|
22
|
-
<a class="rpxnow" onclick="return false;" href="https
|
42
|
+
<a class="rpxnow" onclick="return false;" href="https://#{subdomain}.rpxnow.com/openid/v2/signin?token_url=#{url}">
|
23
43
|
#{text}
|
24
44
|
</a>
|
25
45
|
<script src="https://rpxnow.com/openid/v2/widget" type="text/javascript"></script>
|
@@ -43,6 +63,14 @@ private
|
|
43
63
|
data[:identifier] = user_data['identifier']
|
44
64
|
data[:email] = user_data['verifiedEmail'] || user_data['email']
|
45
65
|
data[:name] = user_data['displayName'] || user_data['preferredUsername'] || data[:email].sub(/@.*/,'')
|
66
|
+
data[:id] = user_data['primaryKey'].to_i unless user_data['primaryKey'].to_s.empty?
|
67
|
+
data
|
68
|
+
end
|
69
|
+
|
70
|
+
def secure_json_post(url,data={})
|
71
|
+
data = ActiveSupport::JSON.decode(post(url,data))
|
72
|
+
raise ServerError.new(data['err']) if data['err']
|
73
|
+
raise ServerError.new(data.inspect) unless data['stat']=='ok'
|
46
74
|
data
|
47
75
|
end
|
48
76
|
|
@@ -53,9 +81,18 @@ private
|
|
53
81
|
if url.scheme == 'https'
|
54
82
|
require 'net/https'
|
55
83
|
http.use_ssl = true
|
84
|
+
#TODO do we really want to verify the certificate? http://notetoself.vrensk.com/2008/09/verified-https-in-ruby/
|
85
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
56
86
|
end
|
57
87
|
resp, data = http.post(url.path, data.to_query)
|
58
88
|
raise "POST FAILED:"+resp.inspect unless resp.is_a? Net::HTTPOK
|
59
|
-
|
89
|
+
data
|
90
|
+
end
|
91
|
+
|
92
|
+
class ServerError < Exception
|
93
|
+
#to_s returns message(which is a hash...)
|
94
|
+
def to_s
|
95
|
+
super.to_s
|
96
|
+
end
|
60
97
|
end
|
61
98
|
end
|
data/rpx_now.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{rpx_now}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.3"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Michael Grosser"]
|
9
|
-
s.date = %q{2009-01-
|
9
|
+
s.date = %q{2009-01-28}
|
10
10
|
s.description = %q{Helper to simplify RPX Now user login/creation}
|
11
11
|
s.email = %q{grosser.michael@gmail.com}
|
12
|
-
s.extra_rdoc_files = ["lib/rpx_now.rb", "README.markdown"]
|
13
|
-
s.files = ["Manifest", "lib/rpx_now.rb", "
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/rpx_now.rb", "README.markdown"]
|
13
|
+
s.files = ["Manifest", "CHANGELOG", "lib/rpx_now.rb", "spec/rpx_now_spec.rb", "spec/spec_helper.rb", "rpx_now.gemspec", "init.rb", "Rakefile", "README.markdown"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://github.com/grosser/rpx_now}
|
16
16
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rpx_now", "--main", "README.markdown"]
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require File.expand_path("spec_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
API_KEY = '4b339169026742245b754fa338b9b0aebbd0a733'
|
4
|
+
|
5
|
+
describe RPXNow do
|
6
|
+
describe :embed_code do
|
7
|
+
it "contains the subdomain" do
|
8
|
+
RPXNow.embed_code('xxx','my_url').should =~ /xxx/
|
9
|
+
end
|
10
|
+
it "contains the url" do
|
11
|
+
RPXNow.embed_code('xxx','my_url').should =~ /token_url=my_url/
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe :popup_code do
|
16
|
+
it "defaults to english" do
|
17
|
+
RPXNow.popup_code('x','y','z').should =~ /RPXNOW.language_preference = 'en'/
|
18
|
+
end
|
19
|
+
it "has a changeable language" do
|
20
|
+
RPXNow.popup_code('x','y','z',:language=>'de').should =~ /RPXNOW.language_preference = 'de'/
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe :user_data do
|
25
|
+
def fake_response
|
26
|
+
'{"profile":{"verifiedEmail":"grosser.michael@googlemail.com","displayName":"Michael Grosser","preferredUsername":"grosser.michael","identifier":"https:\/\/www.google.com\/accounts\/o8\/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM","email":"grosser.michael@gmail.com"},"stat":"ok"}'
|
27
|
+
end
|
28
|
+
it "is empty when used with an invalid token" do
|
29
|
+
RPXNow.user_data('xxxx',API_KEY).should == nil
|
30
|
+
end
|
31
|
+
it "is empty when used with an unknown token" do
|
32
|
+
RPXNow.user_data('60d8c6374f4e9d290a7b55f39da7cc6435aef3d3',API_KEY).should == nil
|
33
|
+
end
|
34
|
+
it "parses JSON response to user data" do
|
35
|
+
RPXNow.expects(:post).returns fake_response
|
36
|
+
RPXNow.user_data('','x').should == {:name=>'Michael Grosser',:email=>'grosser.michael@googlemail.com',:identifier=>"https://www.google.com/accounts/o8/id?id=AItOawmaOlyYezg_WfbgP_qjaUyHjmqZD9qNIVM"}
|
37
|
+
end
|
38
|
+
it "adds a :id when primaryKey was returned" do
|
39
|
+
RPXNow.expects(:post).returns fake_response.sub('"verifiedEmail"','primaryKey:"2","verifiedEmail"')
|
40
|
+
RPXNow.user_data('','x')[:id].should == 2
|
41
|
+
end
|
42
|
+
it "hands JSON response to supplied block" do
|
43
|
+
RPXNow.expects(:post).returns "{x:1,stat:'ok'}"
|
44
|
+
response = nil
|
45
|
+
RPXNow.user_data('','x'){|data| response = data}
|
46
|
+
response.should == {'x'=>1,'stat'=>'ok'}
|
47
|
+
end
|
48
|
+
it "returns what the supplied block returned" do
|
49
|
+
RPXNow.expects(:post).returns "{x:1,stat:'ok'}"
|
50
|
+
RPXNow.user_data('','x'){|data| "x"}.should == 'x'
|
51
|
+
end
|
52
|
+
it "can send additional parameters" do
|
53
|
+
RPXNow.expects(:post).with{|url,data|
|
54
|
+
data[:extended].should == 'true'
|
55
|
+
}.returns fake_response
|
56
|
+
RPXNow.user_data('','x',:extended=>'true')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe :read_user_data_from_response do
|
61
|
+
it "reads secondary names" do
|
62
|
+
RPXNow.send(:read_user_data_from_response,{'profile'=>{'preferredUsername'=>'1'}})[:name].should == '1'
|
63
|
+
end
|
64
|
+
it "parses email when no name is found" do
|
65
|
+
RPXNow.send(:read_user_data_from_response,{'profile'=>{'email'=>'1@xxx.com'}})[:name].should == '1'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe :secure_json_post do
|
70
|
+
it "parses json when status is ok" do
|
71
|
+
RPXNow.expects(:post).returns '{stat:"ok",data:"xx"}'
|
72
|
+
RPXNow.send(:secure_json_post,'xx')['data'].should == 'xx'
|
73
|
+
end
|
74
|
+
it "raises when there is a communication error" do
|
75
|
+
RPXNow.expects(:post).returns '{"err":"wtf",stat:"ok"}'
|
76
|
+
lambda{RPXNow.send(:secure_json_post,'xx')}.should raise_error RPXNow::ServerError
|
77
|
+
end
|
78
|
+
it "raises when status is not ok" do
|
79
|
+
RPXNow.expects(:post).returns '{"stat":"err"}'
|
80
|
+
lambda{RPXNow.send(:secure_json_post,'xx')}.should raise_error RPXNow::ServerError
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe :mappings do
|
85
|
+
it "parses JSON response to unmap data" do
|
86
|
+
RPXNow.expects(:post).returns '{"stat":"ok", "identifiers": ["http://test.myopenid.com/"]}'
|
87
|
+
RPXNow.mappings(1, "x").should == ["http://test.myopenid.com/"]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe :map do
|
92
|
+
it "adds a mapping" do
|
93
|
+
RPXNow.expects(:post).returns '{"stat":"ok"}'
|
94
|
+
RPXNow.map('http://test.myopenid.com',1, API_KEY)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe :unmap do
|
99
|
+
it "unmaps a indentifier" do
|
100
|
+
RPXNow.expects(:post).returns '{"stat":"ok"}'
|
101
|
+
RPXNow.unmap('http://test.myopenid.com', 1, "x")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe :mapping_integration do
|
106
|
+
before do
|
107
|
+
@k1 = 'http://test.myopenid.com'
|
108
|
+
RPXNow.unmap(@k1, 1, API_KEY)
|
109
|
+
@k2 = 'http://test-2.myopenid.com'
|
110
|
+
RPXNow.unmap(@k2, 1, API_KEY)
|
111
|
+
end
|
112
|
+
|
113
|
+
it "has no mappings when nothing was mapped" do
|
114
|
+
RPXNow.mappings(1,API_KEY).should == []
|
115
|
+
end
|
116
|
+
|
117
|
+
it "unmaps mapped keys" do
|
118
|
+
RPXNow.map(@k2, 1, API_KEY)
|
119
|
+
RPXNow.unmap(@k2, 1, API_KEY)
|
120
|
+
RPXNow.mappings(1, API_KEY).should == []
|
121
|
+
end
|
122
|
+
|
123
|
+
it "maps keys to a primary key and then retrieves them" do
|
124
|
+
RPXNow.map(@k1, 1, API_KEY)
|
125
|
+
RPXNow.map(@k2, 1, API_KEY)
|
126
|
+
RPXNow.mappings(1,API_KEY).sort.should == [@k2,@k1]
|
127
|
+
end
|
128
|
+
|
129
|
+
it "does not add duplicate mappings" do
|
130
|
+
RPXNow.map(@k1, 1, API_KEY)
|
131
|
+
RPXNow.map(@k1, 1, API_KEY)
|
132
|
+
RPXNow.mappings(1,API_KEY).should == [@k1]
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# ---- requirements
|
2
|
+
require 'rubygems'
|
3
|
+
require 'spec'
|
4
|
+
require 'mocha'
|
5
|
+
|
6
|
+
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
|
7
|
+
|
8
|
+
|
9
|
+
# ---- rspec
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
config.mock_with :mocha
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
# ---- bugfix
|
16
|
+
#`exit?': undefined method `run?' for Test::Unit:Module (NoMethodError)
|
17
|
+
#can be solved with require test/unit but this will result in extra test-output
|
18
|
+
module Test
|
19
|
+
module Unit
|
20
|
+
def self.run?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# ---- setup environment/plugin
|
28
|
+
require File.expand_path("../init", File.dirname(__FILE__))
|
29
|
+
|
30
|
+
|
31
|
+
# ---- Helpers
|
32
|
+
def pending_it(text,&block)
|
33
|
+
it text do
|
34
|
+
pending(&block)
|
35
|
+
end
|
36
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grosser-rpx_now
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.3"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-01-
|
12
|
+
date: 2009-01-28 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -37,15 +37,19 @@ executables: []
|
|
37
37
|
extensions: []
|
38
38
|
|
39
39
|
extra_rdoc_files:
|
40
|
+
- CHANGELOG
|
40
41
|
- lib/rpx_now.rb
|
41
42
|
- README.markdown
|
42
43
|
files:
|
43
44
|
- Manifest
|
45
|
+
- CHANGELOG
|
44
46
|
- lib/rpx_now.rb
|
47
|
+
- spec/rpx_now_spec.rb
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
- rpx_now.gemspec
|
45
50
|
- init.rb
|
46
51
|
- Rakefile
|
47
52
|
- README.markdown
|
48
|
-
- rpx_now.gemspec
|
49
53
|
has_rdoc: true
|
50
54
|
homepage: http://github.com/grosser/rpx_now
|
51
55
|
post_install_message:
|