guestlist 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -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
+