guestlist 0.0.1
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.textile +48 -0
- data/lib/guestlist.rb +28 -0
- data/lib/guestlist/github.rb +26 -0
- data/spec/guestlist/github_spec.rb +65 -0
- data/spec/guestlist_spec.rb +114 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/stubs/github_200.xml +28 -0
- metadata +80 -0
data/README.textile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
h1. Guestlist
|
2
|
+
|
3
|
+
Simple authentication using Github credentials.
|
4
|
+
|
5
|
+
h2. Installation
|
6
|
+
|
7
|
+
The installation is really simple, just throw this in your @Gemfile@:
|
8
|
+
|
9
|
+
bc. gem 'guestlist'
|
10
|
+
|
11
|
+
And run:
|
12
|
+
|
13
|
+
bc. bundle install
|
14
|
+
|
15
|
+
Or -- if you're using Rails 2.x -- put this in @config/environment.rb@:
|
16
|
+
|
17
|
+
bc. config.gem 'guestlist'
|
18
|
+
|
19
|
+
And run:
|
20
|
+
|
21
|
+
bc. rake gems:install
|
22
|
+
|
23
|
+
Include @Guestlist@ in your user model (mine is called @User@):
|
24
|
+
|
25
|
+
<pre><code>class User
|
26
|
+
# It works with ActiveRecord too. ;)
|
27
|
+
include MongoMapper::Document
|
28
|
+
include Guestlist
|
29
|
+
|
30
|
+
key :login, String
|
31
|
+
key :encrypted_token, String
|
32
|
+
end</code></pre>
|
33
|
+
|
34
|
+
Make sure you have both @login@ and @encrypted_token@ fields in your database if you're using ActiveRecord ("here's a migration":http://gist.github.com/369610), or add some <code>key</code>s to your "MongoMapper":mongomapper.com/ model like in the example above.
|
35
|
+
|
36
|
+
Believe it or not, you're all set. Let's try it (you can find your token on the "Github account page":https://github.com/account):
|
37
|
+
|
38
|
+
bc. User.authenticate 'github_login', 'github_token'
|
39
|
+
|
40
|
+
Guestlist will automatically create a new @User@ for you and return that, or false if you've entered a wrong login or token. The user's token is stored -- yes, encrypted -- , so next time you log in, it'll just authenticate you via the database.
|
41
|
+
|
42
|
+
h2. Contributing
|
43
|
+
|
44
|
+
Found any issues? Have a great idea? Want to help? Great! Create an issue "issue":http://github.com/jeffkreeftmeijer/guestlist/issues for it, or even better; "fork the project":http://github.com/jeffkreeftmeijer/guestlist/fork. Pull requests are always welcome. :)
|
45
|
+
|
46
|
+
h2. License
|
47
|
+
|
48
|
+
Copyright (c) 2009 Jeff Kreeftmeijer, released under the MIT license
|
data/lib/guestlist.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'guestlist/github'
|
2
|
+
|
3
|
+
module Guestlist
|
4
|
+
module ClassMethods
|
5
|
+
def authenticate(login, token)
|
6
|
+
attributes = {:login => login, :encrypted_token => encrypt(token)}
|
7
|
+
|
8
|
+
if user = find_by_login(login)
|
9
|
+
return user if user.encrypted_token == attributes[:encrypted_token]
|
10
|
+
end
|
11
|
+
|
12
|
+
if Github.fetch(login, token)
|
13
|
+
user.update_attributes(attributes) if user
|
14
|
+
user || User.create!(attributes)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def encrypt(string)
|
21
|
+
Digest::SHA1.hexdigest(string)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.included(base)
|
26
|
+
base.extend(ClassMethods)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
module Guestlist
|
5
|
+
class Github
|
6
|
+
class StatusError < StandardError; end
|
7
|
+
|
8
|
+
def self.fetch(login, token)
|
9
|
+
response = HTTParty.post(
|
10
|
+
"http://github.com/api/v2/json/user/show/#{login}",
|
11
|
+
{
|
12
|
+
:query => {
|
13
|
+
:login => login,
|
14
|
+
:token => token
|
15
|
+
}
|
16
|
+
}
|
17
|
+
)
|
18
|
+
|
19
|
+
case response.code
|
20
|
+
when 200; response
|
21
|
+
when 401; false
|
22
|
+
else; raise StatusError, response.code
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Guestlist::Github do
|
4
|
+
describe '.fetch' do
|
5
|
+
before do
|
6
|
+
@ok = File.read(
|
7
|
+
File.expand_path(
|
8
|
+
File.dirname(__FILE__) + '/../stubs/github_200.xml'
|
9
|
+
)
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should call to Github via HTTParty' do
|
14
|
+
HTTParty.should_receive(:post).with(
|
15
|
+
'http://github.com/api/v2/json/user/show/login',
|
16
|
+
:query => {
|
17
|
+
:login => 'login',
|
18
|
+
:token => 't0k3n'
|
19
|
+
}
|
20
|
+
).and_return(
|
21
|
+
HTTParty::Response.new(
|
22
|
+
Crack::JSON.parse(@ok), @ok, 200, 'message'
|
23
|
+
)
|
24
|
+
)
|
25
|
+
|
26
|
+
Guestlist::Github.fetch('login', 't0k3n')
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should return a hash with user data' do
|
30
|
+
HTTParty.stub!(:post).and_return(
|
31
|
+
HTTParty::Response.new(
|
32
|
+
Crack::JSON.parse(@ok), @ok, 200, 'message'
|
33
|
+
)
|
34
|
+
)
|
35
|
+
|
36
|
+
result = Guestlist::Github.fetch('login', 't0k3n')
|
37
|
+
result.should be_instance_of Hash
|
38
|
+
result.length.should == 1
|
39
|
+
result['user']['name'].should == 'Bob'
|
40
|
+
result['user']['blog'].should == 'http://bobsblog.com'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should return false when authentication fails' do
|
44
|
+
HTTParty.stub!(:post).and_return(
|
45
|
+
HTTParty::Response.new(
|
46
|
+
{}, '', 401, 'message'
|
47
|
+
)
|
48
|
+
)
|
49
|
+
|
50
|
+
Guestlist::Github.fetch('wronglogin', 't3k0n').should == false
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should raise an error when anything else happens' do
|
54
|
+
HTTParty.stub!(:post).and_return(
|
55
|
+
HTTParty::Response.new(
|
56
|
+
{}, '', 500, 'message'
|
57
|
+
)
|
58
|
+
)
|
59
|
+
|
60
|
+
lambda {
|
61
|
+
Guestlist::Github.fetch('login', 't0k3n')
|
62
|
+
}.should raise_error(Guestlist::Github::StatusError, 500)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Guestlist do
|
4
|
+
before do
|
5
|
+
@github_200 = Crack::JSON.parse(
|
6
|
+
File.read(
|
7
|
+
File.expand_path(
|
8
|
+
File.dirname(__FILE__) + '/stubs/github_200.xml'
|
9
|
+
)
|
10
|
+
)
|
11
|
+
)
|
12
|
+
end
|
13
|
+
describe '#authenticate' do
|
14
|
+
it 'should call find with the login' do
|
15
|
+
User.should_receive(:find_by_login).with('login')
|
16
|
+
User.authenticate('login', 'token')
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'when authenticating an existing user' do
|
20
|
+
describe 'with the correct token' do
|
21
|
+
it 'should return the user' do
|
22
|
+
User.authenticate('exists', 'token').should be_instance_of User
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should not try to fetch the user' do
|
26
|
+
Guestlist::Github.should_not_receive(:fetch)
|
27
|
+
User.authenticate('exists', 'token')
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should not create a new user' do
|
31
|
+
User.should_not_receive(:create!)
|
32
|
+
User.authenticate('exists', 'token')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'with an incorrect token' do
|
37
|
+
it 'should not return the user' do
|
38
|
+
User.authenticate('exists', 'wrongtoken').should == nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should try to fetch the user' do
|
42
|
+
Guestlist::Github.should_receive(:fetch).with('exists', 'wrongtoken')
|
43
|
+
User.authenticate('exists', 'wrongtoken')
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'that seems to be correct after all' do
|
47
|
+
before do
|
48
|
+
Guestlist::Github.stub!(:fetch).and_return(@github_200)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should return the user' do
|
52
|
+
User.authenticate('exists', 'newtoken').should be_instance_of User
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should not create a new user' do
|
56
|
+
User.should_not_receive(:create!)
|
57
|
+
User.authenticate('exists', 'newtoken')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should update the user token' do
|
61
|
+
user = User.new
|
62
|
+
User.stub(:find_by_login).and_return(user)
|
63
|
+
user.should_receive(:update_attributes).with({
|
64
|
+
:login => 'exists',
|
65
|
+
:encrypted_token => Digest::SHA1.hexdigest('newtoken')
|
66
|
+
})
|
67
|
+
@user = User.authenticate('exists', 'newtoken')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'when authenticating a user that does not exist yet' do
|
74
|
+
before do
|
75
|
+
User.stub(:find_by_login).and_return(nil)
|
76
|
+
Guestlist::Github.stub!(:fetch).and_return(@github_200)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should try to fetch the user' do
|
80
|
+
Guestlist::Github.should_receive(:fetch).with('doesnt_exist_yet', 'token')
|
81
|
+
User.authenticate('doesnt_exist_yet', 'token')
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should create a new user' do
|
85
|
+
User.should_receive(:create!).with({
|
86
|
+
:login => 'doesnt_exist_yet',
|
87
|
+
:encrypted_token => Digest::SHA1.hexdigest('token')
|
88
|
+
})
|
89
|
+
User.authenticate('doesnt_exist_yet', 'token')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'when authenticating a user that does not exist' do
|
94
|
+
before do
|
95
|
+
User.stub(:find_by_login).and_return(nil)
|
96
|
+
Guestlist::Github.stub!(:fetch).and_return(false)
|
97
|
+
end
|
98
|
+
it 'should return nil' do
|
99
|
+
User.should_receive(:find_by_login).and_return(nil)
|
100
|
+
User.authenticate('doesnt_exist', 'token').should == nil
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should try to fetch the user' do
|
104
|
+
Guestlist::Github.should_receive(:fetch).with('doesnt_exist', 'token')
|
105
|
+
User.authenticate('doesnt_exist', 'token')
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should not create a new user' do
|
109
|
+
User.should_not_receive(:create!)
|
110
|
+
User.authenticate('doesnt_exist', 'token')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'guestlist'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
|
7
|
+
require 'crack'
|
8
|
+
|
9
|
+
Spec::Runner.configure do |config|
|
10
|
+
end
|
11
|
+
|
12
|
+
class User
|
13
|
+
include Guestlist
|
14
|
+
|
15
|
+
def self.find_by_login(*args)
|
16
|
+
return new
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.create!(*args)
|
20
|
+
return new
|
21
|
+
end
|
22
|
+
|
23
|
+
def encrypted_token
|
24
|
+
Digest::SHA1.hexdigest('token')
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_attributes(*args)
|
28
|
+
return true
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
{
|
2
|
+
"user": {
|
3
|
+
"plan": {
|
4
|
+
"name":"free",
|
5
|
+
"collaborators":0,
|
6
|
+
"space":307200,
|
7
|
+
"private_repos":0
|
8
|
+
},
|
9
|
+
"gravatar_id":"f03f4ce7b507aede346263d218228b6a",
|
10
|
+
"name":"Bob",
|
11
|
+
"company":"c0mp4ny",
|
12
|
+
"location":"l0c4ti0n",
|
13
|
+
"created_at":"2009/01/01 07:26:12 -0800",
|
14
|
+
"collaborators":0,
|
15
|
+
"disk_usage":21900,
|
16
|
+
"public_gist_count":24,
|
17
|
+
"public_repo_count":15,
|
18
|
+
"blog":"http://bobsblog.com",
|
19
|
+
"following_count":12,
|
20
|
+
"id":43621,
|
21
|
+
"private_gist_count":5,
|
22
|
+
"owned_private_repo_count":0,
|
23
|
+
"total_private_repo_count":0,
|
24
|
+
"followers_count":14,
|
25
|
+
"login":"login",
|
26
|
+
"email":"bob@email.com"
|
27
|
+
}
|
28
|
+
}
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: guestlist
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Kreeftmeijer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-04-18 00:00:00 +02:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: httparty
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.5.2
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.0
|
34
|
+
version:
|
35
|
+
description: Simple authentication using Github credentials.
|
36
|
+
email: jeff@kreeftmeijer.nl
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
files:
|
44
|
+
- lib/guestlist/github.rb
|
45
|
+
- lib/guestlist.rb
|
46
|
+
- spec/guestlist/github_spec.rb
|
47
|
+
- spec/guestlist_spec.rb
|
48
|
+
- spec/spec_helper.rb
|
49
|
+
- spec/stubs/github_200.xml
|
50
|
+
- README.textile
|
51
|
+
has_rdoc: true
|
52
|
+
homepage: http://github.com/jeffkreeftmeijer/guestlist
|
53
|
+
licenses: []
|
54
|
+
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: "0"
|
65
|
+
version:
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
requirements: []
|
73
|
+
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 1.3.5
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Simple authentication using Github credentials.
|
79
|
+
test_files: []
|
80
|
+
|